[Exif] saveExifInfo implementation
authorKonrad Zdunczyk <k.zdunczyk@samsung.com>
Thu, 8 Jan 2015 14:28:43 +0000 (15:28 +0100)
committerRafal Galka <r.galka@samsung.com>
Tue, 13 Jan 2015 14:28:22 +0000 (23:28 +0900)
Change-Id: Ie1c5ae096a39ad6b968bdbfe86bcd03411d6afe9
Signed-off-by: Konrad Zdunczyk <k.zdunczyk@samsung.com>
25 files changed:
src/exif/ExifGPSLocation.cpp
src/exif/ExifGPSLocation.h
src/exif/ExifInformation.cpp [deleted file]
src/exif/ExifInformation.h [deleted file]
src/exif/ExifTagSaver.cpp [deleted file]
src/exif/ExifTagSaver.h [deleted file]
src/exif/ExifUtil.cpp [deleted file]
src/exif/ExifUtil.h [deleted file]
src/exif/JpegFile.cpp [deleted file]
src/exif/JpegFile.h [deleted file]
src/exif/Rational.cpp [deleted file]
src/exif/Rational.h [deleted file]
src/exif/exif.gyp
src/exif/exif_api.js
src/exif/exif_information.cc [new file with mode: 0644]
src/exif/exif_information.h [new file with mode: 0644]
src/exif/exif_instance.cc
src/exif/exif_tag_saver.cc [new file with mode: 0644]
src/exif/exif_tag_saver.h [new file with mode: 0644]
src/exif/exif_util.cc [new file with mode: 0644]
src/exif/exif_util.h [new file with mode: 0644]
src/exif/jpeg_file.cc [new file with mode: 0644]
src/exif/jpeg_file.h [new file with mode: 0644]
src/exif/rational.cc [new file with mode: 0644]
src/exif/rational.h [new file with mode: 0644]

index c53490778f2a09e2833c38148c79af558a317829..b1f5b0b98c117db64c64eedd85a3363109652029 100644 (file)
@@ -33,12 +33,10 @@ GCSPosition::GCSPosition()
 GCSPosition::GCSPosition(Rational _degrees, Rational _minutes, Rational _seconds) :
     degrees(_degrees),
     minutes(_minutes),
