1 /*
2  * Copyright Samsung Electronics Co.,LTD.
3  * Copyright (C) 2015 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include "AppMarkerWriter.h"
19 
20 #include "IFDWriter.h"
21 #include "hwjpeg-internal.h"
22 
23 static const char ExifAsciiPrefix[] = {'A', 'S', 'C', 'I', 'I', 0x0, 0x0, 0x0};
24 static const char ExifIdentifierCode[6] = {'E', 'x', 'i', 'f', 0x00, 0x00};
25 static char TiffHeader[8] = {'I', 'I', 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00};
26 static const unsigned char ComponentsConfiguration[4] = {1, 2, 3, 0}; // YCbCr
27 static const unsigned char SceneType[4] = {1, 0, 0, 0}; // A directly photographed image
28 
29 #ifndef __LITTLE_ENDIAN__
30 CEndianessChecker __LITTLE_ENDIAN__;
31 #endif
32 
CEndianessChecker()33 CEndianessChecker::CEndianessChecker() {
34     int num = 1;
35     __little = (*reinterpret_cast<char *>(&num) == 1);
36     if (__little) {
37         TiffHeader[0] = 'I';
38         TiffHeader[1] = 'I';
39     } else {
40         TiffHeader[0] = 'M';
41         TiffHeader[1] = 'M';
42     }
43 }
44 
CAppMarkerWriter()45 CAppMarkerWriter::CAppMarkerWriter()
46       : m_pAppBase(NULL), m_pApp1End(NULL), m_pExif(NULL), m_pExtra(NULL) {
47     Init();
48 }
49 
CAppMarkerWriter(char * base,exif_attribute_t * exif,debug_attribute_t * debug)50 CAppMarkerWriter::CAppMarkerWriter(char *base, exif_attribute_t *exif, debug_attribute_t *debug) {
51     extra_appinfo_t extraInfo;
52     app_info_t appInfo[15];
53 
54     memset(&extraInfo, 0, sizeof(extraInfo));
55     memset(&appInfo, 0, sizeof(appInfo));
56 
57     extraInfo.appInfo = appInfo;
58 
59     ExtractDebugAttributeInfo(debug, &extraInfo);
60 
61     PrepareAppWriter(base, exif, &extraInfo);
62 }
63 
Init()64 void CAppMarkerWriter::Init() {
65     m_pApp1End = NULL;
66 
67     m_szApp1 = 0;
68 
69     m_n0thIFDFields = 0;
70     m_n1stIFDFields = 0;
71     m_nExifIFDFields = 0;
72     m_nGPSIFDFields = 0;
73 
74     m_szMake = 0;
75     m_szSoftware = 0;
76     m_szModel = 0;
77     m_szUniqueID = 0;
78 
79     m_pThumbBase = NULL;
80     m_szMaxThumbSize = 0;
81     m_pThumbSizePlaceholder = NULL;
82 }
83 
PrepareAppWriter(char * base,exif_attribute_t * exif,extra_appinfo_t * extra)84 void CAppMarkerWriter::PrepareAppWriter(char *base, exif_attribute_t *exif,
85                                         extra_appinfo_t *extra) {
86     m_pAppBase = base;
87     m_pExif = exif;
88 
89     Init();
90 
91     size_t applen = 0;
92 
93     if (exif) {
94         // APP1
95         applen += JPEG_SEGMENT_LENFIELD_SIZE + ARRSIZE(ExifIdentifierCode) + ARRSIZE(TiffHeader);
96 
97         // 0th IFD: Make, Model, Orientation, Software,
98         //          DateTime, YCbCrPositioning, X/Y Resolutions, Exif and GPS
99         applen += IFD_FIELDCOUNT_SIZE + IFD_VALOFF_SIZE;
100         // Orientation, YCbCrPos, XYRes/Unit, DateTime and Exif
101         m_n0thIFDFields = 7;
102         applen += IFD_FIELD_SIZE * m_n0thIFDFields;
103         applen += sizeof(rational_t) * 2; // values of XResolution and YResolution
104         applen += EXIF_DATETIME_LENGTH;
105 
106         m_szMake = strlen(m_pExif->maker);
107         if (m_szMake > 0) {
108             m_n0thIFDFields++;
109             applen += IFD_FIELD_SIZE;
110             if (m_szMake > 3) applen += m_szMake + 1;
111         }
112 
113         m_szSoftware = strlen(m_pExif->software);
114         if (m_szSoftware > 0) {
115             m_n0thIFDFields++;
116             applen += IFD_FIELD_SIZE;
117             if (m_szSoftware > 3) applen += m_szSoftware + 1;
118         }
119 
120         m_szModel = strlen(m_pExif->model);
121         if (m_szModel > 0) {
122             m_n0thIFDFields++;
123             applen += IFD_FIELD_SIZE;
124             if (m_szModel > 3) applen += m_szModel + 1;
125         }
126 
127         if (m_pExif->enableGps) {
128             m_n0thIFDFields++;
129             applen += IFD_FIELD_SIZE;
130         }
131 
132         /*
133          * Exif SubIFD: 37 fields
134          * Fields with no data offset: 19
135          * - ExposureProgram, PhotographicSensitivity, ExifVersion, MeteringMode,
136          * - Flash, FlashPixVersion, ColorSpace, PixelXDimension, PixelYDimension,
137          * - ExposureMode, WhiteBalance, FocalLengthIn35mmFilm, SceneCaptureType,
138          * - ComponentsConfiguration
139          * - SceneType, CustomRendered, Contrast, Saturation, Sharpness
140          * (S)Rational Fields: 9
141          * - ExposureTime, FNumber, ShutterSpeedValue, ApertureValue,
142          * - BrightnessValue, ExposureBiasValue, MaxApertureValue, FocalLength
143          * - DigitalZoomRatio
144          * ASCII Fields: 6
145          * - DateTimeOriginal, DateTimeDigitized, SubsecTime, SubsecTimeOriginal,
146          * - SubsecTimeDigitized, ImageUniqueID
147          * Undefined Long Fields: 2
148          * - MakerNote, UserComment
149          * SubIFD: 1
150          * - Interoperability IFD
151          */
152         m_nExifIFDFields = 28; // rational fields and fields withouth data offset
153         applen += IFD_FIELDCOUNT_SIZE + IFD_VALOFF_SIZE;
154         applen += IFD_FIELD_SIZE * m_nExifIFDFields;
155         applen += sizeof(rational_t) * 9; // 9 rational values
156 
157         // DateTime*
158         m_nExifIFDFields += 2;
159         applen += (IFD_FIELD_SIZE + EXIF_DATETIME_LENGTH) * 2;
160 
161         // SubSecTime*
162         m_nExifIFDFields += 3;
163         applen += (IFD_FIELD_SIZE + EXIF_SUBSECTIME_LENGTH) * 3;
164 
165         m_szUniqueID = strlen(m_pExif->unique_id); // len should be 32!
166         if (m_szUniqueID > 0) {
167             m_nExifIFDFields++;
168             applen += IFD_FIELD_SIZE;
169             if (m_szUniqueID > 3) applen += m_szUniqueID + 1;
170         }
171 
172         if (m_pExif->maker_note_size > 0) {
173             m_nExifIFDFields++;
174             applen += IFD_FIELD_SIZE;
175             if (m_pExif->maker_note_size > 4) applen += m_pExif->maker_note_size;
176         }
177 
178         if (m_pExif->user_comment_size > 0) {
179             m_nExifIFDFields++;
180             applen += IFD_FIELD_SIZE;
181             if (m_pExif->user_comment_size > 4) applen += m_pExif->user_comment_size;
182         }
183 
184         // Interoperability SubIFD
185         m_nExifIFDFields++; // Interoperability is sub IFD of Exif sub IFD
186         applen += IFD_FIELD_SIZE + IFD_FIELDCOUNT_SIZE + IFD_VALOFF_SIZE + IFD_FIELD_SIZE * 2;
187 
188         if (m_pExif->enableGps) {
189             size_t len;
190             /*
191              * GPS SubIFD: 10 fields
192              * Fields with no data offset: 4
193              * - GPSVersionID, GPSLattitudeRef, GPSLongitudeRev, GPSAltitudeRef
194              * Rational Fields: 4 (total 10 rational values)
195              * - GPSLatitude(3), GPSLongitude(3), GPSAltitude(1), GPSTImeStamp(3)
196              * ASCII or Undefined fields: 2
197              * - PGSProcessingMethod, GPSDateStamp
198              */
199             m_nGPSIFDFields = 8;
200             applen += IFD_FIELDCOUNT_SIZE + IFD_VALOFF_SIZE;
201             applen += IFD_FIELD_SIZE * m_nGPSIFDFields;
202             applen += sizeof(rational_t) * 10;
203 
204             // gps date stamp
205             m_nGPSIFDFields += 1;
206             applen += IFD_FIELD_SIZE + EXIF_GPSDATESTAMP_LENGTH;
207 
208             len = min(strlen(m_pExif->gps_processing_method),
209                       MAX_GPS_PROCESSINGMETHOD_SIZE - sizeof(ExifAsciiPrefix) - 1);
210             if (len > 0) {
211                 m_nGPSIFDFields++;
212                 applen += IFD_FIELD_SIZE + len + sizeof(ExifAsciiPrefix) + 1;
213             }
214         }
215 
216         if (m_pExif->enableThumb) {
217             /*
218              * 1st IFD: 6
219              * Fields with no data offset: 6
220              * - ImageWidth, ImageHeight, Compression, Orientation,
221              * - JPEGInterchangeFormat, JPEGInterchangeFormatLength
222              */
223             if ((m_pExif->widthThumb < 16) || (m_pExif->heightThumb < 16)) {
224                 ALOGE("Insufficient thumbnail information %dx%d", m_pExif->widthThumb,
225                       m_pExif->heightThumb);
226                 return;
227             }
228 
229             m_n1stIFDFields = 6;
230             applen += IFD_FIELDCOUNT_SIZE + IFD_VALOFF_SIZE;
231             applen += IFD_FIELD_SIZE * m_n1stIFDFields;
232 
233             m_pThumbBase = m_pAppBase + JPEG_MARKER_SIZE + applen;
234             m_szMaxThumbSize = JPEG_MAX_SEGMENT_SIZE - applen - JPEG_APP1_OEM_RESERVED;
235         }
236 
237         m_szApp1 = applen;
238     }
239 
240     if (extra) {
241         for (int idx = 0; idx < extra->num_of_appmarker; idx++) {
242             if ((extra->appInfo[idx].appid < EXTRA_APPMARKER_MIN) ||
243                 (extra->appInfo[idx].appid >= EXTRA_APPMARKER_LIMIT)) {
244                 ALOGE("Invalid extra APP segment ID %d", extra->appInfo[idx].appid);
245                 return;
246             }
247 
248             if ((extra->appInfo[idx].dataSize == 0) ||
249                 (extra->appInfo[idx].dataSize >
250                  (JPEG_MAX_SEGMENT_SIZE - JPEG_SEGMENT_LENFIELD_SIZE))) {
251                 ALOGE("Invalid APP%d segment size, %u bytes", extra->appInfo[idx].appid,
252                       extra->appInfo[idx].dataSize);
253                 return;
254             }
255 
256             ALOGD("APP%d: %u bytes", extra->appInfo[idx].appid, extra->appInfo[idx].dataSize);
257         }
258     }
259 
260     m_pExtra = extra;
261 
262     //     |<- m_szApp1 ->|<- m_szMaxThumbSize ->|<-m_szAppX->|
263     //     |<----- size of total APP1 and APPX segments ----->|<-APP11->|<-- main image
264     // m_pAppBase   m_pThumbBase                 |            |    return
265     //     |              |                      |            |        ||
266     //     v              v                      |            |        v|
267     //   --|--------------------------------------------------|---------|-----------
268     //   ^ ^              ^                      ^            |        ^^
269     //   | |              |                      |            |        ||
270     //   |APP1        SOIofThumb                APPX                SOIofMain
271     //   |                                                              |
272     //  SOI                                                           DHTofMain
273 
274     ALOGD("APP1: %u bytes(ThumbMax %zu)", m_szApp1, m_szMaxThumbSize);
275 }
276 
277 #define APPMARKLEN (JPEG_MARKER_SIZE + JPEG_SEGMENT_LENFIELD_SIZE)
WriteAPP11(char * current,size_t dummy,size_t align)278 char *CAppMarkerWriter::WriteAPP11(char *current, size_t dummy, size_t align) {
279     ALOG_ASSERT((align & ~align) == 0);
280 
281     if ((dummy == 0) && (align == 1)) return current;
282 
283     if (!m_pExif && !m_pExtra) return current;
284 
285     uint16_t len = PTR_TO_ULONG(current + APPMARKLEN) & (align - 1);
286 
287     if (len) len = align - len;
288 
289     len += dummy + JPEG_SEGMENT_LENFIELD_SIZE;
290 
291     *current++ = 0xFF;
292     *current++ = 0xEB;
293     WriteDataInBig(current, len);
294 
295     return current + len;
296 }
297 
WriteAPPX(char * current,bool just_reserve)298 char *CAppMarkerWriter::WriteAPPX(char *current, bool just_reserve) {
299     if (!m_pExtra) return current;
300 
301     for (int idx = 0; idx < m_pExtra->num_of_appmarker; idx++) {
302         int appid = m_pExtra->appInfo[idx].appid;
303         uint16_t len = m_pExtra->appInfo[idx].dataSize + JPEG_SEGMENT_LENFIELD_SIZE;
304 
305         // APPx marker
306         *current++ = 0xFF;
307         *current++ = 0xE0 + (appid & 0xF);
308         // APPx length
309         current = WriteDataInBig(current, len);
310         // APPx data
311         if (!just_reserve)
312             memcpy(current, m_pExtra->appInfo[idx].appData, m_pExtra->appInfo[idx].dataSize);
313         current += m_pExtra->appInfo[idx].dataSize;
314     }
315 
316     return current;
317 }
318 
WriteAPP1(char * current,bool reserve_thumbnail_space,bool updating)319 char *CAppMarkerWriter::WriteAPP1(char *current, bool reserve_thumbnail_space, bool updating) {
320     if (!m_pExif) return current;
321 
322     // APP1 Marker
323     *current++ = 0xFF;
324     *current++ = 0xE1;
325 
326     // APP1 length
327     if (updating) {
328         current += JPEG_SEGMENT_LENFIELD_SIZE;
329     } else {
330         uint16_t len = m_szApp1;
331         if (reserve_thumbnail_space) len += m_szMaxThumbSize + JPEG_APP1_OEM_RESERVED;
332         current = WriteDataInBig(current, len);
333     }
334 
335     // Exif Identifier
336     for (size_t i = 0; i < ARRSIZE(ExifIdentifierCode); i++) *current++ = ExifIdentifierCode[i];
337 
338     char *tiffheader = current;
339     for (size_t i = 0; i < ARRSIZE(TiffHeader); i++) *current++ = TiffHeader[i];
340 
341     CIFDWriter writer(tiffheader, current, m_n0thIFDFields);
342 
343     writer.WriteShort(EXIF_TAG_ORIENTATION, 1, &m_pExif->orientation);
344     writer.WriteShort(EXIF_TAG_YCBCR_POSITIONING, 1, &m_pExif->ycbcr_positioning);
345     writer.WriteRational(EXIF_TAG_X_RESOLUTION, 1, &m_pExif->x_resolution);
346     writer.WriteRational(EXIF_TAG_Y_RESOLUTION, 1, &m_pExif->y_resolution);
347     writer.WriteShort(EXIF_TAG_RESOLUTION_UNIT, 1, &m_pExif->resolution_unit);
348     if (m_szMake > 0) writer.WriteASCII(EXIF_TAG_MAKE, m_szMake + 1, m_pExif->maker);
349     if (m_szModel > 0) writer.WriteASCII(EXIF_TAG_MODEL, m_szModel + 1, m_pExif->model);
350     if (m_szSoftware > 0) writer.WriteASCII(EXIF_TAG_SOFTWARE, m_szSoftware + 1, m_pExif->software);
351     writer.WriteCString(EXIF_TAG_DATE_TIME, EXIF_DATETIME_LENGTH, m_pExif->date_time);
352 
353     char *pSubIFDBase = writer.BeginSubIFD(EXIF_TAG_EXIF_IFD_POINTER);
354     if (pSubIFDBase) { // This should be always true!!
355         CIFDWriter exifwriter(tiffheader, pSubIFDBase, m_nExifIFDFields);
356         exifwriter.WriteRational(EXIF_TAG_EXPOSURE_TIME, 1, &m_pExif->exposure_time);
357         exifwriter.WriteRational(EXIF_TAG_FNUMBER, 1, &m_pExif->fnumber);
358         exifwriter.WriteShort(EXIF_TAG_EXPOSURE_PROGRAM, 1, &m_pExif->exposure_program);
359         exifwriter.WriteShort(EXIF_TAG_ISO_SPEED_RATING, 1, &m_pExif->iso_speed_rating);
360         exifwriter.WriteUndef(EXIF_TAG_EXIF_VERSION, 4,
361                               reinterpret_cast<unsigned char *>(m_pExif->exif_version));
362         exifwriter.WriteCString(EXIF_TAG_DATE_TIME_ORG, EXIF_DATETIME_LENGTH, m_pExif->date_time);
363         exifwriter.WriteCString(EXIF_TAG_DATE_TIME_DIGITIZE, EXIF_DATETIME_LENGTH,
364                                 m_pExif->date_time);
365         exifwriter.WriteSRational(EXIF_TAG_SHUTTER_SPEED, 1, &m_pExif->shutter_speed);
366         exifwriter.WriteRational(EXIF_TAG_APERTURE, 1, &m_pExif->aperture);
367         exifwriter.WriteSRational(EXIF_TAG_BRIGHTNESS, 1, &m_pExif->brightness);
368         exifwriter.WriteSRational(EXIF_TAG_EXPOSURE_BIAS, 1, &m_pExif->exposure_bias);
369         exifwriter.WriteRational(EXIF_TAG_MAX_APERTURE, 1, &m_pExif->max_aperture);
370         exifwriter.WriteShort(EXIF_TAG_METERING_MODE, 1, &m_pExif->metering_mode);
371         exifwriter.WriteShort(EXIF_TAG_FLASH, 1, &m_pExif->flash);
372         exifwriter.WriteUndef(EXIF_TAG_FLASHPIX_VERSION, 4,
373                               reinterpret_cast<const unsigned char *>("0100"));
374         exifwriter.WriteUndef(EXIF_TAG_COMPONENTS_CONFIGURATION, 4, ComponentsConfiguration);
375         exifwriter.WriteRational(EXIF_TAG_FOCAL_LENGTH, 1, &m_pExif->focal_length);
376         exifwriter.WriteCString(EXIF_TAG_SUBSEC_TIME, EXIF_SUBSECTIME_LENGTH, m_pExif->sec_time);
377         exifwriter.WriteCString(EXIF_TAG_SUBSEC_TIME_ORIG, EXIF_SUBSECTIME_LENGTH,
378                                 m_pExif->sec_time);
379         exifwriter.WriteCString(EXIF_TAG_SUBSEC_TIME_DIG, EXIF_SUBSECTIME_LENGTH,
380                                 m_pExif->sec_time);
381         if (m_pExif->maker_note_size > 0)
382             exifwriter.WriteUndef(EXIF_TAG_MAKER_NOTE, m_pExif->maker_note_size,
383                                   m_pExif->maker_note);
384         if (m_pExif->user_comment_size > 0)
385             exifwriter.WriteUndef(EXIF_TAG_USER_COMMENT, m_pExif->user_comment_size,
386                                   m_pExif->user_comment);
387         exifwriter.WriteShort(EXIF_TAG_COLOR_SPACE, 1, &m_pExif->color_space);
388         exifwriter.WriteLong(EXIF_TAG_PIXEL_X_DIMENSION, 1, &m_pExif->width);
389         exifwriter.WriteLong(EXIF_TAG_PIXEL_Y_DIMENSION, 1, &m_pExif->height);
390         exifwriter.WriteUndef(EXIF_TAG_SCENE_TYPE, sizeof(SceneType), SceneType);
391         exifwriter.WriteShort(EXIF_TAG_CUSTOM_RENDERED, 1, &m_pExif->custom_rendered);
392         exifwriter.WriteShort(EXIF_TAG_EXPOSURE_MODE, 1, &m_pExif->exposure_mode);
393         exifwriter.WriteShort(EXIF_TAG_WHITE_BALANCE, 1, &m_pExif->white_balance);
394         exifwriter.WriteRational(EXIF_TAG_DIGITAL_ZOOM_RATIO, 1, &m_pExif->digital_zoom_ratio);
395         exifwriter.WriteShort(EXIF_TAG_FOCA_LENGTH_IN_35MM_FILM, 1,
396                               &m_pExif->focal_length_in_35mm_length);
397         exifwriter.WriteShort(EXIF_TAG_SCENCE_CAPTURE_TYPE, 1, &m_pExif->scene_capture_type);
398         exifwriter.WriteShort(EXIF_TAG_CONTRAST, 1, &m_pExif->contrast);
399         exifwriter.WriteShort(EXIF_TAG_SATURATION, 1, &m_pExif->saturation);
400         exifwriter.WriteShort(EXIF_TAG_SHARPNESS, 1, &m_pExif->sharpness);
401         if (m_szUniqueID > 0)
402             exifwriter.WriteASCII(EXIF_TAG_IMAGE_UNIQUE_ID, m_szUniqueID + 1, m_pExif->unique_id);
403         pSubIFDBase = exifwriter.BeginSubIFD(EXIF_TAG_INTEROPERABILITY);
404         if (pSubIFDBase) {
405             CIFDWriter interopwriter(tiffheader, pSubIFDBase, 2);
406             interopwriter.WriteASCII(EXIF_TAG_INTEROPERABILITY_INDEX, 4,
407                                      m_pExif->interoperability_index ? "THM" : "R98");
408             interopwriter.WriteUndef(EXIF_TAG_INTEROPERABILITY_VERSION, 4,
409                                      reinterpret_cast<const unsigned char *>("0100"));
410             interopwriter.Finish(true);
411             exifwriter.EndSubIFD(interopwriter.GetNextIFDBase());
412         } else {
413             exifwriter.CancelSubIFD();
414         }
415         exifwriter.Finish(true);
416         writer.EndSubIFD(exifwriter.GetNextIFDBase());
417     } else {
418         writer.CancelSubIFD();
419     }
420 
421     if (m_pExif->enableGps) {
422         pSubIFDBase = writer.BeginSubIFD(EXIF_TAG_GPS_IFD_POINTER);
423         if (pSubIFDBase) { // This should be always true!!
424             CIFDWriter gpswriter(tiffheader, pSubIFDBase, m_nGPSIFDFields);
425             gpswriter.WriteByte(EXIF_TAG_GPS_VERSION_ID, 4, m_pExif->gps_version_id);
426             gpswriter.WriteASCII(EXIF_TAG_GPS_LATITUDE_REF, 2, m_pExif->gps_latitude_ref);
427             gpswriter.WriteRational(EXIF_TAG_GPS_LATITUDE, 3, m_pExif->gps_latitude);
428             gpswriter.WriteASCII(EXIF_TAG_GPS_LONGITUDE_REF, 2, m_pExif->gps_longitude_ref);
429             gpswriter.WriteRational(EXIF_TAG_GPS_LONGITUDE, 3, m_pExif->gps_longitude);
430             gpswriter.WriteByte(EXIF_TAG_GPS_ALTITUDE_REF, 1, &m_pExif->gps_altitude_ref);
431             gpswriter.WriteRational(EXIF_TAG_GPS_ALTITUDE, 1, &m_pExif->gps_altitude);
432             gpswriter.WriteCString(EXIF_TAG_GPS_DATESTAMP, EXIF_GPSDATESTAMP_LENGTH,
433                                    m_pExif->gps_datestamp);
434             gpswriter.WriteRational(EXIF_TAG_GPS_TIMESTAMP, 3, m_pExif->gps_timestamp);
435             size_t len = strlen(m_pExif->gps_processing_method);
436             if (len > 0) {
437                 size_t idx;
438                 len = min(len, static_cast<size_t>(99UL));
439                 unsigned char buf[sizeof(ExifAsciiPrefix) + len + 1];
440                 for (idx = 0; idx < sizeof(ExifAsciiPrefix); idx++) buf[idx] = ExifAsciiPrefix[idx];
441                 strncpy(reinterpret_cast<char *>(buf) + idx, m_pExif->gps_processing_method,
442                         len + 1);
443                 len += idx;
444                 buf[len] = '\0';
445                 gpswriter.WriteUndef(EXIF_TAG_GPS_PROCESSING_METHOD, len + 1, buf);
446             }
447             gpswriter.Finish(true);
448             writer.EndSubIFD(gpswriter.GetNextIFDBase());
449         } else {
450             writer.CancelSubIFD();
451         }
452     }
453 
454     // thumbnail and the next IFD pointer is never updated.
455     if (updating) return NULL;
456 
457     if (m_pExif->enableThumb) {
458         writer.Finish(false);
459 
460         CIFDWriter thumbwriter(tiffheader, writer.GetNextIFDBase(), m_n1stIFDFields);
461         thumbwriter.WriteLong(EXIF_TAG_IMAGE_WIDTH, 1, &m_pExif->widthThumb);
462         thumbwriter.WriteLong(EXIF_TAG_IMAGE_HEIGHT, 1, &m_pExif->heightThumb);
463         thumbwriter.WriteShort(EXIF_TAG_COMPRESSION_SCHEME, 1, &m_pExif->compression_scheme);
464         thumbwriter.WriteShort(EXIF_TAG_ORIENTATION, 1, &m_pExif->orientation);
465 
466         ALOG_ASSERT(thumbwriter.GetNextIFDBase() != m_pThumbBase);
467         uint32_t offset = thumbwriter.Offset(m_pThumbBase);
468         thumbwriter.WriteLong(EXIF_TAG_JPEG_INTERCHANGE_FORMAT, 1, &offset);
469         offset = 0; // temporarilly 0 byte
470         thumbwriter.WriteLong(EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LEN, 1, &offset);
471         m_pThumbSizePlaceholder = thumbwriter.GetNextTagAddress() - 4;
472         thumbwriter.Finish(true);
473 
474         size_t thumbspace = reserve_thumbnail_space ? m_szMaxThumbSize + JPEG_APP1_OEM_RESERVED : 0;
475 
476         return thumbwriter.GetNextIFDBase() + thumbspace;
477     }
478 
479     writer.Finish(true);
480 
481     return writer.GetNextIFDBase();
482 }
483 
Finalize(size_t thumbsize)484 void CAppMarkerWriter::Finalize(size_t thumbsize) {
485     if (m_pThumbSizePlaceholder) {
486         uint32_t len = static_cast<uint32_t>(thumbsize);
487         WriteData(m_pThumbSizePlaceholder, len);
488         m_pThumbSizePlaceholder = NULL;
489     }
490 }
UpdateApp1Size(size_t amount)491 void CAppMarkerWriter::UpdateApp1Size(size_t amount) {
492     if (m_pAppBase) {
493         uint16_t len = m_szApp1 + amount;
494         WriteDataInBig(m_pAppBase + JPEG_MARKER_SIZE, len);
495     }
496 }
497 
498 static const char *dbgerrmsg = "Updating debug data failed";
499 
GetSegLen(char * p)500 static inline size_t GetSegLen(char *p) {
501     size_t len = (*reinterpret_cast<unsigned char *>(p) & 0xFF) << 8;
502     return len | (*reinterpret_cast<unsigned char *>(p + 1) & 0xFF);
503 }
504 
GetExtraAPPSize(extra_appinfo_t * info)505 static inline size_t GetExtraAPPSize(extra_appinfo_t *info) {
506     size_t len = 0;
507 
508     for (int idx = 0; idx < info->num_of_appmarker; idx++) {
509         if ((info->appInfo[idx].appid < EXTRA_APPMARKER_MIN) ||
510             (info->appInfo[idx].appid >= EXTRA_APPMARKER_LIMIT)) {
511             ALOGE("%s: Invalid extra APP segment ID %d", dbgerrmsg, info->appInfo[idx].appid);
512             return 0;
513         }
514 
515         if ((info->appInfo[idx].dataSize == 0) ||
516             (info->appInfo[idx].dataSize > (JPEG_MAX_SEGMENT_SIZE - JPEG_SEGMENT_LENFIELD_SIZE))) {
517             ALOGE("%s: Invalid APP%d segment size, %u bytes.", dbgerrmsg, info->appInfo[idx].appid,
518                   info->appInfo[idx].dataSize);
519             return 0;
520         }
521 
522         len += info->appInfo[idx].dataSize + JPEG_MARKER_SIZE + JPEG_SEGMENT_LENFIELD_SIZE;
523     }
524 
525     return len;
526 }
527 
UpdateDebugData(char * jpeg,size_t jpeglen,debug_attribute_t * debug)528 bool UpdateDebugData(char *jpeg, size_t jpeglen, debug_attribute_t *debug) // include/ExynosExif.h
529 {
530     extra_appinfo_t extraInfo;
531     app_info_t appInfo[15];
532 
533     memset(&extraInfo, 0, sizeof(extraInfo));
534     memset(&appInfo, 0, sizeof(appInfo));
535 
536     extraInfo.appInfo = appInfo;
537 
538     ExtractDebugAttributeInfo(debug, &extraInfo);
539 
540     UpdateDebugData(jpeg, jpeglen, &extraInfo);
541 
542     return true;
543 }
544 
UpdateDebugData(char * jpeg,size_t jpeglen,extra_appinfo_t * extra)545 bool UpdateDebugData(char *jpeg, size_t jpeglen, extra_appinfo_t *extra) // include/ExynosExif.h
546 {
547     if (!extra) {
548         ALOGI("No data to update in APPx");
549         return true;
550     }
551 
552     size_t validlen = GetExtraAPPSize(extra);
553 
554     if (jpeglen < (validlen + JPEG_MARKER_SIZE)) {
555         ALOGE("%s: Too small JPEG stream length %zu", dbgerrmsg, jpeglen);
556         return false;
557     }
558 
559     if ((*jpeg++ != 0xFF) || (*jpeg++ != 0xD8)) {
560         ALOGE("%s: %p is not a valid JPEG stream", dbgerrmsg, jpeg);
561         return false;
562     }
563     jpeglen -= 2;
564 
565     int idx = 0;
566 
567     while ((*jpeg++ == 0xFF) && (validlen > 0) && (jpeglen > validlen)) {
568         size_t seglen;
569         char marker;
570         int appid;
571 
572         marker = *jpeg++;
573         jpeglen -= 2;
574 
575         if ((marker == 0xDA) || (marker == 0xD9)) { // SOS and EOI
576             ALOGE("%s: No further space found for APPx metadata", dbgerrmsg);
577             return false;
578         }
579 
580         appid = marker & 0xF;
581         if (((marker & 0xF0) == 0xE0) &&
582             ((appid >= EXTRA_APPMARKER_MIN) && (appid <= EXTRA_APPMARKER_LIMIT))) {
583             if (appid != extra->appInfo[idx].appid) {
584                 ALOGE("%s: stored appid(%d) is different with updated appid(%d)", dbgerrmsg, appid,
585                       extra->appInfo[idx].appid);
586                 return false;
587             }
588 
589             seglen = GetSegLen(jpeg);
590             if (seglen < (extra->appInfo[idx].dataSize + JPEG_SEGMENT_LENFIELD_SIZE)) {
591                 ALOGE("%s: too small APP%d length %zu to store %u bytes", dbgerrmsg, appid, seglen,
592                       extra->appInfo[idx].dataSize);
593                 return false;
594             }
595 
596             memcpy(jpeg + JPEG_SEGMENT_LENFIELD_SIZE, extra->appInfo[idx].appData,
597                    extra->appInfo[idx].dataSize);
598             ALOGD("Successfully updated %u bytes to APP%d", extra->appInfo[idx].dataSize, appid);
599 
600             validlen -=
601                     extra->appInfo[idx].dataSize + JPEG_MARKER_SIZE + JPEG_SEGMENT_LENFIELD_SIZE;
602             idx++;
603         } else {
604             // just skip all other segments
605             seglen = GetSegLen(jpeg);
606             if (seglen == 0) seglen++; // fixup for invalid segment lengths
607             if (jpeglen < seglen) seglen = jpeglen;
608         }
609 
610         jpeg += seglen;
611         jpeglen -= seglen;
612     }
613 
614     return true;
615 }
616 
617 static const char *exiferrmsg = "Updating exif failed";
618 
UpdateExif(char * jpeg,size_t jpeglen,exif_attribute_t * exif)619 bool UpdateExif(char *jpeg, size_t jpeglen, exif_attribute_t *exif) {
620     if (!exif) {
621         ALOGI("No Exif to update");
622         return true;
623     }
624 
625     if (jpeglen < (JPEG_MARKER_SIZE * 2 + JPEG_SEGMENT_LENFIELD_SIZE)) {
626         ALOGE("%s: Too small stream length %zu", exiferrmsg, jpeglen);
627         return false;
628     }
629 
630     if ((*jpeg++ != 0xFF) || (*jpeg++ != 0xD8)) {
631         ALOGE("%s: %p is not a valid JPEG stream", exiferrmsg, jpeg);
632         return false;
633     }
634 
635     if ((*jpeg != 0xFF) || (*(jpeg + 1) != 0xE1)) {
636         ALOGE("%s: APP1 marker is not found", exiferrmsg);
637         return false;
638     }
639 
640     if (jpeglen < GetSegLen(jpeg + JPEG_MARKER_SIZE)) {
641         ALOGE("%s: Too small stream length %zu", exiferrmsg, jpeglen);
642         return false;
643     }
644 
645     CAppMarkerWriter writer(jpeg, exif, NULL);
646     writer.Update();
647 
648     ALOGD("Successfully updated Exif");
649 
650     return true;
651 }
652 
ExtractDebugAttributeInfo(debug_attribute_t * debug,extra_appinfo_t * extra)653 void ExtractDebugAttributeInfo(debug_attribute_t *debug, extra_appinfo_t *extra) {
654     if (!debug) {
655         extra->num_of_appmarker = 0;
656         return;
657     }
658 
659     extra->num_of_appmarker = debug->num_of_appmarker;
660     for (int idx = 0; idx < debug->num_of_appmarker; idx++) {
661         int appid = debug->idx[idx][0];
662         extra->appInfo[idx].appid = appid;
663         extra->appInfo[idx].appData = debug->debugData[appid];
664         extra->appInfo[idx].dataSize = debug->debugSize[appid];
665     }
666 }
667