6e2ed4a9171e18b82ed28d202c51cd1942ded5e8
[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 <stddef.h>
23 #include <dpl/utils/widget_version.h>
24 #include <dpl/assert.h>
25 #include <dpl/log/wrt_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()) {
75         ++pos;
76
77         if (str[pos] != LEADING_ZERO_CHAR)
78             break;
79     }
80
81     return str.substr(pos);
82 }
83
84 // operator <
85 bool NumberLessOperator(const DPL::String &left,
86                         const DPL::String &right)
87 {
88     // Assume: No leading zeroes
89     if (left.size() < right.size()) {
90         return true;
91     }
92
93     if (left.size() > right.size()) {
94         return false;
95     }
96
97     // Now: left.size() == right.size()
98     for (ssize_t i = static_cast<ssize_t>(left.size()) - 1; i >= 0; --i) {
99         if (left[i] < right[i]) {
100             return true;
101         }
102
103         if (left[i] > right[i]) {
104             return false;
105         }
106     }
107
108     // Equal
109     return false;
110 }
111
112 bool WacCertifyNumberString(const DPL::String &str)
113 {
114     for (DPL::String::const_iterator i = str.begin(); i != str.end(); ++i) {
115         if (!IsDigit(*i)) {
116             return false;
117         }
118     }
119
120     return true;
121 }
122
123 bool WacCertifyAlphaNumberStringSpace(const DPL::String &str)
124 {
125     for (DPL::String::const_iterator i = str.begin(); i != str.end(); ++i) {
126         if (!IsDigit(*i) && !IsAlpha(*i) && !IsSp(*i)) {
127             return false;
128         }
129     }
130
131     return true;
132 }
133 } // anonymous
134
135 WidgetVersion::WidgetVersion(const DPL::String &str) :
136     m_isWac(false),
137     m_raw(str)
138 {
139     WrtLogD("Parsing version string: %ls", str.c_str());
140
141     // Split optional an mandatory parts
142     size_t optionalPartPosition = str.find(
143             WAC_CERTIFY_MANDATORY_VS_OPTIONAL_SPLIT_CHAR);
144
145     DPL::String mandatoryPart;
146     DPL::OptionalString optionalPart;
147
148     if (optionalPartPosition == DPL::String::npos) {
149         mandatoryPart = str;
150     } else {
151         mandatoryPart = str.substr(0, optionalPartPosition);
152         optionalPart = str.substr(optionalPartPosition + 1, DPL::String::npos);
153     }
154
155     WrtLogD("Mandatory part is: %ls", mandatoryPart.c_str());
156     WrtLogD("Optional part is: %ls",
157         optionalPart.get_value_or(DPL::String()).c_str());
158
159     // Split string and construct version
160     std::vector<DPL::String> parts;
161     DPL::Tokenize(mandatoryPart,
162                   WAC_CERTIFY_MANDATORY_NUMBER_PART_SPLIT_CHAR,
163                   std::back_inserter(parts),
164                   false);
165
166     WrtLogD("Tokenized mandatory parts: %i", parts.size());
167
168     if (parts.size() != WAC_CERTIFY_MANDATORY_PART_LOW_COUNT &&
169         parts.size() != WAC_CERTIFY_MANDATORY_PART_HIGH_COUNT)
170     {
171         return;
172     }
173
174     DPL::String major;
175     DPL::String minor;
176     DPL::OptionalString micro;
177
178     // Certify for Wac
179     major = parts[WAC_CERTIFY_MANDATORY_PART_MAJOR_INDEX];
180     minor = parts[WAC_CERTIFY_MANDATORY_PART_MINOR_INDEX];
181
182     if (parts.size() == WAC_CERTIFY_MANDATORY_PART_HIGH_COUNT) {
183         micro = parts[WAC_CERTIFY_MANDATORY_PART_MICRO_INDEX];
184     }
185
186     WacCertify(major, minor, micro, optionalPart);
187 }
188
189 WidgetVersion::WidgetVersion(const DPL::String &major,
190                              const DPL::String &minor,
191                              const DPL::OptionalString &micro,
192                              const DPL::OptionalString &optional) :
193     m_isWac(false)
194 {
195     // Create Raw version
196     m_raw += major;
197     m_raw += WAC_CERTIFY_MANDATORY_NUMBER_PART_SPLIT_CHAR;
198     m_raw += minor;
199
200     if (!!micro) {
201         m_raw += WAC_CERTIFY_MANDATORY_NUMBER_PART_SPLIT_CHAR;
202         m_raw += *micro;
203     }
204
205     if (!!optional) {
206         m_raw += WAC_CERTIFY_MANDATORY_VS_OPTIONAL_SPLIT_CHAR;
207         m_raw += *optional;
208     }
209
210     // Certify for Wac
211     WacCertify(major, minor, micro, optional);
212 }
213
214 void WidgetVersion::WacCertify(const DPL::String &major,
215                                const DPL::String &minor,
216                                const DPL::OptionalString &micro,
217                                const DPL::OptionalString &optional)
218 {
219     WrtLogD("Certyfing...");
220
221     WrtLogD("Major candidate: %ls", major.c_str());
222     WrtLogD("Minor candidate: %ls", minor.c_str());
223     WrtLogD("Micro candidate: %ls", micro.get_value_or(DPL::String()).c_str());
224     WrtLogD("Optional candidate: %ls",
225         optional.get_value_or(DPL::String()).c_str());
226
227     // Check strings
228     if (major.empty() || !WacCertifyNumberString(major)) {
229         WrtLogD("Major version not certified!");
230         return;
231     }
232
233     if (minor.empty() || !WacCertifyNumberString(minor)) {
234         WrtLogD("Minor version not certified!");
235         return;
236     }
237
238     if (!!micro && (micro->empty() || !WacCertifyNumberString(*micro))) {
239         WrtLogD("Microversion not certified!");
240         return;
241     }
242
243     if (!!optional &&
244         (optional->empty() || !WacCertifyAlphaNumberStringSpace(*optional)))
245     {
246         WrtLogD("Optional version not certified!");
247         return;
248     }
249
250     // OK
251     m_major = major;
252     m_minor = minor;
253     m_micro = micro;
254     m_optional = optional;
255
256     m_isWac = true;
257
258     WrtLogD("Certified.");
259 }
260
261 bool WidgetVersion::IsWac() const
262 {
263     return m_isWac;
264 }
265
266 const DPL::String &WidgetVersion::Raw() const
267 {
268     return m_raw;
269 }
270
271 const DPL::String &WidgetVersion::Major() const
272 {
273     return m_major;
274 }
275
276 const DPL::String &WidgetVersion::Minor() const
277 {
278     return m_minor;
279 }
280
281 const DPL::OptionalString &WidgetVersion::Micro() const
282 {
283     return m_micro;
284 }
285
286 const DPL::OptionalString &WidgetVersion::Optional() const
287 {
288     return m_optional;
289 }
290
291 bool operator<(const WidgetVersion &left,
292                const WidgetVersion &right)
293 {
294     AssertMsg(
295         left.IsWac() && right.IsWac(),
296         "Only WAC version strings are comparable!");
297
298     if (NumberLessOperator(RemoveLeadingZeroes(left.Major()),
299                            RemoveLeadingZeroes(right.Major())))
300     {
301         return true;
302     }
303     if (NumberLessOperator(RemoveLeadingZeroes(right.Major()),
304                            RemoveLeadingZeroes(left.Major())))
305     {
306         return false;
307     }
308
309     if (NumberLessOperator(RemoveLeadingZeroes(left.Minor()),
310                            RemoveLeadingZeroes(right.Minor())))
311     {
312         return true;
313     }
314     if (NumberLessOperator(RemoveLeadingZeroes(right.Minor()),
315                            RemoveLeadingZeroes(left.Minor())))
316     {
317         return false;
318     }
319
320     if (!!left.Micro() && !!right.Micro() &&
321         NumberLessOperator(RemoveLeadingZeroes(*left.Micro()),
322                            RemoveLeadingZeroes(*right.Micro())))
323     {
324         return true;
325     }
326     if (!left.Micro() && !!right.Micro()) {
327         return true;
328     }
329
330     return false;
331 }
332
333 bool operator<=(const WidgetVersion &left,
334                 const WidgetVersion &right)
335 {
336     AssertMsg(
337         left.IsWac() && right.IsWac(),
338         "Only WAC version strings are comparable!");
339
340     return (left == right) || (left < right);
341 }
342
343 bool operator>(const WidgetVersion &left,
344                const WidgetVersion &right)
345 {
346     AssertMsg(
347         left.IsWac() && right.IsWac(),
348         "Only WAC version strings are comparable!");
349
350     return !(left <= right);
351 }
352
353 bool operator>=(const WidgetVersion &left,
354                 const WidgetVersion &right)
355 {
356     AssertMsg(
357         left.IsWac() && right.IsWac(),
358         "Only WAC version strings are comparable!");
359
360     return (left == right) || (left > right);
361 }
362
363 bool operator==(const WidgetVersion &left,
364                 const WidgetVersion &right)
365 {
366     AssertMsg(
367         left.IsWac() && right.IsWac(),
368         "Only WAC version strings are comparable!");
369
370     //Major are equal
371     //and
372     //Minor are equal
373     //and
374     //Both Micro exist and are equal
375     //or both Micro do not exist
376     return RemoveLeadingZeroes(left.Major()) ==
377            RemoveLeadingZeroes(right.Major()) &&
378            RemoveLeadingZeroes(left.Minor()) ==
379            RemoveLeadingZeroes(right.Minor()) &&
380            (
381                (!!left.Micro() && !!right.Micro() &&
382                 RemoveLeadingZeroes(*left.Micro()) ==
383                 RemoveLeadingZeroes(*right.Micro())) ||
384                (!left.Micro() && !right.Micro())
385            );
386 }
387
388 bool operator!=(const WidgetVersion &left,
389                 const WidgetVersion &right)
390 {
391     AssertMsg(
392         left.IsWac() && right.IsWac(),
393         "Only WAC version strings are comparable!");
394
395     return !(left == right);
396 }
397
398 std::ostream & operator<<(std::ostream& stream,
399                           const WidgetVersion& version)
400 {
401     stream << version.Raw();
402     return stream;
403 }