-    seconds(_seconds)
-{
+    seconds(_seconds) {
 }
 
-bool GCSPosition::isValid() const
-{
+bool GCSPosition::isValid() const {
   if (!(degrees.isValid() && minutes.isValid() && seconds.isValid())) {
     return false;
   }
@@ -52,16 +50,14 @@ bool GCSPosition::isValid() const
   return toDouble() <= 180.0f;
 }
 
-double GCSPosition::toDouble() const
-{
+double GCSPosition::toDouble() const {
   const double degrees_value = degrees.toDouble();
   const double minutes_value = minutes.toDouble();
   const double seconds_value = seconds.toDouble();
   return (degrees_value + (minutes_value/60.0) + (seconds_value/3600.0));
 }
 
-Rationals GCSPosition::toRationalsVector() const
-{
+Rationals GCSPosition::toRationalsVector() const {
   Rationals vec;
   vec.push_back(degrees);
   vec.push_back(minutes);
@@ -69,8 +65,7 @@ Rationals GCSPosition::toRationalsVector() const
   return vec;
 }
 
-std::string GCSPosition::toDebugString() const
-{
+std::string GCSPosition::toDebugString() const {
   std::stringstream ss;
   ss << degrees.toString() << "d ";
   ss << minutes.toString() << "m ";
@@ -78,50 +73,82 @@ std::string GCSPosition::toDebugString() const
   return ss.str();
 }
 
-GCSPosition GCSPosition::createFromDouble(double value)
-{
+GCSPosition GCSPosition::createFromDouble(double value) {
   LoggerD("Entered value:%f");
   if (value < 0) {
-       LoggerW("Trying to create GCSPosition with double < 0: %f", value);
+    LoggerW("Trying to create GCSPosition with double < 0: %f", value);
     return GCSPosition();
   }
 
   if (value > 180.0) {
-       LoggerW("Trying to create GCSPosition with double > 180.0: %f", value);
+    LoggerW("Trying to create GCSPosition with double > 180.0: %f", value);
     return GCSPosition();
   }
 
-  const double d_degrees = floor(value);
+  double d_degrees = floor(value);
   double left = value - d_degrees;
 
-  const double d_minutes = floor(left * 60.0);
+  double d_minutes = floor(left * 60.0);
   left -= d_minutes / 60.0;
 
-  const double d_seconds = left * 3600.0;
+  double d_seconds = round(left * 3600.0);
+
+  if (d_seconds >= 60.0) {
+    d_seconds -= 60.0;
+    d_minutes++;
+  }
+
+  if (d_minutes >= 60.0) {
+    d_minutes -= 60.0;
+    d_degrees++;
+  }
+
+  assert(d_degrees <= 180.0);
 
-  LOGD("d_degrees:%f d_minutes:%f d_seconds:%f", d_degrees, d_minutes, d_seconds);
+  LoggerD("d_degrees:%f d_minutes:%f d_seconds:%f",
+           d_degrees, d_minutes, d_seconds);
 
   GCSPosition pos;
   pos.degrees = Rational(static_cast<ExifLong>(d_degrees), 1);
   pos.minutes = Rational(static_cast<ExifLong>(d_minutes), 1);
   pos.seconds = Rational::createFromDouble(d_seconds);
+
   return pos;
 }
 
 ExifGPSLocation::ExifGPSLocation() :
     m_longitude_ref(GPS_LOCATION_WEST),
-    m_latitude_ref(GPS_LOCATION_NORTH)
-{
+    m_latitude_ref(GPS_LOCATION_NORTH) {
   for(int i = 0; i < EXIF_GPS_LOCATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES; ++i) {
     m_is_set[i] = false;
   }
   LoggerE("ExifGPSLocation::ExifGPSLocation()");
 }
 
-void ExifGPSLocation::setLongitude(const GCSPosition& longitude)
-{
+ExifGPSLocation::ExifGPSLocation(double longitude, double latitude) {
+  for(int i = 0; i < EXIF_GPS_LOCATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES; ++i) {
+    m_is_set[i] = false;
+  }
+
+  setLongitude(GCSPosition::createFromDouble(longitude));
+  setLatitude(GCSPosition::createFromDouble(latitude));
+
+  if (longitude < 0) {
+    setLongitudeRef(GPS_LOCATION_WEST);
+  } else {
+    setLongitudeRef(GPS_LOCATION_EAST);
+  }
+
+  if (latitude < 0) {
+    setLatitudeRef(GPS_LOCATION_SOUTH);
+  } else {
+    setLatitudeRef(GPS_LOCATION_NORTH);
+  }
+}
+
+void ExifGPSLocation::setLongitude(const GCSPosition& longitude) {
   if (!longitude.isValid()) {
-       LoggerW("longitude is not valid!");
+    LoggerW("longitude is not valid!");
     return;
   }
 
@@ -129,24 +156,20 @@ void ExifGPSLocation::setLongitude(const GCSPosition& longitude)
   m_longitude = longitude;
 }
 
-const GCSPosition& ExifGPSLocation::getLongitude() const
-{
+const GCSPosition& ExifGPSLocation::getLongitude() const {
   return m_longitude;
 }
 
-void ExifGPSLocation::setLongitudeRef(GPSLocationDirectionLongitude ref)
-{
+void ExifGPSLocation::setLongitudeRef(GPSLocationDirectionLongitude ref) {
   m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF] = true;
   m_longitude_ref = ref;
 }
 
-GPSLocationDirectionLongitude ExifGPSLocation::getLongitudeRef() const
-{
+GPSLocationDirectionLongitude ExifGPSLocation::getLongitudeRef() const {
   return m_longitude_ref;
 }
 
-void ExifGPSLocation::setLatitude(const GCSPosition& latitude)
-{
+void ExifGPSLocation::setLatitude(const GCSPosition& latitude) {
   if (!latitude.isValid()) {
     LOGW("latitude is not valid!");
     return;
@@ -156,34 +179,28 @@ void ExifGPSLocation::setLatitude(const GCSPosition& latitude)
   m_latitude = latitude;
 }
 
-const GCSPosition& ExifGPSLocation::getLatitude() const
-{
+const GCSPosition& ExifGPSLocation::getLatitude() const {
   return m_latitude;
 }
 
-void ExifGPSLocation::setLatitudeRef(GPSLocationDirectionLatitude ref)
-{
+void ExifGPSLocation::setLatitudeRef(GPSLocationDirectionLatitude ref) {
   m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE_REF] = true;
   m_latitude_ref = ref;
 }
 
-GPSLocationDirectionLatitude ExifGPSLocation::getLatitudeRef() const
-{
+GPSLocationDirectionLatitude ExifGPSLocation::getLatitudeRef() const {
   return m_latitude_ref;
 }
 
-bool ExifGPSLocation::isSet(ExifGPSLocationAttributes attribute) const
-{
+bool ExifGPSLocation::isSet(ExifGPSLocationAttributes attribute) const {
   return m_is_set[attribute];
 }
 
-void ExifGPSLocation::unset(ExifGPSLocationAttributes attribute)
-{
+void ExifGPSLocation::unset(ExifGPSLocationAttributes attribute) {
   m_is_set[attribute] = false;
 }
 
-void ExifGPSLocation::unsetAll()
-{
+void ExifGPSLocation::unsetAll() {
   m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE] = false;
   m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF] = false;
   m_longitude =  GCSPosition();
@@ -193,8 +210,7 @@ void ExifGPSLocation::unsetAll()
   m_latitude = GCSPosition();
 }
 
-bool ExifGPSLocation::isComplete() const
-{
+bool ExifGPSLocation::isComplete() const {
   return m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE] &&
       m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF] &&
       m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE] &&
@@ -202,101 +218,20 @@ bool ExifGPSLocation::isComplete() const
 }
 
 
-bool ExifGPSLocation::isValid() const
-{
+bool ExifGPSLocation::isValid() const {
   return isComplete() && m_latitude.isValid() && m_longitude.isValid();
 }
-/*
-Tizen::SimpleCoordinatesPtr ExifGPSLocation::getSimpleCoordinates() const
-{
-  if (!isComplete()) {
-    LoggerW("Some attributes are not set!");
-    return Tizen::SimpleCoordinatesPtr();
-  }
-
-  if (!isValid()) {
-    LoggerW("Some attributes are not valid!");
-    return Tizen::SimpleCoordinatesPtr();
-  }
 
-  const double cur_latitude = getLatitudeValue();
-  const double cur_longitude = getLongitudeValue();
-
-  return Tizen::SimpleCoordinatesPtr(
-    new Tizen::SimpleCoordinates(cur_latitude, cur_longitude));
-}*/
-
-double ExifGPSLocation::getLongitudeValue() const
-{
+double ExifGPSLocation::getLongitudeValue() const {
   const double longitude_dir = (m_longitude_ref == GPS_LOCATION_WEST) ? -1.0f : 1.0f;
   const double longitude = m_longitude.toDouble() * longitude_dir;
   return longitude;
 }
 
-double ExifGPSLocation::getLatitudeValue() const
-{
+double ExifGPSLocation::getLatitudeValue() const {
   const double latitude_dir = (m_latitude_ref == GPS_LOCATION_SOUTH) ? -1.0f : 1.0f;
   const double latitude = m_latitude.toDouble() * latitude_dir;
   return latitude;
 }
-/*
-bool ExifGPSLocation::set(Tizen::SimpleCoordinatesPtr scoords)
-{
-  LoggerD("Entered");
-  if (!scoords) {
-    LOGW("Trying to set null SimpleCoordinates!");
-    return false;
-  }
-
-  const double longitude = scoords->getLongitude();
-  const double latitude = scoords->getLatitude();
-  bool updateLongitude = true;
-  bool updateLatitude = true;
-
-  if(isComplete()) {
-    updateLatitude = getLatitudeValue() != latitude;
-    updateLongitude = getLongitudeValue() != longitude;
-  }
-
-  LoggerD("latitude:%f longitude:%f", latitude, longitude);
-
-  GCSPosition gcs_longitude = GCSPosition::createFromDouble(fabs(longitude));
-  LOGD("gcs_longitude deg:%s min:%s sec:%s", gcs_longitude.degrees.toString().c_str(),
-      gcs_longitude.minutes.toString().c_str(),
-      gcs_longitude.seconds.toString().c_str());
-
-  GCSPosition gcs_latitude = GCSPosition::createFromDouble(fabs(latitude));
-  LoggerD("gcs_latitude deg:%s min:%s sec:%s", gcs_latitude.degrees.toString().c_str(),
-      gcs_latitude.minutes.toString().c_str(),
-      gcs_latitude.seconds.toString().c_str());
-
-  if (!gcs_latitude.isValid() || !gcs_longitude.isValid()) {
-    return false;
-  }
-
-  if(updateLongitude) {
-    setLongitude(gcs_longitude);
-    if (longitude >= 0.0) {
-      setLongitudeRef(GPS_LOCATION_EAST);
-    }
-    else {
-      setLongitudeRef(GPS_LOCATION_WEST);
-    }
-  }
-
-  if(updateLatitude) {
-    setLatitude(gcs_latitude);
-    if (latitude >= 0.0) {
-      setLatitudeRef(GPS_LOCATION_NORTH);
-    }
-    else {
-      setLatitudeRef(GPS_LOCATION_SOUTH);
-    }
-  }
-
-  return true;
-}
-*/
-
-} // exif
-} // extension
+}  // namespace exif
+}  // namespace extension
index 4c5103c237da13e80b210daed3e1a7064bd5f1b6..64f69596646ce655389575f32ce764a141633a1d 100644 (file)
 // limitations under the License.
 //
 
-#ifndef __TIZEN_EXIF_EXIF_GPS_LOCATION_H_
-#define __TIZEN_EXIF_EXIF_GPS_LOCATION_H_
+#ifndef EXIF_EXIF_EXIFGPSLOCATION_H_
+#define EXIF_EXIF_EXIFGPSLOCATION_H_
 
 #include <string>
 #include <vector>
 
-//#include <SimpleCoordinates.h>
-
-#include "ExifUtil.h"
-#include "Rational.h"
+#include "exif_util.h"
+#include "rational.h"
 
 namespace extension {
 namespace exif {
@@ -51,8 +49,7 @@ enum ExifGPSLocationAttributes {
  * This class represents Global Coordinate System using
  * three Rational numbers (as stored in Exif)
  */
-struct GCSPosition
-{
+struct GCSPosition {
   GCSPosition();
   GCSPosition(Rational degrees, Rational minutes, Rational seconds);
 
@@ -88,10 +85,10 @@ struct GCSPosition
   Rational seconds;
 };
 
-class ExifGPSLocation
-{
-public:
+class ExifGPSLocation {
+ public:
   ExifGPSLocation();
+  ExifGPSLocation(double longitude, double latitude);
 
   void setLongitude(const GCSPosition& longitude);
   const GCSPosition& getLongitude() const;
@@ -119,18 +116,7 @@ public:
    */
   bool isValid() const;
 
-  /**
-   * Returns null pointer if any information is missing or incorrect
-   */
-  //Tizen::SimpleCoordinatesPtr getSimpleCoordinates() const;
-
-  /**
-   * Return true if scoords has been set
-   */
-  //bool set(Tizen::SimpleCoordinatesPtr scoords);
-
-private:
-
+ private:
   double getLongitudeValue() const;
   double getLatitudeValue() const;
 
@@ -143,7 +129,7 @@ private:
   bool m_is_set[EXIF_GPS_LOCATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES];
 };
 
-} // exif
-} // extension
+}  // namespace exif
+}  // namespace extension
 
-#endif // __TIZEN_EXIF_EXIF_GPS_LOCATION_H_
+#endif  // EXIF_EXIF_EXIFGPSLOCATION_H_
diff --git a/src/exif/ExifInformation.cpp b/src/exif/ExifInformation.cpp
deleted file mode 100644 (file)
index a5223e6..0000000
+++ /dev/null
@@ -1,1340 +0,0 @@
-//
-// Tizen Web Device API
-// Copyright (c) 2014 Samsung Electronics Co., Ltd.
-//
-// Licensed under the Apache License, Version 2.0 (the License);
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#include "ExifInformation.h"
-
-#include <memory>
-#include <math.h>
-
-#include "ExifTagSaver.h"
-#include "ExifUtil.h"
-#include "JpegFile.h"
-
-#include "common/platform_exception.h"
-#include "common/logger.h"
-
-namespace extension {
-namespace exif {
-
-const size_t EXIF_UNDEFINED_TYPE_LENGTH = 8;
-const std::string EXIF_UNDEFINED_TYPE_ASCII =
-    std::string("ASCII\0\0\0", EXIF_UNDEFINED_TYPE_LENGTH);
-const std::string EXIF_UNDEFINED_TYPE_JIS =
-    std::string("JIS\0\0\0\0\0", EXIF_UNDEFINED_TYPE_LENGTH);
-const std::string EXIF_UNDEFINED_TYPE_UNICODE =
-    std::string("UNICODE\0", EXIF_UNDEFINED_TYPE_LENGTH);
-const std::string EXIF_UNDEFINED_TYPE_UNDEFINED =
-    std::string("\0\0\0\0\0\0\0\0", EXIF_UNDEFINED_TYPE_LENGTH);
-
-ExifInformation::ExifInformation()
-{
-  for (int attr = 0; attr < EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES; attr++) {
-    unset(static_cast<ExifInformationAttribute>(attr));
-  }
-}
-
-ExifInformation::~ExifInformation() { }
-
-const std::string& ExifInformation::getUri()
-{
-  LoggerD("Entered");
-  return m_uri;
-}
-
-void ExifInformation::setUri(const std::string& uri)
-{
-  LoggerD("Entered");
-  m_is_set[EXIF_INFORMATION_ATTRIBUTE_URI] = true;
-  m_uri = uri;
-}
-
-unsigned long ExifInformation::getWidth() const
-{
-  LoggerD("Entered");
-  return m_width;
-}
-
-void ExifInformation::setWidth(unsigned long width)
-{
-  LoggerD("Entered");
-  m_is_set[EXIF_INFORMATION_ATTRIBUTE_WIDTH] = true;
-  m_width = width;
-}
-
-unsigned long ExifInformation::getHeight() const
-{
-  LoggerD("Entered");
-  return m_height;
-}
-
-void ExifInformation::setHeight(unsigned long height)
-{
-  LoggerD("Entered");
-  m_is_set[EXIF_INFORMATION_ATTRIBUTE_HEIGHT] = true;
-  m_height = height;
-}
-
-const std::string& ExifInformation::getDeviceMaker()
-{
-  LoggerD("Entered");
-  return m_device_maker;
-}
-
-void ExifInformation::setDeviceMaker(const std::string& device_maker)
-{
-  LoggerD("Entered");
-  m_is_set[EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER] = true;
-  m_device_maker = device_maker;
-}
-
-const std::string& ExifInformation::getDeviceModel()
-{
-  LoggerD("Entered");
-  return m_device_model;
-}
-
-void ExifInformation::setDeviceModel(const std::string& device_model)
-{
-  LoggerD("Entered");
-  m_is_set[EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL] = true;
-  m_device_model = device_model;
-}
-
-time_t ExifInformation::getOriginalTime() const
-{
-  LoggerD("Entered");
-  return m_original_time;
-}
-
-void ExifInformation::setOriginalTime(time_t original_time)
-{
-  LoggerD("Entered");
-  m_is_set[EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME] = true;
-  m_original_time = original_time;
-}
-
-ImageOrientation ExifInformation::getOrientation() const
-{
-  LoggerD("Entered");
-  return m_orientation;
-}
-
-void ExifInformation::setOrientation(ImageOrientation orientation)
-{
-  LoggerD("Entered");
-  if(EXIF_ORIENTATION_NOT_VALID == orientation) {
-    LOGW("Trying to set NOT VALID orientation");
-    return;
-  }
-
-  m_is_set[EXIF_INFORMATION_ATTRIBUTE_ORIENTATION] = true;
-  m_orientation = orientation;
-}
-
-const Rational& ExifInformation::getFNumber() const
-{
-  LoggerD("Entered");
-  return m_f_number;
-}
-
-void ExifInformation::setFNumber(Rational f_number)
-{
-  LoggerD("Entered");
-  if (!f_number.isValid()) {
-    LoggerW("Trying to set invalid F-Number: %s", f_number.toString().c_str());
-    return;
-  }
-
-  m_is_set[EXIF_INFORMATION_ATTRIBUTE_FNUMBER] = true;
-  m_f_number = f_number;
-}
-/*
-Common::JSLongLongVector ExifInformation::getIsoSpeedRatings()
-{
-  LoggerD("Entered");
-  return m_iso_speed_ratings;
-}*/
-/*
-void ExifInformation::setIsoSpeedRatings(
-    const std::vector<long long int>& iso_speed_ratings)
-{
-  LoggerD("Entered");
-  m_is_set[EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS] = true;
-  m_iso_speed_ratings = iso_speed_ratings;
-}*/
-
-void ExifInformation::appendIsoSpeedRatings(long long int iso_speed_rating)
-{
-  m_is_set[EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS] = true;
-  //m_iso_speed_ratings.push_back(iso_speed_rating);
-}
-
-const Rational& ExifInformation::getExposureTime()
-{
-  LoggerD("Entered");
-  return m_exposure_time;
-}
-
-void ExifInformation::setExposureTime(const Rational& exposure_time)
-{
-  LoggerD("Entered");
-  if (!exposure_time.isValid() || 0 == exposure_time.nominator) {
-    LoggerW("Trying to set invalid exposure time: [%s]",
-        exposure_time.toString().c_str());
-    return;
-  }
-
-  m_is_set[EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME] = true;
-  m_exposure_time = exposure_time;
-}
-
-ExposureProgram ExifInformation::getExposureProgram()
-{
-  LoggerD("Entered");
-  return m_exposure_program;
-}
-
-void ExifInformation::setExposureProgram(ExposureProgram exposure_program)
-{
-  LoggerD("Entered");
-  if (EXIF_EXPOSURE_PROGRAM_NOT_VALID == exposure_program) {
-    LOGW("Trying to set NOT VALID exposure program");
-    return;
-  }
-
-  m_is_set[EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM] = true;
-  m_exposure_program = exposure_program;
-}
-
-bool ExifInformation::getFlash() const
-{
-  LoggerD("Entered");
-  return m_flash;
-}
-
-void ExifInformation::setFlash(bool flash)
-{
-  LoggerD("Entered");
-  m_is_set[EXIF_INFORMATION_ATTRIBUTE_FLASH] = true;
-  m_flash = flash;
-}
-
-const Rational& ExifInformation::getFocalLength() const
-{
-  LoggerD("Entered");
-  return m_focal_length;
-}
-
-void ExifInformation::setFocalLength(Rational focal_length)
-{
-  LoggerD("Entered");
-  if(!focal_length.isValid()) {
-    LoggerW("Trying to set invalid focal length: %s", focal_length.toString().c_str());
-    return;
-  }
-
-  m_is_set[EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH] = true;
-  m_focal_length = focal_length;
-}
-
-WhiteBalanceMode ExifInformation::getWhiteBalanceMode() const
-{
-  LoggerD("Entered");
-  return m_white_balance;
-}
-
-void ExifInformation::setWhiteBalanceMode(WhiteBalanceMode white_balance)
-{
-  LoggerD("Entered");
-  if (EXIF_WHITE_BALANCE_MODE_NOT_VALID == white_balance) {
-    LOGW("Trying to set NOT VALID white balance mode");
-    return;
-  }
-
-  m_is_set[EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE] = true;
-  m_white_balance = white_balance;
-}
-
-ExifGPSLocation& ExifInformation::getGPSExifLocation()
-{
-  return m_exif_gps_location;
-}
-/*
-Tizen::SimpleCoordinatesPtr ExifInformation::getGPSLocation()
-{
-  if(m_gps_location) {
-    return m_gps_location;
-  }
-
-
-  Tizen::SimpleCoordinatesPtr nscoords = m_exif_gps_location.getSimpleCoordinates();
-  if(!nscoords) {
-    return nscoords;
-  }
-
-  m_gps_location = nscoords;
-  return m_gps_location;
-}*/
-/*
-void ExifInformation::setGPSLocation(Tizen::SimpleCoordinatesPtr gps_location)
-{
-  if(!gps_location) {
-    LoggerW("Trying to set NULL gps location!");
-    return;
-  }
-
-  m_gps_location = gps_location;
-}*/
-
-void ExifInformation::unsetGPSLocation()
-{
-  //m_gps_location = Tizen::SimpleCoordinatesPtr();
-  m_exif_gps_location.unsetAll();
-}
-
-const Rational& ExifInformation::getGpsAltitude() const
-{
-  LoggerD("Entered");
-  return m_gps_altitude;
-}
-
-void ExifInformation::setGpsAltitude(Rational gps_altitude)
-{
-  LoggerD("Entered");
-  if (!gps_altitude.isValid()) {
-    LoggerW("Trying to set invalid gps altitude: %s", gps_altitude.toString().c_str());
-    return;
-  }
-
-  m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE] = true;
-  m_gps_altitude = gps_altitude;
-}
-
-GpsAltitudeRef ExifInformation::getGpsAltitudeRef() const
-{
-  LoggerD("Entered");
-  return m_gps_altitude_ref;
-}
-
-void ExifInformation::setGpsAltitudeRef(const GpsAltitudeRef ref)
-{
-  LoggerD("Entered");
-  m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF] = true;
-  m_gps_altitude_ref = ref;
-}
-
-void ExifInformation::setGpsAltitudeWithRef(double gps_altitude)
-{
-  LoggerD("Entered");
-  setGpsAltitude(Rational::createFromDouble(fabs(gps_altitude)));
-
-  if(gps_altitude >= 0.0) {
-    setGpsAltitudeRef(GPS_ALTITUDE_REF_ABOVE_SEA);
-  } else {
-    setGpsAltitudeRef(GPS_ALTITUDE_REF_BELOW_SEA);
-  }
-
-}
-
-double ExifInformation::getGpsAltitudeWithRef() const
-{
-  LoggerD("Entered");
-
-  if (!m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF] ||
-      GPS_ALTITUDE_REF_ABOVE_SEA == m_gps_altitude_ref) {
-    return m_gps_altitude.toDouble();
-  } else {
-    return -1.0 * m_gps_altitude.toDouble();
-  }
-}
-
-const std::string& ExifInformation::getGpsProcessingMethod() const
-{
-  LoggerD("Entered");
-  return m_gps_processing_method;
-}
-
-const std::string& ExifInformation::getGpsProcessingMethodType() const
-{
-  LoggerD("Entered");
-  return m_gps_processing_method_type;
-}
-
-void ExifInformation::setGpsProcessingMethod(const std::string& type,
-    const std::string& processing_method)
-{
-  LoggerD("Entered");
-  if (type != EXIF_UNDEFINED_TYPE_ASCII &&
-      type != EXIF_UNDEFINED_TYPE_JIS &&
-      type != EXIF_UNDEFINED_TYPE_UNICODE &&
-      type != EXIF_UNDEFINED_TYPE_UNDEFINED) {
-    LoggerW("Trying to set invalid GPSProcessingMethod type: [%s] len:%d",
-        type.c_str(), type.length());
-    return;
-  }
-
-  m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD] = true;
-  m_gps_processing_method = processing_method;
-  m_gps_processing_method_type = type;
-}
-/*
-ExifGPSTime& ExifInformation::getExifGpsTime()
-{
-  return m_exif_gps_time;
-}*/
-/*
-const ExifGPSTime& ExifInformation::getExifGpsTime() const
-{
-  return m_exif_gps_time;
-}*/
-
-/*
-Time::TZDatePtr ExifInformation::getGpsTime()
-{
-  if(m_gps_time) {
-    return m_gps_time;
-  }
-
-  if(!m_exif_gps_time.isValid()) {
-    return Time::TZDatePtr();
-  }
-
-
-  m_gps_time = m_exif_gps_time.getTZDate();
-  return m_gps_time;
-}*/
-/*
-void ExifInformation::setGpsTime(Time::TZDatePtr new_time)
-{
-  if(!new_time) {
-    LoggerW("Trying to set null new_time!");
-    return;
-  }
-
-  m_gps_time = new_time;
-}*/
-
-void ExifInformation::unsetGPStime()
-{
-  //m_exif_gps_time.unsetAll();
-  //m_gps_time = NULL;
-}
-
-
-const std::string& ExifInformation::getUserComment()
-{
-  LoggerD("Entered");
-  return m_user_comment;
-}
-
-const std::string& ExifInformation::getUserCommentType()
-{
-  LoggerD("Entered");
-  return m_user_comment_type;
-}
-
-void ExifInformation::setUserComment(const std::string& type,
-    const std::string& user_comment)
-{
-  LoggerD("Entered");
-  if (type != EXIF_UNDEFINED_TYPE_ASCII &&
-      type != EXIF_UNDEFINED_TYPE_JIS &&
-      type != EXIF_UNDEFINED_TYPE_UNICODE &&
-      type != EXIF_UNDEFINED_TYPE_UNDEFINED) {
-       LoggerW("Trying to set invalid user comment type: [%s] len:%d",
-        type.c_str(), type.length());
-    return;
-  }
-
-  m_is_set[EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT] = true;
-  m_user_comment_type = type;
-  m_user_comment = user_comment;
-}
-
-bool ExifInformation::isSet(ExifInformationAttribute attribute) const
-{
-  LoggerD("Entered");
-  return m_is_set[attribute];
-}
-
-void ExifInformation::unset(ExifInformationAttribute attribute)
-{
-  LoggerD("Entered");
-  if (attribute >= EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES) {
-    return;
-  }
-
-  m_is_set[attribute] = false;
-  switch (attribute) {
-    case EXIF_INFORMATION_ATTRIBUTE_URI:
-      m_uri = std::string();
-      break;
-    case EXIF_INFORMATION_ATTRIBUTE_WIDTH:
-      m_width = 0;
-      break;
-    case EXIF_INFORMATION_ATTRIBUTE_HEIGHT:
-      m_height = 0;
-      break;
-    case EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER:
-      m_device_maker = std::string();
-      break;
-    case EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL:
-      m_device_model = std::string();
-      break;
-    case EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME:
-      m_original_time = 0;
-      break;
-    case EXIF_INFORMATION_ATTRIBUTE_ORIENTATION:
-      m_orientation = EXIF_ORIENTATION_NOT_VALID;
-      break;
-    case EXIF_INFORMATION_ATTRIBUTE_FNUMBER:
-      m_f_number = Rational::createInvalid();
-      break;
-    case EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS:
-      //m_iso_speed_ratings = std::vector<long long int>();
-      break;
-    case EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME:
-      m_exposure_time = Rational::createInvalid();
-      break;
-    case EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM:
-      m_exposure_program = EXIF_EXPOSURE_PROGRAM_NOT_VALID;
-      break;
-    case EXIF_INFORMATION_ATTRIBUTE_FLASH:
-      m_flash = false;
-      break;
-    case EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH:
-      m_focal_length = Rational::createInvalid();
-      break;
-    case EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE:
-      m_white_balance = EXIF_WHITE_BALANCE_MODE_NOT_VALID;
-      break;
-    case EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE:
-      m_gps_altitude = Rational::createInvalid();
-      break;
-    case EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF:
-      m_gps_altitude_ref = GPS_ALTITUDE_REF_ABOVE_SEA;
-      break;
-    case EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD:
-      m_gps_processing_method = std::string();
-      m_gps_processing_method_type = EXIF_UNDEFINED_TYPE_ASCII;
-      break;
-    case EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT:
-      m_user_comment = std::string();
-      m_user_comment_type = EXIF_UNDEFINED_TYPE_ASCII;
-      break;
-    default:
-      break;
-  }
-}
-
-bool getGCSPositionFromEntry(ExifEntry *entry, ExifData* exif_data, GCSPosition& out_pos)
-{
-  //RATIONAL - 3
-  if (EXIF_FORMAT_RATIONAL == entry->format &&
-      entry->components >= 3 &&
-      entry->data) {
-    const ExifByteOrder order = exif_data_get_byte_order(exif_data);
-    out_pos.degrees = Rational(exif_get_rational(entry->data, order));
-    out_pos.minutes = Rational(exif_get_rational(
-        entry->data +   ExifTypeInfo::RationalSize, order));
-    out_pos.seconds = Rational(exif_get_rational(
-        entry->data + 2*ExifTypeInfo::RationalSize, order));
-    return true;
-  }
-  else {
-    return false;
-  }
-}
-
-bool getRationalsFromEntry(ExifEntry *entry, ExifData* exif_data,
-      unsigned long required_count, Rationals& out_rationals)
-{
-  if (EXIF_FORMAT_RATIONAL == entry->format &&
-      entry->components >= required_count &&
-      entry->data) {
-    const ExifByteOrder order = exif_data_get_byte_order(exif_data);
-    unsigned char* ptr = entry->data;
-
-    for(unsigned long i = 0; i < required_count; ++i) {
-      out_rationals.push_back(Rational(exif_get_rational(ptr, order)));
-      ptr += ExifTypeInfo::RationalSize;
-    }
-
-    return true;
-  }
-  else {
-    return false;
-  }
-}
-
-Rational getRationalFromEntry(ExifEntry *entry, ExifData* exif_data)
-{
-  if (EXIF_FORMAT_RATIONAL == entry->format && entry->components >= 1 && entry->data) {
-    const ExifByteOrder order = exif_data_get_byte_order(exif_data);
-    return Rational(exif_get_rational(entry->data, order));
-  }
-  else {
-    return Rational::createInvalid();
-  }
-}
-
-bool decomposeExifUndefined(ExifEntry* entry, std::string& type, std::string& value)
-{
-  if(!entry || !entry->data) {
-    LoggerW("exif entry is NULL/empty");
-    return false;
-  }
-
-  if(entry->size < EXIF_UNDEFINED_TYPE_LENGTH) {
-    LoggerW("entry size is invalid %d < EXIF_UNDEFINED_TYPE_LENGTH", entry->size);
-    return false;
-  }
-
-  const char* ptr = reinterpret_cast<const char*>(entry->data);
-  type = std::string(ptr, EXIF_UNDEFINED_TYPE_LENGTH);
-  ptr += EXIF_UNDEFINED_TYPE_LENGTH;
-  value = std::string(ptr, entry->size - EXIF_UNDEFINED_TYPE_LENGTH);
-  return true;
-}
-
-void ExifInformation::processEntry(ExifEntry* entry, ExifData* exif_data)
-{
-  char buf[2000];
-  exif_entry_get_value(entry, buf, sizeof(buf));
-  ExifUtil::printExifEntryInfo(entry, exif_data);
-
-  const ExifIfd cur_ifd = exif_entry_get_ifd(entry);
-  if (EXIF_IFD_INTEROPERABILITY == cur_ifd || EXIF_IFD_1 == cur_ifd) {
-    return;
-  }
-
-  switch (static_cast<unsigned int>(entry->tag)) {
-    case EXIF_TAG_IMAGE_WIDTH: {
-      //SHORT or LONG - 1
-      exif_entry_get_value(entry, buf, sizeof(buf));
-      LoggerD( "Setting ExifInformation width to: [%s]", buf );
-      setWidth(atol(buf));
-      break;
-    }
-    case EXIF_TAG_IMAGE_LENGTH: {
-      //SHORT or LONG - 1
-      exif_entry_get_value(entry, buf, sizeof(buf));
-      LoggerD( "Setting ExifInformation height to: [%s]", buf );
-      setHeight(atol(buf));
-      break;
-    }
-    case EXIF_TAG_MAKE: {
-      //ASCII - Any
-      exif_entry_get_value(entry, buf, sizeof(buf));
-      LoggerD( "Setting ExifInformation maker to: [%s]", buf );
-      setDeviceMaker(std::string(buf));
-      break;
-    }
-    case EXIF_TAG_MODEL: {
-      //ASCII - Any
-      exif_entry_get_value(entry, buf, sizeof(buf));
-      LoggerD( "Setting ExifInformation model to: [%s]", buf );
-      setDeviceModel(std::string(buf));
-      break;
-    }
-    case EXIF_TAG_DATE_TIME_ORIGINAL: {
-      //ASCII - 20
-      exif_entry_get_value(entry, buf, sizeof(buf));
-      const time_t time = ExifUtil::exifDateTimeOriginalToTimeT(
-          reinterpret_cast<const char*>(entry->data));
-      LoggerD( "Setting ExifInformation time original to: [%s] time_t:%d", buf,
-          (int)time);
-      setOriginalTime(time);
-    }
-    case EXIF_TAG_ORIENTATION: {
-      //SHORT - 1
-      exif_entry_get_value(entry, buf, sizeof(buf));
-      const ExifByteOrder order = exif_data_get_byte_order(exif_data);
-      const ExifShort orient(exif_get_short(entry->data, order));
-
-      if(orient < EXIF_ORIENTATION_NORMAL || orient >= EXIF_ORIENTATION_NOT_VALID) {
-        LoggerW("Couldn't set ExifInformation - orientation is not valid: %d (%s)",
-            orient, buf);
-      }
-      else {
-        LoggerD("Setting ExifInformation orientation to: %d [%s]", orient, buf);
-        setOrientation(static_cast<ImageOrientation>(orient));
-      }
-      break;
-    }
-    case EXIF_TAG_FNUMBER:
-    {
-      //RATIONAL - 1
-      Rational fnumber = getRationalFromEntry(entry, exif_data);
-      if(fnumber.isValid()) {
-        LOGD("Setting ExifInformation fnumber to: %f (%s)", fnumber.toDouble(),
-          fnumber.toString().c_str());
-        setFNumber(fnumber);
-      }
-      else {
-        LOGW("Couldn't set ExifInformation - fnumber is not valid: %s",
-            fnumber.toString().c_str());
-      }
-      break;
-    }
-    case EXIF_TAG_ISO_SPEED_RATINGS: {
-      //SHORT - Any
-      if (EXIF_FORMAT_SHORT == entry->format &&
-          entry->components > 0 &&
-          entry->data) {
-        const ExifByteOrder order = exif_data_get_byte_order(exif_data);
-        unsigned char* read_ptr = entry->data;
-        const size_t size_per_member =
-            ExifUtil::getSizeOfExifFormatType(entry->format);
-
-        for(unsigned long i = 0; i < entry->components; ++i) {
-          ExifShort iso_rating = exif_get_short(read_ptr, order);
-          appendIsoSpeedRatings(iso_rating);
-
-          LoggerD("Appending ExifInformation speed ratings with: %d",
-              static_cast<int>(iso_rating));
-
-          read_ptr += size_per_member;
-        }
-      }
-      else {
-        LoggerE("iso speed ratings: format or components count is invalid!");
-      }
-      break;
-    }
-    case EXIF_TAG_EXPOSURE_TIME: {
-      //RATIONAL - 1
-      if (EXIF_FORMAT_RATIONAL == entry->format &&
-          entry->components > 0 &&
-          entry->data) {
-
-        const ExifByteOrder order = exif_data_get_byte_order(exif_data);
-        const Rational exp_time(exif_get_rational(entry->data, order));
-
-        if (exp_time.isValid()) {
-          LoggerD("Setting ExifInformation exposure time to: %s (%s)",
-              exp_time.toString().c_str(),
-              exp_time.toExposureTimeString().c_str());
-          setExposureTime(exp_time);
-        }
-        else {
-          LoggerD("Couldn't set ExifInformation - exposure time is not valid: %s",
-              exp_time.toString().c_str());
-        }
-      }
-      else {
-        LoggerE("exposure time: format or components count is invalid!");
-      }
-      break;
-    }
-    case EXIF_TAG_EXPOSURE_PROGRAM: {
-      //SHORT - 1
-      exif_entry_get_value(entry, buf, sizeof(buf));
-
-      const ExifByteOrder order = exif_data_get_byte_order(exif_data);
-      const ExifShort exp_program = exif_get_short(entry->data, order);
-      if(exp_program >= EXIF_EXPOSURE_PROGRAM_NOT_VALID) {
-        LoggerW("ExposureProgram: %d (%s) is not valid!", exp_program, buf);
-      }
-      else {
-        LoggerD("Setting ExifInformation exposure program to: %d [%s]",
-            exp_program, buf );
-        setExposureProgram(static_cast<ExposureProgram>(exp_program));
-      }
-      break;
-    }
-    case EXIF_TAG_FLASH: {
-      //SHORT - 1
-      exif_entry_get_value(entry, buf, sizeof(buf));
-
-      const ExifByteOrder order = exif_data_get_byte_order(exif_data);
-      const ExifShort flash = exif_get_short(entry->data, order);
-
-      LoggerD( "Setting ExifInformation flash to: [%s] flash=%d", buf, flash);
-      setFlash(flash != 0);
-      break;
-    }
-    case EXIF_TAG_FOCAL_LENGTH: {
-      //RATIONAL - 1
-      Rational flength = getRationalFromEntry(entry, exif_data);
-      if(flength.isValid()) {
-        LoggerD("Setting ExifInformation focal length to: %f (%s)",
-            flength.toDouble(), flength.toString().c_str());
-        setFocalLength(flength);
-      }
-      else {
-        LoggerW("Couldn't set ExifInformation - focal length is not valid: %s",
-            flength.toString().c_str());
-      }
-      break;
-    }
-    case EXIF_TAG_WHITE_BALANCE: {
-      //SHORT - 1
-      exif_entry_get_value(entry, buf, sizeof(buf));
-      LoggerD( "Setting ExifInformation white balance to: [%s]", buf );
-      if (entry->data[0]) {
-        setWhiteBalanceMode(EXIF_WHITE_BALANCE_MODE_MANUAL);
-      }
-      else {
-        setWhiteBalanceMode(EXIF_WHITE_BALANCE_MODE_AUTO);
-      }
-      break;
-    }
-    case EXIF_TAG_GPS_LONGITUDE: {
-      //RATIONAL - 3
-      GCSPosition longitude;
-      if (getGCSPositionFromEntry(entry, exif_data, longitude)) {
-        m_exif_gps_location.setLongitude(longitude);
-        LoggerD("Setting ExifInformation gps longitude to: %s; %s; %s valid:%d",
-            longitude.degrees.toString().c_str(),
-            longitude.minutes.toString().c_str(),
-            longitude.seconds.toString().c_str(),
-            longitude.isValid());
-      }
-      else {
-        exif_entry_get_value(entry, buf, sizeof(buf));
-        LoggerW("Couldn't set longitude pos - data is not valid: [%s]", buf);
-      }
-      break;
-    }
-    case EXIF_TAG_GPS_LONGITUDE_REF: {
-      //ASCII - 2
-      if(entry->size < 1) {
-        LoggerW("Longtitude ref entry do not contain enought data!");
-        break;
-      }
-
-      const char ref = static_cast<char>(entry->data[0]);
-      if ('E' == ref || 'e' == ref) {      //East
-        m_exif_gps_location.setLongitudeRef(GPS_LOCATION_EAST);
-        LoggerD("Setting ExifInformation gps longitude REF to: EAST");
-      }
-      else if ('W' == ref || 'w' == ref) {   //West
-        m_exif_gps_location.setLongitudeRef(GPS_LOCATION_WEST);
-        LoggerD("Setting ExifInformation gps longitude REF to: WEST");
-      }
-      else {
-        LoggerW("Unknown longitude ref: %c (0x%x)", ref, static_cast<int>(ref));
-      }
-      break;
-    }
-    case EXIF_TAG_GPS_LATITUDE: {
-      //RATIONAL - 3
-      exif_entry_get_value(entry, buf, sizeof(buf));
-      LoggerD( "Setting ExifInformation latitude to: [%s], tag->%s",
-          buf, exif_tag_get_name(entry->tag) );
-
-      GCSPosition latitude;
-      if (getGCSPositionFromEntry(entry, exif_data, latitude)) {
-        m_exif_gps_location.setLatitude(latitude);
-        LoggerD("Setting ExifInformation gps latitude to: %s; %s; %s valid:%d",
-            latitude.degrees.toString().c_str(),
-            latitude.minutes.toString().c_str(),
-            latitude.seconds.toString().c_str(),
-            latitude.isValid());
-      }
-      else {
-        LoggerW("Couldn't set latitude pos - data is not valid!");
-      }
-      break;
-    }
-    case EXIF_TAG_GPS_LATITUDE_REF: {
-      //ASCII - 2
-      if(entry->size < 1) {
-        LoggerW("Latitude ref entry do not contain enought data!");
-        break;
-      }
-
-      const char ref = static_cast<char>(entry->data[0]);
-      if ('N' == ref || 'n' == ref) {      //North
-        m_exif_gps_location.setLatitudeRef(GPS_LOCATION_NORTH);
-        LoggerD("Setting ExifInformation gps latitude REF to: NORTH");
-      }
-      else if ('S' == ref || 's' == ref) {   //South
-        m_exif_gps_location.setLatitudeRef(GPS_LOCATION_SOUTH);
-        LoggerD("Setting ExifInformation gps latitude REF to: SOUTH");
-      }
-      else {
-        LoggerW("Unknown latitude ref: %c (0x%x)", ref, static_cast<int>(ref));
-      }
-      break;
-    }
-    case EXIF_TAG_GPS_ALTITUDE: {
-      //RATIONAL - 1
-      Rational gps_altitude = getRationalFromEntry(entry, exif_data);
-      if(gps_altitude.isValid()) {
-        LoggerD("Setting ExifInformation gps altitude to: %f (%s)",
-            gps_altitude.toDouble(), gps_altitude.toString().c_str());
-        setGpsAltitude(gps_altitude);
-      }
-      else {
-        LoggerW("Couldn't set ExifInformation - gps altitude is not valid: %s",
-            gps_altitude.toString().c_str());
-      }
-      break;
-    }
-    case EXIF_TAG_GPS_ALTITUDE_REF: {
-      //BYTE - 1
-      const ExifByte altitude_ref = static_cast<ExifByte>(entry->data[0]);
-      if(static_cast<ExifByte>(GPS_ALTITUDE_REF_ABOVE_SEA) == altitude_ref ||
-          static_cast<ExifByte>(GPS_ALTITUDE_REF_BELOW_SEA) == altitude_ref) {
-        setGpsAltitudeRef(static_cast<GpsAltitudeRef>(altitude_ref));
-        LoggerD( "Setting ExifInformation gps altitude ref to: %d (%s)",
-            static_cast<int>(altitude_ref),
-            (altitude_ref > 0) ? "below sea" : "above sea");
-      } else {
-        LoggerW("GPS altitude ref is invalid:%d should be 0 or 1!",
-            static_cast<int>(altitude_ref));
-      }
-      break;
-    }
-    case EXIF_TAG_GPS_PROCESSING_METHOD: {
-      //UNDEFINED - Any
-      std::string type, value;
-      if(decomposeExifUndefined(entry, type, value)) {
-        LoggerD("Extracted GPSProcessingMethod: [%s], len:%d, type:%s",
-            value.c_str(), value.length(), type.c_str());
-        setGpsProcessingMethod(type, value);
-
-        LoggerD("Setting ExifInformation processing method to: [%s], len:%d, type:%s",
-            m_gps_processing_method.c_str(),
-            m_gps_processing_method.length(),
-            m_gps_processing_method_type.c_str());
-      }
-      else {
-        LoggerW("GPSProcessingMethod tag contains invalid values!");
-      }
-      break;
-    }
-    case EXIF_TAG_GPS_DATE_STAMP: {
-      //ASCII - 11
-      exif_entry_get_value(entry, buf, sizeof(buf));
-      LoggerD( "Setting ExifInformation gps date stamp to: [%s]", buf );
-      //m_exif_gps_time.setDate(buf);
-      break;
-    }
-    case EXIF_TAG_GPS_TIME_STAMP: {
-      //Rational - 3
-      exif_entry_get_value(entry, buf, sizeof(buf));
-      LoggerD( "Setting ExifInformation gps time stamp to: [%s]", buf);
-
-      Rationals time;
-      if (getRationalsFromEntry(entry, exif_data, 3, time)) {
-        //m_exif_gps_time.setTime(time);
-      }
-      break;
-    }
-    case EXIF_TAG_USER_COMMENT: {
-      //UNDEFINED - Any
-      std::string type, value;
-      if(decomposeExifUndefined(entry, type, value)) {
-        LoggerD("Extracted UserComment: [%s], len:%d, type:%s",
-            value.c_str(), value.length(), type.c_str());
-        setUserComment(type, value);
-
-        LoggerD("Setting ExifInformation user comment to: [%s], len:%d, type:%s",
-            m_user_comment.c_str(),
-            m_user_comment.length(),
-            m_user_comment_type.c_str());
-      }
-      else {
-        LoggerW("UserComment tag contains invalid values!");
-      }
-
-      break;
-    }
-    default:
-      LoggerD("Field of tag:%x.H [%s] is not supported, value: [%s]", entry->tag,
-          exif_tag_get_name_in_ifd(entry->tag, cur_ifd),
-          exif_entry_get_value(entry, buf, sizeof(buf)));
-  }
-}
-
-struct ExifInfoAndDataHolder {
-  ExifInformationPtr exif_info;
-  ExifData* exif_data;
-};
-
-void ExifInformation::contentForeachFunctionProxy(ExifEntry *entry, void *user_data)
-{
-  ExifInfoAndDataHolder* holder = static_cast<ExifInfoAndDataHolder*>(user_data);
-  if (!holder) {
-    LoggerE("holder is NULL");
-  }
-
-  if (!holder->exif_info) {
-    LoggerE("exif_info is NULL!");
-    return;
-  }
-
-  if (!holder->exif_data) {
-    LoggerE("exif_data is NULL!");
-    return;
-  }
-
-  try {
-    holder->exif_info->processEntry(entry, holder->exif_data);
-  }
-  /*catch(const BasePlatformException &err) {
-    LoggerE("processEntry thrown exception: %s : %s", err.getName().c_str(),
-          err.getMessage().c_str());
-  }*/
-  catch(...) {
-    LoggerE("Unsupported error while processing Exif entry.");
-  }
-}
-
-void ExifInformation::dataForeachFunction(ExifContent *content, void *user_data)
-{
-  exif_content_foreach_entry(content, contentForeachFunctionProxy, user_data);
-}
-
-
-ExifInformationPtr ExifInformation::loadFromURI(const std::string& uri)
-{
-  ExifInformationPtr exif_info(new ExifInformation());
-  exif_info->setUri(uri);
-
-  const std::string file_path = ExifUtil::convertUriToPath(uri);
-  ExifData* ed = exif_data_new_from_file (file_path.c_str());
-  if (!ed) {
-    LoggerE("Error reading exif from file %s", file_path.c_str());
-    LoggerE("Error reading exif from file %s", file_path.c_str());
-    //throw NotFoundException("Error reading exif from file");
-  }
-
-  LoggerD("exif_data_foreach_content START");
-
-  ExifInfoAndDataHolder holder;
-  holder.exif_info = exif_info;
-  holder.exif_data = ed;
-  exif_data_foreach_content(ed, dataForeachFunction, static_cast<void*>(&holder));
-
-  LoggerD("exif_data_foreach_content END");
-
-  exif_data_unref(ed);
-  ed = NULL;
-
-  return exif_info;
-}
-
-
-void ExifInformation::removeNulledAttributesFromExifData(ExifData* exif_data)
-{
-  LOGD("Entered");
-  if(!exif_data) {
-    LoggerE("exif_data is NULL");
-    throw common::UnknownException("Invalid Exif provided");
-  }
-
-  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_WIDTH)) {
-    LoggerD("Removing width");
-    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_IMAGE_WIDTH, exif_data);
-  }
-  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_HEIGHT)) {
-    LoggerD("Removing height");
-    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_IMAGE_LENGTH, exif_data);
-  }
-  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER)) {
-    LoggerD("Removing device maker");
-    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_MAKE, exif_data);
-  }
-  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_ORIENTATION)) {
-    LoggerD("Removing orientation");
-    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_ORIENTATION, exif_data);
-  }
-  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM)) {
-    LoggerD("Removing exposure program");
-    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_EXPOSURE_PROGRAM, exif_data);
-  }
-  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS)) {
-    LoggerD("Removing iso speed ratings");
-    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_ISO_SPEED_RATINGS, exif_data);
-  }
-  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE)) {
-    LoggerD("Removing white balance");
-    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_WHITE_BALANCE, exif_data);
-  }
-  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL)) {
-    LoggerD("Removing device model");
-    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_MODEL, exif_data);
-  }
-  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME)) {
-    LoggerD("Removing original time");
-    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_DATE_TIME_ORIGINAL, exif_data);
-  }
-  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME)) {
-    LoggerD("Removing exposure time");
-    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_EXPOSURE_TIME, exif_data);
-  }
-  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_FNUMBER)) {
-    LoggerD("Removing f-number");
-    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_FNUMBER, exif_data);
-  }
-  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_FLASH)) {
-    LoggerD("Removing flash");
-    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_FLASH, exif_data);
-  }
-  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH)) {
-    LoggerD("Removing focal length");
-    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_FOCAL_LENGTH, exif_data);
-  }
-  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE)) {
-    LoggerD("Removing gps altitude");
-    ExifTagSaver::removeExifEntryWithTag(
-      static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE), exif_data);
-  }
-  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF)) {
-    LoggerD("Removing gps altitude ref");
-    ExifTagSaver::removeExifEntryWithTag(
-        static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE_REF), exif_data);
-  }
-  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD)) {
-    LoggerD("Removing gps processing method");
-    ExifTagSaver::removeExifEntryWithTag(
-        static_cast<ExifTag>(EXIF_TAG_GPS_PROCESSING_METHOD), exif_data);
-  }
-  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT)) {
-    LoggerD("Removing user comment");
-    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_USER_COMMENT, exif_data);
-  }
-
-  if (!m_exif_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE)) {
-    LoggerD("Removing latitude");
-    ExifTagSaver::removeExifEntryWithTag(
-        static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE), exif_data);
-  }
-  if (!m_exif_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE_REF)) {
-    LoggerD("Removing latitude ref");
-    ExifTagSaver::removeExifEntryWithTag(
-        static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE_REF), exif_data);
-  }
-  if (!m_exif_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE)) {
-    LoggerD("Removing longitude");
-    ExifTagSaver::removeExifEntryWithTag(
-        static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE), exif_data);
-  }
-  if (!m_exif_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF)) {
-    LoggerD("Removing longitude ref");
-    ExifTagSaver::removeExifEntryWithTag(
-        static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE_REF), exif_data);
-  }
-/*
-  if (!m_exif_gps_time.isTimeSet()) {
-    LoggerD("Removing gps time");
-    ExifTagSaver::removeExifEntryWithTag(
-        static_cast<ExifTag>(EXIF_TAG_GPS_TIME_STAMP), exif_data);
-  }
-  if (!m_exif_gps_time.isDateSet()) {
-    LoggerD("Removing gps date");
-    ExifTagSaver::removeExifEntryWithTag(
-        static_cast<ExifTag>(EXIF_TAG_GPS_DATE_STAMP), exif_data);
-  }*/
-}
-
-void ExifInformation::updateAttributesInExifData(ExifData* exif_data)
-{
-  LOGD("Entered");
-  if(!exif_data) {
-    LoggerE("exif_data is NULL");
-    throw common::UnknownException("Invalid Exif provided");
-  }
-
-  if (isSet(EXIF_INFORMATION_ATTRIBUTE_WIDTH)) {
-    LoggerD("Saving width: %d", getWidth());
-    ExifTagSaver::saveToExif(getWidth(),
-        EXIF_TAG_IMAGE_WIDTH, exif_data);
-  }
-  if (isSet(EXIF_INFORMATION_ATTRIBUTE_HEIGHT)) {
-    LoggerD("Saving height: %d", getHeight());
-    ExifTagSaver::saveToExif(getHeight(),
-        EXIF_TAG_IMAGE_LENGTH, exif_data);
-  }
-  if (isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER)) {
-    LoggerD("Saving device maker: %s", getDeviceMaker().c_str());
-    ExifTagSaver::saveToExif(getDeviceMaker(),
-        EXIF_TAG_MAKE, exif_data);
-  }
-  if (isSet(EXIF_INFORMATION_ATTRIBUTE_ORIENTATION)) {
-    LoggerD("Saving orientation: %d", static_cast<int>(getOrientation()));
-    ExifTagSaver::saveToExif(static_cast<long int>(getOrientation()),
-        EXIF_TAG_ORIENTATION, exif_data);
-  }
-  if (isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM)) {
-    LoggerD("Saving exposure program: %d", static_cast<int>(getExposureProgram()));
-    ExifTagSaver::saveToExif(getExposureProgram(),
-        EXIF_TAG_EXPOSURE_PROGRAM, exif_data);
-  }
-  if (isSet(EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS)) {
-    //std::vector<long long int> iso_ratings = getIsoSpeedRatings();
-    //LoggerD("Saving iso speed ratings count:%d", iso_ratings.size());
-    //ExifTagSaver::saveToExif(iso_ratings, EXIF_FORMAT_SHORT,
-    //    EXIF_TAG_ISO_SPEED_RATINGS, exif_data);
-  }
-  if (isSet(EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE)) {
-    LoggerD("Saving white balance: %d", static_cast<int>(getWhiteBalanceMode()));
-    ExifTagSaver::saveToExif(getWhiteBalanceMode(),
-        EXIF_TAG_WHITE_BALANCE, exif_data);
-  }
-  if (isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL)) {
-    LoggerD("Saving device model: %s", getDeviceModel().c_str());
-    ExifTagSaver::saveToExif(getDeviceModel(),
-        EXIF_TAG_MODEL, exif_data);
-  }
-  if (isSet(EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME)) {
-    const time_t o_time = getOriginalTime();
-    const std::string o_time_str = ExifUtil::timeTToExifDateTimeOriginal(o_time);
-    LoggerD("Saving original time time_t:%d, format:%s", static_cast<int>(o_time),
-        o_time_str.c_str());
-
-    ExifTagSaver::saveToExif(o_time_str,
-        EXIF_TAG_DATE_TIME_ORIGINAL, exif_data);
-  }
-  if (isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME)) {
-    Rational exposure_time = getExposureTime();
-    if (exposure_time.isValid()) {
-      LoggerD("Saving exposure time: %s (%s)",
-          exposure_time.toString().c_str(),
-          exposure_time.toExposureTimeString().c_str());
-
-      ExifTagSaver::saveToExif(exposure_time,
-          EXIF_TAG_EXPOSURE_TIME, exif_data);
-    }
-  }
-  if (isSet(EXIF_INFORMATION_ATTRIBUTE_FNUMBER)) {
-    auto f_number = getFNumber();
-    LoggerD("Saving f-number: %f (%s)", f_number.toDouble(),
-        f_number.toString().c_str());
-    ExifTagSaver::saveToExif(f_number,
-        EXIF_TAG_FNUMBER, exif_data);
-  }
-  if (isSet(EXIF_INFORMATION_ATTRIBUTE_FLASH)) {
-    LoggerD("Saving flash: %s", getFlash() ? "ON" : "OFF");
-    ExifTagSaver::saveToExif(getFlash(),
-        EXIF_TAG_FLASH, exif_data);
-  }
-  if (isSet(EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH)) {
-    auto f_length = getFocalLength();
-    LoggerD("Saving focal length:%f (%s)", f_length.toDouble(),
-        f_length.toString().c_str());
-    ExifTagSaver::saveToExif(f_length,
-        EXIF_TAG_FOCAL_LENGTH, exif_data);
-  }
-  if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE)) {
-    LoggerD("Saving gps altitude:%f (%s)", m_gps_altitude.toDouble(),
-         m_gps_altitude.toString().c_str());
-    ExifTagSaver::saveToExif(m_gps_altitude,
-        static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE), exif_data);
-  }
-  if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF)) {
-    //Exif spec:
-    //0 = Sea level
-    //1 = Sea level reference (negative value)
-    LoggerD("Saving gps altitude ref:%d (%s)", static_cast<int>(m_gps_altitude_ref),
-        (m_gps_altitude_ref > 0) ? "below sea" : "above sea");
-    ExifTagSaver::saveToExif(static_cast<long int>(m_gps_altitude_ref),
-        static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE_REF), exif_data);
-  }
-  if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD)) {
-    LoggerD("Saving gps processing method: [%s] type:%s",
-        getGpsProcessingMethod().c_str(), getGpsProcessingMethodType().c_str());
-
-    const std::string joined = getGpsProcessingMethodType() + getGpsProcessingMethod();
-    LoggerD("joined: [%s]", joined.c_str());
-
-    ExifTagSaver::saveToExif(joined,
-        static_cast<ExifTag>(EXIF_TAG_GPS_PROCESSING_METHOD), exif_data, false);
-  }
-  if (isSet(EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT)) {
-    LoggerD("Saving user comment: %s (type:%s)", getUserComment().c_str(),
-      getUserCommentType().c_str());
-
-    const std::string joined = getUserCommentType() + getUserComment();
-    LoggerD("joined: [%s]", joined.c_str());
-
-    ExifTagSaver::saveToExif(joined,
-        EXIF_TAG_USER_COMMENT, exif_data, false);
-  }
-
-  //if(m_gps_location) {
-  //  m_exif_gps_location.set(m_gps_location);
-   // }
-  //ExifTagSaver::saveGpsLocationToExif(m_exif_gps_location, exif_data);
-
-/*  if(m_gps_time) {
-    m_exif_gps_time.setDateAndTime(m_gps_time);
-  }
-  ExifTagSaver::saveGpsTimeToExif(m_exif_gps_time, exif_data);*/
-}
-
-void ExifInformation::saveToFile(const std::string& file_path)
-{
-  LoggerD("Entered");
-  LoggerD("Using JpegFile to read: [%s] and Exif if present", file_path.c_str());
-
-  bool exif_data_is_new = false;
-  JpegFilePtr jpg_file = JpegFile::loadFile(file_path);
-  ExifData* exif_data = jpg_file->getExifData();
-
-  //Exif is not present in file - create new ExifData
-  if (!exif_data) {
-    LoggerD("Exif is not present in file: [%s] creating new", file_path.c_str());
-
-    exif_data = exif_data_new();
-    exif_data_set_option(exif_data, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
-    exif_data_set_data_type(exif_data, EXIF_DATA_TYPE_COMPRESSED);
-    exif_data_set_byte_order(exif_data, EXIF_BYTE_ORDER_MOTOROLA);
-    exif_data_is_new = true;
-  }
-
-  if (!exif_data) {
-    LoggerE("Couldn't allocate new ExifData");
-    throw common::UnknownException("Memory allocation failed");
-  }
-
-  LoggerD("Exif data type: %d", exif_data_get_data_type(exif_data) );
-  LoggerD("Exif byte order: %d", exif_data_get_byte_order(exif_data) );
-  exif_data_set_option(exif_data, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
-
-  try {
-    //If we have created new ExifData there is nothing to remove
-    if(!exif_data_is_new) {
-      //Remove attributes that have been nulled
-      removeNulledAttributesFromExifData(exif_data);
-    }
-
-    updateAttributesInExifData(exif_data);
-
-    LOGD("Using JpegFile to save new Exif in: [%s]", file_path.c_str());
-    if(exif_data_is_new) {
-      jpg_file->setNewExifData(exif_data);
-    }
-
-    jpg_file->saveToFile(file_path);
-  }
-  catch (...) {
-    exif_data_unref(exif_data);
-    exif_data = NULL;
-    throw;
-  }
-
-  exif_data_unref(exif_data);
-  exif_data = NULL;
-}
-
-} // exif
-} // extension
diff --git a/src/exif/ExifInformation.h b/src/exif/ExifInformation.h
deleted file mode 100644 (file)
index a1fa343..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-//
-// Tizen Web Device API
-// Copyright (c) 2014 Samsung Electronics Co., Ltd.
-//
-// Licensed under the Apache License, Version 2.0 (the License);
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#ifndef __TIZEN_EXIF_EXIFINFORMATION_H_
-#define __TIZEN_EXIF_EXIFINFORMATION_H_
-
-#include <libexif/exif-loader.h>
-#include <string>
-
-//#include <JSVector.h>
-//#include <TimeDuration.h>
-
-#include "ExifGPSLocation.h"
-//#include "ExifGPSTime.h"
-
-namespace extension {
-namespace exif {
-
-class ExifInformation;
-typedef std::shared_ptr<ExifInformation> ExifInformationPtr;
-
-extern const size_t EXIF_UNDEFINED_TYPE_LENGTH;
-extern const std::string EXIF_UNDEFINED_TYPE_ASCII;
-extern const std::string EXIF_UNDEFINED_TYPE_JIS;
-extern const std::string EXIF_UNDEFINED_TYPE_UNICODE;
-extern const std::string EXIF_UNDEFINED_TYPE_UNDEFINED;
-
-enum ExifInformationAttribute{
-  EXIF_INFORMATION_ATTRIBUTE_URI,
-  EXIF_INFORMATION_ATTRIBUTE_WIDTH,
-  EXIF_INFORMATION_ATTRIBUTE_HEIGHT,
-  EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER,
-  EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL,
-  EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME,
-  EXIF_INFORMATION_ATTRIBUTE_ORIENTATION,
-  EXIF_INFORMATION_ATTRIBUTE_FNUMBER,
-  EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS,
-  EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME,
-  EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM,
-  EXIF_INFORMATION_ATTRIBUTE_FLASH,
-  EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH,
-  EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE,
-  EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE,
-  EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF,
-  EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD,
-  EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT,
-  EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES
-};
-
-enum GpsAltitudeRef {
-  GPS_ALTITUDE_REF_ABOVE_SEA = 0,
-  GPS_ALTITUDE_REF_BELOW_SEA = 1
-};
-
-class ExifInformation
-{
-public:
-  ExifInformation();
-  ~ExifInformation();
-
-  static ExifInformationPtr loadFromURI(const std::string& uri);
-  void saveToFile(const std::string& file_path);
-
-  const std::string& getUri();
-  void setUri(const std::string& uri);
-
-  unsigned long getWidth() const;
-  void setWidth(unsigned long width);
-
-  unsigned long getHeight() const;
-  void setHeight(unsigned long height);
-
-  const std::string& getDeviceMaker();
-  void setDeviceMaker(const std::string& device_maker);
-
-  const std::string& getDeviceModel();
-  void setDeviceModel(const std::string& device_model);
-
-  time_t getOriginalTime() const;
-  void setOriginalTime(time_t original_time);
-
-  ImageOrientation getOrientation() const;
-  void setOrientation(ImageOrientation orientation);
-
-  const Rational& getFNumber() const;
-  void setFNumber(Rational f_number);
-
-  //Common::JSLongLongVector getIsoSpeedRatings();
-  //void setIsoSpeedRatings(const std::vector<long long int>& iso_speed_ratings);
-  void appendIsoSpeedRatings(long long int iso_speed_rating);
-
-  const Rational& getExposureTime();
-  void setExposureTime(const Rational& exposure_time);
-
-  ExposureProgram getExposureProgram();
-  void setExposureProgram(ExposureProgram exposure_program );
-
-  bool getFlash() const;
-  void setFlash(bool flash);
-
-  const Rational& getFocalLength() const;
-  void setFocalLength(Rational focal_length);
-
-  WhiteBalanceMode getWhiteBalanceMode() const;
-  void setWhiteBalanceMode(WhiteBalanceMode white_balance);
-
-  ExifGPSLocation& getGPSExifLocation();
-  //Tizen::SimpleCoordinatesPtr getGPSLocation();
-  //void setGPSLocation(Tizen::SimpleCoordinatesPtr gps_location);
-  void unsetGPSLocation();
-
-  const Rational& getGpsAltitude() const;
-  void setGpsAltitude(Rational gps_altitude);
-
-  GpsAltitudeRef getGpsAltitudeRef() const;
-  void setGpsAltitudeRef(const GpsAltitudeRef ref);
-
-  /**
-   * gps_altitude can be negative and positive:
-   * if gps_altitude < 0.0 GPS_ALTITUDE_REF_BELOW_SEA is set
-   * if gps_altitude >= 0.0 GPS_ALTITUDE_REF_ABOVE_SEA is set
-   */
-  void setGpsAltitudeWithRef(double gps_altitude);
-
-  /**
-   * Return gps altitude which can be negative (below sea level) and positive (above sea
-   * level)
-   */
-  double getGpsAltitudeWithRef() const;
-
-  const std::string& getGpsProcessingMethod() const;
-  const std::string& getGpsProcessingMethodType() const;
-  void setGpsProcessingMethod(const std::string& type,
-      const std::string& processing_method);
-
-  //ExifGPSTime& getExifGpsTime();
-  //const ExifGPSTime& getExifGpsTime() const;
-  //Time::TZDatePtr getGpsTime();
-  //void setGpsTime(Time::TZDatePtr new_time);
-  void unsetGPStime();
-
-  const std::string& getUserComment();
-  const std::string& getUserCommentType();
-  void setUserComment(const std::string& type,
-      const std::string& user_comment);
-
-  bool isSet(ExifInformationAttribute attribute) const;
-  void unset(ExifInformationAttribute attribute);
-
-private:
-  void processEntry(ExifEntry* entry, ExifData* exif_data);
-  static void contentForeachFunctionProxy(ExifEntry* entry, void* user_data);
-  static void dataForeachFunction(ExifContent* content, void* user_data);
-
-  void removeNulledAttributesFromExifData(ExifData* exif_data);
-  void updateAttributesInExifData(ExifData* exif_data);
-
-  std::string m_uri;
-  unsigned long m_width;
-  unsigned long m_height;
-  std::string m_device_maker;
-  std::string m_device_model;
-
-  time_t m_original_time;
-
-  ImageOrientation m_orientation;
-  Rational m_f_number;
-  //Common::JSLongLongVector m_iso_speed_ratings;
-  Rational m_exposure_time;
-  ExposureProgram m_exposure_program;
-  bool m_flash;
-  Rational m_focal_length;
-  WhiteBalanceMode m_white_balance;
-
-  ExifGPSLocation m_exif_gps_location;
-  //Tizen::SimpleCoordinatesPtr m_gps_location;
-
-  Rational m_gps_altitude;
-  GpsAltitudeRef m_gps_altitude_ref;
-
-  std::string m_gps_processing_method;
-  std::string m_gps_processing_method_type;
-
-  //ExifGPSTime m_exif_gps_time;
-  //Time::TZDatePtr m_gps_time;
-
-  std::string m_user_comment;
-  std::string m_user_comment_type;
-
-  bool m_is_set[EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES];
-};
-
-} // exif
-} // extension
-
-#endif // __TIZEN_EXIF_EXIFINFORMATION_H_
diff --git a/src/exif/ExifTagSaver.cpp b/src/exif/ExifTagSaver.cpp
deleted file mode 100644 (file)
index ae1baaa..0000000
+++ /dev/null
@@ -1,412 +0,0 @@
-//
-// Tizen Web Device API
-// Copyright (c) 2014 Samsung Electronics Co., Ltd.
-//
-// Licensed under the Apache License, Version 2.0 (the License);
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#include "ExifTagSaver.h"
-
-#include <libexif/exif-format.h>
-#include <sstream>
-#include <cstring>
-
-#include "common/platform_exception.h"
-#include "common/logger.h"
-
-#include "ExifUtil.h"
-
-namespace extension {
-namespace exif {
-
-void ExifTagSaver::removeExifEntryWithTag(const ExifTag tag, ExifData* exif_data)
-{
-  LoggerD("Entered tag:%d (0x%x)", tag, tag);
-  ExifEntry* exif_entry = exif_data_get_entry(exif_data, tag);
-  if (!exif_entry) {
-    LoggerE("Exif entry with tag:%d (0x%x) is not present", tag, tag);
-    return;
-  }
-
-  exif_content_remove_entry(exif_entry->parent, exif_entry);
-}
-
-void ExifTagSaver::saveToExif(long int value, ExifTag tag, ExifData* exif_data)
-{
-  ExifEntry* entry = prepareEntry(exif_data, tag);
-  ExifByteOrder order = exif_data_get_byte_order(exif_data);
-
-  switch (entry->format) {
-    case EXIF_FORMAT_BYTE:
-      entry->data[0] = static_cast<unsigned char>(value);
-      break;
-    case EXIF_FORMAT_SHORT:
-      exif_set_short (entry->data, order, value);
-      break;
-    case EXIF_FORMAT_LONG:
-      exif_set_long (entry->data, order, value);
-      break;
-    case EXIF_FORMAT_SLONG:
-      exif_set_slong (entry->data, order, value);
-      break;
-    default:
-      LoggerE("Error: wrong format: %d \n", entry->format );
-  }
-}
-
-void ExifTagSaver::saveToExif(const std::string& value, ExifTag tag, ExifData* exif_data,
-    bool add_zero_character)
-{
-  ExifEntry* entry = prepareEntry(exif_data, tag);
-  if (!value.empty()) {
-
-    if (entry->data) {
-      free(entry->data);
-      entry->data = NULL;
-    }
-
-    size_t new_len = value.length();
-    if (add_zero_character) {
-      ++new_len;
-    }
-
-    entry->size = new_len;
-    entry->components = new_len;
-
-    entry->data = static_cast<unsigned char*>(malloc(entry->size));
-    memcpy(entry->data, value.c_str(), value.length());
-    if (add_zero_character) {
-      entry->data[value.length()] = '\0';
-    }
-  }
-}
-
-void ExifTagSaver::saveToExif(const Rational& value, ExifTag tag, ExifData* exif_data)
-{
-  ExifEntry* entry = prepareEntry(exif_data, tag);
-  entry->format = EXIF_FORMAT_RATIONAL;
-
-  if (ExifTypeInfo::RationalSize != entry->size) {
-    if (entry->data) {
-      free(entry->data);
-      entry->data = NULL;
-    }
-
-    entry->size = ExifTypeInfo::RationalSize;
-    entry->data = static_cast<unsigned char*>(malloc(entry->size));
-    memset(entry->data, 0, entry->size);
-  }
-
-  entry->components = 1;
-
-  ExifByteOrder order = exif_data_get_byte_order(exif_data);
-  ExifRational r;
-  r.numerator = value.nominator;
-  r.denominator = value.denominator;
-  exif_set_rational(entry->data, order, r);
-}
-
-void ExifTagSaver::saveToExif(const Rationals& value, ExifTag tag, ExifData* exif_data)
-{
-  ExifEntry* entry = prepareEntry(exif_data, tag);
-  ExifByteOrder order = exif_data_get_byte_order(exif_data);
-  entry->format = EXIF_FORMAT_RATIONAL;
-
-  const unsigned int required_size = ExifTypeInfo::RationalSize * value.size();
-  if (required_size != entry->size) {
-    if (entry->data) {
-      free(entry->data);
-      entry->data = NULL;
-    }
-
-    entry->size = required_size;
-    entry->data = static_cast<unsigned char*>(malloc(entry->size));
-    memset(entry->data, 0, entry->size);
-  }
-
-  entry->components = value.size();
-  for (size_t i = 0; i < value.size(); ++i)
-  {
-    ExifRational r;
-    r.numerator = value[i].nominator;
-    r.denominator = value[i].denominator;
-    exif_set_rational(entry->data + i * ExifTypeInfo::RationalSize, order, r);
-  }
-}
-
-void ExifTagSaver::saveToExif(std::vector<long long int>& value, ExifFormat store_as,
-      ExifTag tag, ExifData* exif_data)
-{
-  ExifEntry* entry = prepareEntry(exif_data, tag);
-  const ExifByteOrder order = exif_data_get_byte_order(exif_data);
-
-  const size_t size_per_member = ExifUtil::getSizeOfExifFormatType(store_as);
-  switch (store_as) {
-    case EXIF_FORMAT_BYTE:
-    case EXIF_FORMAT_SHORT:
-    case EXIF_FORMAT_SSHORT:
-    case EXIF_FORMAT_LONG:
-    case EXIF_FORMAT_SLONG:
-      break;
-    default:
-      LoggerE("output ExifFormat: %d is not supported!");
-      return;
-  }
-  entry->format = store_as;
-
-  const size_t num_elements = value.size();
-  const unsigned int required_size = size_per_member * num_elements;
-  if (required_size != entry->size) {
-    if (entry->data) {
-      free(entry->data);
-      entry->data = NULL;
-    }
-
-    entry->size = required_size;
-    entry->data = static_cast<unsigned char*>(malloc(entry->size));
-    memset(entry->data, 0, entry->size);
-  }
-  entry->components = num_elements;
-
-
-  switch (store_as) {
-    case EXIF_FORMAT_BYTE: {
-      for(size_t i = 0; i < num_elements; ++i) {
-        entry->data[i] = static_cast<ExifByte>(value[i]);
-      }
-      break;
-    }
-
-    case EXIF_FORMAT_SHORT: {
-      for (size_t i = 0; i < num_elements; ++i) {
-        exif_set_short(entry->data + i * size_per_member, order,
-            static_cast<ExifShort>(value[i]));
-      }
-      break;
-    }
-
-    case EXIF_FORMAT_SSHORT: {
-      for (size_t i = 0; i < num_elements; ++i) {
-        exif_set_sshort(entry->data + i * size_per_member, order,
-            static_cast<ExifSShort>(value[i]));
-      }
-      break;
-    }
-
-    case EXIF_FORMAT_LONG: {
-      for (size_t i = 0; i < num_elements; ++i) {
-        exif_set_long(entry->data + i * size_per_member, order,
-            static_cast<ExifLong>(value[i]));
-      }
-      break;
-    }
-
-    case EXIF_FORMAT_SLONG: {
-      for(size_t i = 0; i < num_elements; ++i) {
-        exif_set_slong(entry->data + i * size_per_member, order,
-            static_cast<ExifSLong>(value[i]));
-      }
-      break;
-    }
-
-    default:
-      break;
-  }
-
-
-  LoggerD("entry after save:");
-  ExifUtil::printExifEntryInfo(entry, exif_data);
-}
-
-void ExifTagSaver::saveGpsLocationToExif(const ExifGPSLocation& gps_info,
-    ExifData* exif_data)
-{
-  if (gps_info.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE)) {
-    auto latitude = gps_info.getLatitude();
-    LoggerD("Saving latitude: %s", latitude.toDebugString().c_str());
-    saveToExif(latitude.toRationalsVector(),
-        static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE), exif_data);
-  }
-
-  if (gps_info.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE_REF)) {
-    std::string lat_ref =
-        (gps_info.getLatitudeRef() == GPS_LOCATION_NORTH) ? "N" : "S";
-    LoggerD("Saving latitude ref: %s", lat_ref.c_str());
-    saveToExif(lat_ref, static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE_REF), exif_data);
-  }
-
-  if (gps_info.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE)) {
-
-    auto longitude = gps_info.getLongitude();
-    LoggerD("Saving longitude: %s", longitude.toDebugString().c_str());
-    saveToExif(longitude.toRationalsVector(),
-        static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE), exif_data);
-  }
-
-  if (gps_info.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF)) {
-    std::string long_ref =
-        (gps_info.getLongitudeRef() == GPS_LOCATION_WEST) ? "W" : "E";
-    LoggerD("Saving longitude ref: %s", long_ref.c_str());
-    saveToExif(long_ref, static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE_REF), exif_data);
-  }
-}
-/*
-void ExifTagSaver::saveGpsTimeToExif(const ExifGPSTime& gps_time,
-      ExifData* exif_data)
-{
-  if (gps_time.isTimeSet()) {
-    const Rationals& time = gps_time.getTime();
-    LoggerD("Saving gps time: [%s]h [%s]m [%s]d",
-        time[0].toString().c_str(),
-        time[1].toString().c_str(),
-        time[2].toString().c_str());
-
-    saveToExif(time, static_cast<ExifTag>(EXIF_TAG_GPS_TIME_STAMP), exif_data);
-  }
-
-  if (gps_time.isDateSet()) {
-    std::string date = gps_time.getDate();
-    LoggerD("Saving gps date: [%s]", date.c_str());
-
-    saveToExif(date, static_cast<ExifTag>(EXIF_TAG_GPS_DATE_STAMP), exif_data);
-  }
-}
-*/
-ExifEntry* ExifTagSaver::prepareEntry(ExifData* exif_data, ExifTag tag)
-{
-  LoggerD("Entered m_tag:%d", tag);
-
-  ExifEntry* exif_entry = exif_data_get_entry(exif_data, tag);
-  if (!exif_entry) {
-    exif_entry = createNewTag(exif_data, deduceIfdSection(tag),
-        deduceDataFormat(tag), tag );
-  }
-
-  if (!exif_entry) {
-    LoggerE("Couldn't create new Exif tag");
-    //throw UnknownException("Could not save Exif to file");
-  }
-
-  exif_entry_initialize(exif_entry, tag);
-
-  return exif_entry;
-}
-
-ExifEntry* ExifTagSaver::createNewTag(ExifData* exif_data, ExifIfd ifd,
-    ExifFormat format, ExifTag tag)
-{
-  LoggerD("Creating new tag: %d", tag);
-
-  ExifEntry* new_entry = exif_entry_new();
-  new_entry->tag = tag;
-  new_entry->format = format;
-  exif_content_add_entry(exif_data->ifd[ifd], new_entry);
-  exif_entry_initialize(new_entry, tag);
-  return new_entry;
-}
-
-ExifIfd ExifTagSaver::deduceIfdSection(ExifTag tag)
-{
-  switch (static_cast<unsigned int>(tag)) {
-    //Tags in IFD_0 Section
-    case EXIF_TAG_MAKE:
-    case EXIF_TAG_MODEL:
-    case EXIF_TAG_IMAGE_WIDTH:
-    case EXIF_TAG_IMAGE_LENGTH:
-    case EXIF_TAG_ORIENTATION:
-      return EXIF_IFD_0;
-
-    //Tags in IFD_EXIF Section
-    case EXIF_TAG_USER_COMMENT:
-    case EXIF_TAG_DATE_TIME_ORIGINAL:
-    case EXIF_TAG_EXPOSURE_TIME:
-    case EXIF_TAG_FNUMBER:
-    case EXIF_TAG_EXPOSURE_PROGRAM:
-    case EXIF_TAG_ISO_SPEED_RATINGS:
-    case EXIF_TAG_WHITE_BALANCE:
-    case EXIF_TAG_FLASH:
-    case EXIF_TAG_FOCAL_LENGTH:
-      return EXIF_IFD_EXIF;
-
-    //Tags in IFD_GPS Section
-    case EXIF_TAG_GPS_LATITUDE_REF:
-    case EXIF_TAG_GPS_LONGITUDE_REF:
-    case EXIF_TAG_GPS_LATITUDE:
-    case EXIF_TAG_GPS_LONGITUDE:
-    case EXIF_TAG_GPS_ALTITUDE:
-    case EXIF_TAG_GPS_ALTITUDE_REF:
-    case EXIF_TAG_GPS_TIME_STAMP:
-    case EXIF_TAG_GPS_PROCESSING_METHOD:
-    case EXIF_TAG_GPS_DATE_STAMP:
-      return EXIF_IFD_GPS;
-
-    //Tags in other sections
-    default:
-      LoggerE("Unsupported tag: %d", tag);
-      //throw UnknownException("Unsupported tag");
-  }
-}
-
-ExifFormat ExifTagSaver::deduceDataFormat(ExifTag tag)
-{
-  switch (static_cast<unsigned int>(tag)) {
-    //Tags with byte type:
-    case EXIF_TAG_GPS_ALTITUDE_REF:
-      return EXIF_FORMAT_BYTE;
-
-    //Tags with long type:
-    case EXIF_TAG_IMAGE_WIDTH:
-    case EXIF_TAG_IMAGE_LENGTH:
-      return EXIF_FORMAT_LONG;
-
-    //Tags with short type:
-    case EXIF_TAG_ORIENTATION:
-    case EXIF_TAG_EXPOSURE_PROGRAM:
-    case EXIF_TAG_WHITE_BALANCE:
-    case EXIF_TAG_FLASH:
-      return EXIF_FORMAT_SHORT;
-
-    //Tags with ASCII type:
-    case EXIF_TAG_MAKE:
-    case EXIF_TAG_MODEL:
-    case EXIF_TAG_DATE_TIME_ORIGINAL:
-    case EXIF_TAG_GPS_LATITUDE_REF:
-    case EXIF_TAG_GPS_LONGITUDE_REF:
-    case EXIF_TAG_GPS_DATE_STAMP:
-      return EXIF_FORMAT_ASCII;
-
-    //Tags with rational type:
-    case EXIF_TAG_EXPOSURE_TIME:
-    case EXIF_TAG_FNUMBER:
-    case EXIF_TAG_FOCAL_LENGTH:
-    case EXIF_TAG_GPS_LATITUDE:
-    case EXIF_TAG_GPS_LONGITUDE:
-    case EXIF_TAG_GPS_ALTITUDE:
-    case EXIF_TAG_GPS_TIME_STAMP:
-    case EXIF_TAG_ISO_SPEED_RATINGS:
-      return EXIF_FORMAT_RATIONAL;
-
-    //Tags with undefined type:
-    case EXIF_TAG_USER_COMMENT:
-    case EXIF_TAG_GPS_PROCESSING_METHOD:
-      return EXIF_FORMAT_UNDEFINED;
-
-    //Unsupported tags:
-    default:
-      LoggerE("Unsupported tag: %d", tag);
-      //throw UnknownException("Unsupported tag");
-  }
-}
-
-} // exif
-} // extension
diff --git a/src/exif/ExifTagSaver.h b/src/exif/ExifTagSaver.h
deleted file mode 100644 (file)
index fc07eaf..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-//
-// Tizen Web Device API
-// Copyright (c) 2014 Samsung Electronics Co., Ltd.
-//
-// Licensed under the Apache License, Version 2.0 (the License);
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-/**
- * @file  ExifTagSaver.h
- */
-
-#ifndef __TIZEN_EXIF_EXIF_TAG_SAVER_H__
-#define __TIZEN_EXIF_EXIF_TAG_SAVER_H__
-
-#include <string>
-#include <libexif/exif-data.h>
-
-#include "ExifGPSLocation.h"
-//#include "ExifGPSTime.h"
-
-namespace extension {
-namespace exif {
-
-class ExifTagSaver
-{
-public:
-  static void removeExifEntryWithTag(const ExifTag tag, ExifData* exif_data);
-
-  static void saveToExif(long int value, ExifTag tag, ExifData* exif_data);
-  static void saveToExif(const std::string& value, ExifTag tag, ExifData* exif_data,
-      bool add_zero_character = true);
-  static void saveToExif(const Rational& value, ExifTag tag, ExifData* exif_data);
-  static void saveToExif(const Rationals& value, ExifTag tag, ExifData* exif_data);
-  static void saveToExif(std::vector<long long int>& value, ExifFormat store_as,
-      ExifTag tag, ExifData* exif_data);
-  static void saveGpsLocationToExif(const ExifGPSLocation& gps_info,
-      ExifData* exif_data);
-  //static void saveGpsTimeToExif(const ExifGPSTime& gps_time,
-      //ExifData* exif_data);
-
-private:
-  static ExifEntry* prepareEntry(ExifData* exif_data, ExifTag tag);
-  static ExifIfd deduceIfdSection(ExifTag tag);
-  static ExifFormat deduceDataFormat(ExifTag tag);
-  static ExifEntry* createNewTag(ExifData* exif_data, ExifIfd ifd,
-    ExifFormat format, ExifTag tag);
-};
-
-} // exif
-} // extension
-
-#endif // __TIZEN_EXIF_EXIF_TAG_SAVER_H__
diff --git a/src/exif/ExifUtil.cpp b/src/exif/ExifUtil.cpp
deleted file mode 100644 (file)
index 7f86335..0000000
+++ /dev/null
@@ -1,431 +0,0 @@
-//
-// Tizen Web Device API
-// Copyright (c) 2014 Samsung Electronics Co., Ltd.
-//
-// Licensed under the Apache License, Version 2.0 (the License);
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#include "ExifUtil.h"
-
-#include <iomanip>
-#include <sstream>
-
-#include "common/platform_exception.h"
-#include "common/logger.h"
-
-namespace extension {
-namespace exif {
-
-namespace {
-const std::string ORIENTATION_NORMAL = "NORMAL";
-const std::string ORIENTATION_FLIP_HORIZONTAL = "FLIP_HORIZONTAL";
-const std::string ORIENTATION_ROTATE_180 = "ROTATE_180";
-const std::string ORIENTATION_FLIP_VERTICAL = "FLIP_VERTICAL";
-const std::string ORIENTATION_TRANSPOSE = "TRANSPOSE";
-const std::string ORIENTATION_ROTATE_90 = "ROTATE_90";
-const std::string ORIENTATION_TRANSVERSE = "TRANSVERSE";
-const std::string ORIENTATION_ROTATE_270 = "ROTATE_270";
-
-const std::string WHITE_BALANCE_MODE_AUTO = "AUTO";
-const std::string WHITE_BALANCE_MODE_MANUAL = "MANUAL";
-
-const std::string EXPOSURE_PROGRAM_NOT_DEFINED = "NOT_DEFINED";
-const std::string EXPOSURE_PROGRAM_MANUAL = "MANUAL";
-const std::string EXPOSURE_PROGRAM_NORMAL = "NORMAL";
-const std::string EXPOSURE_PROGRAM_APERTURE_PRIORITY = "APERTURE_PRIORITY";
-const std::string EXPOSURE_PROGRAM_SHUTTER_PRIORITY = "SHUTTER_PRIORITY";
-const std::string EXPOSURE_PROGRAM_CREATIVE_PROGRAM = "CREATIVE_PROGRAM";
-const std::string EXPOSURE_PROGRAM_ACTION_PROGRAM = "ACTION_PROGRAM";
-const std::string EXPOSURE_PROGRAM_PORTRAIT_MODE = "PORTRAIT_MODE";
-const std::string EXPOSURE_PROGRAM_LANDSCAPE_MODE = "LANDSCAPE_MODE";
-
-const std::string DUMMY = ""; // For unexpected input handling
-
-const std::string URI_PREFIX = "file://";
-const std::string URI_ABSOLUTE_PREFIX = "file:///";
-}
-
-const size_t ExifTypeInfo::ByteSize = 1;
-const size_t ExifTypeInfo::ASCIISize = 1;
-const size_t ExifTypeInfo::ShortSize = 2;
-const size_t ExifTypeInfo::LongSize = 4;
-const size_t ExifTypeInfo::RationalSize = 8;
-const size_t ExifTypeInfo::UndefinedSize = 1;
-const size_t ExifTypeInfo::SLongSize = 4;
-const size_t ExifTypeInfo::SRationalSize = 8;
-
-const ExifByte ExifTypeInfo::ByteId = 1;
-const ExifByte ExifTypeInfo::ASCIIId = 2;
-const ExifByte ExifTypeInfo::ShortId = 3;
-const ExifByte ExifTypeInfo::LongId = 4;
-const ExifByte ExifTypeInfo::RationalId = 5;
-const ExifByte ExifTypeInfo::UndefinedId = 7;
-const ExifByte ExifTypeInfo::SLongId = 9;
-const ExifByte ExifTypeInfo::SRationalId = 10;
-
-ExifUtil::ExifUtil()
-{
-}
-
-ExifUtil::~ExifUtil()
-{
-}
-
-ImageOrientation ExifUtil::stringToOrientation(const std::string& orientation)
-{
-  LoggerD("Entered");
-  if (ORIENTATION_NORMAL == orientation) {
-    return ImageOrientation::EXIF_ORIENTATION_NORMAL;
-  }
-  if (ORIENTATION_FLIP_HORIZONTAL == orientation) {
-    return ImageOrientation::EXIF_ORIENTATION_FLIP_HORIZONTAL;
-  }
-  if (ORIENTATION_ROTATE_180 == orientation) {
-    return ImageOrientation::EXIF_ORIENTATION_ROTATE_180;
-  }
-  if (ORIENTATION_FLIP_VERTICAL == orientation) {
-    return ImageOrientation::EXIF_ORIENTATION_FLIP_VERTICAL;
-  }
-  if (ORIENTATION_TRANSPOSE == orientation) {
-    return ImageOrientation::EXIF_ORIENTATION_TRANSPOSE;
-  }
-  if (ORIENTATION_ROTATE_90 == orientation) {
-    return ImageOrientation::EXIF_ORIENTATION_ROTATE_90;
-  }
-  if (ORIENTATION_TRANSVERSE == orientation) {
-    return ImageOrientation::EXIF_ORIENTATION_TRANSVERSE;
-  }
-  if (ORIENTATION_ROTATE_270 == orientation) {
-    return ImageOrientation::EXIF_ORIENTATION_ROTATE_270;
-  }
-  return ImageOrientation::EXIF_ORIENTATION_NOT_VALID;
-}
-
-const std::string& ExifUtil::orientationToString(ImageOrientation orientation)
-{
-  LoggerD("Entered");
-  switch (orientation) {
-    case ImageOrientation::EXIF_ORIENTATION_NORMAL:
-      return ORIENTATION_NORMAL;
-    case ImageOrientation::EXIF_ORIENTATION_FLIP_HORIZONTAL:
-      return ORIENTATION_FLIP_HORIZONTAL;
-    case ImageOrientation::EXIF_ORIENTATION_ROTATE_180:
-      return ORIENTATION_ROTATE_180;
-    case ImageOrientation::EXIF_ORIENTATION_FLIP_VERTICAL:
-      return ORIENTATION_FLIP_VERTICAL;
-    case ImageOrientation::EXIF_ORIENTATION_TRANSPOSE:
-      return ORIENTATION_TRANSPOSE;
-    case ImageOrientation::EXIF_ORIENTATION_ROTATE_90:
-      return ORIENTATION_ROTATE_90;
-    case ImageOrientation::EXIF_ORIENTATION_TRANSVERSE:
-      return ORIENTATION_TRANSVERSE;
-    case ImageOrientation::EXIF_ORIENTATION_ROTATE_270:
-      return ORIENTATION_ROTATE_270;
-    default:
-      return DUMMY;
-  }
-}
-
-WhiteBalanceMode ExifUtil::stringToWhiteBalance(const std::string& white_balance)
-{
-  LoggerD("Entered");
-  if (WHITE_BALANCE_MODE_AUTO == white_balance) {
-    return WhiteBalanceMode::EXIF_WHITE_BALANCE_MODE_AUTO;
-  }
-  if (WHITE_BALANCE_MODE_MANUAL == white_balance) {
-    return WhiteBalanceMode::EXIF_WHITE_BALANCE_MODE_MANUAL;
-  }
-  return WhiteBalanceMode::EXIF_WHITE_BALANCE_MODE_NOT_VALID;
-}
-
-const std::string& ExifUtil::whiteBalanceToString(WhiteBalanceMode value)
-{
-  LoggerD("Entered");
-  switch (value) {
-    case WhiteBalanceMode::EXIF_WHITE_BALANCE_MODE_AUTO:
-      return WHITE_BALANCE_MODE_AUTO;
-    case WhiteBalanceMode::EXIF_WHITE_BALANCE_MODE_MANUAL:
-      return WHITE_BALANCE_MODE_MANUAL;
-    default:
-      return DUMMY;
-  }
-}
-
-ExposureProgram ExifUtil::stringToExposureProgram(
-    const std::string& exposure_program)
-{
-  LoggerD("Entered");
-  if (EXPOSURE_PROGRAM_NOT_DEFINED == exposure_program) {
-    return EXIF_EXPOSURE_PROGRAM_NOT_DEFINED;
-  }
-  if (EXPOSURE_PROGRAM_MANUAL == exposure_program) {
-    return EXIF_EXPOSURE_PROGRAM_MANUAL;
-  }
-  if (EXPOSURE_PROGRAM_NORMAL == exposure_program) {
-    return EXIF_EXPOSURE_PROGRAM_NORMAL;
-  }
-  if (EXPOSURE_PROGRAM_APERTURE_PRIORITY == exposure_program) {
-    return EXIF_EXPOSURE_PROGRAM_APERTURE_PRIORITY;
-  }
-  if (EXPOSURE_PROGRAM_SHUTTER_PRIORITY == exposure_program) {
-    return EXIF_EXPOSURE_PROGRAM_SHUTTER_PRIORITY;
-  }
-  if (EXPOSURE_PROGRAM_CREATIVE_PROGRAM == exposure_program) {
-    return EXIF_EXPOSURE_PROGRAM_CREATIVE_PROGRAM;
-  }
-  if (EXPOSURE_PROGRAM_ACTION_PROGRAM == exposure_program) {
-    return EXIF_EXPOSURE_PROGRAM_ACTION_PROGRAM;
-  }
-  if (EXPOSURE_PROGRAM_PORTRAIT_MODE == exposure_program) {
-    return EXIF_EXPOSURE_PROGRAM_PORTRAIT_MODE;
-  }
-  if (EXPOSURE_PROGRAM_LANDSCAPE_MODE == exposure_program) {
-    return EXIF_EXPOSURE_PROGRAM_LANDSCAPE_MODE;
-  }
-  return EXIF_EXPOSURE_PROGRAM_NOT_VALID;
-}
-
-const std::string& ExifUtil::exposureProgramToString(ExposureProgram value)
-{
-  LoggerD("Entered");
-  switch (value) {
-    case ExposureProgram::EXIF_EXPOSURE_PROGRAM_NOT_DEFINED:
-      return EXPOSURE_PROGRAM_NOT_DEFINED;
-    case ExposureProgram::EXIF_EXPOSURE_PROGRAM_MANUAL:
-      return EXPOSURE_PROGRAM_MANUAL;
-    case ExposureProgram::EXIF_EXPOSURE_PROGRAM_NORMAL:
-      return EXPOSURE_PROGRAM_NORMAL;
-    case ExposureProgram::EXIF_EXPOSURE_PROGRAM_APERTURE_PRIORITY:
-      return EXPOSURE_PROGRAM_APERTURE_PRIORITY;
-    case ExposureProgram::EXIF_EXPOSURE_PROGRAM_SHUTTER_PRIORITY:
-      return EXPOSURE_PROGRAM_SHUTTER_PRIORITY;
-    case ExposureProgram::EXIF_EXPOSURE_PROGRAM_CREATIVE_PROGRAM:
-      return EXPOSURE_PROGRAM_CREATIVE_PROGRAM;
-    case ExposureProgram::EXIF_EXPOSURE_PROGRAM_ACTION_PROGRAM:
-      return EXPOSURE_PROGRAM_ACTION_PROGRAM;
-    case ExposureProgram::EXIF_EXPOSURE_PROGRAM_PORTRAIT_MODE:
-      return EXPOSURE_PROGRAM_PORTRAIT_MODE;
-    case ExposureProgram::EXIF_EXPOSURE_PROGRAM_LANDSCAPE_MODE:
-      return EXPOSURE_PROGRAM_LANDSCAPE_MODE;
-    default:
-      return DUMMY;
-  }
-}
-
-bool ExifUtil::isValidAbsoluteURI(const std::string& uri)
-{
-  return 0 == uri.find(URI_ABSOLUTE_PREFIX);
-}
-
-void ExifUtil::getURIInfo(const std::string& uri,
-    //const Filesystem::NodeType expected_type,
-    const std::string& required_permission,
-    bool& out_exists,
-    //Filesystem::NodeType& out_type,
-    bool& out_permission_granted)
-{
-  const std::string absolute_path = ExifUtil::convertUriToPath(uri);
-  out_exists = false;
-  out_permission_granted = false;
-
-  try {
-    //Filesystem::PathPtr path = Filesystem::Path::create(absolute_path);
-    //Filesystem::NodePtr node = Filesystem::Node::resolve(path);
-    //out_type = node->getType();
-    //out_exists = true;
-
-    //if (expected_type == out_type) {
-    //  out_permission_granted = node->checkPermission(path, required_permission,
-    //      expected_type);
-    //}
-  }
-  /*catch (const common::BasePlatformException &err) {
-    LoggerE("Couldn't resolve path: %s, got:%s (%s)", absolute_path.c_str(),
-        (err.getName()).c_str(), (err.getMessage()).c_str());
-  }*/
-  catch(...) {
-    LoggerE("Couldn't resolve path: %s", absolute_path.c_str());
-  }
-}
-
-// Example:
-// in: uri = file:///opt/usr/media/Images/exif.jpg
-// out: path = /opt/usr/media/Images/exif.jpg
-std::string ExifUtil::convertUriToPath(const std::string& str)
-{
-  std::string path = ltrim(str);
-  std::string prefix = path.substr(0, URI_PREFIX.size());
-
-  if (prefix == URI_PREFIX) {
-    return path.substr(URI_PREFIX.size());
-  }
-  else {
-    return path;
-  }
-}
-
-std::string ExifUtil::ltrim(const std::string& s)
-{
-  std::string str = s;
-  std::string::iterator i;
-  for (i = str.begin(); i != str.end(); i++) {
-    if (!isspace(*i)) {
-      break;
-    }
-  }
-  if (i == str.end()) {
-    str.clear();
-  }
-  else {
-    str.erase(str.begin(), i);
-  }
-  return str;
-}
-
-time_t ExifUtil::exifDateTimeOriginalToTimeT(const char* string)
-{
-  int year, month, day, hour, min, sec;
-  if (sscanf(string, "%d:%d:%d %d:%d:%d",
-        &year, &month, &day, &hour, &min, &sec) >= 6) {
-    return convertToTimeT(year, month, day, hour, min, sec);
-  }
-
-  return 0;
-}
-
-std::string ExifUtil::timeTToExifDateTimeOriginal(time_t time)
-{
-  int year, month, day, hour, min, sec;
-  extractFromTimeT(time, year, month, day, hour, min, sec);
-
-  std::ostringstream ss;
-  ss << std::setfill('0') << std::setw(4) << year << ':' ;
-  ss << std::setfill('0') << std::setw(2) << month << ':' ;
-  ss << std::setfill('0') << std::setw(2) << day << ' ' ;
-
-  ss << std::setfill('0') << std::setw(2) << hour << ':' ;
-  ss << std::setfill('0') << std::setw(2) << min << ':' ;
-  ss << std::setfill('0') << std::setw(2) << sec;
-  return ss.str();
-}
-
-size_t  ExifUtil::getSizeOfExifFormatType(ExifFormat format)
-{
-  size_t size_per_member = 0;
-  switch (format) {
-    case EXIF_FORMAT_BYTE:
-      size_per_member = 1;
-      break;
-
-    case EXIF_FORMAT_SHORT:
-    case EXIF_FORMAT_SSHORT:
-      size_per_member = 2;
-      break;
-
-    case EXIF_FORMAT_LONG:
-    case EXIF_FORMAT_SLONG:
-      size_per_member = 4;
-      break;
-
-    case EXIF_FORMAT_RATIONAL:
-    case EXIF_FORMAT_SRATIONAL:
-      size_per_member = 8;
-      break;
-
-    default:
-      LoggerE("output ExifFormat: %d is not supported!");
-      return 0;
-  }
-
-  return size_per_member;
-}
-
-void ExifUtil::printExifEntryInfo(ExifEntry* entry, ExifData* exif_data)
-{
-  char buf[2000];
-  std::stringstream ss;
-
-  if (!entry) {
-    LoggerE("entry is null");
-    return;
-  }
-
-  if (!entry->data) {
-    LoggerE("entry data is null");
-    return;
-  }
-
-  unsigned char* read_buf_ptr = entry->data;
-
-  size_t size_per_member = getSizeOfExifFormatType(entry->format);
-  if (0 == size_per_member) {
-    size_per_member = 1;  //display as array of bytes
-  }
-
-  for(unsigned long compi = 0; compi < entry->components; ++compi) {
-
-    if (compi > 0) {
-      ss << " ";
-    }
-
-    for(size_t i = 0; i < size_per_member; ++i) {
-      unsigned int value = read_buf_ptr[i];
-      ss << std::hex << std::setw(2) << std::setfill('0') << value;
-    }
-
-    read_buf_ptr += size_per_member;
-  }
-
-  LoggerD("Entry{name:%s type:%s size:%d components:%d value:%s RAW DATA:[%s]}",
-      exif_tag_get_name(entry->tag),
-      exif_format_get_name(entry->format),
-      (int)entry->size,
-      (int)entry->components,
-      exif_entry_get_value(entry, buf, sizeof(buf)),
-      ss.str().c_str());
-}
-
-void ExifUtil::extractFromTimeT(const time_t time,
-      int& out_year, int& out_month, int& out_day,
-      int& out_hour, int& out_min, int& out_sec)
-{
-  struct tm* utc = gmtime(&time);
-
-  out_year = utc->tm_year + 1900;
-  out_month = utc->tm_mon + 1;
-  out_day = utc->tm_mday;
-  out_hour = utc->tm_hour;
-  out_min = utc->tm_min;
-  out_sec = utc->tm_sec;
-}
-
-time_t ExifUtil::convertToTimeT(int year, int month, int day,
-      int hour, int min, int sec)
-{
-  time_t tmp_time = 0;
-  struct tm* timeinfo = localtime(&tmp_time);
-  timeinfo->tm_year = year - 1900;
-  timeinfo->tm_mon = month - 1;
-  timeinfo->tm_mday = day;
-
-  timeinfo->tm_hour = hour;
-  timeinfo->tm_min = min;
-  timeinfo->tm_sec = sec;
-
-  //From mktime documentation:
-  //"The values of the members tm_wday and tm_yday of timeptr are ignored"
-  return timegm(timeinfo);
-}
-
-} // exif
-} // extension
diff --git a/src/exif/ExifUtil.h b/src/exif/ExifUtil.h
deleted file mode 100644 (file)
index dfa0190..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-//
-// Tizen Web Device API
-// Copyright (c) 2014 Samsung Electronics Co., Ltd.
-//
-// Licensed under the Apache License, Version 2.0 (the License);
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-
-#ifndef __TIZEN_EXIF_EXIFUTIL_H_
-#define __TIZEN_EXIF_EXIFUTIL_H_
-
-#include <libexif/exif-data.h>
-#include <libexif/exif-entry.h>
-#include <libexif/exif-utils.h>
-#include <string>
-#include <vector>
-
-//#include <Node.h>
-//#include <Path.h>
-//#include <TZDate.h>
-
-//#include "Rational.h"
-
-namespace extension {
-namespace exif {
-
-enum ImageOrientation {
-  EXIF_ORIENTATION_NORMAL = 1,
-  EXIF_ORIENTATION_FLIP_HORIZONTAL = 2,
-  EXIF_ORIENTATION_ROTATE_180 = 3,
-  EXIF_ORIENTATION_FLIP_VERTICAL = 4,
-  EXIF_ORIENTATION_TRANSPOSE = 5,
-  EXIF_ORIENTATION_ROTATE_90 = 6,
-  EXIF_ORIENTATION_TRANSVERSE = 7,
-  EXIF_ORIENTATION_ROTATE_270 = 8,
-  EXIF_ORIENTATION_NOT_VALID,
-};
-
-enum WhiteBalanceMode {
-  EXIF_WHITE_BALANCE_MODE_AUTO = 0,
-  EXIF_WHITE_BALANCE_MODE_MANUAL = 1,
-  EXIF_WHITE_BALANCE_MODE_NOT_VALID
-};
-
-enum ExposureProgram {
-  EXIF_EXPOSURE_PROGRAM_NOT_DEFINED = 0,
-  EXIF_EXPOSURE_PROGRAM_MANUAL = 1,
-  EXIF_EXPOSURE_PROGRAM_NORMAL = 2,
-  EXIF_EXPOSURE_PROGRAM_APERTURE_PRIORITY = 3,
-  EXIF_EXPOSURE_PROGRAM_SHUTTER_PRIORITY = 4,
-  EXIF_EXPOSURE_PROGRAM_CREATIVE_PROGRAM = 5,
-  EXIF_EXPOSURE_PROGRAM_ACTION_PROGRAM = 6,
-  EXIF_EXPOSURE_PROGRAM_PORTRAIT_MODE = 7,
-  EXIF_EXPOSURE_PROGRAM_LANDSCAPE_MODE = 8,
-  EXIF_EXPOSURE_PROGRAM_NOT_VALID
-};
-
-/**
- * From Exif 2.2 specification:
- *  The following types are used in Exif:
- *  1 = BYTE An 8-bit unsigned integer.,
- *  2 = ASCII An 8-bit byte containing one 7-bit ASCII code. The final byte is terminated
- *    with NULL.,
- *  3 = SHORT A 16-bit (2-byte) unsigned integer,
- *  4 = LONG A 32-bit (4-byte) unsigned integer,
- *  5 = RATIONAL Two LONGs. The first LONG is the numerator and the second LONG expresses
- *    the denominator.,
- *  7 = UNDEFINED An 8-bit byte that can take any value depending on the field definition,
- *  9 = SLONG A 32-bit (4-byte) signed integer (2's complement notation),
- * 10 = SRATIONAL Two SLONGs. The first SLONG is the numerator and the second SLONG is the
- *    denominator.
- */
-struct ExifTypeInfo {
-
-  /**
-   * Number of bytes used by each exif type
-   */
-  static const size_t ByteSize;     //1 byte
-  static const size_t ASCIISize;    //1 byte (*N)
-  static const size_t ShortSize;    //2 bytes
-  static const size_t LongSize;     //4 bytes
-  static const size_t RationalSize;   //8 bytes
-  static const size_t UndefinedSize;  //1 byte (*N)
-  static const size_t SLongSize;    //4 bytes
-  static const size_t SRationalSize;  //8 bytes
-
-  /**
-   * Id values used by Exif to identify type
-   */
-  static const ExifByte ByteId;     // 1
-  static const ExifByte ASCIIId;    // 2
-  static const ExifByte ShortId;    // 3
-  static const ExifByte LongId;     // 4
-  static const ExifByte RationalId;   // 5
-  static const ExifByte UndefinedId;  // 7
-  static const ExifByte SLongId;    // 9
-  static const ExifByte SRationalId;  //10
-};
-
-class ExifUtil
-{
-public:
-  ExifUtil();
-  virtual ~ExifUtil();
-
-  static ImageOrientation stringToOrientation(const std::string& orientation);
-  static const std::string& orientationToString(ImageOrientation value);
-
-  static WhiteBalanceMode stringToWhiteBalance(const std::string& white_balance);
-  static const std::string& whiteBalanceToString(WhiteBalanceMode value);
-
-  static ExposureProgram stringToExposureProgram(const std::string& exposure_program);
-  static const std::string& exposureProgramToString(ExposureProgram value);
-
-  static bool isValidAbsoluteURI(const std::string& uri);
-  static void getURIInfo(const std::string& uri,
-      //const Filesystem::NodeType expected_type,
-      const std::string& required_permission,
-      bool& out_exists,
-      //Filesystem::NodeType& out_type,
-      bool& out_permission_granted);
-
-  static std::string convertUriToPath(const std::string& str);
-  static std::string ltrim(const std::string& s);
-
-  static time_t exifDateTimeOriginalToTimeT(const char* string);
-  static std::string timeTToExifDateTimeOriginal(time_t time);
-
-  static size_t getSizeOfExifFormatType(ExifFormat format);
-  static void  printExifEntryInfo(ExifEntry* entry, ExifData* exif_data);
-
-  static void extractFromTimeT(const time_t time,
-      int& out_year, int& out_month, int& out_day,
-      int& out_hour, int& out_min, int& out_sec);
-
-  static time_t convertToTimeT(int year, int month, int day,
-      int hour, int min, int sec);
-};
-
-} // exif
-} // extension
-
-#endif // __TIZEN_EXIF_EXIFUTIL_H_
diff --git a/src/exif/JpegFile.cpp b/src/exif/JpegFile.cpp
deleted file mode 100644 (file)
index 8542dff..0000000
+++ /dev/null
@@ -1,729 +0,0 @@
-//
-// Tizen Web Device API
-// Copyright (c) 2014 Samsung Electronics Co., Ltd.
-//
-// Licensed under the Apache License, Version 2.0 (the License);
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-//
-// For details of JPEG file format see:
-// http://www.media.mit.edu/pia/Research/deepview/exif.html
-
-#include "JpegFile.h"
-
-#include <iomanip>
-#include <limits>
-#include <stdio.h>
-#include <sstream>
-
-#include "common/platform_exception.h"
-#include "common/logger.h"
-
-namespace extension {
-namespace exif {
-
-/**
- * Size of maximal JPEG's section data length
- * (since it is stored as unsigned short limit is 2^16 -1)
- */
-const unsigned int MAX_JPEG_SECTION_DATA_SIZE = 65535;
-
-/**
- * JPEG's section data length includes 2 bytes for length therefore we need to
- * substract 2 from MAX_JPEG_SECTION_DATA_SIZE
- */
-const unsigned int MAX_AVAILABLE_JPEG_SECTION_DATA_SIZE = MAX_JPEG_SECTION_DATA_SIZE - 2;
-
-bool isJpegMarker(const int value)
-{
-  return value >= JPEG_MARKER_LOWEST_ID && value <= JPEG_MARKER_HIGHEST_ID;
-}
-
-JpegMarker castToJpegMarker(const unsigned char byte)
-{
-  if (byte < JPEG_MARKER_LOWEST_ID || byte > JPEG_MARKER_HIGHEST_ID) {
-    return JPEG_MARKER_UNKNOWN;
-  }
-
-  return static_cast<JpegMarker>(byte);
-}
-
-long readUShortBE(unsigned char* src)
-{
-  return ((static_cast<long>(src[0]) << 8) | static_cast<long>(src[1]));
-}
-
-void writeUShortBE(unsigned short value, unsigned char* buffer)
-{
-  buffer[0] = static_cast<unsigned char>(value >> 8);
-  buffer[1] = static_cast<unsigned char>(value);
-}
-
-struct CArrayDeleter {
-  void operator()(void* buffer) { free(buffer); }
-};
-
-JpegFile::JpegFile() :
-  m_in_data(NULL),
-  m_in_data_size(0),
-  m_image_data(NULL),
-  m_image_size(0),
-  m_padding_data(NULL),
-  m_padding_data_size(0),
-  m_in_file(NULL),
-  m_out_file(NULL)
-{
-
-}
-
-JpegFile::~JpegFile()
-{
-  delete [] m_in_data;
-  m_in_data = NULL;
-  m_in_data_size = 0;
-
-  m_padding_data = NULL;
-  m_padding_data_size = 0;
-
-  for(SectionsVec::iterator it = m_sections.begin(); it != m_sections.end(); ++it) {
-    JpegFileSectionPtr cur = *it;
-
-    if (cur->exif_data) {
-      exif_data_unref(cur->exif_data);
-      cur->exif_data = NULL;
-    }
-
-    cur->data_ptr = NULL;
-    cur->size = 0;
-    cur->type = JPEG_MARKER_UNKNOWN;
-  }
-
-  m_image_data = NULL;
-  m_image_size = 0;
-
-  if (m_in_file) {
-    fclose(m_in_file);
-    m_in_file = NULL;
-  }
-
-  if (m_out_file) {
-    fclose(m_out_file);
-    m_out_file = NULL;
-  }
-}
-
-JpegFilePtr JpegFile::loadFile(const std::string& path)
-{
-  JpegFile* new_jpg = new (std::nothrow) JpegFile();
-  if (!new_jpg) {
-    LoggerE("Couldn't allocate Jpegfile!");
-    throw common::UnknownException("Memory allocation failed");
-  }
-
-  JpegFilePtr jpg_ptr(new_jpg);
-  jpg_ptr->load(path);
-  return jpg_ptr;
-}
-
-void JpegFile::load(const std::string& path)
-{
-  LoggerD("Entered file:%s", path.c_str());
-
-  m_source_file_path = path;
-
-  m_in_file = fopen(path.c_str(), "rb");
-  if (!m_in_file) {
-    LoggerE("Couldn't open Jpeg file: [%s]", path.c_str());
-    throw common::NotFoundException("Could not open JPG file");
-  }
-
-  fseek(m_in_file, 0, SEEK_END);
-  const size_t in_file_size = static_cast<size_t>(ftell(m_in_file));
-  fseek(m_in_file, 0, SEEK_SET);
-  LoggerD("JPEG file: [%s] size:%d", path.c_str(), in_file_size);
-  if (0 == in_file_size) {
-    LoggerE("Input file [%s] is empty!", path.c_str());
-    throw common::UnknownException("JPEG file is invalid");
-  }
-
-  m_in_data = new (std::nothrow) unsigned char[in_file_size];
-  if (!m_in_data) {
-    LoggerE("Couldn't allocate buffer with size: %d", in_file_size);
-    throw common::UnknownException("Memory allocation failed");
-  }
-
-  m_in_data_size = in_file_size;
-
-  const size_t read_bytes = fread(m_in_data, 1, m_in_data_size, m_in_file);
-  if (read_bytes != m_in_data_size) {
-    LoggerE("Couldn't read all: %d bytes. Read only: %d bytes!", m_in_data_size,
-        read_bytes);
-    throw common::UnknownException("Could not read JPEG file");
-  }
-
-  if (fclose(m_in_file) == EOF) {
-    LoggerE("Couldn't close input file: %s!", path.c_str());
-  }
-  m_in_file = NULL;
-
-  generateListOfSections();
-}
-
-std::string JpegFile::getPartOfFile(const size_t offset,
-    const size_t num_bytes_before,
-    const size_t num_bytes_after)
-{
-  long long int start = static_cast<long long int>(offset) - num_bytes_before;
-  if (start < 0) {
-    start = 0;
-  }
-
-  long long int end = static_cast<long long int>(offset) + num_bytes_after;
-  if (end >= m_in_data_size) {
-    end = m_in_data_size - 1;
-  }
-
-  std::stringstream ss;
-  ss << std::setfill('0') << std::setw(2) << std::hex;
-  for(long long int i = start; i <= end; ++i) {
-    ss << static_cast<int>(m_in_data[i]);
-  }
-  return ss.str();
-}
-
-
-void JpegFile::generateListOfSections()
-{
-  LoggerD("Entered");
-
-  //JPEG starts with:
-  //FFD8 (2 bytes) - SOI Marker
-  //
-  //then:
-  //N sections - format of section:
-  //0xFF(1 byte) + Marker Number(1 byte) + Data size(2 bytes) + Data
-  //
-  //then:
-  //SOS 0xFF(1 byte) + Marker Number(1 byte) + Data size(2 bytes) + Data
-  //
-  //Image data
-  //
-  //FFD9 (2 bytes) - EOI Marker
-  //
-  //Warning: some images taken on Android contains some extra data at the end
-  //we will keep it in m_padding_data
-
-  m_padding_data = NULL;
-  m_padding_data_size = 0;
-
-  for(size_t offset = 0, iterration = 0; offset < m_in_data_size;++iterration) {
-
-    LoggerD("offset:%d | Starting iteration: %d", offset, iterration);
-    const size_t search_len = 10;
-    size_t search_offset = 0;
-    for(search_offset = 0; search_offset < search_len; ++search_offset) {
-      //Skip bytes until first no 0xff
-      unsigned char& tmp_marker = m_in_data[offset + search_offset];
-      if (tmp_marker != 0xff) {
-        break;
-      }
-    }
-
-    if (search_len == search_offset) {
-      LoggerE("offset:%d | Couldn't find marker! RAW DATA:{%s}", offset,
-          getPartOfFile(offset, 0, 10).c_str());
-      throw common::UnknownException("JPEG file is invalid");
-    }
-
-    const size_t section_offset = offset + search_offset - 1;
-    unsigned char* section_begin = m_in_data + section_offset;
-
-    offset = section_offset;  //Move to section begin
-    LoggerD("offset:%d | Moved to section begin", offset);
-
-    if (!isJpegMarker(section_begin[1])) {
-      LoggerE("offset:%d | Is not valid marker: 0x%x RAW DATA:{%s}", offset,
-          section_begin[1], getPartOfFile(section_offset,0,4).c_str());
-      throw common::UnknownException("JPEG file is invalid");
-    }
-
-    const JpegMarker cur_marker = castToJpegMarker(section_begin[1]);
-    LoggerD("offset:%d | Found valid marker: 0x%x RAW DATA:{%s}", offset,
-        cur_marker,
-        getPartOfFile(section_offset,0,4).c_str());
-
-    offset += 2;  //Read 0xffxx marker tag - 2 bytes
-
-    JpegFileSectionPtr section;
-    {
-      JpegFileSection* sec = new (std::nothrow) JpegFileSection();
-      if (!sec) {
-        LoggerE("Couldn't allocate JpegFileSection");
-        throw common::UnknownException("Memory allocation failed");
-      }
-
-      section = JpegFileSectionPtr(sec);
-    }
-
-    section->type = cur_marker;
-    m_sections.push_back(section);
-    if (cur_marker == JPEG_MARKER_SOI ||
-      cur_marker == JPEG_MARKER_EOI) {
-      LoggerD("offset:%d | Found: %s marker, moving to next marker at:%d",
-          section_offset, ((cur_marker == JPEG_MARKER_SOI) ? "SOI" : "EOI"),
-          offset);
-
-      if (cur_marker == JPEG_MARKER_EOI && m_padding_data != NULL) {
-        LoggerW("Padding data have been found - do not try to parse end of file");
-        break;
-      }
-    }
-    else {
-      //From JPEG/EXIF info:
-      // Please notice that "Data" contains Data size descriptor, if there is
-      // a Marker like this;
-      //
-      // FF C1 00 0C
-      // It means this Marker(0xFFC1) has 0x000C(equal 12)bytes of data. But the
-      // data size '12' includes "Data size" descriptor, it follows only 10 bytes of
-      // data after 0x000C.
-      //
-
-      const long total_section_len = readUShortBE(section_begin + 2); //Include data
-                                      //size 2 bytes
-
-      const long section_data_len = total_section_len - 2;      //Exclude data
-                                      //size 2 bytes
-
-      LoggerD("offset:%d tag:0x%x | Read total_section_len:%d (data len:%d)",
-          section_offset, cur_marker, total_section_len, section_data_len);
-
-      offset += 2;  //Read data size - 2 bytes
-
-      if (total_section_len < 0) {
-        LoggerE("offset:%d tag:0x%x | Error: total_section_len is: %d < 0", offset,
-            cur_marker, total_section_len);
-        throw common::UnknownException("JPEG file is invalid");
-      }
-
-      if (section_offset + 2 + total_section_len > m_in_data_size) {
-        LoggerE("offset:%d tag:0x%x | Error: current section offset:%d"
-            " + 2 + total_section_len:%d = %d is greater then file size:%d",
-            offset, cur_marker,
-            section_offset, total_section_len,
-            section_offset + total_section_len, m_in_data_size);
-        throw common::UnknownException("JPEG file is invalid");
-      }
-
-      if (JPEG_MARKER_APP1 == cur_marker) {
-        //TODO: verify this
-        //-4 --> 0xFF(1 byte)+Marker Number(1 byte)+Data size(2 bytes))
-        //const unsigned int exif_data_size = section_length - 4;
-
-        const unsigned int exif_data_size = total_section_len + 2;
-        section->exif_data = exif_data_new_from_data (section_begin,
-            exif_data_size);
-
-        LoggerD("offset:%d tag:0x%x | Loading exif from offset:%d"
-            " len:%d exif_data_new_from_data returned: %p",
-            offset, cur_marker, section_offset, exif_data_size,
-            section->exif_data);
-
-        if (!section->exif_data) {
-          LoggerW("offset:%d tag:0x%x | Couldn't load Exif!", offset, cur_marker);
-        }
-      }
-
-      //This just saves pointer not copying data
-      section->data_ptr = section_begin + 2 + 2; //2 bytes marker + 2 bytes data size
-      section->size = section_data_len;  //Exclude data size
-
-      if (JPEG_MARKER_SOS == cur_marker) {
-        //Calculate offset of first image data which is just after this SOS section
-        const size_t image_data_offset = section_offset + 2 + total_section_len;
-
-        //Calculate size of image data from start to expected EOI at end of file.
-        //
-        //-2 (exclude ending EOI marker (2 bytes)
-        size_t image_size = m_in_data_size - image_data_offset - 2;
-        LoggerW("offset:%d tag:0x%x | Image data offset:%d Estimated image size:%d",
-            offset, cur_marker, image_data_offset, image_size);
-
-        m_image_data = m_in_data + image_data_offset;
-
-        size_t eoi_tag_index = 0;
-        bool found_eoi_tag = searchForTagInBuffer(m_in_data + image_data_offset,
-            m_in_data + m_in_data_size, JPEG_MARKER_EOI, eoi_tag_index);
-        if (!found_eoi_tag) {
-          LoggerE("Could not find EOI tag! Assume that there is no EOI and rest of "
-              "JPEG file contains image data stream: image_size+= 2");
-          image_size += 2; //Skip expected EOI tag which is not present
-        } else {
-          LoggerD("EOI tag found at offset: %d from SOS data", eoi_tag_index);
-
-          if(eoi_tag_index != image_size) {
-            LoggerW("Estimated image size:%d doesn't match EOI tag index:%d"
-                " delta:%d", image_size, eoi_tag_index,
-                image_size - eoi_tag_index);
-
-            LoggerW("Setting image_size to EOI tag: %d", eoi_tag_index);
-            image_size = eoi_tag_index;
-
-            m_padding_data = m_image_data + image_size + 2; //(skip EOI tag)
-            m_padding_data_size = (m_in_data + m_in_data_size) - m_padding_data;
-            LoggerW("Saving padding data from offset:%d with size:%d",
-              m_padding_data - m_in_data, m_padding_data_size);
-          }
-        }
-
-        m_image_size = image_size;
-
-        offset = image_data_offset + image_size;
-        LoggerD("offset:%d tag:0x%x | SOS Offset moved to next marker", offset,
-            cur_marker);
-      }
-      else {
-        offset += section_data_len;
-        LoggerD("offset:%d tag:0x%x | Offset moved to next marker", offset, cur_marker);
-      }
-    }
-  }
-}
-
-bool JpegFile::searchForTagInBuffer(const unsigned char* buffer_start,
-    const unsigned char* buffer_end,
-    const JpegMarker marker,
-    size_t& out_index)
-{
-  LoggerD("Entered start:%p end:%p marker:0x%x", buffer_start, buffer_end, marker);
-
-  if(!buffer_start) {
-    LoggerE("buffer_start is NULL");
-    return false;
-  }
-
-  if(!buffer_end) {
-    LoggerE("buffer_end is NULL");
-    return false;
-  }
-
-  if(buffer_end <= buffer_start) {
-    LoggerE("buffer_end: %p <= buffer_start: %p", buffer_end, buffer_start);
-    return false;
-  }
-
-  LoggerD("Bytes to scan: %d", static_cast<size_t>(buffer_end - buffer_start));
-  const unsigned char marker_uchar = static_cast<unsigned char>(marker);
-
-  for(const unsigned char* ptr = buffer_start; ptr < buffer_end; ++ptr) {
-
-    if((0xff == *ptr) && (ptr+1 < buffer_end)) {
-      if(marker_uchar == *(ptr+1)) {
-        out_index = static_cast<size_t>(ptr - buffer_start);
-        return true;
-      }
-    }
-  }
-
-  out_index = 0;
-  return false;
-}
-
-void JpegFile::setNewExifData(ExifData* new_exif_data)
-{
-  if (!new_exif_data) {
-    LoggerE("Trying to set NULL exif_data!");
-    throw common::UnknownException("Could not save Exif in JPEG file");
-  }
-
-  JpegFileSectionPtr exif = getExifSection();
-  if (!exif) {
-    LoggerW("Could't find Exif section - creating new one");
-    {
-      JpegFileSection* new_sec = new (std::nothrow) JpegFileSection();
-      if (!new_sec) {
-        LoggerE("Couldn't allocate JpegFileSection");
-        throw common::UnknownException("Memory allocation failed");
-      }
-      new_sec->type = JPEG_MARKER_APP1;
-
-      exif = JpegFileSectionPtr(new_sec);
-    }
-
-    SectionsVec::iterator insert_it = m_sections.begin();
-    bool soi_is_present = false;
-
-    if (insert_it != m_sections.end()) {
-      if ((*insert_it)->type != JPEG_MARKER_SOI) {
-        LoggerW("First section is not SOI - Start Of Image!");
-      }
-      else {
-        soi_is_present = true;
-      }
-    }
-
-    if (!soi_is_present) {
-      LoggerW("SOI section is missing");
-      throw common::UnknownException("JPEG file is invalid");
-    }
-
-    //Insert new Exif sections just after SOI
-    ++insert_it;
-    if (insert_it != m_sections.begin()) {
-      m_sections.insert(insert_it, exif);
-    }
-    else {
-      //This shouldn't happen since we at lest need SOS and EOI sections
-      m_sections.push_back(exif);
-    }
-  }
-
-  //We don't want to save old data
-  exif->data_ptr = NULL;
-  exif->size = 0;
-
-  exif_data_unref(exif->exif_data);
-  exif_data_ref (new_exif_data);
-  exif->exif_data = new_exif_data;
-}
-
-ExifData* JpegFile::getExifData()
-{
-  JpegFileSectionPtr exif = getExifSection();
-  if (!exif) {
-    return NULL;
-  }
-
-  exif_data_ref(exif->exif_data);
-  return exif->exif_data;
-}
-
-void JpegFile::saveToFile(const std::string& out_path)
-{
-  LoggerD("Entered out_path:%s", out_path.c_str());
-  try {
-    saveToFilePriv(out_path);
-  }
-  catch (...) {
-    LoggerE("Exception occured during saveToFilePriv "
-        "original file: [%] new: [%s]",
-        m_source_file_path.c_str(),
-        out_path.c_str());
-
-    if (out_path == m_source_file_path) {
-
-      LoggerD("Trying to recover broken JPEG file: [%s]", out_path.c_str());
-      //We were writing to source file and since something went wrong let's
-      //restore old file - we have it in m_in_data
-
-      FILE* outf = fopen(out_path.c_str(), "wb");
-      if (!outf) {
-        LoggerE("Couldn't open output file: [%s] - JPEG file will not be restored!");
-      }
-      else {
-        size_t bytes_wrote = fwrite(m_in_data, 1, m_in_data_size, outf);
-        if (bytes_wrote != m_in_data_size) {
-          LoggerE("Couldn't restore whole JPEG! "
-              "Only %d of %d bytes have been wrote!",
-              bytes_wrote, m_in_data_size);
-        }
-        if (EOF == fclose(outf)) {
-          LoggerE("Couldn't close restore output file: [%s]", out_path.c_str());
-        }
-      }
-    }
-
-    throw;
-  }
-}
-
-void JpegFile::saveToFilePriv(const std::string& out_path)
-{
-  LoggerD("Entered out_path:%s", out_path.c_str());
-
-  m_out_file = fopen(out_path.c_str(), "wb");
-  if (!m_out_file) {
-    LoggerE("Couldn't open output file: %s", out_path.c_str());
-    throw common::UnknownException("Could not write JPEG file");
-  }
-
-  unsigned char tmp_buf[128];
-  size_t offset = 0;
-
-  int section_index = 0;
-  for(SectionsVec::iterator it = m_sections.begin();
-      it != m_sections.end();
-      ++it, ++ section_index) {
-
-    JpegFileSectionPtr cur = *it;
-    const JpegMarker cur_marker = cur->type;
-
-    LoggerD("offset:%d | Section: %d marker 0x%x", offset, section_index, cur_marker);
-
-    size_t bytes_to_write = 0;
-    size_t bytes_wrote = 0;
-
-    tmp_buf[0] = 0xff;
-    tmp_buf[1] = cur_marker;
-    bytes_to_write += 2;
-
-    bool write_section_data = false;
-
-    bool write_exif_data = false;
-
-    std::unique_ptr<unsigned char, CArrayDeleter> exif_output_data;
-    unsigned int exif_output_size = 0;
-
-    if (cur_marker != JPEG_MARKER_SOI &&
-        cur_marker != JPEG_MARKER_EOI) {
-
-      unsigned short section_size = 2;
-      if (JPEG_MARKER_APP1 && cur->exif_data) {
-
-        unsigned char* tmp = NULL;
-        exif_data_save_data (cur->exif_data, &tmp, &exif_output_size);
-        if (!tmp || 0 == exif_output_size) {
-          LoggerE("Couldn't generate RAW Exif data!");
-          throw common::UnknownException("Could not save Exif in JPEG file");
-        }
-
-        LoggerD("offset:%d | Generated Exif RAW Data length:%d", offset,
-            exif_output_size);
-
-        exif_output_data.reset(tmp);
-
-        if (exif_output_size > MAX_AVAILABLE_JPEG_SECTION_DATA_SIZE) {
-          LoggerE("exif_output_size:%d is greater then maximum JPEG section"
-              "data block size: %d", exif_output_size,
-              MAX_AVAILABLE_JPEG_SECTION_DATA_SIZE);
-          throw common::UnknownException("Exif data is to big to be saved in JPEG file");
-        }
-        section_size += exif_output_size;
-        write_exif_data = true;
-      }
-      else {
-        section_size += cur->size;
-        write_section_data = true;
-      }
-
-      writeUShortBE(section_size, tmp_buf + bytes_to_write);
-      bytes_to_write += 2;
-    }
-
-    LoggerD("offset:%d | Writing section: marker:0x%x size:%d", offset, cur_marker,
-        cur->size);
-
-    bytes_wrote = fwrite(tmp_buf, 1, bytes_to_write, m_out_file);
-    offset += bytes_wrote;
-
-    if (bytes_wrote != bytes_to_write) {
-      LoggerE("Couldn't wrote %d bytes! Only %d bytes wrote", bytes_to_write,
-          bytes_wrote);
-      throw common::UnknownException("Could not write JPEG file");
-    }
-
-    if (write_section_data && cur->size > 0) {
-      LoggerD("offset:%d | Writing data with length:%d", offset, cur->size);
-
-      bytes_to_write = cur->size;
-      bytes_wrote = fwrite(cur->data_ptr, 1, bytes_to_write, m_out_file);
-      offset += bytes_wrote;
-
-      if (bytes_wrote != bytes_to_write) {
-        LoggerE("Couldn't wrote %d bytes! Only %d bytes wrote", bytes_to_write,
-            bytes_wrote);
-        throw common::UnknownException("Could not write JPEG file");
-      }
-    }
-
-    if (write_exif_data && exif_output_data && exif_output_size > 0) {
-      LoggerD("offset:%d | Writing new exif data with length:%d", offset,
-          exif_output_size);
-
-      bytes_to_write = exif_output_size;
-      bytes_wrote = fwrite(exif_output_data.get(), 1, bytes_to_write, m_out_file);
-      offset += bytes_wrote;
-
-      if (bytes_wrote != bytes_to_write) {
-        LoggerE("Couldn't wrote %d bytes! Only %d bytes wrote", bytes_to_write,
-            bytes_wrote);
-        throw common::UnknownException("Could not write JPEG file");
-      }
-    }
-
-    if (JPEG_MARKER_SOS == cur_marker) {
-      LoggerD("offset:%d | Writing image data stream with lenght:%d", offset,
-          m_image_size);
-
-      bytes_to_write = m_image_size;
-      bytes_wrote = fwrite(m_image_data, 1, bytes_to_write, m_out_file);
-      offset += bytes_wrote;
-
-      if (bytes_wrote != bytes_to_write) {
-        LoggerE("Couldn't wrote %d bytes! Only %d bytes wrote", bytes_to_write,
-            bytes_wrote);
-        throw common::UnknownException("Could not write JPEG file");
-      }
-    }
-  }
-
-  if (m_padding_data && m_padding_data_size > 0) {
-    LoggerD("Padding data exists and contains:%d bytes saving to JPEG file");
-    const size_t bytes_wrote = fwrite(m_image_data, 1, m_padding_data_size,
-        m_out_file);
-
-    if (bytes_wrote != m_padding_data_size) {
-      LoggerE("Couldn't wrote %d bytes! Only %d bytes wrote", m_padding_data_size,
-          bytes_wrote);
-      throw common::UnknownException("Could not write JPEG file");
-    }
-  }
-
-  if (fclose(m_out_file) == EOF) {
-    LoggerE("Couldn't close output file: %s", out_path.c_str());
-    m_out_file = NULL;
-  }  else {
-    m_out_file = NULL;
-    LoggerD("Closed output file: %s wrote:%d bytes: %d", out_path.c_str(), offset);
-  }
-}
-
-JpegFileSectionPtr JpegFile::getExifSection()
-{
-  size_t num_exif_sections = 0;
-  JpegFileSectionPtr first_exif_section;
-
-  for (SectionsVec::iterator it = m_sections.begin(); it != m_sections.end(); ++it) {
-    JpegFileSectionPtr cur = *it;
-
-    if (JPEG_MARKER_APP1 == cur->type) {
-      if (!cur->exif_data) {
-        LoggerW("Warning: found APP1 section but exif_data is NULL (Not Exif?)");
-        continue;
-      }
-
-      ++num_exif_sections;
-      if (!first_exif_section) {
-        first_exif_section = cur;
-      }
-      else {
-        LoggerW("Warning: found %d APP1/Exif sections - only first is currently supported!");
-      }
-    }
-  }
-
-  return first_exif_section;
-}
-
-} // namespace exif
-} // namespace extension
diff --git a/src/exif/JpegFile.h b/src/exif/JpegFile.h
deleted file mode 100644 (file)
index 4eb2b1f..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-//
-// Tizen Web Device API
-// Copyright (c) 2014 Samsung Electronics Co., Ltd.
-//
-// Licensed under the Apache License, Version 2.0 (the License);
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-
-#ifndef __TIZEN_EXIF_JPEG_FILE_H_
-#define __TIZEN_EXIF_JPEG_FILE_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-#include <stdio.h>
-#include <map>
-#include <libexif/exif-data.h>
-#include <libexif/exif-entry.h>
-#include <libexif/exif-utils.h>
-
-namespace extension {
-namespace exif {
-
-enum JpegMarker{
-  JPEG_MARKER_UNKNOWN   = 0x00,
-  JPEG_MARKER_LOWEST_ID   = 0xc0,
-  JPEG_MARKER_SOI     = 0xd8, //Start Of Image
-  JPEG_MARKER_EOI     = 0xd9, //End Of Image
-  JPEG_MARKER_SOS     = 0xda, //Start Of Stream
-  JPEG_MARKER_APP1    = 0xe1, //Application Data 1 - for Exif
-  JPEG_MARKER_HIGHEST_ID  = 0xfe
-};
-
-struct JpegFileSection;
-typedef std::shared_ptr<JpegFileSection> JpegFileSectionPtr;
-
-struct JpegFileSection
-{
-  JpegFileSection() :
-    type(JPEG_MARKER_UNKNOWN),
-    data_ptr(NULL),
-    size(0),
-    exif_data(NULL) {};
-
-  JpegMarker type;
-  unsigned char* data_ptr;
-  unsigned short size;
-
-  ExifData* exif_data;
-};
-
-
-class JpegFile;
-typedef std::shared_ptr<JpegFile> JpegFilePtr;
-
-class JpegFile {
-public:
-  static JpegFilePtr loadFile(const std::string& path);
-  ~JpegFile();
-
-  void setNewExifData(ExifData* new_exif_data);
-
-  /**
-   * You are responsible to unreference returned data with: exif_data_unref(...)
-   * Example:
-   *   ExifData* ed = jpeg.getExifData();
-   *   if(ed) {
-   *     doSth(ed);
-   *     exif_data_unref(ed);
-   *   }
-   */
-  ExifData* getExifData();
-
-  void saveToFile(const std::string& out_path);
-
-private:
-  JpegFile();
-  void load(const std::string& path);
-  void generateListOfSections();
-
-  std::string getPartOfFile(const size_t offset,
-      const size_t num_bytes_before = 10,
-      const size_t num_bytes_after = 10);
-
-  JpegFileSectionPtr getExifSection();
-  void saveToFilePriv(const std::string& out_path);
-
-  /**
-   * Search for first occurence of specific tag inside buffer.
-   *
-   * buffer_end is the first byte that should not be checked:
-   * [buffer_start ... buffer_end)
-   *
-   * For example EOI - search for first 'ffd9' in buffer
-   */
-  static bool searchForTagInBuffer(const unsigned char* buffer_start,
-      const unsigned char* buffer_end,
-      const JpegMarker marker,
-      size_t& out_index);
-
-  std::string m_source_file_path;
-
-  unsigned char* m_in_data;
-  size_t m_in_data_size;
-
-  unsigned char* m_image_data;
-  size_t m_image_size;
-
-  /**
-   * This contains any bytes after EOI.
-   * Usually there should be no extra bytes after EOI unfortunately
-   * some cameras saves extra bytes (for example Android).
-   */
-  unsigned char* m_padding_data;
-  size_t m_padding_data_size;
-
-  FILE* m_in_file;
-  FILE* m_out_file;
-
-  typedef std::vector<JpegFileSectionPtr> SectionsVec;
-  SectionsVec m_sections;
-};
-
-
-} // namespace exif
-} // namespace extension
-
-#endif // __TIZEN_EXIF_JPEG_FILE_H_
diff --git a/src/exif/Rational.cpp b/src/exif/Rational.cpp
deleted file mode 100644 (file)
index bde7a09..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-//
-// Tizen Web Device API
-// Copyright (c) 2014 Samsung Electronics Co., Ltd.
-//
-// Licensed under the Apache License, Version 2.0 (the License);
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#include "Rational.h"
-
-#include "math.h"
-
-#include "common/platform_exception.h"
-#include "common/logger.h"
-
-#include <sstream>
-
-namespace extension {
-namespace exif {
-
-namespace {
-const double DOUBLE_ERROR_REPRESENTATION = static_cast<double>(0x7FFFFFFF);
-} //anonymous namespace
-
-Rational::Rational() :
-    nominator(0),
-    denominator(0)
-{
-}
-
-Rational::Rational(ExifLong nom, ExifLong denom) :
-    nominator(nom),
-    denominator(denom)
-{
-}
-
-Rational::Rational(const ExifRational& exif_rational) :
-    nominator(exif_rational.numerator),
-    denominator(exif_rational.denominator)
-{
-}
-
-Rational Rational::createFromDouble(const double value, const long precision)
-{
-  LoggerD("Entered value:%f precision:%d", value, precision);
-  if (value < 0.0) {
-    LoggerW("Trying to create negative Rational: %f!", value);
-    return Rational();
-  }
-
-  if (value < 0.000000001) {
-    LoggerD("Skipping calculation returning: Rational(0,1)");
-    return Rational(0,1);
-  }
-
-  long m[2][2];
-  double x, startx;
-  long ai;
-
-  startx = x = value;
-
-  // initialize matrix
-  m[0][0] = m[1][1] = 1;
-  m[0][1] = m[1][0] = 0;
-
-  //loop finding terms until daemon gets too big
-  do {
-    ai = static_cast<long>(x);
-    if(m[1][0] * ai + m[1][1] > precision) {
-      break;
-    }
-
-    long t = m[0][0] * ai + m[0][1];
-    m[0][1] = m[0][0];
-    m[0][0] = t;
-
-    t = m[1][0] * ai + m[1][1];
-    m[1][1] = m[1][0];
-    m[1][0] = t;
-
-    if (x == static_cast<double>(ai)) {
-      break;   // AF: division by zero
-    }
-
-    x = 1 / (x - static_cast<double>(ai));
-    if (x > DOUBLE_ERROR_REPRESENTATION) {
-      break;  // AF: representation failure
-    }
-  } while(1);
-
-  // now remaining x is between 0 and 1/ai
-  // approx as either 0 or 1/m where m is max that will fit in precision
-  // first try zero
-  const double error0 = startx - ((double) m[0][0] / (double) m[1][0]);
-  const long numerator0 = m[0][0];
-  const long denominator0 = m[1][0];
-
-  LoggerD("%ld/%ld, error = %e\n", numerator0, denominator0, error0);
-
-  /* now try other possibility */
-  ai = (precision - m[1][1]) / m[1][0];
-  m[0][0] = m[0][0] * ai + m[0][1];
-  m[1][0] = m[1][0] * ai + m[1][1];
-
-  double error1m = startx -
-      (static_cast<double>(m[0][0]) / static_cast<double>(m[1][0]));
-  LoggerD("%ld/%ld, error = %e\n", m[0][0], m[1][0], error1m );
-
-  long result_numerator = 0;
-  long result_denominator = 0;
-
-  if (error0 < error1m ) {
-    result_numerator = numerator0;
-    result_denominator = denominator0;
-  }
-  else {
-    result_numerator = m[0][0];
-    result_denominator = m[1][0];
-  }
-
-  if (result_numerator < 0) {
-    result_numerator *= -1;
-  }
-  if (result_denominator < 0) {
-    result_denominator *= -1;
-  }
-
-  LoggerD("Rational(%d, %d) error0 < error1m:%d", result_numerator, result_denominator,
-      error0 < error1m);
-
-  return Rational(numerator0, denominator0);
-}
-
-Rational Rational::createInvalid()
-{
-  return Rational(0,0);
-}
-
-bool Rational::isValid() const
-{
-  if (0 == denominator) {
-    return false;
-  }
-  else {
-    return true;
-  }
-}
-
-double Rational::toDouble() const
-{
-  if (!isValid()) {
-    return NAN;
-  }
-
-  return (double)nominator / (double)denominator;
-}
-
-Rational Rational::createFromExposureTimeString(const std::string& exp_time)
-{
-  LoggerD("Entered");
-  if (exp_time.length() == 0) {
-    return Rational::createInvalid();  //lets assume that empty string means 0,
-                       //however exposure time = 0 is not valid value
-  }
-
-  std::string integer_part;
-  std::string fraction_part;
-
-  int first_space_at = -1;
-  int first_slash_at = -1;
-
-  for(size_t i=0; i < exp_time.size(); ++i) {
-
-    const char& cur = exp_time[i];
-    if (first_space_at < 0 && ' ' == cur) {
-      first_space_at = i;
-    }
-    if (first_slash_at < 0 && '/' == cur) {
-      first_slash_at = i;
-    }
-  }
-
-  if (first_slash_at > 0) {
-    if (first_space_at > 0) {
-      integer_part = exp_time.substr(0,first_space_at);
-      fraction_part = exp_time.substr(first_space_at+1,
-          exp_time.size() - (first_space_at+1));
-    }
-    else {
-      fraction_part = exp_time;
-    }
-  }
-  else {
-    integer_part = exp_time;
-  }
-
-  LoggerD("first_space_at: %d first_slash_at:%d int: [%s] , frac: [%s]",
-      first_space_at, first_slash_at, integer_part.c_str(), fraction_part.c_str());
-
-  long integer_value = 0;
-  long nominator = 0;
-  long denominator = 1;
-
-  if (integer_part.length() > 0) {
-    integer_value = atol(integer_part.c_str());
-  }
-
-  if (fraction_part.length() > 0) {
-    if (sscanf(fraction_part.c_str(), "%ld/%ld", &nominator, &denominator) != 2) {
-      LoggerD("Failed to parse nominator/denominator string: [%s]",
-          fraction_part.c_str());
-      return Rational::createInvalid();
-    }
-  }
-
-  nominator += denominator * integer_value;
-  LoggerD("%d/%d -> %f", nominator, denominator, (float)nominator / denominator);
-
-  if (0 == nominator) {
-    //Exposure time = 0 is invalid value
-    return Rational::createInvalid();
-  }
-
-  return Rational(nominator, denominator);
-}
-
-std::string Rational::toString() const
-{
-  std::stringstream ss;
-  ss << nominator << "/" << denominator;
-  return ss.str();
-}
-
-std::string Rational::toExposureTimeString() const
-{
-  LoggerD("Entered");
-  if (!isValid() || 0 == nominator) {
-    return std::string();
-  }
-
-  std::string output_str;
-
-  if (nominator < denominator) {
-    output_str = toString();
-  }
-  else if (nominator % denominator == 0) {
-    std::stringstream ss;
-    ss << nominator / denominator;
-    output_str = ss.str();
-  }
-  else {
-    ExifLong new_nominator = nominator % denominator;
-    ExifLong new_denominator = denominator;
-    ExifLong integer_value = nominator / denominator;
-
-    std::stringstream ss;
-    ss << integer_value << " ";
-    ss << new_nominator << "/" << new_denominator;
-    output_str = ss.str();
-  }
-
-  return output_str;
-}
-
-} // exif
-} // extension
diff --git a/src/exif/Rational.h b/src/exif/Rational.h
deleted file mode 100644 (file)
index f31dd87..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-//
-// Tizen Web Device API
-// Copyright (c) 2014 Samsung Electronics Co., Ltd.
-//
-// Licensed under the Apache License, Version 2.0 (the License);
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-
-#ifndef __TIZEN_EXIF_RATIONAL_H_
-#define __TIZEN_EXIF_RATIONAL_H_
-
-#include <string>
-#include <vector>
-#include <memory>
-
-#include <libexif/exif-utils.h>
-#include <libexif/exif-entry.h>
-#include <libexif/exif-data.h>
-
-#include "ExifUtil.h"
-
-namespace extension {
-namespace exif {
-
-class Rational;
-typedef std::vector<Rational> Rationals;
-typedef std::shared_ptr<Rationals> RationalsPtr;
-
-/**
- * This class represents fraction as nominator/denominator - two ExifLong values
- * Rational type is present in Exif specification - used for example in GPS coordinates
- */
-class Rational
-{
-public:
-  /**
-   * Default constructor sets to 0/0 - invalud rational number
-   */
-  Rational();
-
-  Rational(ExifLong nom, ExifLong denom);
-  Rational(const ExifRational& exif_rational);
-
-  static Rational createFromDouble(const double value, const long precision = 1000);
-  static Rational createInvalid();
-
-  /**
-   * Returns true if denominator is valid (!= 0) and therefore whole Rational is valid
-   */
-  bool isValid() const;
-
-  double toDouble() const;
-
-  /**
-   * Returns string in format: nominator/denominator,
-   * for example: "1/4", "1/1", "5/3".
-   *
-   */
-  std::string toString() const;
-
-  /**
-   * Create rational number from exposure string
-   * Accepted format "(integer) (nominator/denominator)"
-   * for example:
-   * "1/5", "4/5" - just fraction part
-   * "1", "5" - just integer part
-   * "1 1/5", "4 1/4" - integer + fraction part
-   */
-  static Rational createFromExposureTimeString(const std::string& exp_time);
-
-  /**
-   * Return time exposure string in following format:
-   *
-   * nominator < denominator                 : "1/5", "4/5"
-   * nominator == x*denominator              : "1", "5"
-   * nominator > denominator && nominator != x*denominator : "1 1/5", "4 1/4"
-   */
-  std::string toExposureTimeString() const;
-
-  ExifLong nominator;
-  ExifLong denominator;
-};
-
-} // exif
-} // extension
-
-#endif // __TIZEN_EXIF_RATIONAL_H_
index be75d89c180d390e7deae11c02e498d978bc024b..bbbd3f7f7e3f22293a930317049a42e4730ed209 100644 (file)
         'exif_instance.cc',
         'exif_instance.h',
 
