1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/glue/nsVersionComparator.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,352 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "nsVersionComparator.h" 1.9 + 1.10 +#include <stdlib.h> 1.11 +#include <string.h> 1.12 +#include <stdint.h> 1.13 +#if defined(XP_WIN) && !defined(UPDATER_NO_STRING_GLUE_STL) 1.14 +#include <wchar.h> 1.15 +#include "nsStringGlue.h" 1.16 +#endif 1.17 + 1.18 +struct VersionPart { 1.19 + int32_t numA; 1.20 + 1.21 + const char *strB; // NOT null-terminated, can be a null pointer 1.22 + uint32_t strBlen; 1.23 + 1.24 + int32_t numC; 1.25 + 1.26 + char *extraD; // null-terminated 1.27 +}; 1.28 + 1.29 +#ifdef XP_WIN 1.30 +struct VersionPartW { 1.31 + int32_t numA; 1.32 + 1.33 + wchar_t *strB; // NOT null-terminated, can be a null pointer 1.34 + uint32_t strBlen; 1.35 + 1.36 + int32_t numC; 1.37 + 1.38 + wchar_t *extraD; // null-terminated 1.39 + 1.40 +}; 1.41 +#endif 1.42 + 1.43 +/** 1.44 + * Parse a version part into a number and "extra text". 1.45 + * 1.46 + * @returns A pointer to the next versionpart, or null if none. 1.47 + */ 1.48 +static char* 1.49 +ParseVP(char *part, VersionPart &result) 1.50 +{ 1.51 + char *dot; 1.52 + 1.53 + result.numA = 0; 1.54 + result.strB = nullptr; 1.55 + result.strBlen = 0; 1.56 + result.numC = 0; 1.57 + result.extraD = nullptr; 1.58 + 1.59 + if (!part) 1.60 + return part; 1.61 + 1.62 + dot = strchr(part, '.'); 1.63 + if (dot) 1.64 + *dot = '\0'; 1.65 + 1.66 + if (part[0] == '*' && part[1] == '\0') { 1.67 + result.numA = INT32_MAX; 1.68 + result.strB = ""; 1.69 + } 1.70 + else { 1.71 + result.numA = strtol(part, const_cast<char**>(&result.strB), 10); 1.72 + } 1.73 + 1.74 + if (!*result.strB) { 1.75 + result.strB = nullptr; 1.76 + result.strBlen = 0; 1.77 + } 1.78 + else { 1.79 + if (result.strB[0] == '+') { 1.80 + static const char kPre[] = "pre"; 1.81 + 1.82 + ++result.numA; 1.83 + result.strB = kPre; 1.84 + result.strBlen = sizeof(kPre) - 1; 1.85 + } 1.86 + else { 1.87 + const char *numstart = strpbrk(result.strB, "0123456789+-"); 1.88 + if (!numstart) { 1.89 + result.strBlen = strlen(result.strB); 1.90 + } 1.91 + else { 1.92 + result.strBlen = numstart - result.strB; 1.93 + 1.94 + result.numC = strtol(numstart, &result.extraD, 10); 1.95 + if (!*result.extraD) 1.96 + result.extraD = nullptr; 1.97 + } 1.98 + } 1.99 + } 1.100 + 1.101 + if (dot) { 1.102 + ++dot; 1.103 + 1.104 + if (!*dot) 1.105 + dot = nullptr; 1.106 + } 1.107 + 1.108 + return dot; 1.109 +} 1.110 + 1.111 + 1.112 +/** 1.113 + * Parse a version part into a number and "extra text". 1.114 + * 1.115 + * @returns A pointer to the next versionpart, or null if none. 1.116 + */ 1.117 +#ifdef XP_WIN 1.118 +static wchar_t* 1.119 +ParseVP(wchar_t *part, VersionPartW &result) 1.120 +{ 1.121 + 1.122 + wchar_t *dot; 1.123 + 1.124 + result.numA = 0; 1.125 + result.strB = nullptr; 1.126 + result.strBlen = 0; 1.127 + result.numC = 0; 1.128 + result.extraD = nullptr; 1.129 + 1.130 + if (!part) 1.131 + return part; 1.132 + 1.133 + dot = wcschr(part, '.'); 1.134 + if (dot) 1.135 + *dot = '\0'; 1.136 + 1.137 + if (part[0] == '*' && part[1] == '\0') { 1.138 + result.numA = INT32_MAX; 1.139 + result.strB = L""; 1.140 + } 1.141 + else { 1.142 + result.numA = wcstol(part, const_cast<wchar_t**>(&result.strB), 10); 1.143 + } 1.144 + 1.145 + if (!*result.strB) { 1.146 + result.strB = nullptr; 1.147 + result.strBlen = 0; 1.148 + } 1.149 + else { 1.150 + if (result.strB[0] == '+') { 1.151 + static wchar_t kPre[] = L"pre"; 1.152 + 1.153 + ++result.numA; 1.154 + result.strB = kPre; 1.155 + result.strBlen = sizeof(kPre) - 1; 1.156 + } 1.157 + else { 1.158 + const wchar_t *numstart = wcspbrk(result.strB, L"0123456789+-"); 1.159 + if (!numstart) { 1.160 + result.strBlen = wcslen(result.strB); 1.161 + } 1.162 + else { 1.163 + result.strBlen = numstart - result.strB; 1.164 + 1.165 + result.numC = wcstol(numstart, &result.extraD, 10); 1.166 + if (!*result.extraD) 1.167 + result.extraD = nullptr; 1.168 + } 1.169 + } 1.170 + } 1.171 + 1.172 + if (dot) { 1.173 + ++dot; 1.174 + 1.175 + if (!*dot) 1.176 + dot = nullptr; 1.177 + } 1.178 + 1.179 + return dot; 1.180 +} 1.181 +#endif 1.182 + 1.183 +// compare two null-terminated strings, which may be null pointers 1.184 +static int32_t 1.185 +ns_strcmp(const char *str1, const char *str2) 1.186 +{ 1.187 + // any string is *before* no string 1.188 + if (!str1) 1.189 + return str2 != 0; 1.190 + 1.191 + if (!str2) 1.192 + return -1; 1.193 + 1.194 + return strcmp(str1, str2); 1.195 +} 1.196 + 1.197 +// compare two length-specified string, which may be null pointers 1.198 +static int32_t 1.199 +ns_strnncmp(const char *str1, uint32_t len1, const char *str2, uint32_t len2) 1.200 +{ 1.201 + // any string is *before* no string 1.202 + if (!str1) 1.203 + return str2 != 0; 1.204 + 1.205 + if (!str2) 1.206 + return -1; 1.207 + 1.208 + for (; len1 && len2; --len1, --len2, ++str1, ++str2) { 1.209 + if (*str1 < *str2) 1.210 + return -1; 1.211 + 1.212 + if (*str1 > *str2) 1.213 + return 1; 1.214 + } 1.215 + 1.216 + if (len1 == 0) 1.217 + return len2 == 0 ? 0 : -1; 1.218 + 1.219 + return 1; 1.220 +} 1.221 + 1.222 +// compare two int32_t 1.223 +static int32_t 1.224 +ns_cmp(int32_t n1, int32_t n2) 1.225 +{ 1.226 + if (n1 < n2) 1.227 + return -1; 1.228 + 1.229 + return n1 != n2; 1.230 +} 1.231 + 1.232 +/** 1.233 + * Compares two VersionParts 1.234 + */ 1.235 +static int32_t 1.236 +CompareVP(VersionPart &v1, VersionPart &v2) 1.237 +{ 1.238 + int32_t r = ns_cmp(v1.numA, v2.numA); 1.239 + if (r) 1.240 + return r; 1.241 + 1.242 + r = ns_strnncmp(v1.strB, v1.strBlen, v2.strB, v2.strBlen); 1.243 + if (r) 1.244 + return r; 1.245 + 1.246 + r = ns_cmp(v1.numC, v2.numC); 1.247 + if (r) 1.248 + return r; 1.249 + 1.250 + return ns_strcmp(v1.extraD, v2.extraD); 1.251 +} 1.252 + 1.253 +/** 1.254 + * Compares two VersionParts 1.255 + */ 1.256 +#ifdef XP_WIN 1.257 +static int32_t 1.258 +CompareVP(VersionPartW &v1, VersionPartW &v2) 1.259 +{ 1.260 + int32_t r = ns_cmp(v1.numA, v2.numA); 1.261 + if (r) 1.262 + return r; 1.263 + 1.264 + r = wcsncmp(v1.strB, v2.strB, XPCOM_MIN(v1.strBlen,v2.strBlen)); 1.265 + if (r) 1.266 + return r; 1.267 + 1.268 + r = ns_cmp(v1.numC, v2.numC); 1.269 + if (r) 1.270 + return r; 1.271 + 1.272 + if (!v1.extraD) 1.273 + return v2.extraD != 0; 1.274 + 1.275 + if (!v2.extraD) 1.276 + return -1; 1.277 + 1.278 + return wcscmp(v1.extraD, v2.extraD); 1.279 +} 1.280 +#endif 1.281 + 1.282 +namespace mozilla { 1.283 + 1.284 +#ifdef XP_WIN 1.285 +int32_t 1.286 +CompareVersions(const char16_t *A, const char16_t *B) 1.287 +{ 1.288 + wchar_t *A2 = wcsdup(char16ptr_t(A)); 1.289 + if (!A2) 1.290 + return 1; 1.291 + 1.292 + wchar_t *B2 = wcsdup(char16ptr_t(B)); 1.293 + if (!B2) { 1.294 + free(A2); 1.295 + return 1; 1.296 + } 1.297 + 1.298 + int32_t result; 1.299 + wchar_t *a = A2, *b = B2; 1.300 + 1.301 + do { 1.302 + VersionPartW va, vb; 1.303 + 1.304 + a = ParseVP(a, va); 1.305 + b = ParseVP(b, vb); 1.306 + 1.307 + result = CompareVP(va, vb); 1.308 + if (result) 1.309 + break; 1.310 + 1.311 + } while (a || b); 1.312 + 1.313 + free(A2); 1.314 + free(B2); 1.315 + 1.316 + return result; 1.317 +} 1.318 +#endif 1.319 + 1.320 +int32_t 1.321 +CompareVersions(const char *A, const char *B) 1.322 +{ 1.323 + char *A2 = strdup(A); 1.324 + if (!A2) 1.325 + return 1; 1.326 + 1.327 + char *B2 = strdup(B); 1.328 + if (!B2) { 1.329 + free(A2); 1.330 + return 1; 1.331 + } 1.332 + 1.333 + int32_t result; 1.334 + char *a = A2, *b = B2; 1.335 + 1.336 + do { 1.337 + VersionPart va, vb; 1.338 + 1.339 + a = ParseVP(a, va); 1.340 + b = ParseVP(b, vb); 1.341 + 1.342 + result = CompareVP(va, vb); 1.343 + if (result) 1.344 + break; 1.345 + 1.346 + } while (a || b); 1.347 + 1.348 + free(A2); 1.349 + free(B2); 1.350 + 1.351 + return result; 1.352 +} 1.353 + 1.354 +} // namespace mozilla 1.355 +