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