-        'ExifInformation.cpp',
-        'ExifInformation.h',
-        'ExifUtil.cpp',
-        'ExifUtil.h',
-        'ExifTagSaver.cpp',
-        'ExifTagSaver.h',
-        'JpegFile.cpp',
-        'JpegFile.h',
-        'Rational.cpp',
-        'Rational.h',
+        'exif_information.cc',
+        'exif_information.h',
+        'exif_util.cc',
+        'exif_util.h',
+        'exif_tag_saver.cc',
+        'exif_tag_saver.h',
+        'jpeg_file.cc',
+        'jpeg_file.h',
+        'rational.cc',
+        'rational.h',
         'ExifGPSLocation.cpp',
         'ExifGPSLocation.h',
       ],
index 59d2b99868c80efab4b39d3c8499ee68d9c26d03..e36058be77c5da4c10b59941e75da454125cff23 100644 (file)
@@ -37,6 +37,51 @@ var WhiteBalanceMode = {
   MANUAL: 'MANUAL'
 };
 
+var propertiesList = {
+  URI: 'uri',
+  WIDTH: 'width',
+  HEIGHT: 'height',
+  DEVICE_MAKER: 'deviceMaker',
+  DEVICE_MODEL: 'deviceModel',
+  ORIGINAL_TIME: 'originalTime',
+  ORIENTATION: 'orientation',
+  FNUMBER: 'fNumber',
+  ISO_SPEED_RATINGS: 'isoSpeedRatings',
+  EXPOSURE_TIME: 'exposureTime',
+  EXPOSURE_PROGRAM: 'exposureProgram',
+  FLASH: 'flash',
+  FOCAL_LENGTH: 'focalLength',
+  WHITE_BALANCE: 'whiteBalance',
+  GPS_LOCATION: 'gpsLocation',
+  GPS_ALTITUDE: 'gpsAltitude',
+  GPS_PROCESSING_METHOD: 'gpsProcessingMethod',
+  GPS_TIME: 'gpsTime',
+  USER_COMMENT: 'userComment'
+};
+
+function _getJsonFromExifInformation(exifInfo) {
+  var json = {};
+
+  for (var prop in propertiesList) {
+    var propName = propertiesList[prop];
+
+    if (exifInfo[propName] !== null) {
+      if (propName === 'originalTime') {
+        json[propName] = Math.floor(exifInfo[propName].getTime() / 1000);
+      } else if (propName === 'gpsTime') {
+        var str = exifInfo[propName].toLocaleString().split(', ');
+        var res = str[1] + ', ' + str[2] + ', ' + str[3];
+
+        json[propName] = Math.floor(Date.parse(res) / 1000);
+      } else {
+        json[propName] = exifInfo[propName];
+      }
+    }
+  }
+
+  return json;
+}
+
 ExifManager.prototype.getExifInfo = function() {
   var args = validator_.validateArgs(arguments, [
     {
@@ -55,7 +100,7 @@ ExifManager.prototype.getExifInfo = function() {
       name: 'errorCallback',
       type: validator_.Types.FUNCTION,
       optional: true,
-      nullable: false
+      nullable: true
     }
   ]);
 
@@ -89,17 +134,28 @@ ExifManager.prototype.saveExifInfo = function() {
       name: 'successCallback',
       type: validator_.Types.FUNCTION,
       optional: true,
-      nullable: false
+      nullable: true
     },
     {
       name: 'errorCallback',
       type: validator_.Types.FUNCTION,
       optional: true,
-      nullable: false
+      nullable: true
     }
   ]);
 
