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