Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "nsVersionComparator.h"
7 #include <stdlib.h>
8 #include <string.h>
9 #include <stdint.h>
10 #if defined(XP_WIN) && !defined(UPDATER_NO_STRING_GLUE_STL)
11 #include <wchar.h>
12 #include "nsStringGlue.h"
13 #endif
15 struct VersionPart {
16 int32_t numA;
18 const char *strB; // NOT null-terminated, can be a null pointer
19 uint32_t strBlen;
21 int32_t numC;
23 char *extraD; // null-terminated
24 };
26 #ifdef XP_WIN
27 struct VersionPartW {
28 int32_t numA;
30 wchar_t *strB; // NOT null-terminated, can be a null pointer
31 uint32_t strBlen;
33 int32_t numC;
35 wchar_t *extraD; // null-terminated
37 };
38 #endif
40 /**
41 * Parse a version part into a number and "extra text".
42 *
43 * @returns A pointer to the next versionpart, or null if none.
44 */
45 static char*
46 ParseVP(char *part, VersionPart &result)
47 {
48 char *dot;
50 result.numA = 0;
51 result.strB = nullptr;
52 result.strBlen = 0;
53 result.numC = 0;
54 result.extraD = nullptr;
56 if (!part)
57 return part;
59 dot = strchr(part, '.');
60 if (dot)
61 *dot = '\0';
63 if (part[0] == '*' && part[1] == '\0') {
64 result.numA = INT32_MAX;
65 result.strB = "";
66 }
67 else {
68 result.numA = strtol(part, const_cast<char**>(&result.strB), 10);
69 }
71 if (!*result.strB) {
72 result.strB = nullptr;
73 result.strBlen = 0;
74 }
75 else {
76 if (result.strB[0] == '+') {
77 static const char kPre[] = "pre";
79 ++result.numA;
80 result.strB = kPre;
81 result.strBlen = sizeof(kPre) - 1;
82 }
83 else {
84 const char *numstart = strpbrk(result.strB, "0123456789+-");
85 if (!numstart) {
86 result.strBlen = strlen(result.strB);
87 }
88 else {
89 result.strBlen = numstart - result.strB;
91 result.numC = strtol(numstart, &result.extraD, 10);
92 if (!*result.extraD)
93 result.extraD = nullptr;
94 }
95 }
96 }
98 if (dot) {
99 ++dot;
101 if (!*dot)
102 dot = nullptr;
103 }
105 return dot;
106 }
109 /**
110 * Parse a version part into a number and "extra text".
111 *
112 * @returns A pointer to the next versionpart, or null if none.
113 */
114 #ifdef XP_WIN
115 static wchar_t*
116 ParseVP(wchar_t *part, VersionPartW &result)
117 {
119 wchar_t *dot;
121 result.numA = 0;
122 result.strB = nullptr;
123 result.strBlen = 0;
124 result.numC = 0;
125 result.extraD = nullptr;
127 if (!part)
128 return part;
130 dot = wcschr(part, '.');
131 if (dot)
132 *dot = '\0';
134 if (part[0] == '*' && part[1] == '\0') {
135 result.numA = INT32_MAX;
136 result.strB = L"";
137 }
138 else {
139 result.numA = wcstol(part, const_cast<wchar_t**>(&result.strB), 10);
140 }
142 if (!*result.strB) {
143 result.strB = nullptr;
144 result.strBlen = 0;
145 }
146 else {
147 if (result.strB[0] == '+') {
148 static wchar_t kPre[] = L"pre";
150 ++result.numA;
151 result.strB = kPre;
152 result.strBlen = sizeof(kPre) - 1;
153 }
154 else {
155 const wchar_t *numstart = wcspbrk(result.strB, L"0123456789+-");
156 if (!numstart) {
157 result.strBlen = wcslen(result.strB);
158 }
159 else {
160 result.strBlen = numstart - result.strB;
162 result.numC = wcstol(numstart, &result.extraD, 10);
163 if (!*result.extraD)
164 result.extraD = nullptr;
165 }
166 }
167 }
169 if (dot) {
170 ++dot;
172 if (!*dot)
173 dot = nullptr;
174 }
176 return dot;
177 }
178 #endif
180 // compare two null-terminated strings, which may be null pointers
181 static int32_t
182 ns_strcmp(const char *str1, const char *str2)
183 {
184 // any string is *before* no string
185 if (!str1)
186 return str2 != 0;
188 if (!str2)
189 return -1;
191 return strcmp(str1, str2);
192 }
194 // compare two length-specified string, which may be null pointers
195 static int32_t
196 ns_strnncmp(const char *str1, uint32_t len1, const char *str2, uint32_t len2)
197 {
198 // any string is *before* no string
199 if (!str1)
200 return str2 != 0;
202 if (!str2)
203 return -1;
205 for (; len1 && len2; --len1, --len2, ++str1, ++str2) {
206 if (*str1 < *str2)
207 return -1;
209 if (*str1 > *str2)
210 return 1;
211 }
213 if (len1 == 0)
214 return len2 == 0 ? 0 : -1;
216 return 1;
217 }
219 // compare two int32_t
220 static int32_t
221 ns_cmp(int32_t n1, int32_t n2)
222 {
223 if (n1 < n2)
224 return -1;
226 return n1 != n2;
227 }
229 /**
230 * Compares two VersionParts
231 */
232 static int32_t
233 CompareVP(VersionPart &v1, VersionPart &v2)
234 {
235 int32_t r = ns_cmp(v1.numA, v2.numA);
236 if (r)
237 return r;
239 r = ns_strnncmp(v1.strB, v1.strBlen, v2.strB, v2.strBlen);
240 if (r)
241 return r;
243 r = ns_cmp(v1.numC, v2.numC);
244 if (r)
245 return r;
247 return ns_strcmp(v1.extraD, v2.extraD);
248 }
250 /**
251 * Compares two VersionParts
252 */
253 #ifdef XP_WIN
254 static int32_t
255 CompareVP(VersionPartW &v1, VersionPartW &v2)
256 {
257 int32_t r = ns_cmp(v1.numA, v2.numA);
258 if (r)
259 return r;
261 r = wcsncmp(v1.strB, v2.strB, XPCOM_MIN(v1.strBlen,v2.strBlen));
262 if (r)
263 return r;
265 r = ns_cmp(v1.numC, v2.numC);
266 if (r)
267 return r;
269 if (!v1.extraD)
270 return v2.extraD != 0;
272 if (!v2.extraD)
273 return -1;
275 return wcscmp(v1.extraD, v2.extraD);
276 }
277 #endif
279 namespace mozilla {
281 #ifdef XP_WIN
282 int32_t
283 CompareVersions(const char16_t *A, const char16_t *B)
284 {
285 wchar_t *A2 = wcsdup(char16ptr_t(A));
286 if (!A2)
287 return 1;
289 wchar_t *B2 = wcsdup(char16ptr_t(B));
290 if (!B2) {
291 free(A2);
292 return 1;
293 }
295 int32_t result;
296 wchar_t *a = A2, *b = B2;
298 do {
299 VersionPartW va, vb;
301 a = ParseVP(a, va);
302 b = ParseVP(b, vb);
304 result = CompareVP(va, vb);
305 if (result)
306 break;
308 } while (a || b);
310 free(A2);
311 free(B2);
313 return result;
314 }
315 #endif
317 int32_t
318 CompareVersions(const char *A, const char *B)
319 {
320 char *A2 = strdup(A);
321 if (!A2)
322 return 1;
324 char *B2 = strdup(B);
325 if (!B2) {
326 free(A2);
327 return 1;
328 }
330 int32_t result;
331 char *a = A2, *b = B2;
333 do {
334 VersionPart va, vb;
336 a = ParseVP(a, va);
337 b = ParseVP(b, vb);
339 result = CompareVP(va, vb);
340 if (result)
341 break;
343 } while (a || b);
345 free(A2);
346 free(B2);
348 return result;
349 }
351 } // namespace mozilla