-  throw 'Not implemented';
+  var json = _getJsonFromExifInformation(args.exifInfo);
+  var callback = function(result) {
+    if (native_.isFailure(result)) {
+      native_.callIfPossible(args.errorCallback,
+          native_.getErrorObject(result));
+    } else {
+      var exifInfo = native_.getResultObject(result);
+      args.successCallback(exifInfo);
+    }
+  };
+
+  native_.call('Exif_saveExifInfo', json, callback);
 };
 
 ExifManager.prototype.getThumbnail = function() {
@@ -120,7 +176,7 @@ ExifManager.prototype.getThumbnail = function() {
       name: 'errorCallback',
       type: validator_.Types.FUNCTION,
       optional: true,
-      nullable: false
+      nullable: true
     }
   ]);
 
@@ -162,9 +218,9 @@ tizen.ExifInformation = function() {
 
   var exifInitDict = args.ExifInitDict;
   if (exifInitDict) {
-    if (exifInitDict['uri'] == null) {
+    if (exifInitDict.uri === null) {
       throw new tizen.WebAPIException(tizen.WebAPIException.INVALID_VALUES_ERR,
-        'Parameter "uri" is required.');
+          'Parameter "uri" is required.');
     }
   }
 
@@ -181,11 +237,11 @@ tizen.ExifInformation = function() {
     width: {
       get: function() {
         return width_;
-    },
-    set: function(v) {
-      width_ = v ? converter_.toLong(v, true) : width_;
-    },
-    enumerable: true
+      },
+      set: function(v) {
+        width_ = v ? converter_.toLong(v, true) : width_;
+      },
+      enumerable: true
     },
     height: {
       get: function() {
@@ -229,7 +285,7 @@ tizen.ExifInformation = function() {
       },
       set: function(v) {
         orientation_ = v ? converter_.toEnum(v, Object.keys(ImageContentOrientation), true) :
-          orientation_;
+            orientation_;
       },
       enumerable: true
     },
@@ -275,7 +331,7 @@ tizen.ExifInformation = function() {
         return flash_;
       },
       set: function(val) {
-        flash_ = val ? converter_.toBoolean(val, true) : flash_;
+        flash_ = converter_.toBoolean(val, true);
       },
       enumerable: true
     },
@@ -294,7 +350,7 @@ tizen.ExifInformation = function() {
       },
       set: function(v) {
         whiteBalance_ = v ? converter_.toEnum(v, Object.keys(WhiteBalanceMode), true) :
-           whiteBalance_;
+            whiteBalance_;
       },
       enumerable: true
     },
