[Archive][Exif] Fixed svace issues
[platform/core/api/webapi-plugins.git] / src / exif / exif_information.cc
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 #include "exif/exif_information.h"
18
19 #include <cmath>
20 #include <memory>
21
22 #include "common/assert.h"
23 #include "common/converter.h"
24 #include "common/logger.h"
25 #include "common/platform_result.h"
26
27 #include "exif/exif_tag_saver.h"
28 #include "exif/exif_util.h"
29 #include "exif/jpeg_file.h"
30
31 namespace extension {
32 namespace exif {
33
34 using common::ErrorCode;
35 using common::PlatformResult;
36
37 const std::size_t EXIF_UNDEFINED_TYPE_LENGTH = 8;
38 const std::string EXIF_UNDEFINED_TYPE_ASCII =
39     std::string("ASCII\0\0\0", EXIF_UNDEFINED_TYPE_LENGTH);
40 const std::string EXIF_UNDEFINED_TYPE_JIS =
41     std::string("JIS\0\0\0\0\0", EXIF_UNDEFINED_TYPE_LENGTH);
42 const std::string EXIF_UNDEFINED_TYPE_UNICODE =
43     std::string("UNICODE\0", EXIF_UNDEFINED_TYPE_LENGTH);
44 const std::string EXIF_UNDEFINED_TYPE_UNDEFINED =
45     std::string("\0\0\0\0\0\0\0\0", EXIF_UNDEFINED_TYPE_LENGTH);
46
47 namespace {
48 constexpr unsigned int str2int(const char* str, int h = 0) {
49   return !str[h] ? 5381 : (str2int(str, h + 1) * 33) ^ str[h];
50 }
51
52 IsoSpeedRatingsVector jsonArray2vector(const picojson::value& a) {
53   ScopeLogger();
54   if (!a.is<picojson::array>()) {
55     return IsoSpeedRatingsVector();
56   }
57
58   IsoSpeedRatingsVector result;
59
60   picojson::array v = a.get<picojson::array>();
61
62   for (picojson::array::iterator it = v.begin(); it != v.end(); ++it) {
63     if ((*it).is<double>()) result.push_back(static_cast<long long int>((*it).get<double>()));
64   }
65
66   return result;
67 }
68 }  // namespace
69
70 ExifInformation::ExifInformation() {
71   ScopeLogger();
72   for (int attr = 0; attr < EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES; attr++) {
73     unset(static_cast<ExifInformationAttribute>(attr));
74   }
75 }
76
77 ExifInformation::ExifInformation(const picojson::value& args) {
78   ScopeLogger();
79   for (int attr = 0; attr < EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES; attr++) {
80     unset(static_cast<ExifInformationAttribute>(attr));
81   }
82
83   for (AttributeMap::const_iterator it = ExifInformationAttributeMap.begin();
84        it != ExifInformationAttributeMap.end(); ++it) {
85     std::string attributeName = it->second;
86     picojson::value v = args.get(attributeName);
87     if (!common::IsNull(v)) {
88       set(attributeName, v);
89     }
90   }
91 }
92
93 ExifInformation::~ExifInformation() {
94   ScopeLogger();
95 }
96
97 const std::string& ExifInformation::getUri() {
98   return m_uri;
99 }
100
101 void ExifInformation::setUri(const std::string& uri) {
102   m_is_set[EXIF_INFORMATION_ATTRIBUTE_URI] = true;
103   m_uri = uri;
104   LoggerD("URI: %s", uri.c_str());
105 }
106
107 unsigned long ExifInformation::getWidth() const {
108   return m_width;
109 }
110
111 void ExifInformation::setWidth(unsigned long width) {
112   m_is_set[EXIF_INFORMATION_ATTRIBUTE_WIDTH] = true;
113   m_width = width;
114 }
115
116 unsigned long ExifInformation::getHeight() const {
117   return m_height;
118 }
119
120 void ExifInformation::setHeight(unsigned long height) {
121   m_is_set[EXIF_INFORMATION_ATTRIBUTE_HEIGHT] = true;
122   m_height = height;
123 }
124
125 const std::string& ExifInformation::getDeviceMaker() {
126   return m_device_maker;
127 }
128
129 void ExifInformation::setDeviceMaker(const std::string& device_maker) {
130   m_is_set[EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER] = true;
131   m_device_maker = device_maker;
132 }
133
134 const std::string& ExifInformation::getDeviceModel() {
135   return m_device_model;
136 }
137
138 void ExifInformation::setDeviceModel(const std::string& device_model) {
139   m_is_set[EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL] = true;
140   m_device_model = device_model;
141 }
142
143 time_t ExifInformation::getOriginalTime() const {
144   return m_original_time;
145 }
146
147 void ExifInformation::setOriginalTime(time_t original_time) {
148   m_is_set[EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME] = true;
149   m_original_time = original_time;
150 }
151
152 const std::string& ExifInformation::getOrientationString() {
153   return ExifUtil::orientationToString(m_orientation);
154 }
155
156 ImageOrientation ExifInformation::getOrientation() {
157   return m_orientation;
158 }
159
160 void ExifInformation::setOrientation(const std::string& orientation) {
161   ScopeLogger();
162   setOrientation(ExifUtil::stringToOrientation(orientation));
163 }
164
165 void ExifInformation::setOrientation(ImageOrientation orientation) {
166   m_is_set[EXIF_INFORMATION_ATTRIBUTE_ORIENTATION] = true;
167   m_orientation = orientation;
168 }
169
170 const Rational& ExifInformation::getFNumber() const {
171   return m_f_number;
172 }
173
174 void ExifInformation::setFNumber(Rational f_number) {
175   if (!f_number.isValid()) {
176     LoggerW("Trying to set invalid F-Number: %s", f_number.toString().c_str());
177     return;
178   }
179
180   m_is_set[EXIF_INFORMATION_ATTRIBUTE_FNUMBER] = true;
181   m_f_number = f_number;
182 }
183
184 const std::vector<long long int>& ExifInformation::getIsoSpeedRatings() {
185   return m_iso_speed_ratings;
186 }
187
188 void ExifInformation::setIsoSpeedRatings(const std::vector<long long int>& iso_speed_ratings) {
189   m_is_set[EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS] = true;
190   m_iso_speed_ratings = iso_speed_ratings;
191 }
192
193 const Rational& ExifInformation::getExposureTime() {
194   return m_exposure_time;
195 }
196
197 void ExifInformation::setExposureTime(const Rational& exposure_time) {
198   if (!exposure_time.isValid() || 0 == exposure_time.nominator) {
199     LoggerW("Trying to set invalid exposure time: [%s]", exposure_time.toString().c_str());
200     return;
201   }
202
203   m_is_set[EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME] = true;
204   m_exposure_time = exposure_time;
205 }
206
207 const std::string& ExifInformation::getExposureProgramString() {
208   ScopeLogger();
209   return ExifUtil::exposureProgramToString(m_exposure_program);
210 }
211
212 ExposureProgram ExifInformation::getExposureProgram() {
213   return m_exposure_program;
214 }
215
216 void ExifInformation::setExposureProgram(const std::string& exposure_program) {
217   ScopeLogger();
218   setExposureProgram(ExifUtil::stringToExposureProgram(exposure_program));
219 }
220
221 void ExifInformation::setExposureProgram(ExposureProgram exposure_program) {
222   m_is_set[EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM] = true;
223   m_exposure_program = exposure_program;
224 }
225
226 bool ExifInformation::getFlash() const {
227   return m_flash;
228 }
229
230 void ExifInformation::setFlash(bool flash) {
231   m_is_set[EXIF_INFORMATION_ATTRIBUTE_FLASH] = true;
232   m_flash = flash;
233 }
234
235 const Rational& ExifInformation::getFocalLength() const {
236   return m_focal_length;
237 }
238
239 void ExifInformation::setFocalLength(Rational focal_length) {
240   if (!focal_length.isValid()) {
241     LoggerW("Trying to set invalid focal length: %s", focal_length.toString().c_str());
242     return;
243   }
244
245   m_is_set[EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH] = true;
246   m_focal_length = focal_length;
247 }
248
249 const std::string& ExifInformation::getWhiteBalanceModeString() {
250   return ExifUtil::whiteBalanceToString(m_white_balance);
251 }
252
253 WhiteBalanceMode ExifInformation::getWhiteBalanceMode() {
254   return m_white_balance;
255 }
256
257 void ExifInformation::setWhiteBalanceMode(const std::string& white_balance) {
258   ScopeLogger();
259   setWhiteBalanceMode(ExifUtil::stringToWhiteBalance(white_balance));
260 }
261
262 void ExifInformation::setWhiteBalanceMode(WhiteBalanceMode white_balance) {
263   m_is_set[EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE] = true;
264   m_white_balance = white_balance;
265 }
266
267 ExifGPSLocation& ExifInformation::getGPSExifLocation() {
268   return m_gps_location;
269 }
270
271 void ExifInformation::setGPSLocation(ExifGPSLocation gps_location) {
272   m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_LOCATION] = true;
273   m_gps_location = gps_location;
274 }
275
276 void ExifInformation::unsetGPSLocation() {
277   m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_LOCATION] = false;
278   m_gps_location.unsetAll();
279 }
280
281 const Rational& ExifInformation::getGpsAltitude() const {
282   return m_gps_altitude;
283 }
284
285 void ExifInformation::setGpsAltitude(Rational gps_altitude) {
286   if (!gps_altitude.isValid()) {
287     LoggerW("Trying to set invalid gps altitude: %s", gps_altitude.toString().c_str());
288     return;
289   }
290
291   m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE] = true;
292   m_gps_altitude = gps_altitude;
293 }
294
295 GpsAltitudeRef ExifInformation::getGpsAltitudeRef() const {
296   return m_gps_altitude_ref;
297 }
298
299 void ExifInformation::setGpsAltitudeRef(const GpsAltitudeRef ref) {
300   m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF] = true;
301   m_gps_altitude_ref = ref;
302 }
303
304 void ExifInformation::setGpsAltitudeWithRef(double gps_altitude) {
305   ScopeLogger();
306   setGpsAltitude(Rational::createFromDouble(fabs(gps_altitude)));
307
308   if (gps_altitude >= 0.0) {
309     setGpsAltitudeRef(GPS_ALTITUDE_REF_ABOVE_SEA);
310   } else {
311     setGpsAltitudeRef(GPS_ALTITUDE_REF_BELOW_SEA);
312   }
313 }
314
315 double ExifInformation::getGpsAltitudeWithRef() const {
316   if (!m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF] ||
317       GPS_ALTITUDE_REF_ABOVE_SEA == m_gps_altitude_ref) {
318     return m_gps_altitude.toDouble();
319   } else {
320     return -1.0 * m_gps_altitude.toDouble();
321   }
322 }
323
324 const std::string& ExifInformation::getGpsProcessingMethod() const {
325   return m_gps_processing_method;
326 }
327
328 const std::string& ExifInformation::getGpsProcessingMethodType() const {
329   return m_gps_processing_method_type;
330 }
331
332 void ExifInformation::setGpsProcessingMethod(const std::string& type,
333                                              const std::string& processing_method) {
334   if (type != EXIF_UNDEFINED_TYPE_ASCII && type != EXIF_UNDEFINED_TYPE_JIS &&
335       type != EXIF_UNDEFINED_TYPE_UNICODE && type != EXIF_UNDEFINED_TYPE_UNDEFINED) {
336     LoggerW("Trying to set invalid GPSProcessingMethod type: [%s] len: %zu", type.c_str(),
337             type.length());
338     return;
339   }
340
341   m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD] = true;
342   m_gps_processing_method = processing_method;
343   m_gps_processing_method_type = type;
344 }
345
346 void ExifInformation::setGpsTime(time_t time) {
347   m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_TIME] = true;
348   m_gps_time = time;
349 }
350
351 time_t ExifInformation::getGpsTime() {
352   return m_gps_time;
353 }
354
355 void ExifInformation::unsetGPStime() {
356   m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_TIME] = false;
357   m_gps_time = 0;
358 }
359
360 const std::string& ExifInformation::getUserComment() {
361   return m_user_comment;
362 }
363
364 const std::string& ExifInformation::getUserCommentType() {
365   return m_user_comment_type;
366 }
367
368 void ExifInformation::setUserComment(const std::string& type, const std::string& user_comment) {
369   if (type != EXIF_UNDEFINED_TYPE_ASCII && type != EXIF_UNDEFINED_TYPE_JIS &&
370       type != EXIF_UNDEFINED_TYPE_UNICODE && type != EXIF_UNDEFINED_TYPE_UNDEFINED) {
371     LoggerW("Trying to set invalid user comment type: [%s] len: %zu", type.c_str(), type.length());
372     return;
373   }
374
375   m_is_set[EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT] = true;
376   m_user_comment_type = type;
377   m_user_comment = user_comment;
378 }
379
380 bool ExifInformation::isSet(ExifInformationAttribute attribute) const {
381   return m_is_set[attribute];
382 }
383
384 void ExifInformation::unset(ExifInformationAttribute attribute) {
385   if (attribute >= EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES) {
386     return;
387   }
388
389   m_is_set[attribute] = false;
390   switch (attribute) {
391     case EXIF_INFORMATION_ATTRIBUTE_URI:
392       m_uri = std::string();
393       break;
394     case EXIF_INFORMATION_ATTRIBUTE_WIDTH:
395       m_width = 0;
396       break;
397     case EXIF_INFORMATION_ATTRIBUTE_HEIGHT:
398       m_height = 0;
399       break;
400     case EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER:
401       m_device_maker = std::string();
402       break;
403     case EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL:
404       m_device_model = std::string();
405       break;
406     case EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME:
407       m_original_time = 0;
408       break;
409     case EXIF_INFORMATION_ATTRIBUTE_ORIENTATION:
410       m_orientation = EXIF_ORIENTATION_NOT_VALID;
411       break;
412     case EXIF_INFORMATION_ATTRIBUTE_FNUMBER:
413       m_f_number = Rational::createInvalid();
414       break;
415     case EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS:
416       m_iso_speed_ratings = std::vector<long long int>();
417       break;
418     case EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME:
419       m_exposure_time = Rational::createInvalid();
420       break;
421     case EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM:
422       m_exposure_program = EXIF_EXPOSURE_PROGRAM_NOT_VALID;
423       break;
424     case EXIF_INFORMATION_ATTRIBUTE_FLASH:
425       m_flash = false;
426       break;
427     case EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH:
428       m_focal_length = Rational::createInvalid();
429       break;
430     case EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE:
431       m_white_balance = EXIF_WHITE_BALANCE_MODE_NOT_VALID;
432       break;
433     case EXIF_INFORMATION_ATTRIBUTE_GPS_LOCATION:
434       unsetGPSLocation();
435       break;
436     case EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE:
437       m_gps_altitude = Rational::createInvalid();
438       break;
439     case EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF:
440       m_gps_altitude_ref = GPS_ALTITUDE_REF_ABOVE_SEA;
441       break;
442     case EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD:
443       m_gps_processing_method = std::string();
444       m_gps_processing_method_type = EXIF_UNDEFINED_TYPE_ASCII;
445       break;
446     case EXIF_INFORMATION_ATTRIBUTE_GPS_TIME:
447       unsetGPStime();
448       break;
449     case EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT:
450       m_user_comment = std::string();
451       m_user_comment_type = EXIF_UNDEFINED_TYPE_ASCII;
452       break;
453     default:
454       break;
455   }
456 }
457
458 void ExifInformation::set(std::string attributeName, const picojson::value& v) {
459   ScopeLogger("%s", attributeName.c_str());
460
461   switch (str2int(attributeName.c_str())) {
462     case str2int(EI_URI): {
463       setUri(v.get<std::string>());
464       break;
465     }
466     case str2int(EI_WIDTH): {
467       setWidth(static_cast<int>(v.get<double>()));
468       break;
469     }
470     case str2int(EI_HEIGHT): {
471       setHeight(static_cast<int>(v.get<double>()));
472       break;
473     }
474     case str2int(EI_DEVICE_MAKER): {
475       setDeviceMaker(v.get<std::string>());
476       break;
477     }
478     case str2int(EI_DEVICE_MODEL): {
479       setDeviceModel(v.get<std::string>());
480       break;
481     }
482     case str2int(EI_ORIGINAL_TIME): {
483       setOriginalTime(static_cast<unsigned long long>(v.get<double>()));
484       break;
485     }
486     case str2int(EI_ORIENTATION): {
487       setOrientation(v.get<std::string>());
488       break;
489     }
490     case str2int(EI_FNUMBER): {
491       setFNumber(Rational::createFromDouble(v.get<double>()));
492       break;
493     }
494     case str2int(EI_ISO_SPEED_RATINGS): {
495       setIsoSpeedRatings(jsonArray2vector(v));
496       break;
497     }
498     case str2int(EI_EXPOSURE_TIME): {
499       setExposureTime(Rational::createFromExposureTimeString(v.get<std::string>()));
500       break;
501     }
502     case str2int(EI_EXPOSURE_PROGRAM): {
503       setExposureProgram(v.get<std::string>());
504       break;
505     }
506     case str2int(EI_FLASH): {
507       setFlash(v.get<bool>());
508       break;
509     }
510     case str2int(EI_FOCAL_LENGTH): {
511       setFocalLength(Rational::createFromDouble(v.get<double>()));
512       break;
513     }
514     case str2int(EI_WHITE_BALANCE): {
515       setWhiteBalanceMode(v.get<std::string>());
516       break;
517     }
518     case str2int(EI_GPS_LOCATION): {
519       setGPSLocation(
520           ExifGPSLocation(v.get("longitude").get<double>(), v.get("latitude").get<double>()));
521       break;
522     }
523     case str2int(EI_GPS_ALTITUDE): {
524       setGpsAltitudeWithRef(v.get<double>());
525       break;
526     }
527     case str2int(EI_GPS_PROCESSING_METHOD): {
528       setGpsProcessingMethod(EXIF_UNDEFINED_TYPE_ASCII, v.get<std::string>());
529       break;
530     }
531     case str2int(EI_GPS_TIME): {
532       setGpsTime(static_cast<time_t>(v.get<double>()));
533       break;
534     }
535     case str2int(EI_USER_COMMENT): {
536       setUserComment(EXIF_UNDEFINED_TYPE_ASCII, v.get<std::string>());
537       break;
538     }
539     default:
540       break;
541   }
542 }
543
544 PlatformResult ExifInformation::removeNulledAttributesFromExifData(ExifData* exif_data) {
545   ScopeLogger();
546   if (!exif_data) {
547     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "exif_data is NULL");
548   }
549
550   if (!isSet(EXIF_INFORMATION_ATTRIBUTE_WIDTH)) {
551     LoggerD("Removing width");
552     ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_IMAGE_WIDTH, exif_data);
553   }
554   if (!isSet(EXIF_INFORMATION_ATTRIBUTE_HEIGHT)) {
555     LoggerD("Removing height");
556     ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_IMAGE_LENGTH, exif_data);
557   }
558   if (!isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER)) {
559     LoggerD("Removing device maker");
560     ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_MAKE, exif_data);
561   }
562   if (!isSet(EXIF_INFORMATION_ATTRIBUTE_ORIENTATION)) {
563     LoggerD("Removing orientation");
564     ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_ORIENTATION, exif_data);
565   }
566   if (!isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM)) {
567     LoggerD("Removing exposure program");
568     ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_EXPOSURE_PROGRAM, exif_data);
569   }
570   if (!isSet(EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS)) {
571     LoggerD("Removing iso speed ratings");
572     ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_ISO_SPEED_RATINGS, exif_data);
573   }
574   if (!isSet(EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE)) {
575     LoggerD("Removing white balance");
576     ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_WHITE_BALANCE, exif_data);
577   }
578   if (!isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL)) {
579     LoggerD("Removing device model");
580     ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_MODEL, exif_data);
581   }
582   if (!isSet(EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME)) {
583     LoggerD("Removing original time");
584     ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_DATE_TIME_ORIGINAL, exif_data);
585   }
586   if (!isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME)) {
587     LoggerD("Removing exposure time");
588     ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_EXPOSURE_TIME, exif_data);
589   }
590   if (!isSet(EXIF_INFORMATION_ATTRIBUTE_FNUMBER)) {
591     LoggerD("Removing f-number");
592     ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_FNUMBER, exif_data);
593   }
594   if (!isSet(EXIF_INFORMATION_ATTRIBUTE_FLASH)) {
595     LoggerD("Removing flash");
596     ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_FLASH, exif_data);
597   }
598   if (!isSet(EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH)) {
599     LoggerD("Removing focal length");
600     ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_FOCAL_LENGTH, exif_data);
601   }
602   if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_TIME)) {
603     LoggerD("Removing gps altitude");
604     ExifTagSaver::removeExifEntryWithTag(static_cast<ExifTag>(EXIF_TAG_GPS_TIME_STAMP), exif_data);
605   }
606   if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE)) {
607     LoggerD("Removing gps altitude");
608     ExifTagSaver::removeExifEntryWithTag(static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE), exif_data);
609   }
610   if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF)) {
611     LoggerD("Removing gps altitude ref");
612     ExifTagSaver::removeExifEntryWithTag(static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE_REF),
613                                          exif_data);
614   }
615   if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD)) {
616     LoggerD("Removing gps processing method");
617     ExifTagSaver::removeExifEntryWithTag(static_cast<ExifTag>(EXIF_TAG_GPS_PROCESSING_METHOD),
618                                          exif_data);
619   }
620   if (!isSet(EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT)) {
621     LoggerD("Removing user comment");
622     ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_USER_COMMENT, exif_data);
623   }
624   if (!m_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE)) {
625     LoggerD("Removing latitude");
626     ExifTagSaver::removeExifEntryWithTag(static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE), exif_data);
627   }
628   if (!m_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE_REF)) {
629     LoggerD("Removing latitude ref");
630     ExifTagSaver::removeExifEntryWithTag(static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE_REF),
631                                          exif_data);
632   }
633   if (!m_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE)) {
634     LoggerD("Removing longitude");
635     ExifTagSaver::removeExifEntryWithTag(static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE), exif_data);
636   }
637   if (!m_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF)) {
638     LoggerD("Removing longitude ref");
639     ExifTagSaver::removeExifEntryWithTag(static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE_REF),
640                                          exif_data);
641   }
642   return PlatformResult(ErrorCode::NO_ERROR);
643 }
644
645 PlatformResult ExifInformation::updateAttributesInExifData(ExifData* exif_data) {
646   ScopeLogger();
647
648   common::PlatformResult ret(common::ErrorCode::NO_ERROR);
649
650   if (!exif_data) {
651     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "exif_data is NULL");
652   }
653
654   if (isSet(EXIF_INFORMATION_ATTRIBUTE_WIDTH)) {
655     LoggerD("Saving width: %lu", getWidth());
656     ret = ExifTagSaver::saveToExif(getWidth(), EXIF_TAG_IMAGE_WIDTH, exif_data);
657     if (!ret) {
658       return ret;
659     }
660   }
661   if (isSet(EXIF_INFORMATION_ATTRIBUTE_HEIGHT)) {
662     LoggerD("Saving height: %lu", getHeight());
663     ret = ExifTagSaver::saveToExif(getHeight(), EXIF_TAG_IMAGE_LENGTH, exif_data);
664     if (!ret) {
665       return ret;
666     }
667   }
668   if (isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER)) {
669     LoggerD("Saving device maker: %s", getDeviceMaker().c_str());
670     ret = ExifTagSaver::saveToExif(getDeviceMaker(), EXIF_TAG_MAKE, exif_data);
671     if (!ret) {
672       return ret;
673     }
674   }
675   if (isSet(EXIF_INFORMATION_ATTRIBUTE_ORIENTATION)) {
676     LoggerD("Saving orientation: %d", static_cast<int>(getOrientation()));
677     ret = ExifTagSaver::saveToExif(static_cast<long int>(getOrientation()), EXIF_TAG_ORIENTATION,
678                                    exif_data);
679     if (!ret) {
680       return ret;
681     }
682   }
683   if (isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM)) {
684     LoggerD("Saving exposure program: %d", static_cast<int>(getExposureProgram()));
685     ret = ExifTagSaver::saveToExif(getExposureProgram(), EXIF_TAG_EXPOSURE_PROGRAM, exif_data);
686     if (!ret) {
687       return ret;
688     }
689   }
690   if (isSet(EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS)) {
691     std::vector<long long int> iso_ratings = getIsoSpeedRatings();
692     LoggerD("Saving iso speed ratings count: %zu", iso_ratings.size());
693     ret = ExifTagSaver::saveToExif(iso_ratings, EXIF_FORMAT_SHORT, EXIF_TAG_ISO_SPEED_RATINGS,
694                                    exif_data);
695     if (!ret) {
696       return ret;
697     }
698   }
699   if (isSet(EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE)) {
700     LoggerD("Saving white balance: %d", static_cast<int>(getWhiteBalanceMode()));
701     ret = ExifTagSaver::saveToExif(getWhiteBalanceMode(), EXIF_TAG_WHITE_BALANCE, exif_data);
702     if (!ret) {
703       return ret;
704     }
705   }
706   if (isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL)) {
707     LoggerD("Saving device model: %s", getDeviceModel().c_str());
708     ret = ExifTagSaver::saveToExif(getDeviceModel(), EXIF_TAG_MODEL, exif_data);
709     if (!ret) {
710       return ret;
711     }
712   }
713   if (isSet(EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME)) {
714     const time_t o_time = getOriginalTime();
715     const std::string o_time_str = ExifUtil::timeTToExifDateTimeOriginal(o_time);
716     LoggerD("Saving original time time_t:%d, format:%s", static_cast<int>(o_time),
717             o_time_str.c_str());
718
719     ret = ExifTagSaver::saveToExif(o_time_str, EXIF_TAG_DATE_TIME_ORIGINAL, exif_data);
720     if (!ret) {
721       return ret;
722     }
723   }
724   if (isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME)) {
725     Rational exposure_time = getExposureTime();
726     if (exposure_time.isValid()) {
727       LoggerD("Saving exposure time: %s (%s)", exposure_time.toString().c_str(),
728               exposure_time.toExposureTimeString().c_str());
729
730       ret = ExifTagSaver::saveToExif(exposure_time, EXIF_TAG_EXPOSURE_TIME, exif_data);
731       if (!ret) {
732         return ret;
733       }
734     }
735   }
736   if (isSet(EXIF_INFORMATION_ATTRIBUTE_FNUMBER)) {
737     auto f_number = getFNumber();
738     LoggerD("Saving f-number: %f (%s)", f_number.toDouble(), f_number.toString().c_str());
739     ret = ExifTagSaver::saveToExif(f_number, EXIF_TAG_FNUMBER, exif_data);
740     if (!ret) {
741       return ret;
742     }
743   }
744   if (isSet(EXIF_INFORMATION_ATTRIBUTE_FLASH)) {
745     LoggerD("Saving flash: %s", getFlash() ? "ON" : "OFF");
746     ret = ExifTagSaver::saveToExif(getFlash(), EXIF_TAG_FLASH, exif_data);
747     if (!ret) {
748       return ret;
749     }
750   }
751   if (isSet(EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH)) {
752     auto f_length = getFocalLength();
753     LoggerD("Saving focal length:%f (%s)", f_length.toDouble(), f_length.toString().c_str());
754     ret = ExifTagSaver::saveToExif(f_length, EXIF_TAG_FOCAL_LENGTH, exif_data);
755     if (!ret) {
756       return ret;
757     }
758   }
759   if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_LOCATION)) {
760     LoggerD("Saving gps location");
761     ret = ExifTagSaver::saveGpsLocationToExif(m_gps_location, exif_data);
762     if (!ret) {
763       return ret;
764     }
765   }
766   if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE)) {
767     LoggerD("Saving gps altitude:%f (%s)", m_gps_altitude.toDouble(),
768             m_gps_altitude.toString().c_str());
769     ret = ExifTagSaver::saveToExif(m_gps_altitude, static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE),
770                                    exif_data);
771     if (!ret) {
772       return ret;
773     }
774   }
775   if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF)) {
776     // Exif spec:
777     // 0 = Sea level
778     // 1 = Sea level reference (negative value)
779     LoggerD("Saving gps altitude ref:%d (%s)", static_cast<int>(m_gps_altitude_ref),
780             (static_cast<int>(m_gps_altitude_ref) > 0) ? "below sea" : "above sea");
781     std::vector<long long int> value = {static_cast<long long int>(m_gps_altitude_ref)};
782     ret = ExifTagSaver::saveToExif(value, EXIF_FORMAT_BYTE,
783                                    static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE_REF), exif_data);
784     if (!ret) {
785       return ret;
786     }
787   }
788   if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD)) {
789     LoggerD("Saving gps processing method: [%s] type:%s", getGpsProcessingMethod().c_str(),
790             getGpsProcessingMethodType().c_str());
791
792     const std::string& joined = getGpsProcessingMethodType() + getGpsProcessingMethod();
793     LoggerD("joined: [%s]", joined.c_str());
794
795     ret = ExifTagSaver::saveToExif(joined, static_cast<ExifTag>(EXIF_TAG_GPS_PROCESSING_METHOD),
796                                    exif_data, EXIF_FORMAT_UNDEFINED, false);
797     if (!ret) {
798       return ret;
799     }
800   }
801   if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_TIME)) {
802     const time_t gps_time = getGpsTime();
803     const Rationals gps_time_vec = ExifUtil::timeTToExifGpsTimeStamp(gps_time);
804     const std::string& gps_date_str = ExifUtil::timeTToExifGpsDateStamp(gps_time);
805     LoggerD("Saving gps time stamp time_t: %d", static_cast<int>(gps_time));
806
807     ret = ExifTagSaver::saveToExif(gps_time_vec, static_cast<ExifTag>(EXIF_TAG_GPS_TIME_STAMP),
808                                    exif_data);
809     if (!ret) {
810       return ret;
811     }
812
813     LoggerD("Saving gps date stamp: %s", gps_date_str.c_str());
814
815     ret = ExifTagSaver::saveToExif(gps_date_str, static_cast<ExifTag>(EXIF_TAG_GPS_DATE_STAMP),
816                                    exif_data, EXIF_FORMAT_ASCII, false);
817     if (!ret) {
818       return ret;
819     }
820   }
821   if (isSet(EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT)) {
822     LoggerD("Saving user comment: %s (type:%s)", getUserComment().c_str(),
823             getUserCommentType().c_str());
824
825     const std::string& joined = getUserCommentType() + getUserComment();
826     LoggerD("joined: [%s]", joined.c_str());
827
828     ret = ExifTagSaver::saveToExif(joined, EXIF_TAG_USER_COMMENT, exif_data, EXIF_FORMAT_UNDEFINED,
829                                    false);
830     if (!ret) {
831       return ret;
832     }
833   }
834
835   return ret;
836 }
837
838 PlatformResult ExifInformation::saveToFile(const std::string& file_path) {
839   ScopeLogger("Using JpegFile to read: [%s] and Exif if present", file_path.c_str());
840
841   JpegFilePtr jpg_file;
842   PlatformResult result = JpegFile::loadFile(file_path, &jpg_file);
843   if (!result) return result;
844
845   ExifData* exif_data = jpg_file->getExifData();
846   bool exif_data_is_new = false;
847
848   // Exif is not present in file - create new ExifData
849   if (!exif_data) {
850     LoggerD("Exif is not present in file: [%s] creating new", file_path.c_str());
851
852     exif_data = exif_data_new();
853     if (!exif_data) {
854       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Memory allocation failed",
855                                 ("Couldn't allocate new ExifData"));
856     }
857
858     exif_data_set_option(exif_data, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
859     exif_data_set_data_type(exif_data, EXIF_DATA_TYPE_COMPRESSED);
860     exif_data_set_byte_order(exif_data, EXIF_BYTE_ORDER_MOTOROLA);
861     exif_data_is_new = true;
862   }
863
864   LoggerD("Exif data type: %d", exif_data_get_data_type(exif_data));
865   LoggerD("Exif byte order: %d", exif_data_get_byte_order(exif_data));
866   exif_data_set_option(exif_data, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
867
868   // If we have created new ExifData there is nothing to remove
869   if (!exif_data_is_new) {
870     // Remove attributes that have been nulled
871     PlatformResult ret = removeNulledAttributesFromExifData(exif_data);
872     if (ret.error_code() != ErrorCode::NO_ERROR) {
873       exif_data_unref(exif_data);
874       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Could not remove nulled attribute");
875     }
876   }
877   result = updateAttributesInExifData(exif_data);
878   if (!result) {
879     exif_data_unref(exif_data);
880     return result;
881   }
882
883   LoggerD("Using JpegFile to save new Exif in: [%s]", file_path.c_str());
884   if (exif_data_is_new) {
885     result = jpg_file->setNewExifData(exif_data);
886   }
887
888   exif_data_unref(exif_data);
889
890   if (!result) {
891     return result;
892   }
893
894   return jpg_file->saveToFile(file_path);
895 }
896
897 }  // namespace exif
898 }  // namespace extension