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