diff --git a/src/exif/exif_information.cc b/src/exif/exif_information.cc
new file mode 100644 (file)
index 0000000..eaaed31
--- /dev/null
@@ -0,0 +1,1368 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "exif_information.h"
+
+#include <memory>
+#include <math.h>
+
+#include "exif_tag_saver.h"
+#include "exif_util.h"
+#include "jpeg_file.h"
+
+#include "common/platform_exception.h"
+#include "common/converter.h"
+#include "common/logger.h"
+
+namespace extension {
+namespace exif {
+
+const size_t EXIF_UNDEFINED_TYPE_LENGTH = 8;
+const std::string EXIF_UNDEFINED_TYPE_ASCII =
+    std::string("ASCII\0\0\0", EXIF_UNDEFINED_TYPE_LENGTH);
+const std::string EXIF_UNDEFINED_TYPE_JIS =
+    std::string("JIS\0\0\0\0\0", EXIF_UNDEFINED_TYPE_LENGTH);
+const std::string EXIF_UNDEFINED_TYPE_UNICODE =
+    std::string("UNICODE\0", EXIF_UNDEFINED_TYPE_LENGTH);
+const std::string EXIF_UNDEFINED_TYPE_UNDEFINED =
+    std::string("\0\0\0\0\0\0\0\0", EXIF_UNDEFINED_TYPE_LENGTH);
+
+namespace {
+constexpr unsigned int str2int(const char* str, int h = 0) {
+  return !str[h] ? 5381 : (str2int(str, h+1)*33) ^ str[h];
+}
+
+IsoSpeedRatingsVector jsonArray2vector(const picojson::value& a) {
+  if (!a.is<picojson::array>()) {
+    return IsoSpeedRatingsVector();
+  }
+
+  IsoSpeedRatingsVector result;
+
+  picojson::array v = a.get<picojson::array>();
+
+  for (picojson::array::iterator it = v.begin(); it != v.end(); it++) {
+    result.push_back(static_cast<long long int>((*it).get<double>()));
+  }
+
+  return result;
+}
+}  // namespace
+
+ExifInformation::ExifInformation() {
+  for (int attr = 0; attr < EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES; attr++) {
+    unset(static_cast<ExifInformationAttribute>(attr));
+  }
+}
+
+ExifInformation::ExifInformation(const picojson::value& args) {
+  for (int attr = 0; attr < EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES; attr++) {
+    unset(static_cast<ExifInformationAttribute>(attr));
+  }
+
+  for (AttributeMap::const_iterator it = ExifInformationAttributeMap.begin();
+      it != ExifInformationAttributeMap.end(); it++) {
+    std::string attributeName = it->second;
+    picojson::value v = args.get(attributeName);
+    if (!common::IsNull(v)) {
+      set(attributeName, v);
+    }
+  }
+}
+
+ExifInformation::~ExifInformation() { }
+
+const std::string& ExifInformation::getUri() {
+  LoggerD("Entered");
+  return m_uri;
+}
+
+void ExifInformation::setUri(const std::string& uri) {
+  LoggerD("Entered");
+  LoggerD("URI: %s", uri.c_str());
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_URI] = true;
+  m_uri = uri;
+}
+
+unsigned long ExifInformation::getWidth() const {
+  LoggerD("Entered");
+  return m_width;
+}
+
+void ExifInformation::setWidth(unsigned long width) {
+  LoggerD("Entered");
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_WIDTH] = true;
+  m_width = width;
+}
+
+unsigned long ExifInformation::getHeight() const {
+  LoggerD("Entered");
+  return m_height;
+}
+
+void ExifInformation::setHeight(unsigned long height) {
+  LoggerD("Entered");
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_HEIGHT] = true;
+  m_height = height;
+}
+
+const std::string& ExifInformation::getDeviceMaker() {
+  LoggerD("Entered");
+  return m_device_maker;
+}
+
+void ExifInformation::setDeviceMaker(const std::string& device_maker) {
+  LoggerD("Entered");
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER] = true;
+  m_device_maker = device_maker;
+}
+
+const std::string& ExifInformation::getDeviceModel() {
+  LoggerD("Entered");
+  return m_device_model;
+}
+
+void ExifInformation::setDeviceModel(const std::string& device_model) {
+  LoggerD("Entered");
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL] = true;
+  m_device_model = device_model;
+}
+
+time_t ExifInformation::getOriginalTime() const {
+  LoggerD("Entered");
+  return m_original_time;
+}
+
+void ExifInformation::setOriginalTime(time_t original_time) {
+  LoggerD("Entered");
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME] = true;
+  m_original_time = original_time;
+}
+
+const std::string& ExifInformation::getOrientationString() {
+  LoggerD("Entered");
+  return ExifUtil::orientationToString(m_orientation);
+}
+
+ImageOrientation ExifInformation::getOrientation() {
+  LoggerD("Entered");
+  return m_orientation;
+}
+
+void ExifInformation::setOrientation(const std::string& orientation) {
+  LoggerD("Entered");
+  setOrientation(ExifUtil::stringToOrientation(orientation));
+}
+
+void ExifInformation::setOrientation(ImageOrientation orientation) {
+  LoggerD("Entered");
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_ORIENTATION] = true;
+  m_orientation = orientation;
+}
+
+const Rational& ExifInformation::getFNumber() const {
+  LoggerD("Entered");
+  return m_f_number;
+}
+
+void ExifInformation::setFNumber(Rational f_number) {
+  LoggerD("Entered");
+  if (!f_number.isValid()) {
+    LoggerW("Trying to set invalid F-Number: %s", f_number.toString().c_str());
+    return;
+  }
+
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_FNUMBER] = true;
+  m_f_number = f_number;
+}
+
+const std::vector<long long int>& ExifInformation::getIsoSpeedRatings() {
+  LoggerD("Entered");
+  return m_iso_speed_ratings;
+}
+
+void ExifInformation::setIsoSpeedRatings(
+const std::vector<long long int>& iso_speed_ratings) {
+  LoggerD("Entered");
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS] = true;
+  m_iso_speed_ratings = iso_speed_ratings;
+}
+
+const Rational& ExifInformation::getExposureTime() {
+  LoggerD("Entered");
+  return m_exposure_time;
+}
+
+void ExifInformation::setExposureTime(const Rational& exposure_time) {
+  LoggerD("Entered");
+  if (!exposure_time.isValid() || 0 == exposure_time.nominator) {
+    LoggerW("Trying to set invalid exposure time: [%s]",
+        exposure_time.toString().c_str());
+    return;
+  }
+
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME] = true;
+  m_exposure_time = exposure_time;
+}
+
+const std::string& ExifInformation::getExposureProgramString() {
+  LoggerD("Entered");
+  return ExifUtil::exposureProgramToString(m_exposure_program);;
+}
+
+ExposureProgram ExifInformation::getExposureProgram() {
+  LoggerD("Entered");
+  return m_exposure_program;
+}
+
+void ExifInformation::setExposureProgram(const std::string& exposure_program) {
+  LoggerD("Entered");
+  setExposureProgram(ExifUtil::stringToExposureProgram(exposure_program));
+}
+
+void ExifInformation::setExposureProgram(ExposureProgram exposure_program) {
+  LoggerD("Entered");
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM] = true;
+  m_exposure_program = exposure_program;
+}
+
+bool ExifInformation::getFlash() const {
+  LoggerD("Entered");
+  return m_flash;
+}
+
+void ExifInformation::setFlash(bool flash) {
+  LoggerD("Entered");
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_FLASH] = true;
+  m_flash = flash;
+}
+
+const Rational& ExifInformation::getFocalLength() const {
+  LoggerD("Entered");
+  return m_focal_length;
+}
+
+void ExifInformation::setFocalLength(Rational focal_length) {
+  LoggerD("Entered");
+  if(!focal_length.isValid()) {
+    LoggerW("Trying to set invalid focal length: %s", focal_length.toString().c_str());
+    return;
+  }
+
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH] = true;
+  m_focal_length = focal_length;
+}
+
+const std::string& ExifInformation::getWhiteBalanceModeString() {
+  LoggerD("Entered");
+  return ExifUtil::whiteBalanceToString(m_white_balance);
+}
+
+WhiteBalanceMode ExifInformation::getWhiteBalanceMode() {
+  LoggerD("Entered");
+  return m_white_balance;
+}
+
+void ExifInformation::setWhiteBalanceMode(const std::string& white_balance) {
+  LoggerD("Entered");
+  setWhiteBalanceMode(ExifUtil::stringToWhiteBalance(white_balance));
+}
+
+void ExifInformation::setWhiteBalanceMode(WhiteBalanceMode white_balance) {
+  LoggerD("Entered");
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE] = true;
+  m_white_balance = white_balance;
+}
+
+ExifGPSLocation& ExifInformation::getGPSExifLocation() {
+  LoggerD("Entered");
+  return m_gps_location;
+}
+
+void ExifInformation::setGPSLocation(ExifGPSLocation gps_location) {
+  LoggerD("Entered");
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_LOCATION] = true;
+  m_gps_location = gps_location;
+}
+
+void ExifInformation::unsetGPSLocation() {
+  LoggerD("Entered");
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_LOCATION] = false;
+  m_gps_location.unsetAll();
+}
+
+const Rational& ExifInformation::getGpsAltitude() const {
+  LoggerD("Entered");
+  return m_gps_altitude;
+}
+
+void ExifInformation::setGpsAltitude(Rational gps_altitude) {
+  LoggerD("Entered");
+  if (!gps_altitude.isValid()) {
+    LoggerW("Trying to set invalid gps altitude: %s", gps_altitude.toString().c_str());
+    return;
+  }
+
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE] = true;
+  m_gps_altitude = gps_altitude;
+}
+
+GpsAltitudeRef ExifInformation::getGpsAltitudeRef() const {
+  LoggerD("Entered");
+  return m_gps_altitude_ref;
+}
+
+void ExifInformation::setGpsAltitudeRef(const GpsAltitudeRef ref) {
+  LoggerD("Entered");
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF] = true;
+  m_gps_altitude_ref = ref;
+}
+
+void ExifInformation::setGpsAltitudeWithRef(double gps_altitude) {
+  LoggerD("Entered");
+  setGpsAltitude(Rational::createFromDouble(fabs(gps_altitude)));
+
+  if(gps_altitude >= 0.0) {
+    setGpsAltitudeRef(GPS_ALTITUDE_REF_ABOVE_SEA);
+  } else {
+    setGpsAltitudeRef(GPS_ALTITUDE_REF_BELOW_SEA);
+  }
+}
+
+double ExifInformation::getGpsAltitudeWithRef() const {
+  LoggerD("Entered");
+
+  if (!m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF] ||
+      GPS_ALTITUDE_REF_ABOVE_SEA == m_gps_altitude_ref) {
+    return m_gps_altitude.toDouble();
+  } else {
+    return -1.0 * m_gps_altitude.toDouble();
+  }
+}
+
+const std::string& ExifInformation::getGpsProcessingMethod() const {
+  LoggerD("Entered");
+  return m_gps_processing_method;
+}
+
+const std::string& ExifInformation::getGpsProcessingMethodType() const {
+  LoggerD("Entered");
+  return m_gps_processing_method_type;
+}
+
+void ExifInformation::setGpsProcessingMethod(const std::string& type,
+    const std::string& processing_method) {
+  LoggerD("Entered");
+  if (type != EXIF_UNDEFINED_TYPE_ASCII &&
+      type != EXIF_UNDEFINED_TYPE_JIS &&
+      type != EXIF_UNDEFINED_TYPE_UNICODE &&
+      type != EXIF_UNDEFINED_TYPE_UNDEFINED) {
+    LoggerW("Trying to set invalid GPSProcessingMethod type: [%s] len:%d",
+        type.c_str(), type.length());
+    return;
+  }
+
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD] = true;
+  m_gps_processing_method = processing_method;
+  m_gps_processing_method_type = type;
+}
+
+void ExifInformation::setGpsTime(time_t time) {
+  LoggerD("Entered");
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_TIME] = true;
+  m_gps_time = time;
+}
+
+time_t ExifInformation::getGpsTime() {
+  LoggerD("Entered");
+  return m_gps_time;
+}
+
+void ExifInformation::unsetGPStime() {
+  LoggerD("Entered");
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_GPS_TIME] = false;
+  m_gps_time = 0;
+}
+
+const std::string& ExifInformation::getUserComment() {
+  LoggerD("Entered");
+  return m_user_comment;
+}
+
+const std::string& ExifInformation::getUserCommentType() {
+  LoggerD("Entered");
+  return m_user_comment_type;
+}
+
+void ExifInformation::setUserComment(const std::string& type,
+    const std::string& user_comment) {
+  LoggerD("Entered");
+  if (type != EXIF_UNDEFINED_TYPE_ASCII &&
+      type != EXIF_UNDEFINED_TYPE_JIS &&
+      type != EXIF_UNDEFINED_TYPE_UNICODE &&
+      type != EXIF_UNDEFINED_TYPE_UNDEFINED) {
+    LoggerW("Trying to set invalid user comment type: [%s] len:%d",
+        type.c_str(), type.length());
+    return;
+  }
+
+  m_is_set[EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT] = true;
+  m_user_comment_type = type;
+  m_user_comment = user_comment;
+}
+
+bool ExifInformation::isSet(ExifInformationAttribute attribute) const {
+  LoggerD("Entered");
+  return m_is_set[attribute];
+}
+
+void ExifInformation::unset(ExifInformationAttribute attribute) {
+  LoggerD("Entered");
+  if (attribute >= EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES) {
+    return;
+  }
+
+  m_is_set[attribute] = false;
+  switch (attribute) {
+    case EXIF_INFORMATION_ATTRIBUTE_URI:
+      m_uri = std::string();
+      break;
+    case EXIF_INFORMATION_ATTRIBUTE_WIDTH:
+      m_width = 0;
+      break;
+    case EXIF_INFORMATION_ATTRIBUTE_HEIGHT:
+      m_height = 0;
+      break;
+    case EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER:
+      m_device_maker = std::string();
+      break;
+    case EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL:
+      m_device_model = std::string();
+      break;
+    case EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME:
+      m_original_time = 0;
+      break;
+    case EXIF_INFORMATION_ATTRIBUTE_ORIENTATION:
+      m_orientation = EXIF_ORIENTATION_NOT_VALID;
+      break;
+    case EXIF_INFORMATION_ATTRIBUTE_FNUMBER:
+      m_f_number = Rational::createInvalid();
+      break;
+    case EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS:
+      m_iso_speed_ratings = std::vector<long long int>();
+      break;
+    case EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME:
+      m_exposure_time = Rational::createInvalid();
+      break;
+    case EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM:
+      m_exposure_program = EXIF_EXPOSURE_PROGRAM_NOT_VALID;
+      break;
+    case EXIF_INFORMATION_ATTRIBUTE_FLASH:
+      m_flash = false;
+      break;
+    case EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH:
+      m_focal_length = Rational::createInvalid();
+      break;
+    case EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE:
+      m_white_balance = EXIF_WHITE_BALANCE_MODE_NOT_VALID;
+      break;
+    case EXIF_INFORMATION_ATTRIBUTE_GPS_LOCATION:
+      unsetGPSLocation();
+      break;
+    case EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE:
+      m_gps_altitude = Rational::createInvalid();
+      break;
+    case EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF:
+      m_gps_altitude_ref = GPS_ALTITUDE_REF_ABOVE_SEA;
+      break;
+    case EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD:
+      m_gps_processing_method = std::string();
+      m_gps_processing_method_type = EXIF_UNDEFINED_TYPE_ASCII;
+      break;
+    case EXIF_INFORMATION_ATTRIBUTE_GPS_TIME:
+      unsetGPStime();
+      break;
+    case EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT:
+      m_user_comment = std::string();
+      m_user_comment_type = EXIF_UNDEFINED_TYPE_ASCII;
+      break;
+    default:
+      break;
+  }
+}
+
+void ExifInformation::set(std::string attributeName, const picojson::value& v) {
+  LoggerD("Entered | name: %s", attributeName.c_str());
+
+  switch (str2int(attributeName.c_str())) {
+    case str2int(EI_URI):
+      setUri(v.get<std::string>());
+      break;
+    case str2int(EI_WIDTH):
+      setWidth(static_cast<int>(v.get<double>()));
+      break;
+    case str2int(EI_HEIGHT):
+      setHeight(static_cast<int>(v.get<double>()));
+      break;
+    case str2int(EI_DEVICE_MAKER):
+      setDeviceMaker(v.get<std::string>());
+      break;
+    case str2int(EI_DEVICE_MODEL):
+      setDeviceModel(v.get<std::string>());
+      break;
+    case str2int(EI_ORIGINAL_TIME):
+      setOriginalTime(static_cast<unsigned long long>(v.get<double>()));
+    break;
+    case str2int(EI_ORIENTATION):
+      setOrientation(v.get<std::string>());
+      break;
+    case str2int(EI_FNUMBER):
+      setFNumber(Rational::createFromDouble(v.get<double>()));
+      break;
+    case str2int(EI_ISO_SPEED_RATINGS):
+      setIsoSpeedRatings(jsonArray2vector(v));
+      break;
+    case str2int(EI_EXPOSURE_TIME):
+      setExposureTime(
+        Rational::createFromExposureTimeString(v.get<std::string>()));
+      break;
+    case str2int(EI_EXPOSURE_PROGRAM):
+      setExposureProgram(v.get<std::string>());
+      break;
+    case str2int(EI_FLASH):
+      setFlash(v.get<bool>());
+      break;
+    case str2int(EI_FOCAL_LENGTH):
+      setFocalLength(Rational::createFromDouble(v.get<double>()));
+      break;
+    case str2int(EI_WHITE_BALANCE):
+      setWhiteBalanceMode(v.get<std::string>());
+      break;
+    case str2int(EI_GPS_LOCATION):
+      setGPSLocation(ExifGPSLocation(v.get("longitude").get<double>(),
+       v.get("latitude").get<double>()));
+      break;
+    case str2int(EI_GPS_ALTITUDE):
+      setGpsAltitudeWithRef(v.get<double>());
+      break;
+    case str2int(EI_GPS_PROCESSING_METHOD):
+      setGpsProcessingMethod(EXIF_UNDEFINED_TYPE_ASCII, v.get<std::string>());
+      break;
+    case str2int(EI_GPS_TIME):
+      setGpsTime(static_cast<unsigned long long>(v.get<double>()));
+    break;
+    case str2int(EI_USER_COMMENT):
+      setUserComment(EXIF_UNDEFINED_TYPE_ASCII, v.get<std::string>());
+      break;
+    default:
+      break;
+  }
+}
+
+bool getGCSPositionFromEntry(ExifEntry *entry, ExifData* exif_data, GCSPosition& out_pos) {
+  //RATIONAL - 3
+  if (EXIF_FORMAT_RATIONAL == entry->format &&
+      entry->components >= 3 &&
+      entry->data) {
+    const ExifByteOrder order = exif_data_get_byte_order(exif_data);
+    out_pos.degrees = Rational(exif_get_rational(entry->data, order));
+    out_pos.minutes = Rational(exif_get_rational(
+        entry->data +   ExifTypeInfo::RationalSize, order));
+    out_pos.seconds = Rational(exif_get_rational(
+        entry->data + 2*ExifTypeInfo::RationalSize, order));
+    return true;
+  }
+  else {
+    return false;
+  }
+}
+
+bool getRationalsFromEntry(ExifEntry *entry, ExifData* exif_data,
+                           unsigned long required_count,
+                           Rationals& out_rationals) {
+  if (EXIF_FORMAT_RATIONAL == entry->format &&
+      entry->components >= required_count &&
+      entry->data) {
+    const ExifByteOrder order = exif_data_get_byte_order(exif_data);
+    unsigned char* ptr = entry->data;
+
+    for(unsigned long i = 0; i < required_count; ++i) {
+      out_rationals.push_back(Rational(exif_get_rational(ptr, order)));
+      ptr += ExifTypeInfo::RationalSize;
+    }
+
+    return true;
+  }
+  else {
+    return false;
+  }
+}
+
+Rational getRationalFromEntry(ExifEntry *entry, ExifData* exif_data) {
+  if (EXIF_FORMAT_RATIONAL == entry->format && entry->components >= 1 && entry->data) {
+    const ExifByteOrder order = exif_data_get_byte_order(exif_data);
+    return Rational(exif_get_rational(entry->data, order));
+  }
+  else {
+    return Rational::createInvalid();
+  }
+}
+
+bool decomposeExifUndefined(ExifEntry* entry, std::string& type, std::string& value) {
+  if(!entry || !entry->data) {
+    LoggerW("exif entry is NULL/empty");
+    return false;
+  }
+
+  if(entry->size < EXIF_UNDEFINED_TYPE_LENGTH) {
+    LoggerW("entry size is invalid %d < EXIF_UNDEFINED_TYPE_LENGTH", entry->size);
+    return false;
+  }
+
+  const char* ptr = reinterpret_cast<const char*>(entry->data);
+  type = std::string(ptr, EXIF_UNDEFINED_TYPE_LENGTH);
+  ptr += EXIF_UNDEFINED_TYPE_LENGTH;
+  value = std::string(ptr, entry->size - EXIF_UNDEFINED_TYPE_LENGTH);
+  return true;
+}
+
+void ExifInformation::processEntry(ExifEntry* entry, ExifData* exif_data) {
+  char buf[2000];
+  exif_entry_get_value(entry, buf, sizeof(buf));
+  ExifUtil::printExifEntryInfo(entry, exif_data);
+
+  const ExifIfd cur_ifd = exif_entry_get_ifd(entry);
+  if (EXIF_IFD_INTEROPERABILITY == cur_ifd || EXIF_IFD_1 == cur_ifd) {
+    return;
+  }
+
+  switch (static_cast<unsigned int>(entry->tag)) {
+    case EXIF_TAG_IMAGE_WIDTH: {
+      //SHORT or LONG - 1
+      exif_entry_get_value(entry, buf, sizeof(buf));
+      LoggerD( "Setting ExifInformation width to: [%s]", buf );
+      setWidth(atol(buf));
+      break;
+    }
+    case EXIF_TAG_IMAGE_LENGTH: {
+      //SHORT or LONG - 1
+      exif_entry_get_value(entry, buf, sizeof(buf));
+      LoggerD( "Setting ExifInformation height to: [%s]", buf );
+      setHeight(atol(buf));
+      break;
+    }
+    case EXIF_TAG_MAKE: {
+      //ASCII - Any
+      exif_entry_get_value(entry, buf, sizeof(buf));
+      LoggerD( "Setting ExifInformation maker to: [%s]", buf );
+      setDeviceMaker(std::string(buf));
+      break;
+    }
+    case EXIF_TAG_MODEL: {
+      //ASCII - Any
+      exif_entry_get_value(entry, buf, sizeof(buf));
+      LoggerD( "Setting ExifInformation model to: [%s]", buf );
+      setDeviceModel(std::string(buf));
+      break;
+    }
+    case EXIF_TAG_DATE_TIME_ORIGINAL: {
+      //ASCII - 20
+      exif_entry_get_value(entry, buf, sizeof(buf));
+      const time_t time = ExifUtil::exifDateTimeOriginalToTimeT(
+          reinterpret_cast<const char*>(entry->data));
+      LoggerD( "Setting ExifInformation time original to: [%s] time_t:%d", buf,
+          (int)time);
+      setOriginalTime(time);
+    }
+    case EXIF_TAG_ORIENTATION: {
+      //SHORT - 1
+      exif_entry_get_value(entry, buf, sizeof(buf));
+      const ExifByteOrder order = exif_data_get_byte_order(exif_data);
+      const ExifShort orient(exif_get_short(entry->data, order));
+
+      if(orient < EXIF_ORIENTATION_NORMAL || orient >= EXIF_ORIENTATION_NOT_VALID) {
+        LoggerW("Couldn't set ExifInformation - orientation is not valid: %d (%s)",
+            orient, buf);
+      }
+      else {
+        LoggerD("Setting ExifInformation orientation to: %d [%s]", orient, buf);
+        setOrientation(static_cast<ImageOrientation>(orient));
+      }
+      break;
+    }
+    case EXIF_TAG_FNUMBER:
+    {
+      //RATIONAL - 1
+      Rational fnumber = getRationalFromEntry(entry, exif_data);
+      if(fnumber.isValid()) {
+        LOGD("Setting ExifInformation fnumber to: %f (%s)", fnumber.toDouble(),
+          fnumber.toString().c_str());
+        setFNumber(fnumber);
+      }
+      else {
+        LOGW("Couldn't set ExifInformation - fnumber is not valid: %s",
+            fnumber.toString().c_str());
+      }
+      break;
+    }
+    case EXIF_TAG_ISO_SPEED_RATINGS: {
+      //SHORT - Any
+      if (EXIF_FORMAT_SHORT == entry->format &&
+          entry->components > 0 &&
+          entry->data) {
+        const ExifByteOrder order = exif_data_get_byte_order(exif_data);
+        unsigned char* read_ptr = entry->data;
+        const size_t size_per_member =
+            ExifUtil::getSizeOfExifFormatType(entry->format);
+
+        for(unsigned long i = 0; i < entry->components; ++i) {
+          ExifShort iso_rating = exif_get_short(read_ptr, order);
+
+          LoggerD("Appending ExifInformation speed ratings with: %d",
+              static_cast<int>(iso_rating));
+
+          read_ptr += size_per_member;
+        }
+      }
+      else {
+        LoggerE("iso speed ratings: format or components count is invalid!");
+      }
+      break;
+    }
+    case EXIF_TAG_EXPOSURE_TIME: {
+      //RATIONAL - 1
+      if (EXIF_FORMAT_RATIONAL == entry->format &&
+          entry->components > 0 &&
+          entry->data) {
+
+        const ExifByteOrder order = exif_data_get_byte_order(exif_data);
+        const Rational exp_time(exif_get_rational(entry->data, order));
+
+        if (exp_time.isValid()) {
+          LoggerD("Setting ExifInformation exposure time to: %s (%s)",
+              exp_time.toString().c_str(),
+              exp_time.toExposureTimeString().c_str());
+          setExposureTime(exp_time);
+        }
+        else {
+          LoggerD("Couldn't set ExifInformation - exposure time is not valid: %s",
+              exp_time.toString().c_str());
+        }
+      }
+      else {
+        LoggerE("exposure time: format or components count is invalid!");
+      }
+      break;
+    }
+    case EXIF_TAG_EXPOSURE_PROGRAM: {
+      //SHORT - 1
+      exif_entry_get_value(entry, buf, sizeof(buf));
+
+      const ExifByteOrder order = exif_data_get_byte_order(exif_data);
+      const ExifShort exp_program = exif_get_short(entry->data, order);
+      if(exp_program >= EXIF_EXPOSURE_PROGRAM_NOT_VALID) {
+        LoggerW("ExposureProgram: %d (%s) is not valid!", exp_program, buf);
+      }
+      else {
+        LoggerD("Setting ExifInformation exposure program to: %d [%s]",
+            exp_program, buf );
+        setExposureProgram(static_cast<ExposureProgram>(exp_program));
+      }
+      break;
+    }
+    case EXIF_TAG_FLASH: {
+      //SHORT - 1
+      exif_entry_get_value(entry, buf, sizeof(buf));
+
+      const ExifByteOrder order = exif_data_get_byte_order(exif_data);
+      const ExifShort flash = exif_get_short(entry->data, order);
+
+      LoggerD( "Setting ExifInformation flash to: [%s] flash=%d", buf, flash);
+      setFlash(flash != 0);
+      break;
+    }
+    case EXIF_TAG_FOCAL_LENGTH: {
+      //RATIONAL - 1
+      Rational flength = getRationalFromEntry(entry, exif_data);
+      if(flength.isValid()) {
+        LoggerD("Setting ExifInformation focal length to: %f (%s)",
+            flength.toDouble(), flength.toString().c_str());
+        setFocalLength(flength);
+      }
+      else {
+        LoggerW("Couldn't set ExifInformation - focal length is not valid: %s",
+            flength.toString().c_str());
+      }
+      break;
+    }
+    case EXIF_TAG_WHITE_BALANCE: {
+      //SHORT - 1
+      exif_entry_get_value(entry, buf, sizeof(buf));
+      LoggerD( "Setting ExifInformation white balance to: [%s]", buf );
+      if (entry->data[0]) {
+        setWhiteBalanceMode(EXIF_WHITE_BALANCE_MODE_MANUAL);
+      }
+      else {
+        setWhiteBalanceMode(EXIF_WHITE_BALANCE_MODE_AUTO);
+      }
+      break;
+    }
+    case EXIF_TAG_GPS_LONGITUDE: {
+      //RATIONAL - 3
+      GCSPosition longitude;
+      if (getGCSPositionFromEntry(entry, exif_data, longitude)) {
+        m_gps_location.setLongitude(longitude);
+        LoggerD("Setting ExifInformation gps longitude to: %s; %s; %s valid:%d",
+            longitude.degrees.toString().c_str(),
+            longitude.minutes.toString().c_str(),
+            longitude.seconds.toString().c_str(),
+            longitude.isValid());
+      }
+      else {
+        exif_entry_get_value(entry, buf, sizeof(buf));
+        LoggerW("Couldn't set longitude pos - data is not valid: [%s]", buf);
+      }
+      break;
+    }
+    case EXIF_TAG_GPS_LONGITUDE_REF: {
+      //ASCII - 2
+      if(entry->size < 1) {
+        LoggerW("Longtitude ref entry do not contain enought data!");
+        break;
+      }
+
+      const char ref = static_cast<char>(entry->data[0]);
+      if ('E' == ref || 'e' == ref) {      //East
+        m_gps_location.setLongitudeRef(GPS_LOCATION_EAST);
+        LoggerD("Setting ExifInformation gps longitude REF to: EAST");
+      }
+      else if ('W' == ref || 'w' == ref) {   //West
+        m_gps_location.setLongitudeRef(GPS_LOCATION_WEST);
+        LoggerD("Setting ExifInformation gps longitude REF to: WEST");
+      }
+      else {
+        LoggerW("Unknown longitude ref: %c (0x%x)", ref, static_cast<int>(ref));
+      }
+      break;
+    }
+    case EXIF_TAG_GPS_LATITUDE: {
+      //RATIONAL - 3
+      exif_entry_get_value(entry, buf, sizeof(buf));
+      LoggerD( "Setting ExifInformation latitude to: [%s], tag->%s",
+          buf, exif_tag_get_name(entry->tag) );
+
+      GCSPosition latitude;
+      if (getGCSPositionFromEntry(entry, exif_data, latitude)) {
+        m_gps_location.setLatitude(latitude);
+        LoggerD("Setting ExifInformation gps latitude to: %s; %s; %s valid:%d",
+            latitude.degrees.toString().c_str(),
+            latitude.minutes.toString().c_str(),
+            latitude.seconds.toString().c_str(),
+            latitude.isValid());
+      }
+      else {
+        LoggerW("Couldn't set latitude pos - data is not valid!");
+      }
+      break;
+    }
+    case EXIF_TAG_GPS_LATITUDE_REF: {
+      //ASCII - 2
+      if(entry->size < 1) {
+        LoggerW("Latitude ref entry do not contain enought data!");
+        break;
+      }
+
+      const char ref = static_cast<char>(entry->data[0]);
+      if ('N' == ref || 'n' == ref) {      //North
+        m_gps_location.setLatitudeRef(GPS_LOCATION_NORTH);
+        LoggerD("Setting ExifInformation gps latitude REF to: NORTH");
+      }
+      else if ('S' == ref || 's' == ref) {   //South
+        m_gps_location.setLatitudeRef(GPS_LOCATION_SOUTH);
+        LoggerD("Setting ExifInformation gps latitude REF to: SOUTH");
+      }
+      else {
+        LoggerW("Unknown latitude ref: %c (0x%x)", ref, static_cast<int>(ref));
+      }
+      break;
+    }
+    case EXIF_TAG_GPS_ALTITUDE: {
+      //RATIONAL - 1
+      Rational gps_altitude = getRationalFromEntry(entry, exif_data);
+      if(gps_altitude.isValid()) {
+        LoggerD("Setting ExifInformation gps altitude to: %f (%s)",
+            gps_altitude.toDouble(), gps_altitude.toString().c_str());
+        setGpsAltitude(gps_altitude);
+      }
+      else {
+        LoggerW("Couldn't set ExifInformation - gps altitude is not valid: %s",
+            gps_altitude.toString().c_str());
+      }
+      break;
+    }
+    case EXIF_TAG_GPS_ALTITUDE_REF: {
+      //BYTE - 1
+      const ExifByte altitude_ref = static_cast<ExifByte>(entry->data[0]);
+      if(static_cast<ExifByte>(GPS_ALTITUDE_REF_ABOVE_SEA) == altitude_ref ||
+          static_cast<ExifByte>(GPS_ALTITUDE_REF_BELOW_SEA) == altitude_ref) {
+        setGpsAltitudeRef(static_cast<GpsAltitudeRef>(altitude_ref));
+        LoggerD( "Setting ExifInformation gps altitude ref to: %d (%s)",
+            static_cast<int>(altitude_ref),
+            (altitude_ref > 0) ? "below sea" : "above sea");
+      } else {
+        LoggerW("GPS altitude ref is invalid:%d should be 0 or 1!",
+            static_cast<int>(altitude_ref));
+      }
+      break;
+    }
+    case EXIF_TAG_GPS_PROCESSING_METHOD: {
+      //UNDEFINED - Any
+      std::string type, value;
+      if(decomposeExifUndefined(entry, type, value)) {
+        LoggerD("Extracted GPSProcessingMethod: [%s], len:%d, type:%s",
+            value.c_str(), value.length(), type.c_str());
+        setGpsProcessingMethod(type, value);
+
+        LoggerD("Setting ExifInformation processing method to: [%s], len:%d, type:%s",
+            m_gps_processing_method.c_str(),
+            m_gps_processing_method.length(),
+            m_gps_processing_method_type.c_str());
+      }
+      else {
+        LoggerW("GPSProcessingMethod tag contains invalid values!");
+      }
+      break;
+    }
+    case EXIF_TAG_GPS_DATE_STAMP: {
+      //ASCII - 11
+      exif_entry_get_value(entry, buf, sizeof(buf));
+      LoggerD( "Setting ExifInformation gps date stamp to: [%s]", buf );
+      //m_exif_gps_time.setDate(buf);
+      break;
+    }
+    case EXIF_TAG_GPS_TIME_STAMP: {
+      //Rational - 3
+      exif_entry_get_value(entry, buf, sizeof(buf));
+      LoggerD( "Setting ExifInformation gps time stamp to: [%s]", buf);
+
+      Rationals time;
+      if (getRationalsFromEntry(entry, exif_data, 3, time)) {
+        //m_exif_gps_time.setTime(time);
+      }
+      break;
+    }
+    case EXIF_TAG_USER_COMMENT: {
+      //UNDEFINED - Any
+      std::string type, value;
+      if(decomposeExifUndefined(entry, type, value)) {
+        LoggerD("Extracted UserComment: [%s], len:%d, type:%s",
+            value.c_str(), value.length(), type.c_str());
+        setUserComment(type, value);
+
+        LoggerD("Setting ExifInformation user comment to: [%s], len:%d, type:%s",
+            m_user_comment.c_str(),
+            m_user_comment.length(),
+            m_user_comment_type.c_str());
+      }
+      else {
+        LoggerW("UserComment tag contains invalid values!");
+      }
+
+      break;
+    }
+    default:
+      LoggerD("Field of tag:%x.H [%s] is not supported, value: [%s]", entry->tag,
+          exif_tag_get_name_in_ifd(entry->tag, cur_ifd),
+          exif_entry_get_value(entry, buf, sizeof(buf)));
+  }
+}
+
+struct ExifInfoAndDataHolder {
+  ExifInformationPtr exif_info;
+  ExifData* exif_data;
+};
+
+void ExifInformation::contentForeachFunctionProxy(ExifEntry *entry, void *user_data) {
+  ExifInfoAndDataHolder* holder = static_cast<ExifInfoAndDataHolder*>(user_data);
+  if (!holder) {
+    LoggerE("holder is NULL");
+  }
+
+  if (!holder->exif_info) {
+    LoggerE("exif_info is NULL!");
+    return;
+  }
+
+  if (!holder->exif_data) {
+    LoggerE("exif_data is NULL!");
+    return;
+  }
+
+  try {
+    holder->exif_info->processEntry(entry, holder->exif_data);
+  }
+  /*catch(const BasePlatformException &err) {
+    LoggerE("processEntry thrown exception: %s : %s", err.getName().c_str(),
+          err.getMessage().c_str());
+  }*/
+  catch(...) {
+    LoggerE("Unsupported error while processing Exif entry.");
+  }
+}
+
+void ExifInformation::dataForeachFunction(ExifContent *content, void *user_data) {
+  exif_content_foreach_entry(content, contentForeachFunctionProxy, user_data);
+}
+
+
+ExifInformationPtr ExifInformation::loadFromURI(const std::string& uri) {
+  ExifInformationPtr exif_info(new ExifInformation());
+  exif_info->setUri(uri);
+
+  const std::string file_path = ExifUtil::convertUriToPath(uri);
+  ExifData* ed = exif_data_new_from_file (file_path.c_str());
+  if (!ed) {
+    LoggerE("Error reading exif from file %s", file_path.c_str());
+    LoggerE("Error reading exif from file %s", file_path.c_str());
+    //throw NotFoundException("Error reading exif from file");
+  }
+
+  LoggerD("exif_data_foreach_content START");
+
+  ExifInfoAndDataHolder holder;
+  holder.exif_info = exif_info;
+  holder.exif_data = ed;
+  exif_data_foreach_content(ed, dataForeachFunction, static_cast<void*>(&holder));
+
+  LoggerD("exif_data_foreach_content END");
+
+  exif_data_unref(ed);
+  ed = NULL;
+
+  return exif_info;
+}
+
+
+void ExifInformation::removeNulledAttributesFromExifData(ExifData* exif_data) {
+  LOGD("Entered");
+  if(!exif_data) {
+    LoggerE("exif_data is NULL");
+    throw common::UnknownException("Invalid Exif provided");
+  }
+
+  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_WIDTH)) {
+    LoggerD("Removing width");
+    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_IMAGE_WIDTH, exif_data);
+  }
+  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_HEIGHT)) {
+    LoggerD("Removing height");
+    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_IMAGE_LENGTH, exif_data);
+  }
+  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER)) {
+    LoggerD("Removing device maker");
+    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_MAKE, exif_data);
+  }
+  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_ORIENTATION)) {
+    LoggerD("Removing orientation");
+    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_ORIENTATION, exif_data);
+  }
+  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM)) {
+    LoggerD("Removing exposure program");
+    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_EXPOSURE_PROGRAM, exif_data);
+  }
+  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS)) {
+    LoggerD("Removing iso speed ratings");
+    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_ISO_SPEED_RATINGS, exif_data);
+  }
+  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE)) {
+    LoggerD("Removing white balance");
+    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_WHITE_BALANCE, exif_data);
+  }
+  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL)) {
+    LoggerD("Removing device model");
+    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_MODEL, exif_data);
+  }
+  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME)) {
+    LoggerD("Removing original time");
+    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_DATE_TIME_ORIGINAL, exif_data);
+  }
+  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME)) {
+    LoggerD("Removing exposure time");
+    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_EXPOSURE_TIME, exif_data);
+  }
+  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_FNUMBER)) {
+    LoggerD("Removing f-number");
+    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_FNUMBER, exif_data);
+  }
+  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_FLASH)) {
+    LoggerD("Removing flash");
+    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_FLASH, exif_data);
+  }
+  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH)) {
+    LoggerD("Removing focal length");
+    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_FOCAL_LENGTH, exif_data);
+  }
+  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_TIME)) {
+    LoggerD("Removing gps altitude");
+    ExifTagSaver::removeExifEntryWithTag(
+    static_cast<ExifTag>(EXIF_TAG_GPS_TIME_STAMP), exif_data);
+  }
+  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE)) {
+    LoggerD("Removing gps altitude");
+    ExifTagSaver::removeExifEntryWithTag(
+      static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE), exif_data);
+  }
+  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF)) {
+    LoggerD("Removing gps altitude ref");
+    ExifTagSaver::removeExifEntryWithTag(
+        static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE_REF), exif_data);
+  }
+  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD)) {
+    LoggerD("Removing gps processing method");
+    ExifTagSaver::removeExifEntryWithTag(
+        static_cast<ExifTag>(EXIF_TAG_GPS_PROCESSING_METHOD), exif_data);
+  }
+  if (!isSet(EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT)) {
+    LoggerD("Removing user comment");
+    ExifTagSaver::removeExifEntryWithTag(EXIF_TAG_USER_COMMENT, exif_data);
+  }
+  if (!m_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE)) {
+    LoggerD("Removing latitude");
+    ExifTagSaver::removeExifEntryWithTag(
+        static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE), exif_data);
+  }
+  if (!m_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE_REF)) {
+    LoggerD("Removing latitude ref");
+    ExifTagSaver::removeExifEntryWithTag(
+        static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE_REF), exif_data);
+  }
+  if (!m_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE)) {
+    LoggerD("Removing longitude");
+    ExifTagSaver::removeExifEntryWithTag(
+        static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE), exif_data);
+  }
+  if (!m_gps_location.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF)) {
+    LoggerD("Removing longitude ref");
+    ExifTagSaver::removeExifEntryWithTag(
+        static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE_REF), exif_data);
+  }
+}
+
+void ExifInformation::updateAttributesInExifData(ExifData* exif_data) {
+  LoggerD("Entered");
+  if(!exif_data) {
+    LoggerE("exif_data is NULL");
+    throw common::UnknownException("Invalid Exif provided");
+  }
+
+  if (isSet(EXIF_INFORMATION_ATTRIBUTE_WIDTH)) {
+    LoggerD("Saving width: %d", getWidth());
+    ExifTagSaver::saveToExif(getWidth(),
+        EXIF_TAG_IMAGE_WIDTH, exif_data);
+  }
+  if (isSet(EXIF_INFORMATION_ATTRIBUTE_HEIGHT)) {
+    LoggerD("Saving height: %d", getHeight());
+    ExifTagSaver::saveToExif(getHeight(),
+        EXIF_TAG_IMAGE_LENGTH, exif_data);
+  }
+  if (isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER)) {
+    LoggerD("Saving device maker: %s", getDeviceMaker().c_str());
+    ExifTagSaver::saveToExif(getDeviceMaker(),
+        EXIF_TAG_MAKE, exif_data);
+  }
+  if (isSet(EXIF_INFORMATION_ATTRIBUTE_ORIENTATION)) {
+    LoggerD("Saving orientation: %d", static_cast<int>(getOrientation()));
+    ExifTagSaver::saveToExif(static_cast<long int>(getOrientation()),
+        EXIF_TAG_ORIENTATION, exif_data);
+  }
+  if (isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM)) {
+    LoggerD("Saving exposure program: %d", static_cast<int>(getExposureProgram()));
+    ExifTagSaver::saveToExif(getExposureProgram(),
+        EXIF_TAG_EXPOSURE_PROGRAM, exif_data);
+  }
+  if (isSet(EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS)) {
+    std::vector<long long int> iso_ratings = getIsoSpeedRatings();
+    LoggerD("Saving iso speed ratings count:%d", iso_ratings.size());
+    ExifTagSaver::saveToExif(iso_ratings, EXIF_FORMAT_SHORT,
+       EXIF_TAG_ISO_SPEED_RATINGS, exif_data);
+  }
+  if (isSet(EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE)) {
+    LoggerD("Saving white balance: %d", static_cast<int>(getWhiteBalanceMode()));
+    ExifTagSaver::saveToExif(getWhiteBalanceMode(),
+        EXIF_TAG_WHITE_BALANCE, exif_data);
+  }
+  if (isSet(EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL)) {
+    LoggerD("Saving device model: %s", getDeviceModel().c_str());
+    ExifTagSaver::saveToExif(getDeviceModel(),
+        EXIF_TAG_MODEL, exif_data);
+  }
+  if (isSet(EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME)) {
+    const time_t o_time = getOriginalTime();
+    const std::string o_time_str = ExifUtil::timeTToExifDateTimeOriginal(o_time);
+    LoggerD("Saving original time time_t:%d, format:%s", static_cast<int>(o_time),
+        o_time_str.c_str());
+
+    ExifTagSaver::saveToExif(o_time_str,
+        EXIF_TAG_DATE_TIME_ORIGINAL, exif_data);
+  }
+  if (isSet(EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME)) {
+    Rational exposure_time = getExposureTime();
+    if (exposure_time.isValid()) {
+      LoggerD("Saving exposure time: %s (%s)",
+          exposure_time.toString().c_str(),
+          exposure_time.toExposureTimeString().c_str());
+
+      ExifTagSaver::saveToExif(exposure_time,
+          EXIF_TAG_EXPOSURE_TIME, exif_data);
+    }
+  }
+  if (isSet(EXIF_INFORMATION_ATTRIBUTE_FNUMBER)) {
+    auto f_number = getFNumber();
+    LoggerD("Saving f-number: %f (%s)", f_number.toDouble(),
+        f_number.toString().c_str());
+    ExifTagSaver::saveToExif(f_number,
+        EXIF_TAG_FNUMBER, exif_data);
+  }
+  if (isSet(EXIF_INFORMATION_ATTRIBUTE_FLASH)) {
+    LoggerD("Saving flash: %s", getFlash() ? "ON" : "OFF");
+    ExifTagSaver::saveToExif(getFlash(),
+        EXIF_TAG_FLASH, exif_data);
+  }
+  if (isSet(EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH)) {
+    auto f_length = getFocalLength();
+    LoggerD("Saving focal length:%f (%s)", f_length.toDouble(),
+        f_length.toString().c_str());
+    ExifTagSaver::saveToExif(f_length,
+        EXIF_TAG_FOCAL_LENGTH, exif_data);
+  }
+  if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_LOCATION)) {
+    LoggerD("Saving gps location");
+    ExifTagSaver::saveGpsLocationToExif(m_gps_location, exif_data);
+  }
+  if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE)) {
+    LoggerD("Saving gps altitude:%f (%s)", m_gps_altitude.toDouble(),
+         m_gps_altitude.toString().c_str());
+    ExifTagSaver::saveToExif(m_gps_altitude,
+        static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE), exif_data);
+  }
+  if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF)) {
+    //Exif spec:
+    //0 = Sea level
+    //1 = Sea level reference (negative value)
+    LoggerD("Saving gps altitude ref:%d (%s)",
+        static_cast<int>(m_gps_altitude_ref),
+        (static_cast<int>(m_gps_altitude_ref) > 0) ? "below sea" : "above sea");
+    std::vector<long long int> value = {
+      static_cast<long long int>(m_gps_altitude_ref)
+    };
+    ExifTagSaver::saveToExif(value, EXIF_FORMAT_BYTE,
+        static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE_REF), exif_data);
+  }
+  if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD)) {
+    LoggerD("Saving gps processing method: [%s] type:%s",
+        getGpsProcessingMethod().c_str(), getGpsProcessingMethodType().c_str());
+
+    const std::string joined = getGpsProcessingMethodType() + getGpsProcessingMethod();
+    LoggerD("joined: [%s]", joined.c_str());
+
+    ExifTagSaver::saveToExif(joined,
+        static_cast<ExifTag>(EXIF_TAG_GPS_PROCESSING_METHOD), exif_data,
+        EXIF_FORMAT_UNDEFINED, false);
+  }
+  if (isSet(EXIF_INFORMATION_ATTRIBUTE_GPS_TIME)) {
+    const time_t gps_time = getGpsTime();
+    const Rationals gps_time_vec = ExifUtil::timeTToExifGpsTimeStamp(gps_time);
+    const std::string gps_date_str =
+      ExifUtil::timeTToExifGpsDateStamp(gps_time);
+    LoggerD("Saving gps time stamp time_t: %d", static_cast<int>(gps_time));
+
+    ExifTagSaver::saveToExif(gps_time_vec,
+      static_cast<ExifTag>(EXIF_TAG_GPS_TIME_STAMP), exif_data);
+
+    LoggerD("Saving gps date stamp: %s", gps_date_str.c_str());
+
+    ExifTagSaver::saveToExif(gps_date_str,
+      static_cast<ExifTag>(EXIF_TAG_GPS_DATE_STAMP), exif_data, EXIF_FORMAT_ASCII, false);
+  }
+  if (isSet(EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT)) {
+    LoggerD("Saving user comment: %s (type:%s)", getUserComment().c_str(),
+      getUserCommentType().c_str());
+
+    const std::string joined = getUserCommentType() + getUserComment();
+    LoggerD("joined: [%s]", joined.c_str());
+
+    ExifTagSaver::saveToExif(joined,
+        EXIF_TAG_USER_COMMENT, exif_data, EXIF_FORMAT_UNDEFINED, false);
+  }
+}
+
+void ExifInformation::saveToFile(const std::string& file_path) {
+  LoggerD("Entered");
+  LoggerD("Using JpegFile to read: [%s] and Exif if present", file_path.c_str());
+
+  bool exif_data_is_new = false;
+  JpegFilePtr jpg_file = JpegFile::loadFile(file_path);
+  ExifData* exif_data = jpg_file->getExifData();
+
+  //Exif is not present in file - create new ExifData
+  if (!exif_data) {
+    LoggerD("Exif is not present in file: [%s] creating new", file_path.c_str());
+
+    exif_data = exif_data_new();
+    exif_data_set_option(exif_data, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
+    exif_data_set_data_type(exif_data, EXIF_DATA_TYPE_COMPRESSED);
+    exif_data_set_byte_order(exif_data, EXIF_BYTE_ORDER_MOTOROLA);
+    exif_data_is_new = true;
+  }
+
+  if (!exif_data) {
+    LoggerE("Couldn't allocate new ExifData");
+    throw common::UnknownException("Memory allocation failed");
+  }
+
+  LoggerD("Exif data type: %d", exif_data_get_data_type(exif_data) );
+  LoggerD("Exif byte order: %d", exif_data_get_byte_order(exif_data) );
+  exif_data_set_option(exif_data, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
+
+  try {
+    //If we have created new ExifData there is nothing to remove
+    if(!exif_data_is_new) {
+      //Remove attributes that have been nulled
+      removeNulledAttributesFromExifData(exif_data);
+    }
+
+    updateAttributesInExifData(exif_data);
+
+    LOGD("Using JpegFile to save new Exif in: [%s]", file_path.c_str());
+    if(exif_data_is_new) {
+      jpg_file->setNewExifData(exif_data);
+    }
+
+    jpg_file->saveToFile(file_path);
+  }
+  catch (...) {
+    exif_data_unref(exif_data);
+    exif_data = NULL;
+    throw;
+  }
+
+  exif_data_unref(exif_data);
+  exif_data = NULL;
+}
+
+}  // namespace exif
+}  // namespace extension
diff --git a/src/exif/exif_information.h b/src/exif/exif_information.h
new file mode 100644 (file)
index 0000000..e5c74f2
--- /dev/null
@@ -0,0 +1,256 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef EXIF_EXIF_EXIFINFORMATION_H_
+#define EXIF_EXIF_EXIFINFORMATION_H_
+
+#include <libexif/exif-loader.h>
+#include <string>
+#include <vector>
+#include <map>
+
+#include "ExifGPSLocation.h"
+#include "common/picojson.h"
+
+namespace extension {
+namespace exif {
+
+#define EI_URI "uri"
+#define EI_WIDTH "width"
+#define EI_HEIGHT "height"
+#define EI_DEVICE_MAKER "deviceMaker"
+#define EI_DEVICE_MODEL "deviceModel"
+#define EI_ORIGINAL_TIME "originalTime"
+#define EI_ORIENTATION "orientation"
+#define EI_FNUMBER "fNumber"
+#define EI_ISO_SPEED_RATINGS "isoSpeedRatings"
+#define EI_EXPOSURE_TIME "exposureTime"
+#define EI_EXPOSURE_PROGRAM "exposureProgram"
+#define EI_FLASH "flash"
+#define EI_FOCAL_LENGTH "focalLength"
+#define EI_WHITE_BALANCE "whiteBalance"
+#define EI_GPS_LOCATION "gpsLocation"
+#define EI_GPS_ALTITUDE "gpsAltitude"
+#define EI_GPS_PROCESSING_METHOD "gpsProcessingMethod"
+#define EI_GPS_TIME "gpsTime"
+#define EI_USER_COMMENT "userComment"
+
+class ExifInformation;
+typedef std::shared_ptr<ExifInformation> ExifInformationPtr;
+typedef std::map<std::string, std::string> AttributeMap;
+typedef std::vector<long long int> IsoSpeedRatingsVector;
+
+extern const size_t EXIF_UNDEFINED_TYPE_LENGTH;
+extern const std::string EXIF_UNDEFINED_TYPE_ASCII;
+extern const std::string EXIF_UNDEFINED_TYPE_JIS;
+extern const std::string EXIF_UNDEFINED_TYPE_UNICODE;
+extern const std::string EXIF_UNDEFINED_TYPE_UNDEFINED;
+
+enum ExifInformationAttribute{
+  EXIF_INFORMATION_ATTRIBUTE_URI,
+  EXIF_INFORMATION_ATTRIBUTE_WIDTH,
+  EXIF_INFORMATION_ATTRIBUTE_HEIGHT,
+  EXIF_INFORMATION_ATTRIBUTE_DEVICE_MAKER,
+  EXIF_INFORMATION_ATTRIBUTE_DEVICE_MODEL,
+  EXIF_INFORMATION_ATTRIBUTE_ORIGINAL_TIME,
+  EXIF_INFORMATION_ATTRIBUTE_ORIENTATION,
+  EXIF_INFORMATION_ATTRIBUTE_FNUMBER,
+  EXIF_INFORMATION_ATTRIBUTE_ISO_SPEED_RATINGS,
+  EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_TIME,
+  EXIF_INFORMATION_ATTRIBUTE_EXPOSURE_PROGRAM,
+  EXIF_INFORMATION_ATTRIBUTE_FLASH,
+  EXIF_INFORMATION_ATTRIBUTE_FOCAL_LENGTH,
+  EXIF_INFORMATION_ATTRIBUTE_WHITE_BALANCE,
+  EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE,
+  EXIF_INFORMATION_ATTRIBUTE_GPS_ALTITUDE_REF,
+  EXIF_INFORMATION_ATTRIBUTE_GPS_LOCATION,
+  EXIF_INFORMATION_ATTRIBUTE_GPS_PROCESSING_METHOD,
+  EXIF_INFORMATION_ATTRIBUTE_GPS_TIME,
+  EXIF_INFORMATION_ATTRIBUTE_USER_COMMENT,
+  EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES
+};
+
+enum GpsAltitudeRef {
+  GPS_ALTITUDE_REF_ABOVE_SEA = 0,
+  GPS_ALTITUDE_REF_BELOW_SEA = 1
+};
+
+const AttributeMap ExifInformationAttributeMap = {
+  {"uri", "uri"},
+  {"width", "width"},
+  {"height", "height"},
+  {"deviceMaker", "deviceMaker"},
+  {"deviceModel", "deviceModel"},
+  {"originalTime", "originalTime"},
+  {"orientation", "orientation"},
+  {"fNumber", "fNumber"},
+  {"isoSpeedRatings", "isoSpeedRatings"},
+  {"exposureTime", "exposureTime"},
+  {"exposureProgram", "exposureProgram"},
+  {"flash", "flash"},
+  {"focalLength", "focalLength"},
+  {"whiteBalance", "whiteBalance"},
+  {"gpsLocation", "gpsLocation"},
+  {"gpsAltitude", "gpsAltitude"},
+  {"gpsProcessingMethod", "gpsProcessingMethod"},
+  {"gpsTime", "gpsTime"},
+  {"userComment", "userComment"}
+};
+
+class ExifInformation {
+ public:
+  ExifInformation();
+  explicit ExifInformation(const picojson::value& args);
+  ~ExifInformation();
+
+  static ExifInformationPtr loadFromURI(const std::string& uri);
+  void saveToFile(const std::string& file_path);
+
+  const std::string& getUri();
+  void setUri(const std::string& uri);
+
+  unsigned long getWidth() const;
+  void setWidth(unsigned long width);
+
+  unsigned long getHeight() const;
+  void setHeight(unsigned long height);
+
+  const std::string& getDeviceMaker();
+  void setDeviceMaker(const std::string& device_maker);
+
+  const std::string& getDeviceModel();
+  void setDeviceModel(const std::string& device_model);
+
+  time_t getOriginalTime() const;
+  void setOriginalTime(time_t original_time);
+
+  const std::string& getOrientationString();
+  ImageOrientation getOrientation();
+  void setOrientation(const std::string& orientation);
+  void setOrientation(ImageOrientation orientation);
+
+  const Rational& getFNumber() const;
+  void setFNumber(Rational f_number);
+
+  const std::vector<long long int>& getIsoSpeedRatings();
+  void setIsoSpeedRatings(const std::vector<long long int>& iso_speed_ratings);
+
+  const Rational& getExposureTime();
+  void setExposureTime(const Rational& exposure_time);
+
+  const std::string& getExposureProgramString();
+  ExposureProgram getExposureProgram();
+  void setExposureProgram(const std::string& exposure_program);
+  void setExposureProgram(ExposureProgram exposure_program);
+
+  bool getFlash() const;
+  void setFlash(bool flash);
+
+  const Rational& getFocalLength() const;
+  void setFocalLength(Rational focal_length);
+
+  const std::string& getWhiteBalanceModeString();
+  WhiteBalanceMode getWhiteBalanceMode();
+  void setWhiteBalanceMode(const std::string& white_balance);
+  void setWhiteBalanceMode(WhiteBalanceMode white_balance);
+
+  ExifGPSLocation& getGPSExifLocation();
+  void setGPSLocation(ExifGPSLocation gps_location);
+  void unsetGPSLocation();
+
+  const Rational& getGpsAltitude() const;
+  void setGpsAltitude(Rational gps_altitude);
+
+  GpsAltitudeRef getGpsAltitudeRef() const;
+  void setGpsAltitudeRef(const GpsAltitudeRef ref);
+
+  /**
+   * gps_altitude can be negative and positive:
+   * if gps_altitude < 0.0 GPS_ALTITUDE_REF_BELOW_SEA is set
+   * if gps_altitude >= 0.0 GPS_ALTITUDE_REF_ABOVE_SEA is set
+   */
+  void setGpsAltitudeWithRef(double gps_altitude);
+
+  /**
+   * Return gps altitude which can be negative (below sea level) and positive (above sea
+   * level)
+   */
+  double getGpsAltitudeWithRef() const;
+
+  const std::string& getGpsProcessingMethod() const;
+  const std::string& getGpsProcessingMethodType() const;
+  void setGpsProcessingMethod(const std::string& type,
+      const std::string& processing_method);
+
+  void setGpsTime(time_t time);
+  time_t getGpsTime();
+  void unsetGPStime();
+
+  const std::string& getUserComment();
+  const std::string& getUserCommentType();
+  void setUserComment(const std::string& type,
+      const std::string& user_comment);
+
+  bool isSet(ExifInformationAttribute attribute) const;
+  void unset(ExifInformationAttribute attribute);
+  void set(std::string attributeName, const picojson::value& args);
+
+ private:
+  void processEntry(ExifEntry* entry, ExifData* exif_data);
+  static void contentForeachFunctionProxy(ExifEntry* entry, void* user_data);
+  static void dataForeachFunction(ExifContent* content, void* user_data);
+
+  void removeNulledAttributesFromExifData(ExifData* exif_data);
+  void updateAttributesInExifData(ExifData* exif_data);
+
+  std::string m_uri;
+  unsigned long m_width;
+  unsigned long m_height;
+  std::string m_device_maker;
+  std::string m_device_model;
+
+  time_t m_original_time;
+
+  ImageOrientation m_orientation;
+  Rational m_f_number;
+  std::vector<long long int> m_iso_speed_ratings;
+  Rational m_exposure_time;
+  ExposureProgram m_exposure_program;
+  bool m_flash;
+  Rational m_focal_length;
+  WhiteBalanceMode m_white_balance;
+
+  ExifGPSLocation m_gps_location;
+
+  Rational m_gps_altitude;
+  GpsAltitudeRef m_gps_altitude_ref;
+
+  std::string m_gps_processing_method;
+  std::string m_gps_processing_method_type;
+
+  time_t m_gps_time;
+
+  std::string m_user_comment;
+  std::string m_user_comment_type;
+
+  bool m_is_set[EXIF_INFORMATION_ATTRIBUTE_NUMBER_OF_ATTRIBUTES];
+};
+
+}  // namespace exif
+}  // namespace extension
+
+#endif  // EXIF_EXIF_EXIFINFORMATION_H_
index f996bd8228813ea2ca452b708ec6204eaac5d36a..b6878c0d6e5483b7cbd2d46a7d3432b3d61b010f 100644 (file)
@@ -4,20 +4,20 @@
 
 #include "exif/exif_instance.h"
 
