LibreOffice Module onlineupdate (master) 1
nsVersionComparator.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
8
9#include <stdlib.h>
10#include <string.h>
11#include <stdint.h>
12#if defined(_WIN32) && !defined(UPDATER_NO_STRING_GLUE_STL)
13#include <wchar.h>
14#include "Char16.h"
15#endif
16
17#ifdef _WIN32
18// from Mozilla's nsAlgorithm.h
19template <class T> inline const T& XPCOM_MIN(const T& aA, const T& aB) { return aB < aA ? aB : aA; }
20#endif
21
23{
24 int32_t numA;
25
26 const char* strB; // NOT null-terminated, can be a null pointer
27 uint32_t strBlen;
28
29 int32_t numC;
30
31 char* extraD; // null-terminated
32};
33
34#ifdef _WIN32
35struct VersionPartW
36{
37 int32_t numA;
38
39 wchar_t* strB; // NOT null-terminated, can be a null pointer
40 uint32_t strBlen;
41
42 int32_t numC;
43
44 wchar_t* extraD; // null-terminated
45};
46#endif
47
53static char* ParseVP(char* aPart, VersionPart& aResult)
54{
55 char* dot;
56
57 aResult.numA = 0;
58 aResult.strB = nullptr;
59 aResult.strBlen = 0;
60 aResult.numC = 0;
61 aResult.extraD = nullptr;
62
63 if (!aPart)
64 {
65 return aPart;
66 }
67
68 dot = strchr(aPart, '.');
69 if (dot)
70 {
71 *dot = '\0';
72 }
73
74 if (aPart[0] == '*' && aPart[1] == '\0')
75 {
76 aResult.numA = INT32_MAX;
77 aResult.strB = "";
78 }
79 else
80 {
81 aResult.numA = strtol(aPart, const_cast<char**>(&aResult.strB), 10);
82 }
83
84 if (!*aResult.strB)
85 {
86 aResult.strB = nullptr;
87 aResult.strBlen = 0;
88 }
89 else
90 {
91 if (aResult.strB[0] == '+')
92 {
93 static const char kPre[] = "pre";
94
95 ++aResult.numA;
96 aResult.strB = kPre;
97 aResult.strBlen = sizeof(kPre) - 1;
98 }
99 else
100 {
101 const char* numstart = strpbrk(aResult.strB, "0123456789+-");
102 if (!numstart)
103 {
104 aResult.strBlen = strlen(aResult.strB);
105 }
106 else
107 {
108 aResult.strBlen = numstart - aResult.strB;
109
110 aResult.numC = strtol(numstart, &aResult.extraD, 10);
111 if (!*aResult.extraD)
112 {
113 aResult.extraD = nullptr;
114 }
115 }
116 }
117 }
118
119 if (dot)
120 {
121 ++dot;
122
123 if (!*dot)
124 {
125 dot = nullptr;
126 }
127 }
128
129 return dot;
130}
131
137#ifdef _WIN32
138static wchar_t* ParseVP(wchar_t* aPart, VersionPartW& aResult)
139{
140 wchar_t* dot;
141
142 aResult.numA = 0;
143 aResult.strB = nullptr;
144 aResult.strBlen = 0;
145 aResult.numC = 0;
146 aResult.extraD = nullptr;
147
148 if (!aPart)
149 {
150 return aPart;
151 }
152
153 dot = wcschr(aPart, '.');
154 if (dot)
155 {
156 *dot = '\0';
157 }
158
159 if (aPart[0] == '*' && aPart[1] == '\0')
160 {
161 aResult.numA = INT32_MAX;
162 aResult.strB = L"";
163 }
164 else
165 {
166 aResult.numA = wcstol(aPart, const_cast<wchar_t**>(&aResult.strB), 10);
167 }
168
169 if (!*aResult.strB)
170 {
171 aResult.strB = nullptr;
172 aResult.strBlen = 0;
173 }
174 else
175 {
176 if (aResult.strB[0] == '+')
177 {
178 static wchar_t kPre[] = L"pre";
179
180 ++aResult.numA;
181 aResult.strB = kPre;
182 aResult.strBlen = sizeof(kPre) - 1;
183 }
184 else
185 {
186 const wchar_t* numstart = wcspbrk(aResult.strB, L"0123456789+-");
187 if (!numstart)
188 {
189 aResult.strBlen = wcslen(aResult.strB);
190 }
191 else
192 {
193 aResult.strBlen = numstart - aResult.strB;
194
195 aResult.numC = wcstol(numstart, &aResult.extraD, 10);
196 if (!*aResult.extraD)
197 {
198 aResult.extraD = nullptr;
199 }
200 }
201 }
202 }
203
204 if (dot)
205 {
206 ++dot;
207
208 if (!*dot)
209 {
210 dot = nullptr;
211 }
212 }
213
214 return dot;
215}
216#endif
217
218// compare two null-terminated strings, which may be null pointers
219static int32_t ns_strcmp(const char* aStr1, const char* aStr2)
220{
221 // any string is *before* no string
222 if (!aStr1)
223 {
224 return aStr2 != 0;
225 }
226
227 if (!aStr2)
228 {
229 return -1;
230 }
231
232 return strcmp(aStr1, aStr2);
233}
234
235// compare two length-specified string, which may be null pointers
236static int32_t ns_strnncmp(const char* aStr1, uint32_t aLen1, const char* aStr2, uint32_t aLen2)
237{
238 // any string is *before* no string
239 if (!aStr1)
240 {
241 return aStr2 != 0;
242 }
243
244 if (!aStr2)
245 {
246 return -1;
247 }
248
249 for (; aLen1 && aLen2; --aLen1, --aLen2, ++aStr1, ++aStr2)
250 {
251 if (*aStr1 < *aStr2)
252 {
253 return -1;
254 }
255
256 if (*aStr1 > *aStr2)
257 {
258 return 1;
259 }
260 }
261
262 if (aLen1 == 0)
263 {
264 return aLen2 == 0 ? 0 : -1;
265 }
266
267 return 1;
268}
269
270// compare two int32_t
271static int32_t ns_cmp(int32_t aNum1, int32_t aNum2)
272{
273 if (aNum1 < aNum2)
274 {
275 return -1;
276 }
277
278 return aNum1 != aNum2;
279}
280
284static int32_t CompareVP(VersionPart& aVer1, VersionPart& aVer2)
285{
286 int32_t r = ns_cmp(aVer1.numA, aVer2.numA);
287 if (r)
288 {
289 return r;
290 }
291
292 r = ns_strnncmp(aVer1.strB, aVer1.strBlen, aVer2.strB, aVer2.strBlen);
293 if (r)
294 {
295 return r;
296 }
297
298 r = ns_cmp(aVer1.numC, aVer2.numC);
299 if (r)
300 {
301 return r;
302 }
303
304 return ns_strcmp(aVer1.extraD, aVer2.extraD);
305}
306
310#ifdef _WIN32
311static int32_t CompareVP(VersionPartW& aVer1, VersionPartW& aVer2)
312{
313 int32_t r = ns_cmp(aVer1.numA, aVer2.numA);
314 if (r)
315 {
316 return r;
317 }
318
319 r = wcsncmp(aVer1.strB, aVer2.strB, XPCOM_MIN(aVer1.strBlen, aVer2.strBlen));
320 if (r)
321 {
322 return r;
323 }
324
325 r = ns_cmp(aVer1.numC, aVer2.numC);
326 if (r)
327 {
328 return r;
329 }
330
331 if (!aVer1.extraD)
332 {
333 return aVer2.extraD != 0;
334 }
335
336 if (!aVer2.extraD)
337 {
338 return -1;
339 }
340
341 return wcscmp(aVer1.extraD, aVer2.extraD);
342}
343#endif
344
345namespace mozilla
346{
347#ifdef _WIN32
348int32_t CompareVersions(const wchar_t* aStrA, const wchar_t* aStrB)
349{
350 wchar_t* A2 = wcsdup(aStrA);
351 if (!A2)
352 {
353 return 1;
354 }
355
356 wchar_t* B2 = wcsdup(aStrB);
357 if (!B2)
358 {
359 free(A2);
360 return 1;
361 }
362
363 int32_t result;
364 wchar_t* a = A2;
365 wchar_t* b = B2;
366
367 do
368 {
369 VersionPartW va, vb;
370
371 a = ParseVP(a, va);
372 b = ParseVP(b, vb);
373
374 result = CompareVP(va, vb);
375 if (result)
376 {
377 break;
378 }
379
380 } while (a || b);
381
382 free(A2);
383 free(B2);
384
385 return result;
386}
387#endif
388
389int32_t CompareVersions(const char* aStrA, const char* aStrB)
390{
391 char* A2 = strdup(aStrA);
392 if (!A2)
393 {
394 return 1;
395 }
396
397 char* B2 = strdup(aStrB);
398 if (!B2)
399 {
400 free(A2);
401 return 1;
402 }
403
404 int32_t result;
405 char* a = A2;
406 char* b = B2;
407
408 do
409 {
410 VersionPart va, vb;
411
412 a = ParseVP(a, va);
413 b = ParseVP(b, vb);
414
415 result = CompareVP(va, vb);
416 if (result)
417 {
418 break;
419 }
420
421 } while (a || b);
422
423 free(A2);
424 free(B2);
425
426 return result;
427}
428
429} // namespace mozilla
uno_Any a
Compares two VersionParts.
int32_t CompareVersions(const char *aStrA, const char *aStrB)
static int32_t ns_strcmp(const char *aStr1, const char *aStr2)
Parse a version part into a number and "extra text".
static int32_t CompareVP(VersionPart &aVer1, VersionPart &aVer2)
Compares two VersionParts.
static char * ParseVP(char *aPart, VersionPart &aResult)
Parse a version part into a number and "extra text".
static int32_t ns_strnncmp(const char *aStr1, uint32_t aLen1, const char *aStr2, uint32_t aLen2)
static int32_t ns_cmp(int32_t aNum1, int32_t aNum2)
const char * strB
Any result