Initialize Tizen 2.3
[framework/web/wrt-commons.git] / modules_mobile / utils / src / widget_version.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file    widget_version.cpp
18  * @author  Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @version 1.0
20  * @brief   Implementation file for widget version
21  */
22 #include <stddef.h>
23 #include <dpl/utils/widget_version.h>
24 #include <dpl/assert.h>
25 #include <dpl/log/log.h>
26 #include <ctype.h>
27 #include <list>
28
29 namespace // anonymous
30 {
31 size_t WAC_CERTIFY_MANDATORY_PART_LOW_COUNT = 2;
32 size_t WAC_CERTIFY_MANDATORY_PART_HIGH_COUNT = 3;
33 size_t WAC_CERTIFY_MANDATORY_PART_MAJOR_INDEX = 0;
34 size_t WAC_CERTIFY_MANDATORY_PART_MINOR_INDEX = 1;
35 size_t WAC_CERTIFY_MANDATORY_PART_MICRO_INDEX = 2;
36 DPL::String::value_type WAC_CERTIFY_MANDATORY_VS_OPTIONAL_SPLIT_CHAR = L' ';
37 DPL::String::value_type WAC_CERTIFY_MANDATORY_NUMBER_PART_SPLIT_CHAR = L'.';
38 DPL::String::value_type LEADING_ZERO_CHAR = L'0';
39
40 //
41 // [ABNF]
42 // Augmented BNF for Syntax Specifications: ABNF. RFC5234. D. Crocker and P.
43 // Overell. January 2008.
44 //
45 // ALPHA          =  %x41-5A / %x61-7A
46 inline bool IsAlpha(int c)
47 {
48     return (c >= 0x41 && c <= 0x5A) ||
49            (c >= 0x61 && c <= 0x7A);
50 }
51
52 // DIGIT          =  %x30-39
53 inline bool IsDigit(int c)
54 {
55     return c >= 0x30 && c <= 0x39;
56 }
57
58 // SP             =  %x20
59 inline bool IsSp(int c)
60 {
61     return c == 0x20;
62 }
63
64 DPL::String RemoveLeadingZeroes(const DPL::String &str)
65 {
66     Assert(!str.empty());
67
68     if (str[0] != LEADING_ZERO_CHAR) {
69         return str;
70     }
71
72     size_t pos = 0;
73
74     while (pos + 1 < str.size() && str[pos + 1] == LEADING_ZERO_CHAR) {
75         ++pos;
76     }
77
78     return str.substr(pos);
79 }
80
81 // operator <
82 bool NumberLessOperator(const DPL::String &left,
83                         const DPL::String &right)
84 {
85     // Assume: No leading zeroes
86     if (left.size() < right.size()) {
87         return true;
88     }
89
90     if (left.size() > right.size()) {
91         return false;
92     }
93
94     // Now: left.size() == right.size()
95     for (ssize_t i = static_cast<ssize_t>(left.size()) - 1; i >= 0; --i) {
96         if (left[i] < right[i]) {
97             return true;
98         }
99
100         if (left[i] > right[i]) {
101             return false;
102         }
103     }
104
105     // Equal
106     return false;
107 }
108
109 bool WacCertifyNumberString(const DPL::String &str)
110 {
111     for (DPL::String::const_iterator i = str.begin(); i != str.end(); ++i) {
112         if (!IsDigit(*i)) {
113             return false;
114         }
115     }
116
117     return true;
118 }
119
120 bool WacCertifyAlphaNumberStringSpace(const DPL::String &str)
121 {
122     for (DPL::String::const_iterator i = str.begin(); i != str.end(); ++i) {
123         if (!IsDigit(*i) && !IsAlpha(*i) && !IsSp(*i)) {
124             return false;
125         }
126     }
127
128     return true;
129 }
130 } // anonymous
131
132 WidgetVersion::WidgetVersion(const DPL::String &str) :
133     m_isWac(false),
134     m_raw(str)
135 {
136     LogDebug("Parsing version string: " << str);
137
138     // Split optional an mandatory parts
139     size_t optionalPartPosition = str.find(
140             WAC_CERTIFY_MANDATORY_VS_OPTIONAL_SPLIT_CHAR);
141
142     DPL::String mandatoryPart;
143     DPL::Optional<DPL::String> optionalPart;
144
145     if (optionalPartPosition == DPL::String::npos) {
146         mandatoryPart = str;
147     } else {
148         mandatoryPart = str.substr(0, optionalPartPosition);
149         optionalPart = str.substr(optionalPartPosition + 1, DPL::String::npos);
150     }
151
152     LogDebug("Mandatory part is: " << mandatoryPart);
153     LogDebug("Optional part is: " << optionalPart);
154
155     // Split string and construct version
156     std::vector<DPL::String> parts;
157     DPL::Tokenize(mandatoryPart,
158                   WAC_CERTIFY_MANDATORY_NUMBER_PART_SPLIT_CHAR,
159                   std::back_inserter(parts),
160                   false);
161
162     LogDebug("Tokenized mandatory parts: " << parts.size());
163
164     if (parts.size() != WAC_CERTIFY_MANDATORY_PART_LOW_COUNT &&
165         parts.size() != WAC_CERTIFY_MANDATORY_PART_HIGH_COUNT)
166     {
167         return;
168     }
169
170     DPL::String major;
171     DPL::String minor;
172     DPL::Optional<DPL::String> micro;
173
174     // Certify for Wac
175     major = parts[WAC_CERTIFY_MANDATORY_PART_MAJOR_INDEX];
176     minor = parts[WAC_CERTIFY_MANDATORY_PART_MINOR_INDEX];
177
178     if (parts.size() == WAC_CERTIFY_MANDATORY_PART_HIGH_COUNT) {
179         micro = parts[WAC_CERTIFY_MANDATORY_PART_MICRO_INDEX];
180     }
181
182     WacCertify(major, minor, micro, optionalPart);
183 }
184
185 WidgetVersion::WidgetVersion(const DPL::String &major,
186                              const DPL::String &minor,
187                              const DPL::Optional<DPL::String> &micro,
188                              const DPL::Optional<DPL::String> &optional) :
189     m_isWac(false)
190 {
191     // Create Raw version
192     m_raw += major;
193     m_raw += WAC_CERTIFY_MANDATORY_NUMBER_PART_SPLIT_CHAR;
194     m_raw += minor;
195     m_raw += WAC_CERTIFY_MANDATORY_NUMBER_PART_SPLIT_CHAR;
196
197     if (!!micro) {
198         m_raw += *micro;
199     }
200
201     if (!!optional) {
202         m_raw += WAC_CERTIFY_MANDATORY_VS_OPTIONAL_SPLIT_CHAR;
203         m_raw += *optional;
204     }
205
206     // Certify for Wac
207     WacCertify(major, minor, micro, optional);
208 }
209
210 void WidgetVersion::WacCertify(const DPL::String &major,
211                                const DPL::String &minor,
212                                const DPL::Optional<DPL::String> &micro,
213                                const DPL::Optional<DPL::String> &optional)
214 {
215     LogDebug("Certyfing...");
216
217     LogDebug("Major candidate: " << major);
218     LogDebug("Minor candidate: " << minor);
219     LogDebug("Micro candidate: " << micro);
220     LogDebug("Optional candidate: " << optional);
221
222     // Check strings
223     if (major.empty() || !WacCertifyNumberString(major)) {
224         LogDebug("Major version not certified!");
225         return;
226     }
227
228     if (minor.empty() || !WacCertifyNumberString(minor)) {
229         LogDebug("Minor version not certified!");
230         return;
231     }
232
233     if (!!micro && (micro->empty() || !WacCertifyNumberString(*micro))) {
234         LogDebug("Microversion not certified!");
235         return;
236     }
237
238     if (!!optional &&
239         (optional->empty() || !WacCertifyAlphaNumberStringSpace(*optional)))
240     {
241         LogDebug("Optional version not certified!");
242         return;
243     }
244
245     // OK
246     m_major = major;
247     m_minor = minor;
248     m_micro = micro;
249     m_optional = optional;
250
251     m_isWac = true;
252
253     LogDebug("Certified.");
254 }
255
256 bool WidgetVersion::IsWac() const
257 {
258     return m_isWac;
259 }
260
261 const DPL::String &WidgetVersion::Raw() const
262 {
263     return m_raw;
264 }
265
266 const DPL::String &WidgetVersion::Major() const
267 {
268     return m_major;
269 }
270
271 const DPL::String &WidgetVersion::Minor() const
272 {
273     return m_minor;
274 }
275
276 const DPL::Optional<DPL::String> &WidgetVersion::Micro() const
277 {
278     return m_micro;
279 }
280
281 const DPL::Optional<DPL::String> &WidgetVersion::Optional() const
282 {
283     return m_optional;
284 }
285
286 bool operator<(const WidgetVersion &left,
287                const WidgetVersion &right)
288 {
289     Assert(
290         left.IsWac() && right.IsWac() &&
291         "Only WAC version strings are comparable!");
292
293     if (NumberLessOperator(RemoveLeadingZeroes(left.Major()),
294                            RemoveLeadingZeroes(right.Major())))
295     {
296         return true;
297     }
298     if (NumberLessOperator(RemoveLeadingZeroes(right.Major()),
299                            RemoveLeadingZeroes(left.Major())))
300     {
301         return false;
302     }
303
304     if (NumberLessOperator(RemoveLeadingZeroes(left.Minor()),
305                            RemoveLeadingZeroes(right.Minor())))
306     {
307         return true;
308     }
309     if (NumberLessOperator(RemoveLeadingZeroes(right.Minor()),
310                            RemoveLeadingZeroes(left.Minor())))
311     {
312         return false;
313     }
314
315     if (!!left.Micro() && !!right.Micro() &&
316         NumberLessOperator(RemoveLeadingZeroes(*left.Micro()),
317                            RemoveLeadingZeroes(*right.Micro())))
318     {
319         return true;
320     }
321     if (!left.Micro() && !!right.Micro()) {
322         return true;
323     }
324
325     return false;
326 }
327
328 bool operator<=(const WidgetVersion &left,
329                 const WidgetVersion &right)
330 {
331     Assert(
332         left.IsWac() && right.IsWac() &&
333         "Only WAC version strings are comparable!");
334
335     return (left == right) || (left < right);
336 }
337
338 bool operator>(const WidgetVersion &left,
339                const WidgetVersion &right)
340 {
341     Assert(
342         left.IsWac() && right.IsWac() &&
343         "Only WAC version strings are comparable!");
344
345     return !(left <= right);
346 }
347
348 bool operator>=(const WidgetVersion &left,
349                 const WidgetVersion &right)
350 {
351     Assert(
352         left.IsWac() && right.IsWac() &&
353         "Only WAC version strings are comparable!");
354
355     return (left == right) || (left > right);
356 }
357
358 bool operator==(const WidgetVersion &left,
359                 const WidgetVersion &right)
360 {
361     Assert(
362         left.IsWac() && right.IsWac() &&
363         "Only WAC version strings are comparable!");
364
365     //Major are equal
366     //and
367     //Minor are equal
368     //and
369     //Both Micro exist and are equal
370     //or both Micro do not exist
371     return RemoveLeadingZeroes(left.Major()) ==
372            RemoveLeadingZeroes(right.Major()) &&
373            RemoveLeadingZeroes(left.Minor()) ==
374            RemoveLeadingZeroes(right.Minor()) &&
375            (
376                (!!left.Micro() && !!right.Micro() &&
377                 RemoveLeadingZeroes(*left.Micro()) ==
378                 RemoveLeadingZeroes(*right.Micro())) ||
379                (!left.Micro() && !right.Micro())
380            );
381 }
382
383 bool operator!=(const WidgetVersion &left,
384                 const WidgetVersion &right)
385 {
386     Assert(
387         left.IsWac() && right.IsWac() &&
388         "Only WAC version strings are comparable!");
389
390     return !(left == right);
391 }
392
393 std::ostream & operator<<(std::ostream& stream,
394                           const WidgetVersion& version)
395 {
396     stream << version.Raw();
397     return stream;
398 }