Update wrt-commons_0.2.53
[framework/web/wrt-commons.git] / modules / 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 <dpl/utils/widget_version.h>
23 #include <dpl/assert.h>
24 #include <dpl/log/log.h>
25 #include <ctype.h>
26 #include <list>
27
28 namespace // anonymous
29 {
30 size_t WAC_CERTIFY_MANDATORY_PART_LOW_COUNT = 2;
31 size_t WAC_CERTIFY_MANDATORY_PART_HIGH_COUNT = 3;
32 size_t WAC_CERTIFY_MANDATORY_PART_MAJOR_INDEX = 0;
33 size_t WAC_CERTIFY_MANDATORY_PART_MINOR_INDEX = 1;
34 size_t WAC_CERTIFY_MANDATORY_PART_MICRO_INDEX = 2;
35 DPL::String::value_type WAC_CERTIFY_MANDATORY_VS_OPTIONAL_SPLIT_CHAR = L' ';
36 DPL::String::value_type WAC_CERTIFY_MANDATORY_NUMBER_PART_SPLIT_CHAR = L'.';
37 DPL::String::value_type LEADING_ZERO_CHAR = L'0';
38
39 //
40 // [ABNF]
41 // Augmented BNF for Syntax Specifications: ABNF. RFC5234. D. Crocker and P. Overell. January 2008.
42 //
43 // ALPHA          =  %x41-5A / %x61-7A
44 inline bool IsAlpha(int c)
45 {
46     return (c >= 0x41 && c <= 0x5A) ||
47            (c >= 0x61 && c <= 0x7A);
48 }
49
50 // DIGIT          =  %x30-39
51 inline bool IsDigit(int c)
52 {
53     return c >= 0x30 && c <= 0x39;
54 }
55
56 // SP             =  %x20
57 inline bool IsSp(int c)
58 {
59     return c == 0x20;
60 }
61
62 DPL::String RemoveLeadingZeroes(const DPL::String &str)
63 {
64     Assert(!str.empty());
65
66     if (str[0] != LEADING_ZERO_CHAR) {
67         return str;
68     }
69
70     size_t pos = 0;
71
72     while (pos + 1 < str.size() && str[pos + 1] == LEADING_ZERO_CHAR) {
73         ++pos;
74     }
75
76     return str.substr(pos);
77 }
78
79 // operator <
80 bool NumberLessOperator(const DPL::String &left,
81         const DPL::String &right)
82 {
83     // Assume: No leading zeroes
84     if (left.size() < right.size()) {
85         return true;
86     }
87
88     if (left.size() > right.size()) {
89         return false;
90     }
91
92     // Now: left.size() == right.size()
93     for (ssize_t i = static_cast<ssize_t>(left.size()) - 1; i >= 0; --i) {
94         if (left[i] < right[i]) {
95             return true;
96         }
97
98         if (left[i] > right[i]) {
99             return false;
100         }
101     }
102
103     // Equal
104     return false;
105 }
106
107 bool WacCertifyNumberString(const DPL::String &str)
108 {
109     for (DPL::String::const_iterator i = str.begin(); i != str.end(); ++i) {
110         if (!IsDigit(*i)) {
111             return false;
112         }
113     }
114
115     return true;
116 }
117
118 bool WacCertifyAlphaNumberStringSpace(const DPL::String &str)
119 {
120     for (DPL::String::const_iterator i = str.begin(); i != str.end(); ++i) {
121         if (!IsDigit(*i) && !IsAlpha(*i) && !IsSp(*i)) {
122             return false;
123         }
124     }
125
126     return true;
127 }
128 } // anonymous
129
130 WidgetVersion::WidgetVersion(const DPL::String &str) :
131     m_isWac(false),
132     m_raw(str)
133 {
134     LogDebug("Parsing version string: " << str);
135
136     // Split optional an mandatory parts
137     size_t optionalPartPosition = str.find(
138             WAC_CERTIFY_MANDATORY_VS_OPTIONAL_SPLIT_CHAR);
139
140     DPL::String mandatoryPart;
141     DPL::Optional<DPL::String> optionalPart;
142
143     if (optionalPartPosition == DPL::String::npos) {
144         mandatoryPart = str;
145     } else {
146         mandatoryPart = str.substr(0, optionalPartPosition);
147         optionalPart = str.substr(optionalPartPosition + 1, DPL::String::npos);
148     }
149
150     LogDebug("Mandatory part is: " << mandatoryPart);
151     LogDebug("Optional part is: " << optionalPart);
152
153     // Split string and construct version
154     std::vector<DPL::String> parts;
155     DPL::Tokenize(mandatoryPart,
156                   WAC_CERTIFY_MANDATORY_NUMBER_PART_SPLIT_CHAR,
157                   std::back_inserter(parts),
158                   false);
159
160     LogDebug("Tokenized mandatory parts: " << parts.size());
161
162     if (parts.size() != WAC_CERTIFY_MANDATORY_PART_LOW_COUNT &&
163         parts.size() != WAC_CERTIFY_MANDATORY_PART_HIGH_COUNT) {
164         return;
165     }
166
167     DPL::String major;
168     DPL::String minor;
169     DPL::Optional<DPL::String> micro;
170
171     // Certify for Wac
172     major = parts[WAC_CERTIFY_MANDATORY_PART_MAJOR_INDEX];
173     minor = parts[WAC_CERTIFY_MANDATORY_PART_MINOR_INDEX];
174
175     if (parts.size() == WAC_CERTIFY_MANDATORY_PART_HIGH_COUNT) {
176         micro = parts[WAC_CERTIFY_MANDATORY_PART_MICRO_INDEX];
177     }
178
179     WacCertify(major, minor, micro, optionalPart);
180 }
181
182 WidgetVersion::WidgetVersion(const DPL::String &major,
183         const DPL::String &minor,
184         const DPL::Optional<DPL::String> &micro,
185         const DPL::Optional<DPL::String> &optional) :
186     m_isWac(false)
187 {
188     // Create Raw version
189     m_raw += major;
190     m_raw += WAC_CERTIFY_MANDATORY_NUMBER_PART_SPLIT_CHAR;
191     m_raw += minor;
192     m_raw += WAC_CERTIFY_MANDATORY_NUMBER_PART_SPLIT_CHAR;
193
194     if (!!micro) {
195         m_raw += *micro;
196     }
197
198     if (!!optional) {
199         m_raw += WAC_CERTIFY_MANDATORY_VS_OPTIONAL_SPLIT_CHAR;
200         m_raw += *optional;
201     }
202
203     // Certify for Wac
204     WacCertify(major, minor, micro, optional);
205 }
206
207 void WidgetVersion::WacCertify(const DPL::String &major,
208         const DPL::String &minor,
209         const DPL::Optional<DPL::String> &micro,
210         const DPL::Optional<DPL::String> &optional)
211 {
212     LogDebug("Certyfing...");
213
214     LogDebug("Major candidate: " << major);
215     LogDebug("Minor candidate: " << minor);
216     LogDebug("Micro candidate: " << micro);
217     LogDebug("Optional candidate: " << optional);
218
219     // Check strings
220     if (major.empty() || !WacCertifyNumberString(major)) {
221         LogDebug("Major version not certified!");
222         return;
223     }
224
225     if (minor.empty() || !WacCertifyNumberString(minor)) {
226         LogDebug("Minor version not certified!");
227         return;
228     }
229
230     if (!!micro && (micro->empty() || !WacCertifyNumberString(*micro))) {
231         LogDebug("Microversion not certified!");
232         return;
233     }
234
235     if (!!optional &&
236         (optional->empty() || !WacCertifyAlphaNumberStringSpace(*optional))) {
237         LogDebug("Optional version not certified!");
238         return;
239     }
240
241     // OK
242     m_major = major;
243     m_minor = minor;
244     m_micro = micro;
245     m_optional = optional;
246
247     m_isWac = true;
248
249     LogDebug("Certified.");
250 }
251
252 bool WidgetVersion::IsWac() const
253 {
254     return m_isWac;
255 }
256
257 const DPL::String &WidgetVersion::Raw() const
258 {
259     return m_raw;
260 }
261
262 const DPL::String &WidgetVersion::Major() const
263 {
264     return m_major;
265 }
266
267 const DPL::String &WidgetVersion::Minor() const
268 {
269     return m_minor;
270 }
271
272 const DPL::Optional<DPL::String> &WidgetVersion::Micro() const
273 {
274     return m_micro;
275 }
276
277 const DPL::Optional<DPL::String> &WidgetVersion::Optional() const
278 {
279     return m_optional;
280 }
281
282 bool operator<(const WidgetVersion &left,
283         const WidgetVersion &right)
284 {
285     Assert(
286         left.IsWac() && right.IsWac() &&
287         "Only WAC version strings are comparable!");
288
289     if (NumberLessOperator(RemoveLeadingZeroes(left.Major()),
290                            RemoveLeadingZeroes(right.Major()))) { return true; }
291     if (NumberLessOperator(RemoveLeadingZeroes(right.Major()),
292                            RemoveLeadingZeroes(left.Major()))) { return false; }
293
294     if (NumberLessOperator(RemoveLeadingZeroes(left.Minor()),
295                            RemoveLeadingZeroes(right.Minor()))) { return true; }
296     if (NumberLessOperator(RemoveLeadingZeroes(right.Minor()),
297                            RemoveLeadingZeroes(left.Minor()))) { return false; }
298
299     if (!!left.Micro() && !!right.Micro() &&
300         NumberLessOperator(RemoveLeadingZeroes(*left.Micro()),
301                            RemoveLeadingZeroes(*right.Micro()))) { return true; }
302     if (!left.Micro() && !!right.Micro()) { return true; }
303
304     return false;
305 }
306
307 bool operator<=(const WidgetVersion &left,
308         const WidgetVersion &right)
309 {
310     Assert(
311         left.IsWac() && right.IsWac() &&
312         "Only WAC version strings are comparable!");
313
314     return (left == right) || (left < right);
315 }
316
317 bool operator>(const WidgetVersion &left,
318         const WidgetVersion &right)
319 {
320     Assert(
321         left.IsWac() && right.IsWac() &&
322         "Only WAC version strings are comparable!");
323
324     return !(left <= right);
325 }
326
327 bool operator>=(const WidgetVersion &left,
328         const WidgetVersion &right)
329 {
330     Assert(
331         left.IsWac() && right.IsWac() &&
332         "Only WAC version strings are comparable!");
333
334     return (left == right) || (left > right);
335 }
336
337 bool operator==(const WidgetVersion &left,
338         const WidgetVersion &right)
339 {
340     Assert(
341         left.IsWac() && right.IsWac() &&
342         "Only WAC version strings are comparable!");
343
344     return RemoveLeadingZeroes(left.Major()) ==
345            RemoveLeadingZeroes(right.Major()) &&                                       // Major are equal
346            RemoveLeadingZeroes(left.Minor()) ==
347            RemoveLeadingZeroes(right.Minor()) &&                                       // and Minor are equal
348            (                                                                           // and ...
349                (!!left.Micro() && !!right.Micro() &&
350                 RemoveLeadingZeroes(*left.Micro()) ==
351                 RemoveLeadingZeroes(*right.Micro())) ||                                                                              // Both Micro exist and are equal
352                (!left.Micro() && !right.Micro())                                                                                     // or both Micro do not exist
353            );
354 }
355
356 bool operator!=(const WidgetVersion &left,
357         const WidgetVersion &right)
358 {
359     Assert(
360         left.IsWac() && right.IsWac() &&
361         "Only WAC version strings are comparable!");
362
363     return !(left == right);
364 }
365
366 std::ostream & operator<<(std::ostream& stream,
367         const WidgetVersion& version)
368 {
369     stream << version.Raw();
370     return stream;
371 }