tizen 2.3.1 release
[framework/web/wearable/wrt-plugins-tizen.git] / src / Exif / Rational.cpp
1 //
2 // Tizen Web Device API
3 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 #include "Rational.h"
19
20 #include <Logger.h>
21
22 namespace DeviceAPI {
23 namespace Exif {
24
25 namespace {
26 const double DOUBLE_ERROR_REPRESENTATION = static_cast<double>(0x7FFFFFFF);
27 } //anonymous namespace
28
29 Rational::Rational() :
30         nominator(0),
31         denominator(0)
32 {
33 }
34
35 Rational::Rational(ExifLong nom, ExifLong denom) :
36         nominator(nom),
37         denominator(denom)
38 {
39 }
40
41 Rational::Rational(const ExifRational& exif_rational) :
42         nominator(exif_rational.numerator),
43         denominator(exif_rational.denominator)
44 {
45 }
46
47 Rational Rational::createFromDouble(const double value, const long precision)
48 {
49     LOGD("Entered value:%f precision:%d", value, precision);
50     if (value < 0.0) {
51         LOGW("Trying to create negative Rational: %f!", value);
52         return Rational();
53     }
54
55     if (value < 0.000000001) {
56         LOGD("Skipping calculation returning: Rational(0,1)");
57         return Rational(0,1);
58     }
59
60     long m[2][2];
61     double x, startx;
62     long ai;
63
64     startx = x = value;
65
66     // initialize matrix
67     m[0][0] = m[1][1] = 1;
68     m[0][1] = m[1][0] = 0;
69
70     //loop finding terms until denom gets too big
71     do {
72         ai = static_cast<long>(x);
73         if(m[1][0] * ai + m[1][1] > precision) {
74             break;
75         }
76
77         long t = m[0][0] * ai + m[0][1];
78         m[0][1] = m[0][0];
79         m[0][0] = t;
80
81         t = m[1][0] * ai + m[1][1];
82         m[1][1] = m[1][0];
83         m[1][0] = t;
84
85         if (x == static_cast<double>(ai)) {
86             break;     // AF: division by zero
87         }
88
89         x = 1 / (x - static_cast<double>(ai));
90         if (x > DOUBLE_ERROR_REPRESENTATION) {
91             break;  // AF: representation failure
92         }
93     } while(1);
94
95     // now remaining x is between 0 and 1/ai
96     // approx as either 0 or 1/m where m is max that will fit in precision
97     // first try zero
98     const long numerator0 = m[0][0];
99     const long denominator0 = m[1][0];
100
101     return Rational(numerator0, denominator0);
102 }
103
104 Rational Rational::createInvalid()
105 {
106     return Rational(0,0);
107 }
108
109 bool Rational::isValid() const
110 {
111     if (0 == denominator) {
112         return false;
113     }
114     else {
115         return true;
116     }
117 }
118
119 double Rational::toDouble() const
120 {
121     if (!isValid()) {
122         return NAN;
123     }
124
125     return (double)nominator / (double)denominator;
126 }
127
128 Rational Rational::createFromExposureTimeString(const std::string& exp_time)
129 {
130     LOGD("Entered");
131     if (exp_time.length() == 0) {
132         return Rational::createInvalid();  //lets assume that empty string means 0,
133                                            //however exposure time = 0 is not valid value
134     }
135
136     std::string integer_part;
137     std::string fraction_part;
138
139     int first_space_at = -1;
140     int first_slash_at = -1;
141
142     for(size_t i=0; i < exp_time.size(); ++i) {
143
144         const char& cur = exp_time[i];
145         if (first_space_at < 0 && ' ' == cur) {
146             first_space_at = i;
147         }
148         if (first_slash_at < 0 && '/' == cur) {
149             first_slash_at = i;
150         }
151     }
152
153     if (first_slash_at > 0) {
154         if (first_space_at > 0) {
155             integer_part = exp_time.substr(0,first_space_at);
156             fraction_part = exp_time.substr(first_space_at+1,
157                     exp_time.size() - (first_space_at+1));
158         }
159         else {
160             fraction_part = exp_time;
161         }
162     }
163     else {
164         integer_part = exp_time;
165     }
166
167     LOGD("first_space_at: %d first_slash_at:%d int: [%s] , frac: [%s]",
168             first_space_at, first_slash_at, integer_part.c_str(), fraction_part.c_str());
169
170     long integer_value = 0;
171     long nominator = 0;
172     long denominator = 1;
173
174     if (integer_part.length() > 0) {
175         integer_value = atol(integer_part.c_str());
176     }
177
178     if (fraction_part.length() > 0) {
179         if (sscanf(fraction_part.c_str(), "%ld/%ld", &nominator, &denominator) != 2) {
180             LOGD("Failed to parse nominator/denominator string: [%s]",
181                     fraction_part.c_str());
182             return Rational::createInvalid();
183         }
184     }
185
186     nominator += denominator * integer_value;
187     LOGD("%d/%d -> %f", nominator, denominator, (float)nominator / denominator);
188
189     if (0 == nominator) {
190         //Exposure time = 0 is invalid value
191         return Rational::createInvalid();
192     }
193
194     return Rational(nominator, denominator);
195 }
196
197 std::string Rational::toString() const
198 {
199     std::stringstream ss;
200     ss << nominator << "/" << denominator;
201     return ss.str();
202 }
203
204 std::string Rational::toExposureTimeString() const
205 {
206     LOGD("Entered");
207     if (!isValid() || 0 == nominator) {
208         return std::string();
209     }
210
211     std::string output_str;
212
213     if (nominator < denominator) {
214         output_str = toString();
215     }
216     else if (nominator % denominator == 0) {
217         std::stringstream ss;
218         ss << nominator / denominator;
219         output_str = ss.str();
220     }
221     else {
222         ExifLong new_nominator = nominator % denominator;
223         ExifLong new_denominator = denominator;
224         ExifLong integer_value = nominator / denominator;
225
226         std::stringstream ss;
227         ss << integer_value << " ";
228         ss << new_nominator << "/" << new_denominator;
229         output_str = ss.str();
230     }
231
232     return output_str;
233 }
234
235 } // Exif
236 } // DeviceAPI