-#include "common/task-queue.h"
-#include "common/logger.h"
-
-#include <string>
-#include <sstream>
-
 #include <libexif/exif-data.h>
 #include <libexif/exif-entry.h>
 #include <libexif/exif-utils.h>
 #include <libexif/exif-loader.h>
 
-#include "ExifUtil.h"
-#include "JpegFile.h"
-#include "ExifInformation.h"
+#include <string>
+#include <sstream>
+
+#include "common/task-queue.h"
+#include "common/logger.h"
+
+#include "exif_util.h"
+#include "jpeg_file.h"
+#include "exif_information.h"
 
 namespace extension {
 namespace exif {
@@ -46,7 +46,8 @@ ExifInstance::ExifInstance() {
 
 ExifInstance::~ExifInstance() { }
 
-void ExifInstance::getExifInfo(const picojson::value& args, picojson::object& out) {
+void ExifInstance::getExifInfo(const picojson::value& args,
+                               picojson::object& out) {
   LoggerD("ExifInstance::getExifInfo() in c++ A");
 
   const std::string& uri = args.get("uri").get<std::string>();
@@ -61,9 +62,9 @@ void ExifInstance::getExifInfo(const picojson::value& args, picojson::object& ou
 
       LoggerD("ExifInformation::loadFromURI... %s", file_path.c_str());
       ExifInformationPtr exif_info = ExifInformation::loadFromURI(uri);
-      if (!exif_info)
-      {
-          LoggerE("ExifInformation::loadFromURI failed for %s", file_path.c_str());
+      if (!exif_info) {
+        LoggerE("ExifInformation::loadFromURI failed for %s",
+            file_path.c_str());
       }
 
       unsigned long width = exif_info->getWidth();
@@ -78,9 +79,6 @@ void ExifInstance::getExifInfo(const picojson::value& args, picojson::object& ou
       LoggerD("original_time = %s", asctime(localtime(&original_time)));
       //...
 
-
-
-
       /* todo: all fields that need to be implemented:
       DOMString uri;
       unsigned long width;
@@ -103,8 +101,6 @@ void ExifInstance::getExifInfo(const picojson::value& args, picojson::object& ou
       DOMString userComment;
 */
 
-
-
       JsonValue result = JsonValue(JsonObject());
       JsonObject& result_obj = result.get<JsonObject>();
       std::ostringstream ss_width;
@@ -116,7 +112,8 @@ void ExifInstance::getExifInfo(const picojson::value& args, picojson::object& ou
       result_obj.insert(std::make_pair("device_maker", device_maker.c_str()));
       result_obj.insert(std::make_pair("device_model", device_model.c_str()));
       // todo: convert to js type: Date
-      result_obj.insert(std::make_pair("original_time", asctime(localtime(&original_time))));
+      result_obj.insert(std::make_pair("original_time",
+          asctime(localtime(&original_time))));
 
       // todo: implement remaining fields
 
@@ -141,11 +138,39 @@ void ExifInstance::getExifInfo(const picojson::value& args, picojson::object& ou
   LoggerD("ExifInstance::getExifInfo() END (c++)");
 }
 
-void ExifInstance::saveExifInfo(const picojson::value& args, picojson::object& out) {
-  LoggerE("saveExifInfo is not implemented (c++)");
+void ExifInstance::saveExifInfo(const picojson::value& args,
+    picojson::object& out) {
+  const std::string& uri = args.get("uri").get<std::string>();
+
+  const double callback_id = args.get("callbackId").get<double>();
+  auto get = [=](const std::shared_ptr<JsonValue>& response) -> void {
+    try {
+      ExifInformationPtr exifInfo(new ExifInformation(args));
+      std::string uri = exifInfo->getUri();
+      std::string path = ExifUtil::convertUriToPath(uri);
+      exifInfo->saveToFile(path);
+
+      ReportSuccess(args, response->get<picojson::object>());
+    } catch (const common::PlatformException& e) {
+      ReportError(e, response->get<picojson::object>());
+    }
+  };
+
+  auto get_response =
+  [callback_id, this](const std::shared_ptr<JsonValue>& response) -> void {
+    picojson::object& obj = response->get<picojson::object>();
+    obj.insert(std::make_pair("callbackId", callback_id));
+    LoggerD("callback is %s", response->serialize().c_str());
+    PostMessage(response->serialize().c_str());
+  };
+
+  common::TaskQueue::GetInstance().Queue<JsonValue>(
+      get, get_response,
+      std::shared_ptr<JsonValue>(new JsonValue(JsonObject())));
 }
 
-void ExifInstance::getThumbnail(const picojson::value& args, picojson::object& out) {
+void ExifInstance::getThumbnail(const picojson::value& args,
+    picojson::object& out) {
   LoggerE("getThumbnail is not implemented (c++)");
 }
 
diff --git a/src/exif/exif_tag_saver.cc b/src/exif/exif_tag_saver.cc
new file mode 100644 (file)
index 0000000..9f9a1db
--- /dev/null
@@ -0,0 +1,387 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "exif_tag_saver.h"
+
+#include <libexif/exif-format.h>
+#include <sstream>
+#include <cstring>
+
+#include "common/platform_exception.h"
+#include "common/logger.h"
+
+#include "exif_util.h"
+
+namespace extension {
+namespace exif {
+
+void ExifTagSaver::removeExifEntryWithTag(const ExifTag tag, ExifData* exif_data) {
+  LoggerD("Entered tag:%d (0x%x)", tag, tag);
+  ExifEntry* exif_entry = exif_data_get_entry(exif_data, tag);
+  if (!exif_entry) {
+    LoggerE("Exif entry with tag:%d (0x%x) is not present", tag, tag);
+    return;
+  }
+
+  exif_content_remove_entry(exif_entry->parent, exif_entry);
+}
+
+void ExifTagSaver::saveToExif(long int value, ExifTag tag, ExifData* exif_data) {
+  ExifEntry* entry = prepareEntry(exif_data, tag);
+  ExifByteOrder order = exif_data_get_byte_order(exif_data);
+
+  LoggerD("entry->format: %d", entry->format);
+  LoggerD("EXIF_FORMAT_BYTE: %d", EXIF_FORMAT_BYTE);
+
+  switch (entry->format) {
+    case EXIF_FORMAT_BYTE:
+      entry->data[0] = static_cast<unsigned char>(value);
+      break;
+    case EXIF_FORMAT_SHORT:
+      exif_set_short (entry->data, order, value);
+      break;
+    case EXIF_FORMAT_LONG:
+      exif_set_long (entry->data, order, value);
+      break;
+    case EXIF_FORMAT_SLONG:
+      exif_set_slong (entry->data, order, value);
+      break;
+    default:
+      LoggerE("Error: wrong format: %d \n", entry->format );
+  }
+}
+
+void ExifTagSaver::saveToExif(const std::string& value, ExifTag tag,
+                              ExifData* exif_data, ExifFormat format,
+                              bool add_zero_character) {
+  ExifEntry* entry = prepareEntry(exif_data, tag);
+  if (!value.empty()) {
+
+    if (entry->data) {
+      free(entry->data);
+      entry->data = NULL;
+    }
+
+    size_t new_len = value.length();
+    if (add_zero_character) {
+      ++new_len;
+    }
+
+    entry->format = format;
+    entry->size = new_len;
+    entry->components = new_len;
+
+    entry->data = static_cast<unsigned char*>(malloc(entry->size));
+    memcpy(entry->data, value.c_str(), value.length());
+    if (add_zero_character) {
+      entry->data[value.length()] = '\0';
+    }
+  }
+}
+
+void ExifTagSaver::saveToExif(const Rational& value, ExifTag tag, ExifData* exif_data) {
+  ExifEntry* entry = prepareEntry(exif_data, tag);
+  entry->format = EXIF_FORMAT_RATIONAL;
+
+  if (ExifTypeInfo::RationalSize != entry->size) {
+    if (entry->data) {
+      free(entry->data);
+      entry->data = NULL;
+    }
+
+    entry->size = ExifTypeInfo::RationalSize;
+    entry->data = static_cast<unsigned char*>(malloc(entry->size));
+    memset(entry->data, 0, entry->size);
+  }
+
+  entry->components = 1;
+
+  ExifByteOrder order = exif_data_get_byte_order(exif_data);
+  ExifRational r;
+  r.numerator = value.nominator;
+  r.denominator = value.denominator;
+  exif_set_rational(entry->data, order, r);
+}
+
+void ExifTagSaver::saveToExif(const Rationals& value, ExifTag tag, ExifData* exif_data) {
+  ExifEntry* entry = prepareEntry(exif_data, tag);
+  ExifByteOrder order = exif_data_get_byte_order(exif_data);
+  entry->format = EXIF_FORMAT_RATIONAL;
+
+  const unsigned int required_size = ExifTypeInfo::RationalSize * value.size();
+  if (required_size != entry->size) {
+    if (entry->data) {
+      free(entry->data);
+      entry->data = NULL;
+    }
+
+    entry->size = required_size;
+    entry->data = static_cast<unsigned char*>(malloc(entry->size));
+    memset(entry->data, 0, entry->size);
+  }
+
+  entry->components = value.size();
+  for (size_t i = 0; i < value.size(); ++i)
+  {
+    ExifRational r;
+    r.numerator = value[i].nominator;
+    r.denominator = value[i].denominator;
+    exif_set_rational(entry->data + i * ExifTypeInfo::RationalSize, order, r);
+  }
+}
+
+void ExifTagSaver::saveToExif(std::vector<long long int>& value, ExifFormat store_as,
+      ExifTag tag, ExifData* exif_data) {
+  ExifEntry* entry = prepareEntry(exif_data, tag);
+  const ExifByteOrder order = exif_data_get_byte_order(exif_data);
+
+  const size_t size_per_member = ExifUtil::getSizeOfExifFormatType(store_as);
+  switch (store_as) {
+    case EXIF_FORMAT_BYTE:
+    case EXIF_FORMAT_SHORT:
+    case EXIF_FORMAT_SSHORT:
+    case EXIF_FORMAT_LONG:
+    case EXIF_FORMAT_SLONG:
+      break;
+    default:
+      LoggerE("output ExifFormat: %d is not supported!");
+      return;
+  }
+  entry->format = store_as;
+
+  const size_t num_elements = value.size();
+  const unsigned int required_size = size_per_member * num_elements;
+  if (required_size != entry->size) {
+    if (entry->data) {
+      free(entry->data);
+      entry->data = NULL;
+    }
+
+    entry->size = required_size;
+    entry->data = static_cast<unsigned char*>(malloc(entry->size));
+    memset(entry->data, 0, entry->size);
+  }
+  entry->components = num_elements;
+
+
+  switch (store_as) {
+    case EXIF_FORMAT_BYTE: {
+      for(size_t i = 0; i < num_elements; ++i) {
+        entry->data[i] = static_cast<ExifByte>(value[i]);
+      }
+      break;
+    }
+
+    case EXIF_FORMAT_SHORT: {
+      for (size_t i = 0; i < num_elements; ++i) {
+        exif_set_short(entry->data + i * size_per_member, order,
+            static_cast<ExifShort>(value[i]));
+      }
+      break;
+    }
+
+    case EXIF_FORMAT_SSHORT: {
+      for (size_t i = 0; i < num_elements; ++i) {
+        exif_set_sshort(entry->data + i * size_per_member, order,
+            static_cast<ExifSShort>(value[i]));
+      }
+      break;
+    }
+
+    case EXIF_FORMAT_LONG: {
+      for (size_t i = 0; i < num_elements; ++i) {
+        exif_set_long(entry->data + i * size_per_member, order,
+            static_cast<ExifLong>(value[i]));
+      }
+      break;
+    }
+
+    case EXIF_FORMAT_SLONG: {
+      for(size_t i = 0; i < num_elements; ++i) {
+        exif_set_slong(entry->data + i * size_per_member, order,
+            static_cast<ExifSLong>(value[i]));
+      }
+      break;
+    }
+
+    default:
+      break;
+  }
+
+
+  LoggerD("entry after save:");
+  ExifUtil::printExifEntryInfo(entry, exif_data);
+}
+
+void ExifTagSaver::saveGpsLocationToExif(const ExifGPSLocation& gps_info,
+    ExifData* exif_data) {
+  if (gps_info.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE)) {
+    auto latitude = gps_info.getLatitude();
+    LoggerD("Saving latitude: %s", latitude.toDebugString().c_str());
+    saveToExif(latitude.toRationalsVector(),
+        static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE), exif_data);
+  }
+
+  if (gps_info.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LATITUDE_REF)) {
+    std::string lat_ref =
+        (gps_info.getLatitudeRef() == GPS_LOCATION_NORTH) ? "N" : "S";
+    LoggerD("Saving latitude ref: %s", lat_ref.c_str());
+    saveToExif(lat_ref, static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE_REF),
+               exif_data, EXIF_FORMAT_ASCII, false);
+  }
+
+  if (gps_info.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE)) {
+
+    auto longitude = gps_info.getLongitude();
+    LoggerD("Saving longitude: %s", longitude.toDebugString().c_str());
+    saveToExif(longitude.toRationalsVector(),
+        static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE), exif_data);
+  }
+
+  if (gps_info.isSet(EXIF_GPS_LOCATION_ATTRIBUTE_LONGITUDE_REF)) {
+    std::string long_ref =
+        (gps_info.getLongitudeRef() == GPS_LOCATION_WEST) ? "W" : "E";
+    LoggerD("Saving longitude ref: %s", long_ref.c_str());
+    saveToExif(long_ref, static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE_REF),
+               exif_data, EXIF_FORMAT_ASCII, false);
+  }
+}
+
+ExifEntry* ExifTagSaver::prepareEntry(ExifData* exif_data, ExifTag tag) {
+  LoggerD("Entered m_tag:%d", tag);
+
+  ExifEntry* exif_entry = exif_data_get_entry(exif_data, tag);
+  if (!exif_entry) {
+    exif_entry = createNewTag(exif_data, deduceIfdSection(tag),
+        deduceDataFormat(tag), tag );
+  }
+
+  if (!exif_entry) {
+    LoggerE("Couldn't create new Exif tag");
+    //throw UnknownException("Could not save Exif to file");
+  }
+
+  exif_entry_initialize(exif_entry, tag);
+
+  return exif_entry;
+}
+
+ExifEntry* ExifTagSaver::createNewTag(ExifData* exif_data, ExifIfd ifd,
+    ExifFormat format, ExifTag tag) {
+  LoggerD("Creating new tag: %d", tag);
+
+  ExifEntry* new_entry = exif_entry_new();
+  new_entry->tag = tag;
+  new_entry->format = format;
+  exif_content_add_entry(exif_data->ifd[ifd], new_entry);
+  exif_entry_initialize(new_entry, tag);
+  return new_entry;
+}
+
+ExifIfd ExifTagSaver::deduceIfdSection(ExifTag tag) {
+  switch (static_cast<unsigned int>(tag)) {
+    //Tags in IFD_0 Section
+    case EXIF_TAG_MAKE:
+    case EXIF_TAG_MODEL:
+    case EXIF_TAG_IMAGE_WIDTH:
+    case EXIF_TAG_IMAGE_LENGTH:
+    case EXIF_TAG_ORIENTATION:
+      return EXIF_IFD_0;
+
+    //Tags in IFD_EXIF Section
+    case EXIF_TAG_USER_COMMENT:
+    case EXIF_TAG_DATE_TIME_ORIGINAL:
+    case EXIF_TAG_EXPOSURE_TIME:
+    case EXIF_TAG_FNUMBER:
+    case EXIF_TAG_EXPOSURE_PROGRAM:
+    case EXIF_TAG_ISO_SPEED_RATINGS:
+    case EXIF_TAG_WHITE_BALANCE:
+    case EXIF_TAG_FLASH:
+    case EXIF_TAG_FOCAL_LENGTH:
+      return EXIF_IFD_EXIF;
+
+    //Tags in IFD_GPS Section
+    case EXIF_TAG_GPS_LATITUDE_REF:
+    case EXIF_TAG_GPS_LONGITUDE_REF:
+    case EXIF_TAG_GPS_LATITUDE:
+    case EXIF_TAG_GPS_LONGITUDE:
+    case EXIF_TAG_GPS_ALTITUDE:
+    case EXIF_TAG_GPS_ALTITUDE_REF:
+    case EXIF_TAG_GPS_TIME_STAMP:
+    case EXIF_TAG_GPS_PROCESSING_METHOD:
+    case EXIF_TAG_GPS_DATE_STAMP:
+      return EXIF_IFD_GPS;
+
+    //Tags in other sections
+    default:
+      LoggerE("Unsupported tag: %d", tag);
+      //throw UnknownException("Unsupported tag");
+  }
+}
+
+ExifFormat ExifTagSaver::deduceDataFormat(ExifTag tag) {
+  switch (static_cast<unsigned int>(tag)) {
+    //Tags with byte type:
+    case EXIF_TAG_GPS_ALTITUDE_REF:
+      return EXIF_FORMAT_BYTE;
+
+    //Tags with long type:
+    case EXIF_TAG_IMAGE_WIDTH:
+    case EXIF_TAG_IMAGE_LENGTH:
+      return EXIF_FORMAT_LONG;
+
+    //Tags with short type:
+    case EXIF_TAG_ORIENTATION:
+    case EXIF_TAG_EXPOSURE_PROGRAM:
+    case EXIF_TAG_WHITE_BALANCE:
+    case EXIF_TAG_FLASH:
+      return EXIF_FORMAT_SHORT;
+
+    //Tags with ASCII type:
+    case EXIF_TAG_MAKE:
+    case EXIF_TAG_MODEL:
+    case EXIF_TAG_DATE_TIME_ORIGINAL:
+    case EXIF_TAG_GPS_LATITUDE_REF:
+    case EXIF_TAG_GPS_LONGITUDE_REF:
+    case EXIF_TAG_GPS_DATE_STAMP:
+      return EXIF_FORMAT_ASCII;
+
+    //Tags with rational type:
+    case EXIF_TAG_EXPOSURE_TIME:
+    case EXIF_TAG_FNUMBER:
+    case EXIF_TAG_FOCAL_LENGTH:
+    case EXIF_TAG_GPS_LATITUDE:
+    case EXIF_TAG_GPS_LONGITUDE:
+    case EXIF_TAG_GPS_ALTITUDE:
+    case EXIF_TAG_GPS_TIME_STAMP:
+    case EXIF_TAG_ISO_SPEED_RATINGS:
+      return EXIF_FORMAT_RATIONAL;
+
+    //Tags with undefined type:
+    case EXIF_TAG_USER_COMMENT:
+    case EXIF_TAG_GPS_PROCESSING_METHOD:
+      return EXIF_FORMAT_UNDEFINED;
+
+    //Unsupported tags:
+    default:
+      LoggerE("Unsupported tag: %d", tag);
+      //throw UnknownException("Unsupported tag");
+  }
+}
+
+}  // namespace exif
+}  // namespace extension
diff --git a/src/exif/exif_tag_saver.h b/src/exif/exif_tag_saver.h
new file mode 100644 (file)
index 0000000..692f1c3
--- /dev/null
@@ -0,0 +1,66 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+/**
+ * @file  exif_tag_saver.h
+ */
+
+#ifndef EXIF_EXIF_TAG_SAVER_H__
+#define EXIF_EXIF_TAG_SAVER_H__
+
+#include <libexif/exif-data.h>
+
+#include <string>
+#include <vector>
+
+#include "ExifGPSLocation.h"
+
+namespace extension {
+namespace exif {
+
+class ExifTagSaver {
+ public:
+  static void removeExifEntryWithTag(const ExifTag tag, ExifData* exif_data);
+
+  static void saveToExif(long int value,
+                         ExifTag tag,
+                         ExifData* exif_data);
+  static void saveToExif(const std::string& value, ExifTag tag,
+                         ExifData* exif_data,
+                         ExifFormat format = EXIF_FORMAT_ASCII,
+                         bool add_zero_character = true);
+  static void saveToExif(const Rational& value, ExifTag tag,
+                         ExifData* exif_data);
+  static void saveToExif(const Rationals& value, ExifTag tag,
+                         ExifData* exif_data);
+  static void saveToExif(std::vector<long long int>& value, ExifFormat store_as,
+      ExifTag tag, ExifData* exif_data);
+  static void saveGpsLocationToExif(const ExifGPSLocation& gps_info,
+      ExifData* exif_data);
+
+ private:
+  static ExifEntry* prepareEntry(ExifData* exif_data, ExifTag tag);
+  static ExifIfd deduceIfdSection(ExifTag tag);
+  static ExifFormat deduceDataFormat(ExifTag tag);
+  static ExifEntry* createNewTag(ExifData* exif_data, ExifIfd ifd,
+    ExifFormat format, ExifTag tag);
+};
+
+}  // namespace exif
+}  // namespace extension
+
+#endif  // EXIF_EXIF_TAG_SAVER_H__
diff --git a/src/exif/exif_util.cc b/src/exif/exif_util.cc
new file mode 100644 (file)
index 0000000..a3fb017
--- /dev/null
@@ -0,0 +1,448 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "exif_util.h"
+
+#include <iomanip>
+#include <sstream>
+
+#include "common/platform_exception.h"
+#include "common/logger.h"
+
+namespace extension {
+namespace exif {
+
+namespace {
+const std::string ORIENTATION_NORMAL = "NORMAL";
+const std::string ORIENTATION_FLIP_HORIZONTAL = "FLIP_HORIZONTAL";
+const std::string ORIENTATION_ROTATE_180 = "ROTATE_180";
+const std::string ORIENTATION_FLIP_VERTICAL = "FLIP_VERTICAL";
+const std::string ORIENTATION_TRANSPOSE = "TRANSPOSE";
+const std::string ORIENTATION_ROTATE_90 = "ROTATE_90";
+const std::string ORIENTATION_TRANSVERSE = "TRANSVERSE";
+const std::string ORIENTATION_ROTATE_270 = "ROTATE_270";
+
+const std::string WHITE_BALANCE_MODE_AUTO = "AUTO";
+const std::string WHITE_BALANCE_MODE_MANUAL = "MANUAL";
+
+const std::string EXPOSURE_PROGRAM_NOT_DEFINED = "NOT_DEFINED";
+const std::string EXPOSURE_PROGRAM_MANUAL = "MANUAL";
+const std::string EXPOSURE_PROGRAM_NORMAL = "NORMAL";
+const std::string EXPOSURE_PROGRAM_APERTURE_PRIORITY = "APERTURE_PRIORITY";
+const std::string EXPOSURE_PROGRAM_SHUTTER_PRIORITY = "SHUTTER_PRIORITY";
+const std::string EXPOSURE_PROGRAM_CREATIVE_PROGRAM = "CREATIVE_PROGRAM";
+const std::string EXPOSURE_PROGRAM_ACTION_PROGRAM = "ACTION_PROGRAM";
+const std::string EXPOSURE_PROGRAM_PORTRAIT_MODE = "PORTRAIT_MODE";
+const std::string EXPOSURE_PROGRAM_LANDSCAPE_MODE = "LANDSCAPE_MODE";
+
+const std::string DUMMY = ""; // For unexpected input handling
+
+const std::string URI_PREFIX = "file://";
+const std::string URI_ABSOLUTE_PREFIX = "file:///";
+}
+
+const size_t ExifTypeInfo::ByteSize = 1;
+const size_t ExifTypeInfo::ASCIISize = 1;
+const size_t ExifTypeInfo::ShortSize = 2;
+const size_t ExifTypeInfo::LongSize = 4;
+const size_t ExifTypeInfo::RationalSize = 8;
+const size_t ExifTypeInfo::UndefinedSize = 1;
+const size_t ExifTypeInfo::SLongSize = 4;
+const size_t ExifTypeInfo::SRationalSize = 8;
+
+const ExifByte ExifTypeInfo::ByteId = 1;
+const ExifByte ExifTypeInfo::ASCIIId = 2;
+const ExifByte ExifTypeInfo::ShortId = 3;
+const ExifByte ExifTypeInfo::LongId = 4;
+const ExifByte ExifTypeInfo::RationalId = 5;
+const ExifByte ExifTypeInfo::UndefinedId = 7;
+const ExifByte ExifTypeInfo::SLongId = 9;
+const ExifByte ExifTypeInfo::SRationalId = 10;
+
+ExifUtil::ExifUtil() {
+}
+
+ExifUtil::~ExifUtil() {
+}
+
+ImageOrientation ExifUtil::stringToOrientation(const std::string& orientation) {
+  LoggerD("Entered");
+  if (ORIENTATION_NORMAL == orientation) {
+    return ImageOrientation::EXIF_ORIENTATION_NORMAL;
+  }
+  if (ORIENTATION_FLIP_HORIZONTAL == orientation) {
+    return ImageOrientation::EXIF_ORIENTATION_FLIP_HORIZONTAL;
+  }
+  if (ORIENTATION_ROTATE_180 == orientation) {
+    return ImageOrientation::EXIF_ORIENTATION_ROTATE_180;
+  }
+  if (ORIENTATION_FLIP_VERTICAL == orientation) {
+    return ImageOrientation::EXIF_ORIENTATION_FLIP_VERTICAL;
+  }
+  if (ORIENTATION_TRANSPOSE == orientation) {
+    return ImageOrientation::EXIF_ORIENTATION_TRANSPOSE;
+  }
+  if (ORIENTATION_ROTATE_90 == orientation) {
+    return ImageOrientation::EXIF_ORIENTATION_ROTATE_90;
+  }
+  if (ORIENTATION_TRANSVERSE == orientation) {
+    return ImageOrientation::EXIF_ORIENTATION_TRANSVERSE;
+  }
+  if (ORIENTATION_ROTATE_270 == orientation) {
+    return ImageOrientation::EXIF_ORIENTATION_ROTATE_270;
+  }
+  return ImageOrientation::EXIF_ORIENTATION_NOT_VALID;
+}
+
+const std::string& ExifUtil::orientationToString(ImageOrientation orientation) {
+  LoggerD("Entered");
+  switch (orientation) {
+    case ImageOrientation::EXIF_ORIENTATION_NORMAL:
+      return ORIENTATION_NORMAL;
+    case ImageOrientation::EXIF_ORIENTATION_FLIP_HORIZONTAL:
+      return ORIENTATION_FLIP_HORIZONTAL;
+    case ImageOrientation::EXIF_ORIENTATION_ROTATE_180:
+      return ORIENTATION_ROTATE_180;
+    case ImageOrientation::EXIF_ORIENTATION_FLIP_VERTICAL:
+      return ORIENTATION_FLIP_VERTICAL;
+    case ImageOrientation::EXIF_ORIENTATION_TRANSPOSE:
+      return ORIENTATION_TRANSPOSE;
+    case ImageOrientation::EXIF_ORIENTATION_ROTATE_90:
+      return ORIENTATION_ROTATE_90;
+    case ImageOrientation::EXIF_ORIENTATION_TRANSVERSE:
+      return ORIENTATION_TRANSVERSE;
+    case ImageOrientation::EXIF_ORIENTATION_ROTATE_270:
+      return ORIENTATION_ROTATE_270;
+    default:
+      return DUMMY;
+  }
+}
+
+WhiteBalanceMode ExifUtil::stringToWhiteBalance(const std::string& white_balance) {
+  LoggerD("Entered");
+  if (WHITE_BALANCE_MODE_AUTO == white_balance) {
+    return WhiteBalanceMode::EXIF_WHITE_BALANCE_MODE_AUTO;
+  }
+  if (WHITE_BALANCE_MODE_MANUAL == white_balance) {
+    return WhiteBalanceMode::EXIF_WHITE_BALANCE_MODE_MANUAL;
+  }
+  return WhiteBalanceMode::EXIF_WHITE_BALANCE_MODE_NOT_VALID;
+}
+
+const std::string& ExifUtil::whiteBalanceToString(WhiteBalanceMode value) {
+  LoggerD("Entered");
+  switch (value) {
+    case WhiteBalanceMode::EXIF_WHITE_BALANCE_MODE_AUTO:
+      return WHITE_BALANCE_MODE_AUTO;
+    case WhiteBalanceMode::EXIF_WHITE_BALANCE_MODE_MANUAL:
+      return WHITE_BALANCE_MODE_MANUAL;
+    default:
+      return DUMMY;
+  }
+}
+
+ExposureProgram ExifUtil::stringToExposureProgram(
+    const std::string& exposure_program) {
+  LoggerD("Entered");
+  if (EXPOSURE_PROGRAM_NOT_DEFINED == exposure_program) {
+    return EXIF_EXPOSURE_PROGRAM_NOT_DEFINED;
+  }
+  if (EXPOSURE_PROGRAM_MANUAL == exposure_program) {
+    return EXIF_EXPOSURE_PROGRAM_MANUAL;
+  }
+  if (EXPOSURE_PROGRAM_NORMAL == exposure_program) {
+    return EXIF_EXPOSURE_PROGRAM_NORMAL;
+  }
+  if (EXPOSURE_PROGRAM_APERTURE_PRIORITY == exposure_program) {
+    return EXIF_EXPOSURE_PROGRAM_APERTURE_PRIORITY;
+  }
+  if (EXPOSURE_PROGRAM_SHUTTER_PRIORITY == exposure_program) {
+    return EXIF_EXPOSURE_PROGRAM_SHUTTER_PRIORITY;
+  }
+  if (EXPOSURE_PROGRAM_CREATIVE_PROGRAM == exposure_program) {
+    return EXIF_EXPOSURE_PROGRAM_CREATIVE_PROGRAM;
+  }
+  if (EXPOSURE_PROGRAM_ACTION_PROGRAM == exposure_program) {
+    return EXIF_EXPOSURE_PROGRAM_ACTION_PROGRAM;
+  }
+  if (EXPOSURE_PROGRAM_PORTRAIT_MODE == exposure_program) {
+    return EXIF_EXPOSURE_PROGRAM_PORTRAIT_MODE;
+  }
+  if (EXPOSURE_PROGRAM_LANDSCAPE_MODE == exposure_program) {
+    return EXIF_EXPOSURE_PROGRAM_LANDSCAPE_MODE;
+  }
+  return EXIF_EXPOSURE_PROGRAM_NOT_VALID;
+}
+
+const std::string& ExifUtil::exposureProgramToString(ExposureProgram value) {
+  LoggerD("Entered");
+  switch (value) {
+    case ExposureProgram::EXIF_EXPOSURE_PROGRAM_NOT_DEFINED:
+      return EXPOSURE_PROGRAM_NOT_DEFINED;
+    case ExposureProgram::EXIF_EXPOSURE_PROGRAM_MANUAL:
+      return EXPOSURE_PROGRAM_MANUAL;
+    case ExposureProgram::EXIF_EXPOSURE_PROGRAM_NORMAL:
+      return EXPOSURE_PROGRAM_NORMAL;
+    case ExposureProgram::EXIF_EXPOSURE_PROGRAM_APERTURE_PRIORITY:
+      return EXPOSURE_PROGRAM_APERTURE_PRIORITY;
+    case ExposureProgram::EXIF_EXPOSURE_PROGRAM_SHUTTER_PRIORITY:
+      return EXPOSURE_PROGRAM_SHUTTER_PRIORITY;
+    case ExposureProgram::EXIF_EXPOSURE_PROGRAM_CREATIVE_PROGRAM:
+      return EXPOSURE_PROGRAM_CREATIVE_PROGRAM;
+    case ExposureProgram::EXIF_EXPOSURE_PROGRAM_ACTION_PROGRAM:
+      return EXPOSURE_PROGRAM_ACTION_PROGRAM;
+    case ExposureProgram::EXIF_EXPOSURE_PROGRAM_PORTRAIT_MODE:
+      return EXPOSURE_PROGRAM_PORTRAIT_MODE;
+    case ExposureProgram::EXIF_EXPOSURE_PROGRAM_LANDSCAPE_MODE:
+      return EXPOSURE_PROGRAM_LANDSCAPE_MODE;
+    default:
+      return DUMMY;
+  }
+}
+
+bool ExifUtil::isValidAbsoluteURI(const std::string& uri) {
+  return 0 == uri.find(URI_ABSOLUTE_PREFIX);
+}
+
+void ExifUtil::getURIInfo(const std::string& uri,
+    //const Filesystem::NodeType expected_type,
+    const std::string& required_permission,
+    bool& out_exists,
+    //Filesystem::NodeType& out_type,
+    bool& out_permission_granted) {
+  const std::string absolute_path = ExifUtil::convertUriToPath(uri);
+  out_exists = false;
+  out_permission_granted = false;
+
+  try {
+    //Filesystem::PathPtr path = Filesystem::Path::create(absolute_path);
+    //Filesystem::NodePtr node = Filesystem::Node::resolve(path);
+    //out_type = node->getType();
+    //out_exists = true;
+
+    //if (expected_type == out_type) {
+    //  out_permission_granted = node->checkPermission(path, required_permission,
+    //      expected_type);
+    //}
+  }
+  /*catch (const common::BasePlatformException &err) {
+    LoggerE("Couldn't resolve path: %s, got:%s (%s)", absolute_path.c_str(),
+        (err.getName()).c_str(), (err.getMessage()).c_str());
+  }*/
+  catch(...) {
+    LoggerE("Couldn't resolve path: %s", absolute_path.c_str());
+  }
+}
+
+// Example:
+// in: uri = file:///opt/usr/media/Images/exif.jpg
+// out: path = /opt/usr/media/Images/exif.jpg
+std::string ExifUtil::convertUriToPath(const std::string& str) {
+  std::string path = ltrim(str);
+  std::string prefix = path.substr(0, URI_PREFIX.size());
+
+  if (prefix == URI_PREFIX) {
+    return path.substr(URI_PREFIX.size());
+  }
+  else {
+    return path;
+  }
+}
+
+std::string ExifUtil::ltrim(const std::string& s) {
+  std::string str = s;
+  std::string::iterator i;
+  for (i = str.begin(); i != str.end(); i++) {
+    if (!isspace(*i)) {
+      break;
+    }
+  }
+  if (i == str.end()) {
+    str.clear();
+  }
+  else {
+    str.erase(str.begin(), i);
+  }
+  return str;
+}
+
+time_t ExifUtil::exifDateTimeOriginalToTimeT(const char* string) {
+  int year, month, day, hour, min, sec;
+  if (sscanf(string, "%d:%d:%d %d:%d:%d",
+        &year, &month, &day, &hour, &min, &sec) >= 6) {
+    return convertToTimeT(year, month, day, hour, min, sec);
+  }
+
+  return 0;
+}
+
+std::string ExifUtil::timeTToExifDateTimeOriginal(time_t time) {
+  int year, month, day, hour, min, sec;
+  extractFromTimeT(time, year, month, day, hour, min, sec);
+
+  std::ostringstream ss;
+  ss << std::setfill('0') << std::setw(4) << year << ':' ;
+  ss << std::setfill('0') << std::setw(2) << month << ':' ;
+  ss << std::setfill('0') << std::setw(2) << day << ' ' ;
+
+  ss << std::setfill('0') << std::setw(2) << hour << ':' ;
+  ss << std::setfill('0') << std::setw(2) << min << ':' ;
+  ss << std::setfill('0') << std::setw(2) << sec;
+  return ss.str();
+}
+
+const Rationals ExifUtil::timeTToExifGpsTimeStamp(time_t time) {
+  int year, month, day, hour, min, sec;
+  extractFromTimeT(time, year, month, day, hour, min, sec);
+
+  Rational hourRational = Rational::createFromDouble(static_cast<double>(hour));
+  Rational minRational = Rational::createFromDouble(static_cast<double>(min));
+  Rational secRational = Rational::createFromDouble(static_cast<double>(sec));
+
+  Rationals result;
+  result.push_back(hourRational);
+  result.push_back(minRational);
+  result.push_back(secRational);
+
+  return result;
+}
+
+
+std::string ExifUtil::timeTToExifGpsDateStamp(time_t time) {
+  int year, month, day, hour, min, sec;
+  extractFromTimeT(time, year, month, day, hour, min, sec);
+
+  LoggerD("year: %d", year);
+  LoggerD("month: %d", month);
+  LoggerD("day: %d", day);
+
+  std::ostringstream ss;
+  ss << std::setfill('0') << std::setw(4) << year << ':' ;
+  ss << std::setfill('0') << std::setw(2) << month << ':' ;
+  ss << std::setfill('0') << std::setw(2) << day;
+
+  LoggerD("SS: %s", ss.str().c_str());
+
+  return ss.str();
+}
+
+size_t  ExifUtil::getSizeOfExifFormatType(ExifFormat format) {
+  size_t size_per_member = 0;
+  switch (format) {
+    case EXIF_FORMAT_BYTE:
+      size_per_member = 1;
+      break;
+
+    case EXIF_FORMAT_SHORT:
+    case EXIF_FORMAT_SSHORT:
+      size_per_member = 2;
+      break;
+
+    case EXIF_FORMAT_LONG:
+    case EXIF_FORMAT_SLONG:
+      size_per_member = 4;
+      break;
+
+    case EXIF_FORMAT_RATIONAL:
+    case EXIF_FORMAT_SRATIONAL:
+      size_per_member = 8;
+      break;
+
+    default:
+      LoggerE("output ExifFormat: %d is not supported!");
+      return 0;
+  }
+
+  return size_per_member;
+}
+
+void ExifUtil::printExifEntryInfo(ExifEntry* entry, ExifData* exif_data) {
+  char buf[2000];
+  std::stringstream ss;
+
+  if (!entry) {
+    LoggerE("entry is null");
+    return;
+  }
+
+  if (!entry->data) {
+    LoggerE("entry data is null");
+    return;
+  }
+
+  unsigned char* read_buf_ptr = entry->data;
+
+  size_t size_per_member = getSizeOfExifFormatType(entry->format);
+  if (0 == size_per_member) {
+    size_per_member = 1;  //display as array of bytes
+  }
+
+  for(unsigned long compi = 0; compi < entry->components; ++compi) {
+
+    if (compi > 0) {
+      ss << " ";
+    }
+
+    for(size_t i = 0; i < size_per_member; ++i) {
+      unsigned int value = read_buf_ptr[i];
+      ss << std::hex << std::setw(2) << std::setfill('0') << value;
+    }
+
+    read_buf_ptr += size_per_member;
+  }
+
+  LoggerD("Entry{name:%s type:%s size:%d components:%d value:%s RAW DATA:[%s]}",
+      exif_tag_get_name(entry->tag),
+      exif_format_get_name(entry->format),
+      (int)entry->size,
+      (int)entry->components,
+      exif_entry_get_value(entry, buf, sizeof(buf)),
+      ss.str().c_str());
+}
+
+void ExifUtil::extractFromTimeT(const time_t time,
+      int& out_year, int& out_month, int& out_day,
+      int& out_hour, int& out_min, int& out_sec) {
+  struct tm* utc = gmtime(&time);
+
+  out_year = utc->tm_year + 1900;
+  out_month = utc->tm_mon + 1;
+  out_day = utc->tm_mday;
+  out_hour = utc->tm_hour;
+  out_min = utc->tm_min;
+  out_sec = utc->tm_sec;
+}
+
+time_t ExifUtil::convertToTimeT(int year, int month, int day,
+                                int hour, int min, int sec) {
+  time_t tmp_time = 0;
+  struct tm* timeinfo = localtime(&tmp_time);
+  timeinfo->tm_year = year - 1900;
+  timeinfo->tm_mon = month - 1;
+  timeinfo->tm_mday = day;
+
+  timeinfo->tm_hour = hour;
+  timeinfo->tm_min = min;
+  timeinfo->tm_sec = sec;
+
+  //From mktime documentation:
+  //"The values of the members tm_wday and tm_yday of timeptr are ignored"
+  return timegm(timeinfo);
+}
+
+}  // namespace exif
+}  // namespace extension
diff --git a/src/exif/exif_util.h b/src/exif/exif_util.h
new file mode 100644 (file)
index 0000000..7ccb081
--- /dev/null
@@ -0,0 +1,149 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+#ifndef EXIF_EXIF_UTIL_H_
+#define EXIF_EXIF_UTIL_H_
+
+#include <libexif/exif-data.h>
+#include <libexif/exif-entry.h>
+#include <libexif/exif-utils.h>
+#include <string>
+#include <vector>
+
+#include "rational.h"
+
+namespace extension {
+namespace exif {
+
+enum ImageOrientation {
+  EXIF_ORIENTATION_NORMAL = 1,
+  EXIF_ORIENTATION_FLIP_HORIZONTAL = 2,
+  EXIF_ORIENTATION_ROTATE_180 = 3,
+  EXIF_ORIENTATION_FLIP_VERTICAL = 4,
+  EXIF_ORIENTATION_TRANSPOSE = 5,
+  EXIF_ORIENTATION_ROTATE_90 = 6,
+  EXIF_ORIENTATION_TRANSVERSE = 7,
+  EXIF_ORIENTATION_ROTATE_270 = 8,
+  EXIF_ORIENTATION_NOT_VALID,
+};
+
+enum WhiteBalanceMode {
+  EXIF_WHITE_BALANCE_MODE_AUTO = 0,
+  EXIF_WHITE_BALANCE_MODE_MANUAL = 1,
+  EXIF_WHITE_BALANCE_MODE_NOT_VALID
+};
+
+enum ExposureProgram {
+  EXIF_EXPOSURE_PROGRAM_NOT_DEFINED = 0,
+  EXIF_EXPOSURE_PROGRAM_MANUAL = 1,
+  EXIF_EXPOSURE_PROGRAM_NORMAL = 2,
+  EXIF_EXPOSURE_PROGRAM_APERTURE_PRIORITY = 3,
+  EXIF_EXPOSURE_PROGRAM_SHUTTER_PRIORITY = 4,
+  EXIF_EXPOSURE_PROGRAM_CREATIVE_PROGRAM = 5,
+  EXIF_EXPOSURE_PROGRAM_ACTION_PROGRAM = 6,
+  EXIF_EXPOSURE_PROGRAM_PORTRAIT_MODE = 7,
+  EXIF_EXPOSURE_PROGRAM_LANDSCAPE_MODE = 8,
+  EXIF_EXPOSURE_PROGRAM_NOT_VALID
+};
+
+/**
+ * From Exif 2.2 specification:
+ *  The following types are used in Exif:
+ *  1 = BYTE An 8-bit unsigned integer.,
+ *  2 = ASCII An 8-bit byte containing one 7-bit ASCII code. The final byte is terminated
+ *    with NULL.,
+ *  3 = SHORT A 16-bit (2-byte) unsigned integer,
+ *  4 = LONG A 32-bit (4-byte) unsigned integer,
+ *  5 = RATIONAL Two LONGs. The first LONG is the numerator and the second LONG expresses
+ *    the denominator.,
+ *  7 = UNDEFINED An 8-bit byte that can take any value depending on the field definition,
+ *  9 = SLONG A 32-bit (4-byte) signed integer (2's complement notation),
+ * 10 = SRATIONAL Two SLONGs. The first SLONG is the numerator and the second SLONG is the
+ *    denominator.
+ */
+struct ExifTypeInfo {
+  /**
+   * Number of bytes used by each exif type
+   */
+  static const size_t ByteSize;       // 1 byte
+  static const size_t ASCIISize;      // 1 byte (*N)
+  static const size_t ShortSize;      // 2 bytes
+  static const size_t LongSize;       // 4 bytes
+  static const size_t RationalSize;   // 8 bytes
+  static const size_t UndefinedSize;  // 1 byte (*N)
+  static const size_t SLongSize;      // 4 bytes
+  static const size_t SRationalSize;  // 8 bytes
+
+  /**
+   * Id values used by Exif to identify type
+   */
+  static const ExifByte ByteId;       // 1
+  static const ExifByte ASCIIId;      // 2
+  static const ExifByte ShortId;      // 3
+  static const ExifByte LongId;       // 4
+  static const ExifByte RationalId;   // 5
+  static const ExifByte UndefinedId;  // 7
+  static const ExifByte SLongId;      // 9
+  static const ExifByte SRationalId;  // 10
+};
+
+class ExifUtil {
+ public:
+  ExifUtil();
+  virtual ~ExifUtil();
+
+  static ImageOrientation stringToOrientation(const std::string& orientation);
+  static const std::string& orientationToString(ImageOrientation value);
+
+  static WhiteBalanceMode stringToWhiteBalance(
+      const std::string& white_balance);
+  static const std::string& whiteBalanceToString(WhiteBalanceMode value);
+
+  static ExposureProgram stringToExposureProgram(
+      const std::string& exposure_program);
+  static const std::string& exposureProgramToString(ExposureProgram value);
+
+  static bool isValidAbsoluteURI(const std::string& uri);
+  static void getURIInfo(const std::string& uri,
+      const std::string& required_permission,
+      bool& out_exists,
+      bool& out_permission_granted);
+
+  static std::string convertUriToPath(const std::string& str);
+  static std::string ltrim(const std::string& s);
+
+  static time_t exifDateTimeOriginalToTimeT(const char* string);
+  static std::string timeTToExifDateTimeOriginal(time_t time);
+  static const Rationals timeTToExifGpsTimeStamp(time_t time);
+  static std::string timeTToExifGpsDateStamp(time_t time);
+
+  static size_t getSizeOfExifFormatType(ExifFormat format);
+  static void  printExifEntryInfo(ExifEntry* entry, ExifData* exif_data);
+
+  static void extractFromTimeT(const time_t time,
+      int& out_year, int& out_month, int& out_day,
+      int& out_hour, int& out_min, int& out_sec);
+
+  static time_t convertToTimeT(int year, int month, int day,
+      int hour, int min, int sec);
+};
+
+}  // namespace exif
+}  // namespace extension
+
+#endif  // EXIF_EXIF_UTIL_H_
diff --git a/src/exif/jpeg_file.cc b/src/exif/jpeg_file.cc
new file mode 100644 (file)
index 0000000..f7c5d0f
--- /dev/null
@@ -0,0 +1,712 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+//
+// For details of JPEG file format see:
+// http://www.media.mit.edu/pia/Research/deepview/exif.html
+
+#include "jpeg_file.h"
+
+#include <iomanip>
+#include <limits>
+#include <stdio.h>
+#include <sstream>
+
+#include "common/platform_exception.h"
+#include "common/logger.h"
+
+namespace extension {
+namespace exif {
+
+/**
+ * Size of maximal JPEG's section data length
+ * (since it is stored as unsigned short limit is 2^16 -1)
+ */
+const unsigned int MAX_JPEG_SECTION_DATA_SIZE = 65535;
+
+/**
+ * JPEG's section data length includes 2 bytes for length therefore we need to
+ * substract 2 from MAX_JPEG_SECTION_DATA_SIZE
+ */
+const unsigned int MAX_AVAILABLE_JPEG_SECTION_DATA_SIZE = MAX_JPEG_SECTION_DATA_SIZE - 2;
+
+bool isJpegMarker(const int value) {
+  return value >= JPEG_MARKER_LOWEST_ID && value <= JPEG_MARKER_HIGHEST_ID;
+}
+
+JpegMarker castToJpegMarker(const unsigned char byte) {
+  if (byte < JPEG_MARKER_LOWEST_ID || byte > JPEG_MARKER_HIGHEST_ID) {
+    return JPEG_MARKER_UNKNOWN;
+  }
+
+  return static_cast<JpegMarker>(byte);
+}
+
+long readUShortBE(unsigned char* src) {
+  return ((static_cast<long>(src[0]) << 8) | static_cast<long>(src[1]));
+}
+
+void writeUShortBE(unsigned short value, unsigned char* buffer) {
+  buffer[0] = static_cast<unsigned char>(value >> 8);
+  buffer[1] = static_cast<unsigned char>(value);
+}
+
+struct CArrayDeleter {
+  void operator()(void* buffer) { free(buffer); }
+};
+
+JpegFile::JpegFile() :
+  m_in_data(NULL),
+  m_in_data_size(0),
+  m_image_data(NULL),
+  m_image_size(0),
+  m_padding_data(NULL),
+  m_padding_data_size(0),
+  m_in_file(NULL),
+  m_out_file(NULL) {
+}
+
+JpegFile::~JpegFile() {
+  delete [] m_in_data;
+  m_in_data = NULL;
+  m_in_data_size = 0;
+
+  m_padding_data = NULL;
+  m_padding_data_size = 0;
+
+  for(SectionsVec::iterator it = m_sections.begin(); it != m_sections.end(); ++it) {
+    JpegFileSectionPtr cur = *it;
+
+    if (cur->exif_data) {
+      exif_data_unref(cur->exif_data);
+      cur->exif_data = NULL;
+    }
+
+    cur->data_ptr = NULL;
+    cur->size = 0;
+    cur->type = JPEG_MARKER_UNKNOWN;
+  }
+
+  m_image_data = NULL;
+  m_image_size = 0;
+
+  if (m_in_file) {
+    fclose(m_in_file);
+    m_in_file = NULL;
+  }
+
+  if (m_out_file) {
+    fclose(m_out_file);
+    m_out_file = NULL;
+  }
+}
+
+JpegFilePtr JpegFile::loadFile(const std::string& path) {
+  JpegFile* new_jpg = new (std::nothrow) JpegFile();
+  if (!new_jpg) {
+    LoggerE("Couldn't allocate Jpegfile!");
+    throw common::UnknownException("Memory allocation failed");
+  }
+
+  JpegFilePtr jpg_ptr(new_jpg);
+  jpg_ptr->load(path);
+  return jpg_ptr;
+}
+
+void JpegFile::load(const std::string& path) {
+  LoggerD("Entered file:%s", path.c_str());
+
+  m_source_file_path = path;
+
+  m_in_file = fopen(path.c_str(), "rb");
+  if (!m_in_file) {
+    LoggerE("Couldn't open Jpeg file: [%s]", path.c_str());
+    throw common::NotFoundException("Could not open JPG file");
+  }
+
+  fseek(m_in_file, 0, SEEK_END);
+  const size_t in_file_size = static_cast<size_t>(ftell(m_in_file));
+  fseek(m_in_file, 0, SEEK_SET);
+  LoggerD("JPEG file: [%s] size:%d", path.c_str(), in_file_size);
+  if (0 == in_file_size) {
+    LoggerE("Input file [%s] is empty!", path.c_str());
+    throw common::UnknownException("JPEG file is invalid");
+  }
+
+  m_in_data = new (std::nothrow) unsigned char[in_file_size];
+  if (!m_in_data) {
+    LoggerE("Couldn't allocate buffer with size: %d", in_file_size);
+    throw common::UnknownException("Memory allocation failed");
+  }
+
+  m_in_data_size = in_file_size;
+
+  const size_t read_bytes = fread(m_in_data, 1, m_in_data_size, m_in_file);
+  if (read_bytes != m_in_data_size) {
+    LoggerE("Couldn't read all: %d bytes. Read only: %d bytes!", m_in_data_size,
+        read_bytes);
+    throw common::UnknownException("Could not read JPEG file");
+  }
+
+  if (fclose(m_in_file) == EOF) {
+    LoggerE("Couldn't close input file: %s!", path.c_str());
+  }
+  m_in_file = NULL;
+
+  generateListOfSections();
+}
+
+std::string JpegFile::getPartOfFile(const size_t offset,
+    const size_t num_bytes_before,
+    const size_t num_bytes_after) {
+  long long int start = static_cast<long long int>(offset) - num_bytes_before;
+  if (start < 0) {
+    start = 0;
+  }
+
+  long long int end = static_cast<long long int>(offset) + num_bytes_after;
+  if (end >= m_in_data_size) {
+    end = m_in_data_size - 1;
+  }
+
+  std::stringstream ss;
+  ss << std::setfill('0') << std::setw(2) << std::hex;
+  for(long long int i = start; i <= end; ++i) {
+    ss << static_cast<int>(m_in_data[i]);
+  }
+  return ss.str();
+}
+
+
+void JpegFile::generateListOfSections() {
+  LoggerD("Entered");
+
+  //JPEG starts with:
+  //FFD8 (2 bytes) - SOI Marker
+  //
+  //then:
+  //N sections - format of section:
+  //0xFF(1 byte) + Marker Number(1 byte) + Data size(2 bytes) + Data
+  //
+  //then:
+  //SOS 0xFF(1 byte) + Marker Number(1 byte) + Data size(2 bytes) + Data
+  //
+  //Image data
+  //
+  //FFD9 (2 bytes) - EOI Marker
+  //
+  //Warning: some images taken on Android contains some extra data at the end
+  //we will keep it in m_padding_data
+
+  m_padding_data = NULL;
+  m_padding_data_size = 0;
+
+  for(size_t offset = 0, iterration = 0; offset < m_in_data_size;++iterration) {
+
+    LoggerD("offset:%d | Starting iteration: %d", offset, iterration);
+    const size_t search_len = 10;
+    size_t search_offset = 0;
+    for(search_offset = 0; search_offset < search_len; ++search_offset) {
+      //Skip bytes until first no 0xff
+      unsigned char& tmp_marker = m_in_data[offset + search_offset];
+      if (tmp_marker != 0xff) {
+        break;
+      }
+    }
+
+    if (search_len == search_offset) {
+      LoggerE("offset:%d | Couldn't find marker! RAW DATA:{%s}", offset,
+          getPartOfFile(offset, 0, 10).c_str());
+      throw common::UnknownException("JPEG file is invalid");
+    }
+
+    const size_t section_offset = offset + search_offset - 1;
+    unsigned char* section_begin = m_in_data + section_offset;
+
+    offset = section_offset;  //Move to section begin
+    LoggerD("offset:%d | Moved to section begin", offset);
+
+    if (!isJpegMarker(section_begin[1])) {
+      LoggerE("offset:%d | Is not valid marker: 0x%x RAW DATA:{%s}", offset,
+          section_begin[1], getPartOfFile(section_offset,0,4).c_str());
+      throw common::UnknownException("JPEG file is invalid");
+    }
+
+    const JpegMarker cur_marker = castToJpegMarker(section_begin[1]);
+    LoggerD("offset:%d | Found valid marker: 0x%x RAW DATA:{%s}", offset,
+        cur_marker,
+        getPartOfFile(section_offset,0,4).c_str());
+
+    offset += 2;  //Read 0xffxx marker tag - 2 bytes
+
+    JpegFileSectionPtr section;
+    {
+      JpegFileSection* sec = new (std::nothrow) JpegFileSection();
+      if (!sec) {
+        LoggerE("Couldn't allocate JpegFileSection");
+        throw common::UnknownException("Memory allocation failed");
+      }
+
+      section = JpegFileSectionPtr(sec);
+    }
+
+    section->type = cur_marker;
+    m_sections.push_back(section);
+    if (cur_marker == JPEG_MARKER_SOI ||
+      cur_marker == JPEG_MARKER_EOI) {
+      LoggerD("offset:%d | Found: %s marker, moving to next marker at:%d",
+          section_offset, ((cur_marker == JPEG_MARKER_SOI) ? "SOI" : "EOI"),
+          offset);
+
+      if (cur_marker == JPEG_MARKER_EOI && m_padding_data != NULL) {
+        LoggerW("Padding data have been found - do not try to parse end of file");
+        break;
+      }
+    }
+    else {
+      //From JPEG/EXIF info:
+      // Please notice that "Data" contains Data size descriptor, if there is
+      // a Marker like this;
+      //
+      // FF C1 00 0C
+      // It means this Marker(0xFFC1) has 0x000C(equal 12)bytes of data. But the
+      // data size '12' includes "Data size" descriptor, it follows only 10 bytes of
+      // data after 0x000C.
+      //
+
+      const long total_section_len = readUShortBE(section_begin + 2); //Include data
+                                      //size 2 bytes
+
+      const long section_data_len = total_section_len - 2;      //Exclude data
+                                      //size 2 bytes
+
+      LoggerD("offset:%d tag:0x%x | Read total_section_len:%d (data len:%d)",
+          section_offset, cur_marker, total_section_len, section_data_len);
+
+      offset += 2;  //Read data size - 2 bytes
+
+      if (total_section_len < 0) {
+        LoggerE("offset:%d tag:0x%x | Error: total_section_len is: %d < 0", offset,
+            cur_marker, total_section_len);
+        throw common::UnknownException("JPEG file is invalid");
+      }
+
+      if (section_offset + 2 + total_section_len > m_in_data_size) {
+        LoggerE("offset:%d tag:0x%x | Error: current section offset:%d"
+            " + 2 + total_section_len:%d = %d is greater then file size:%d",
+            offset, cur_marker,
+            section_offset, total_section_len,
+            section_offset + total_section_len, m_in_data_size);
+        throw common::UnknownException("JPEG file is invalid");
+      }
+
+      if (JPEG_MARKER_APP1 == cur_marker) {
+        //TODO: verify this
+        //-4 --> 0xFF(1 byte)+Marker Number(1 byte)+Data size(2 bytes))
+        //const unsigned int exif_data_size = section_length - 4;
+
+        const unsigned int exif_data_size = total_section_len + 2;
+        section->exif_data = exif_data_new_from_data (section_begin,
+            exif_data_size);
+
+        LoggerD("offset:%d tag:0x%x | Loading exif from offset:%d"
+            " len:%d exif_data_new_from_data returned: %p",
+            offset, cur_marker, section_offset, exif_data_size,
+            section->exif_data);
+
+        if (!section->exif_data) {
+          LoggerW("offset:%d tag:0x%x | Couldn't load Exif!", offset, cur_marker);
+        }
+      }
+
+      //This just saves pointer not copying data
+      section->data_ptr = section_begin + 2 + 2; //2 bytes marker + 2 bytes data size
+      section->size = section_data_len;  //Exclude data size
+
+      if (JPEG_MARKER_SOS == cur_marker) {
+        //Calculate offset of first image data which is just after this SOS section
+        const size_t image_data_offset = section_offset + 2 + total_section_len;
+
+        //Calculate size of image data from start to expected EOI at end of file.
+        //
+        //-2 (exclude ending EOI marker (2 bytes)
+        size_t image_size = m_in_data_size - image_data_offset - 2;
+        LoggerW("offset:%d tag:0x%x | Image data offset:%d Estimated image size:%d",
+            offset, cur_marker, image_data_offset, image_size);
+
+        m_image_data = m_in_data + image_data_offset;
+
+        size_t eoi_tag_index = 0;
+        bool found_eoi_tag = searchForTagInBuffer(m_in_data + image_data_offset,
+            m_in_data + m_in_data_size, JPEG_MARKER_EOI, eoi_tag_index);
+        if (!found_eoi_tag) {
+          LoggerE("Could not find EOI tag! Assume that there is no EOI and rest of "
+              "JPEG file contains image data stream: image_size+= 2");
+          image_size += 2; //Skip expected EOI tag which is not present
+        } else {
+          LoggerD("EOI tag found at offset: %d from SOS data", eoi_tag_index);
+
+          if(eoi_tag_index != image_size) {
+            LoggerW("Estimated image size:%d doesn't match EOI tag index:%d"
+                " delta:%d", image_size, eoi_tag_index,
+                image_size - eoi_tag_index);
+
+            LoggerW("Setting image_size to EOI tag: %d", eoi_tag_index);
+            image_size = eoi_tag_index;
+
+            m_padding_data = m_image_data + image_size + 2; //(skip EOI tag)
+            m_padding_data_size = (m_in_data + m_in_data_size) - m_padding_data;
+            LoggerW("Saving padding data from offset:%d with size:%d",
+              m_padding_data - m_in_data, m_padding_data_size);
+          }
+        }
+
+        m_image_size = image_size;
+
+        offset = image_data_offset + image_size;
+        LoggerD("offset:%d tag:0x%x | SOS Offset moved to next marker", offset,
+            cur_marker);
+      }
+      else {
+        offset += section_data_len;
+        LoggerD("offset:%d tag:0x%x | Offset moved to next marker", offset, cur_marker);
+      }
+    }
+  }
+}
+
+bool JpegFile::searchForTagInBuffer(const unsigned char* buffer_start,
+    const unsigned char* buffer_end,
+    const JpegMarker marker,
+    size_t& out_index) {
+  LoggerD("Entered start:%p end:%p marker:0x%x", buffer_start, buffer_end, marker);
+
+  if(!buffer_start) {
+    LoggerE("buffer_start is NULL");
+    return false;
+  }
+
+  if(!buffer_end) {
+    LoggerE("buffer_end is NULL");
+    return false;
+  }
+
+  if(buffer_end <= buffer_start) {
+    LoggerE("buffer_end: %p <= buffer_start: %p", buffer_end, buffer_start);
+    return false;
+  }
+
+  LoggerD("Bytes to scan: %d", static_cast<size_t>(buffer_end - buffer_start));
+  const unsigned char marker_uchar = static_cast<unsigned char>(marker);
+
+  for(const unsigned char* ptr = buffer_start; ptr < buffer_end; ++ptr) {
+
+    if((0xff == *ptr) && (ptr+1 < buffer_end)) {
+      if(marker_uchar == *(ptr+1)) {
+        out_index = static_cast<size_t>(ptr - buffer_start);
+        return true;
+      }
+    }
+  }
+
+  out_index = 0;
+  return false;
+}
+
+void JpegFile::setNewExifData(ExifData* new_exif_data) {
+  if (!new_exif_data) {
+    LoggerE("Trying to set NULL exif_data!");
+    throw common::UnknownException("Could not save Exif in JPEG file");
+  }
+
+  JpegFileSectionPtr exif = getExifSection();
+  if (!exif) {
+    LoggerW("Could't find Exif section - creating new one");
+    {
+      JpegFileSection* new_sec = new (std::nothrow) JpegFileSection();
+      if (!new_sec) {
+        LoggerE("Couldn't allocate JpegFileSection");
+        throw common::UnknownException("Memory allocation failed");
+      }
+      new_sec->type = JPEG_MARKER_APP1;
+
+      exif = JpegFileSectionPtr(new_sec);
+    }
+
+    SectionsVec::iterator insert_it = m_sections.begin();
+    bool soi_is_present = false;
+
+    if (insert_it != m_sections.end()) {
+      if ((*insert_it)->type != JPEG_MARKER_SOI) {
+        LoggerW("First section is not SOI - Start Of Image!");
+      }
+      else {
+        soi_is_present = true;
+      }
+    }
+
+    if (!soi_is_present) {
+      LoggerW("SOI section is missing");
+      throw common::UnknownException("JPEG file is invalid");
+    }
+
+    //Insert new Exif sections just after SOI
+    ++insert_it;
+    if (insert_it != m_sections.begin()) {
+      m_sections.insert(insert_it, exif);
+    }
+    else {
+      //This shouldn't happen since we at lest need SOS and EOI sections
+      m_sections.push_back(exif);
+    }
+  }
+
+  //We don't want to save old data
+  exif->data_ptr = NULL;
+  exif->size = 0;
+
+  exif_data_unref(exif->exif_data);
+  exif_data_ref (new_exif_data);
+  exif->exif_data = new_exif_data;
+}
+
+ExifData* JpegFile::getExifData() {
+  JpegFileSectionPtr exif = getExifSection();
+  if (!exif) {
+    return NULL;
+  }
+
+  exif_data_ref(exif->exif_data);
+  return exif->exif_data;
+}
+
+void JpegFile::saveToFile(const std::string& out_path) {
+  LoggerD("Entered out_path:%s", out_path.c_str());
+  try {
+    saveToFilePriv(out_path);
+  }
+  catch (...) {
+    LoggerE("Exception occured during saveToFilePriv "
+        "original file: [%] new: [%s]",
+        m_source_file_path.c_str(),
+        out_path.c_str());
+
+    if (out_path == m_source_file_path) {
+
+      LoggerD("Trying to recover broken JPEG file: [%s]", out_path.c_str());
+      //We were writing to source file and since something went wrong let's
+      //restore old file - we have it in m_in_data
+
+      FILE* outf = fopen(out_path.c_str(), "wb");
+      if (!outf) {
+        LoggerE("Couldn't open output file: [%s] - JPEG file will not be restored!");
+      }
+      else {
+        size_t bytes_wrote = fwrite(m_in_data, 1, m_in_data_size, outf);
+        if (bytes_wrote != m_in_data_size) {
+          LoggerE("Couldn't restore whole JPEG! "
+              "Only %d of %d bytes have been wrote!",
+              bytes_wrote, m_in_data_size);
+        }
+        if (EOF == fclose(outf)) {
+          LoggerE("Couldn't close restore output file: [%s]", out_path.c_str());
+        }
+      }
+    }
+
+    throw;
+  }
+}
+
+void JpegFile::saveToFilePriv(const std::string& out_path) {
+  LoggerD("Entered out_path:%s", out_path.c_str());
+
+  m_out_file = fopen(out_path.c_str(), "wb");
+  if (!m_out_file) {
+    LoggerE("Couldn't open output file: %s", out_path.c_str());
+    throw common::UnknownException("Could not write JPEG file");
+  }
+
+  unsigned char tmp_buf[128];
+  size_t offset = 0;
+
+  int section_index = 0;
+  for(SectionsVec::iterator it = m_sections.begin();
+      it != m_sections.end();
+      ++it, ++ section_index) {
+
+    JpegFileSectionPtr cur = *it;
+    const JpegMarker cur_marker = cur->type;
+
+    LoggerD("offset:%d | Section: %d marker 0x%x", offset, section_index, cur_marker);
+
+    size_t bytes_to_write = 0;
+    size_t bytes_wrote = 0;
+
+    tmp_buf[0] = 0xff;
+    tmp_buf[1] = cur_marker;
+    bytes_to_write += 2;
+
+    bool write_section_data = false;
+
+    bool write_exif_data = false;
+
+    std::unique_ptr<unsigned char, CArrayDeleter> exif_output_data;
+    unsigned int exif_output_size = 0;
+
+    if (cur_marker != JPEG_MARKER_SOI &&
+        cur_marker != JPEG_MARKER_EOI) {
+
+      unsigned short section_size = 2;
+      if (JPEG_MARKER_APP1 && cur->exif_data) {
+
+        unsigned char* tmp = NULL;
+        exif_data_save_data (cur->exif_data, &tmp, &exif_output_size);
+        if (!tmp || 0 == exif_output_size) {
+          LoggerE("Couldn't generate RAW Exif data!");
+          throw common::UnknownException("Could not save Exif in JPEG file");
+        }
+
+        LoggerD("offset:%d | Generated Exif RAW Data length:%d", offset,
+            exif_output_size);
+
+        exif_output_data.reset(tmp);
+
+        if (exif_output_size > MAX_AVAILABLE_JPEG_SECTION_DATA_SIZE) {
+          LoggerE("exif_output_size:%d is greater then maximum JPEG section"
+              "data block size: %d", exif_output_size,
+              MAX_AVAILABLE_JPEG_SECTION_DATA_SIZE);
+          throw common::UnknownException("Exif data is to big to be saved in JPEG file");
+        }
+        section_size += exif_output_size;
+        write_exif_data = true;
+      }
+      else {
+        section_size += cur->size;
+        write_section_data = true;
+      }
+
+      writeUShortBE(section_size, tmp_buf + bytes_to_write);
+      bytes_to_write += 2;
+    }
+
+    LoggerD("offset:%d | Writing section: marker:0x%x size:%d", offset, cur_marker,
+        cur->size);
+
+    bytes_wrote = fwrite(tmp_buf, 1, bytes_to_write, m_out_file);
+    offset += bytes_wrote;
+
+    if (bytes_wrote != bytes_to_write) {
+      LoggerE("Couldn't wrote %d bytes! Only %d bytes wrote", bytes_to_write,
+          bytes_wrote);
+      throw common::UnknownException("Could not write JPEG file");
+    }
+
+    if (write_section_data && cur->size > 0) {
+      LoggerD("offset:%d | Writing data with length:%d", offset, cur->size);
+
+      bytes_to_write = cur->size;
+      bytes_wrote = fwrite(cur->data_ptr, 1, bytes_to_write, m_out_file);
+      offset += bytes_wrote;
+
+      if (bytes_wrote != bytes_to_write) {
+        LoggerE("Couldn't wrote %d bytes! Only %d bytes wrote", bytes_to_write,
+            bytes_wrote);
+        throw common::UnknownException("Could not write JPEG file");
+      }
+    }
+
+    if (write_exif_data && exif_output_data && exif_output_size > 0) {
+      LoggerD("offset:%d | Writing new exif data with length:%d", offset,
+          exif_output_size);
+
+      bytes_to_write = exif_output_size;
+      bytes_wrote = fwrite(exif_output_data.get(), 1, bytes_to_write, m_out_file);
+      offset += bytes_wrote;
+
+      if (bytes_wrote != bytes_to_write) {
+        LoggerE("Couldn't wrote %d bytes! Only %d bytes wrote", bytes_to_write,
+            bytes_wrote);
+        throw common::UnknownException("Could not write JPEG file");
+      }
+    }
+
+    if (JPEG_MARKER_SOS == cur_marker) {
+      LoggerD("offset:%d | Writing image data stream with lenght:%d", offset,
+          m_image_size);
+
+      bytes_to_write = m_image_size;
+      bytes_wrote = fwrite(m_image_data, 1, bytes_to_write, m_out_file);
+      offset += bytes_wrote;
+
+      if (bytes_wrote != bytes_to_write) {
+        LoggerE("Couldn't wrote %d bytes! Only %d bytes wrote", bytes_to_write,
+            bytes_wrote);
+        throw common::UnknownException("Could not write JPEG file");
+      }
+    }
+  }
+
+  if (m_padding_data && m_padding_data_size > 0) {
+    LoggerD("Padding data exists and contains:%d bytes saving to JPEG file");
+    const size_t bytes_wrote = fwrite(m_image_data, 1, m_padding_data_size,
+        m_out_file);
+
+    if (bytes_wrote != m_padding_data_size) {
+      LoggerE("Couldn't wrote %d bytes! Only %d bytes wrote", m_padding_data_size,
+          bytes_wrote);
+      throw common::UnknownException("Could not write JPEG file");
+    }
+  }
+
+  if (fclose(m_out_file) == EOF) {
+    LoggerE("Couldn't close output file: %s", out_path.c_str());
+    m_out_file = NULL;
+  }  else {
+    m_out_file = NULL;
+    LoggerD("Closed output file: %s wrote:%d bytes: %d", out_path.c_str(), offset);
+  }
+}
+
+JpegFileSectionPtr JpegFile::getExifSection() {
+  size_t num_exif_sections = 0;
+  JpegFileSectionPtr first_exif_section;
+
+  for (SectionsVec::iterator it = m_sections.begin(); it != m_sections.end(); ++it) {
+    JpegFileSectionPtr cur = *it;
+
+    if (JPEG_MARKER_APP1 == cur->type) {
+      if (!cur->exif_data) {
+        LoggerW("Warning: found APP1 section but exif_data is NULL (Not Exif?)");
+        continue;
+      }
+
+      ++num_exif_sections;
+      if (!first_exif_section) {
+        first_exif_section = cur;
+      }
+      else {
+        LoggerW("Warning: found %d APP1/Exif sections - only first is currently supported!");
+      }
+    }
+  }
+
+  return first_exif_section;
+}
+
+}  // namespace exif
+}  // namespace extension
diff --git a/src/exif/jpeg_file.h b/src/exif/jpeg_file.h
new file mode 100644 (file)
index 0000000..27324af
--- /dev/null
@@ -0,0 +1,137 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+#ifndef EXIF_EXIF_JPEG_FILE_H_
+#define EXIF_EXIF_JPEG_FILE_H_
+
+#include <libexif/exif-data.h>
+#include <libexif/exif-entry.h>
+#include <libexif/exif-utils.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+#include <cstdio>
+#include <map>
+
+namespace extension {
+namespace exif {
+
+enum JpegMarker{
+  JPEG_MARKER_UNKNOWN     = 0x00,
+  JPEG_MARKER_LOWEST_ID   = 0xc0,
+  JPEG_MARKER_SOI         = 0xd8,  // Start Of Image
+  JPEG_MARKER_EOI         = 0xd9,  // End Of Image
+  JPEG_MARKER_SOS         = 0xda,  // Start Of Stream
+  JPEG_MARKER_APP1        = 0xe1,  // Application Data 1 - for Exif
+  JPEG_MARKER_HIGHEST_ID  = 0xfe
+};
+
+struct JpegFileSection;
+typedef std::shared_ptr<JpegFileSection> JpegFileSectionPtr;
+
+struct JpegFileSection {
+  JpegFileSection() :
+    type(JPEG_MARKER_UNKNOWN),
+    data_ptr(NULL),
+    size(0),
+    exif_data(NULL) {}
+
+  JpegMarker type;
+  unsigned char* data_ptr;
+  unsigned short size;
+
+  ExifData* exif_data;
+};
+
+
+class JpegFile;
+typedef std::shared_ptr<JpegFile> JpegFilePtr;
+
+class JpegFile {
+ public:
+  static JpegFilePtr loadFile(const std::string& path);
+  ~JpegFile();
+
+  void setNewExifData(ExifData* new_exif_data);
+
+  /**
+   * You are responsible to unreference returned data with: exif_data_unref(...)
+   * Example:
+   *   ExifData* ed = jpeg.getExifData();
+   *   if(ed) {
+   *     doSth(ed);
+   *     exif_data_unref(ed);
+   *   }
+   */
+  ExifData* getExifData();
+
+  void saveToFile(const std::string& out_path);
+
+ private:
+  JpegFile();
+  void load(const std::string& path);
+  void generateListOfSections();
+
+  std::string getPartOfFile(const size_t offset,
+      const size_t num_bytes_before = 10,
+      const size_t num_bytes_after = 10);
+
+  JpegFileSectionPtr getExifSection();
+  void saveToFilePriv(const std::string& out_path);
+
+  /**
+   * Search for first occurence of specific tag inside buffer.
+   *
+   * buffer_end is the first byte that should not be checked:
+   * [buffer_start ... buffer_end)
+   *
+   * For example EOI - search for first 'ffd9' in buffer
+   */
+  static bool searchForTagInBuffer(const unsigned char* buffer_start,
+      const unsigned char* buffer_end,
+      const JpegMarker marker,
+      size_t& out_index);
+
+  std::string m_source_file_path;
+
+  unsigned char* m_in_data;
+  size_t m_in_data_size;
+
+  unsigned char* m_image_data;
+  size_t m_image_size;
+
+  /**
+   * This contains any bytes after EOI.
+   * Usually there should be no extra bytes after EOI unfortunately
+   * some cameras saves extra bytes (for example Android).
+   */
+  unsigned char* m_padding_data;
+  size_t m_padding_data_size;
+
+  FILE* m_in_file;
+  FILE* m_out_file;
+
+  typedef std::vector<JpegFileSectionPtr> SectionsVec;
+  SectionsVec m_sections;
+};
+
+}  // namespace exif
+}  // namespace extension
+
+#endif  // EXIF_EXIF_JPEG_FILE_H_
diff --git a/src/exif/rational.cc b/src/exif/rational.cc
new file mode 100644 (file)
index 0000000..9426402
--- /dev/null
@@ -0,0 +1,267 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "rational.h"
+
+#include "math.h"
+
+#include "common/platform_exception.h"
+#include "common/logger.h"
+
+#include "exif_util.h"
+
+#include <sstream>
+
+namespace extension {
+namespace exif {
+
+namespace {
+const double DOUBLE_ERROR_REPRESENTATION = static_cast<double>(0x7FFFFFFF);
+}  // namespace
+
+Rational::Rational() :
+    nominator(0),
+    denominator(0) {
+}
+
+Rational::Rational(ExifLong nom, ExifLong denom) :
+    nominator(nom),
+    denominator(denom) {
+}
+
+Rational::Rational(const ExifRational& exif_rational) :
+    nominator(exif_rational.numerator),
+    denominator(exif_rational.denominator) {
+}
+
+Rational Rational::createFromDouble(const double value, const long precision) {
+  LoggerD("Entered value:%f precision:%d", value, precision);
+  if (value < 0.0) {
+    LoggerW("Trying to create negative Rational: %f!", value);
+    return Rational();
+  }
+
+  if (value < 0.000000001) {
+    LoggerD("Skipping calculation returning: Rational(0,1)");
+    return Rational(0,1);
+  }
+
+  long m[2][2];
+  double x, startx;
+  long ai;
+
+  startx = x = value;
+
+  // initialize matrix
+  m[0][0] = m[1][1] = 1;
+  m[0][1] = m[1][0] = 0;
+
+  //loop finding terms until daemon gets too big
+  do {
+    ai = static_cast<long>(x);
+    if(m[1][0] * ai + m[1][1] > precision) {
+      break;
+    }
+
+    long t = m[0][0] * ai + m[0][1];
+    m[0][1] = m[0][0];
+    m[0][0] = t;
+
+    t = m[1][0] * ai + m[1][1];
+    m[1][1] = m[1][0];
+    m[1][0] = t;
+
+    if (x == static_cast<double>(ai)) {
+      break;   // AF: division by zero
+    }
+
+    x = 1 / (x - static_cast<double>(ai));
+    if (x > DOUBLE_ERROR_REPRESENTATION) {
+      break;  // AF: representation failure
+    }
+  } while(1);
+
+  // now remaining x is between 0 and 1/ai
+  // approx as either 0 or 1/m where m is max that will fit in precision
+  // first try zero
+  const double error0 = startx - ((double) m[0][0] / (double) m[1][0]);
+  const long numerator0 = m[0][0];
+  const long denominator0 = m[1][0];
+
+  LoggerD("%ld/%ld, error = %e\n", numerator0, denominator0, error0);
+
+  /* now try other possibility */
+  ai = (precision - m[1][1]) / m[1][0];
+  m[0][0] = m[0][0] * ai + m[0][1];
+  m[1][0] = m[1][0] * ai + m[1][1];
+
+  double error1m = startx -
+      (static_cast<double>(m[0][0]) / static_cast<double>(m[1][0]));
+  LoggerD("%ld/%ld, error = %e\n", m[0][0], m[1][0], error1m );
+
+  long result_numerator = 0;
+  long result_denominator = 0;
+
+  if (error0 < error1m ) {
+    result_numerator = numerator0;
+    result_denominator = denominator0;
+  }
+  else {
+    result_numerator = m[0][0];
+    result_denominator = m[1][0];
+  }
+
+  if (result_numerator < 0) {
+    result_numerator *= -1;
+  }
+  if (result_denominator < 0) {
+    result_denominator *= -1;
+  }
+
+  LoggerD("Rational(%d, %d) error0 < error1m:%d", result_numerator, result_denominator,
+      error0 < error1m);
+
+  return Rational(numerator0, denominator0);
+}
+
+Rational Rational::createInvalid() {
+  return Rational(0,0);
+}
+
+bool Rational::isValid() const {
+  if (0 == denominator) {
+    return false;
+  }
+  else {
+    return true;
+  }
+}
+
+double Rational::toDouble() const {
+  if (!isValid()) {
+    return NAN;
+  }
+
+  return (double)nominator / (double)denominator;
+}
+
+Rational Rational::createFromExposureTimeString(const std::string& exp_time) {
+  LoggerD("Entered");
+  if (exp_time.length() == 0) {
+    return Rational::createInvalid();  //lets assume that empty string means 0,
+                       //however exposure time = 0 is not valid value
+  }
+
+  std::string integer_part;
+  std::string fraction_part;
+
+  int first_space_at = -1;
+  int first_slash_at = -1;
+
+  for(size_t i=0; i < exp_time.size(); ++i) {
+
+    const char& cur = exp_time[i];
+    if (first_space_at < 0 && ' ' == cur) {
+      first_space_at = i;
+    }
+    if (first_slash_at < 0 && '/' == cur) {
+      first_slash_at = i;
+    }
+  }
+
+  if (first_slash_at > 0) {
+    if (first_space_at > 0) {
+      integer_part = exp_time.substr(0,first_space_at);
+      fraction_part = exp_time.substr(first_space_at+1,
+          exp_time.size() - (first_space_at+1));
+    }
+    else {
+      fraction_part = exp_time;
+    }
+  }
+  else {
+    integer_part = exp_time;
+  }
+
+  LoggerD("first_space_at: %d first_slash_at:%d int: [%s] , frac: [%s]",
+      first_space_at, first_slash_at, integer_part.c_str(), fraction_part.c_str());
+
+  long integer_value = 0;
+  long nominator = 0;
+  long denominator = 1;
+
+  if (integer_part.length() > 0) {
+    integer_value = atol(integer_part.c_str());
+  }
+
+  if (fraction_part.length() > 0) {
+    if (sscanf(fraction_part.c_str(), "%ld/%ld", &nominator, &denominator) != 2) {
+      LoggerD("Failed to parse nominator/denominator string: [%s]",
+          fraction_part.c_str());
+      return Rational::createInvalid();
+    }
+  }
+
+  nominator += denominator * integer_value;
+  LoggerD("%d/%d -> %f", nominator, denominator, (float)nominator / denominator);
+
+  if (0 == nominator) {
+    //Exposure time = 0 is invalid value
+    return Rational::createInvalid();
+  }
+
+  return Rational(nominator, denominator);
+}
+
+std::string Rational::toString() const {
+  std::stringstream ss;
+  ss << nominator << "/" << denominator;
+  return ss.str();
+}
+
+std::string Rational::toExposureTimeString() const {
+  LoggerD("Entered");
+  if (!isValid() || 0 == nominator) {
+    return std::string();
+  }
+
+  std::string output_str;
+
+  if (nominator < denominator) {
+    output_str = toString();
+  }
+  else if (nominator % denominator == 0) {
+    std::stringstream ss;
+    ss << nominator / denominator;
+    output_str = ss.str();
+  }
+  else {
+    ExifLong new_nominator = nominator % denominator;
+    ExifLong new_denominator = denominator;
+    ExifLong integer_value = nominator / denominator;
+
+    std::stringstream ss;
+    ss << integer_value << " ";
+    ss << new_nominator << "/" << new_denominator;
+    output_str = ss.str();
+  }
+
+  return output_str;
+}
+
+}  // namespace exif
+}  // namespace extension
diff --git a/src/exif/rational.h b/src/exif/rational.h
new file mode 100644 (file)
index 0000000..f2fadcb
--- /dev/null
@@ -0,0 +1,95 @@
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+
+#ifndef EXIF_EXIF_RATIONAL_H_
+#define EXIF_EXIF_RATIONAL_H_
+
+#include <libexif/exif-utils.h>
+#include <libexif/exif-entry.h>
+#include <libexif/exif-data.h>
+
+#include <string>
+#include <vector>
+#include <memory>
+
+namespace extension {
+namespace exif {
+
+class Rational;
+typedef std::vector<Rational> Rationals;
+typedef std::shared_ptr<Rationals> RationalsPtr;
+
+/**
+ * This class represents fraction as nominator/denominator - two ExifLong values
+ * Rational type is present in Exif specification - used for example in GPS coordinates
+ */
+class Rational {
+ public:
+  /**
+   * Default constructor sets to 0/0 - invalud rational number
+   */
+  Rational();
+
+  Rational(ExifLong nom, ExifLong denom);
+  explicit Rational(const ExifRational& exif_rational);
+
+  static Rational createFromDouble(const double value,
+      const long precision = 1000);
+  static Rational createInvalid();
+
+  /**
+   * Returns true if denominator is valid (!= 0) and therefore whole Rational is valid
+   */
+  bool isValid() const;
+
+  double toDouble() const;
+
+  /**
+   * Returns string in format: nominator/denominator,
+   * for example: "1/4", "1/1", "5/3".
+   *
+   */
+  std::string toString() const;
+
+  /**
+   * Create rational number from exposure string
+   * Accepted format "(integer) (nominator/denominator)"
+   * for example:
+   * "1/5", "4/5" - just fraction part
+   * "1", "5" - just integer part
+   * "1 1/5", "4 1/4" - integer + fraction part
+   */
+  static Rational createFromExposureTimeString(const std::string& exp_time);
+
+  /**
+   * Return time exposure string in following format:
+   *
+   * nominator < denominator                 : "1/5", "4/5"
+   * nominator == x*denominator              : "1", "5"
+   * nominator > denominator && nominator != x*denominator : "1 1/5", "4 1/4"
+   */
+  std::string toExposureTimeString() const;
+
+  ExifLong nominator;
+  ExifLong denominator;
+};
+
+}  // namespace exif
+}  // namespace extension
+
+#endif  // EXIF_EXIF_RATIONAL_H_