xpcom/glue/nsVersionComparator.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:d060090d972e
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/. */
4
5 #include "nsVersionComparator.h"
6
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
14
15 struct VersionPart {
16 int32_t numA;
17
18 const char *strB; // NOT null-terminated, can be a null pointer
19 uint32_t strBlen;
20
21 int32_t numC;
22
23 char *extraD; // null-terminated
24 };
25
26 #ifdef XP_WIN
27 struct VersionPartW {
28 int32_t numA;
29
30 wchar_t *strB; // NOT null-terminated, can be a null pointer
31 uint32_t strBlen;
32
33 int32_t numC;
34
35 wchar_t *extraD; // null-terminated
36
37 };
38 #endif
39
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;
49
50 result.numA = 0;
51 result.strB = nullptr;
52 result.strBlen = 0;
53 result.numC = 0;
54 result.extraD = nullptr;
55
56 if (!part)
57 return part;
58
59 dot = strchr(part, '.');
60 if (dot)
61 *dot = '\0';
62
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 }
70
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";
78
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;
90
91 result.numC = strtol(numstart, &result.extraD, 10);
92 if (!*result.extraD)
93 result.extraD = nullptr;
94 }
95 }
96 }
97
98 if (dot) {
99 ++dot;
100
101 if (!*dot)
102 dot = nullptr;
103 }
104
105 return dot;
106 }
107
108
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 {
118
119 wchar_t *dot;
120
121 result.numA = 0;
122 result.strB = nullptr;
123 result.strBlen = 0;
124 result.numC = 0;
125 result.extraD = nullptr;
126
127 if (!part)
128 return part;
129
130 dot = wcschr(part, '.');
131 if (dot)
132 *dot = '\0';
133
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 }
141
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";
149
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;
161
162 result.numC = wcstol(numstart, &result.extraD, 10);
163 if (!*result.extraD)
164 result.extraD = nullptr;
165 }
166 }
167 }
168
169 if (dot) {
170 ++dot;
171
172 if (!*dot)
173 dot = nullptr;
174 }
175
176 return dot;
177 }
178 #endif
179
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;
187
188 if (!str2)
189 return -1;
190
191 return strcmp(str1, str2);
192 }
193
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;
201
202 if (!str2)
203 return -1;
204
205 for (; len1 && len2; --len1, --len2, ++str1, ++str2) {
206 if (*str1 < *str2)
207 return -1;
208
209 if (*str1 > *str2)
210 return 1;
211 }
212
213 if (len1 == 0)
214 return len2 == 0 ? 0 : -1;
215
216 return 1;
217 }
218
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;
225
226 return n1 != n2;
227 }
228
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;
238
239 r = ns_strnncmp(v1.strB, v1.strBlen, v2.strB, v2.strBlen);
240 if (r)
241 return r;
242
243 r = ns_cmp(v1.numC, v2.numC);
244 if (r)
245 return r;
246
247 return ns_strcmp(v1.extraD, v2.extraD);
248 }
249
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;
260
261 r = wcsncmp(v1.strB, v2.strB, XPCOM_MIN(v1.strBlen,v2.strBlen));
262 if (r)
263 return r;
264
265 r = ns_cmp(v1.numC, v2.numC);
266 if (r)
267 return r;
268
269 if (!v1.extraD)
270 return v2.extraD != 0;
271
272 if (!v2.extraD)
273 return -1;
274
275 return wcscmp(v1.extraD, v2.extraD);
276 }
277 #endif
278
279 namespace mozilla {
280
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;
288
289 wchar_t *B2 = wcsdup(char16ptr_t(B));
290 if (!B2) {
291 free(A2);
292 return 1;
293 }
294
295 int32_t result;
296 wchar_t *a = A2, *b = B2;
297
298 do {
299 VersionPartW va, vb;
300
301 a = ParseVP(a, va);
302 b = ParseVP(b, vb);
303
304 result = CompareVP(va, vb);
305 if (result)
306 break;
307
308 } while (a || b);
309
310 free(A2);
311 free(B2);
312
313 return result;
314 }
315 #endif
316
317 int32_t
318 CompareVersions(const char *A, const char *B)
319 {
320 char *A2 = strdup(A);
321 if (!A2)
322 return 1;
323
324 char *B2 = strdup(B);
325 if (!B2) {
326 free(A2);
327 return 1;
328 }
329
330 int32_t result;
331 char *a = A2, *b = B2;
332
333 do {
334 VersionPart va, vb;
335
336 a = ParseVP(a, va);
337 b = ParseVP(b, vb);
338
339 result = CompareVP(va, vb);
340 if (result)
341 break;
342
343 } while (a || b);
344
345 free(A2);
346 free(B2);
347
348 return result;
349 }
350
351 } // namespace mozilla
352

mercurial