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