LCOV - code coverage report
Current view: top level - xpcom/base - nsVersionComparator.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 68 88 77.3 %
Date: 2017-07-14 16:53:18 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : 
       7             : #include "nsVersionComparator.h"
       8             : 
       9             : #include <stdlib.h>
      10             : #include <string.h>
      11             : #include <stdint.h>
      12             : #if defined(XP_WIN) && !defined(UPDATER_NO_STRING_GLUE_STL)
      13             : #include <wchar.h>
      14             : #include "nsStringGlue.h"
      15             : #endif
      16             : 
      17             : struct VersionPart
      18             : {
      19             :   int32_t     numA;
      20             : 
      21             :   const char* strB;    // NOT null-terminated, can be a null pointer
      22             :   uint32_t    strBlen;
      23             : 
      24             :   int32_t     numC;
      25             : 
      26             :   char*       extraD;  // null-terminated
      27             : };
      28             : 
      29             : #ifdef XP_WIN
      30             : struct VersionPartW
      31             : {
      32             :   int32_t     numA;
      33             : 
      34             :   wchar_t*    strB;    // NOT null-terminated, can be a null pointer
      35             :   uint32_t    strBlen;
      36             : 
      37             :   int32_t     numC;
      38             : 
      39             :   wchar_t*    extraD;  // null-terminated
      40             : 
      41             : };
      42             : #endif
      43             : 
      44             : /**
      45             :  * Parse a version part into a number and "extra text".
      46             :  *
      47             :  * @returns A pointer to the next versionpart, or null if none.
      48             :  */
      49             : static char*
      50        6236 : ParseVP(char* aPart, VersionPart& aResult)
      51             : {
      52             :   char* dot;
      53             : 
      54        6236 :   aResult.numA = 0;
      55        6236 :   aResult.strB = nullptr;
      56        6236 :   aResult.strBlen = 0;
      57        6236 :   aResult.numC = 0;
      58        6236 :   aResult.extraD = nullptr;
      59             : 
      60        6236 :   if (!aPart) {
      61           0 :     return aPart;
      62             :   }
      63             : 
      64        6236 :   dot = strchr(aPart, '.');
      65        6236 :   if (dot) {
      66        5686 :     *dot = '\0';
      67             :   }
      68             : 
      69        6236 :   if (aPart[0] == '*' && aPart[1] == '\0') {
      70           0 :     aResult.numA = INT32_MAX;
      71           0 :     aResult.strB = "";
      72             :   } else {
      73        6236 :     aResult.numA = strtol(aPart, const_cast<char**>(&aResult.strB), 10);
      74             :   }
      75             : 
      76        6236 :   if (!*aResult.strB) {
      77        5688 :     aResult.strB = nullptr;
      78        5688 :     aResult.strBlen = 0;
      79             :   } else {
      80         548 :     if (aResult.strB[0] == '+') {
      81             :       static const char kPre[] = "pre";
      82             : 
      83           0 :       ++aResult.numA;
      84           0 :       aResult.strB = kPre;
      85           0 :       aResult.strBlen = sizeof(kPre) - 1;
      86             :     } else {
      87         548 :       const char* numstart = strpbrk(aResult.strB, "0123456789+-");
      88         548 :       if (!numstart) {
      89           0 :         aResult.strBlen = strlen(aResult.strB);
      90             :       } else {
      91         548 :         aResult.strBlen = numstart - aResult.strB;
      92             : 
      93         548 :         aResult.numC = strtol(numstart, &aResult.extraD, 10);
      94         548 :         if (!*aResult.extraD) {
      95         548 :           aResult.extraD = nullptr;
      96             :         }
      97             :       }
      98             :     }
      99             :   }
     100             : 
     101        6236 :   if (dot) {
     102        5686 :     ++dot;
     103             : 
     104        5686 :     if (!*dot) {
     105           0 :       dot = nullptr;
     106             :     }
     107             :   }
     108             : 
     109        6236 :   return dot;
     110             : }
     111             : 
     112             : 
     113             : /**
     114             :  * Parse a version part into a number and "extra text".
     115             :  *
     116             :  * @returns A pointer to the next versionpart, or null if none.
     117             :  */
     118             : #ifdef XP_WIN
     119             : static wchar_t*
     120             : ParseVP(wchar_t* aPart, VersionPartW& aResult)
     121             : {
     122             : 
     123             :   wchar_t* dot;
     124             : 
     125             :   aResult.numA = 0;
     126             :   aResult.strB = nullptr;
     127             :   aResult.strBlen = 0;
     128             :   aResult.numC = 0;
     129             :   aResult.extraD = nullptr;
     130             : 
     131             :   if (!aPart) {
     132             :     return aPart;
     133             :   }
     134             : 
     135             :   dot = wcschr(aPart, '.');
     136             :   if (dot) {
     137             :     *dot = '\0';
     138             :   }
     139             : 
     140             :   if (aPart[0] == '*' && aPart[1] == '\0') {
     141             :     aResult.numA = INT32_MAX;
     142             :     aResult.strB = L"";
     143             :   } else {
     144             :     aResult.numA = wcstol(aPart, const_cast<wchar_t**>(&aResult.strB), 10);
     145             :   }
     146             : 
     147             :   if (!*aResult.strB) {
     148             :     aResult.strB = nullptr;
     149             :     aResult.strBlen = 0;
     150             :   } else {
     151             :     if (aResult.strB[0] == '+') {
     152             :       static wchar_t kPre[] = L"pre";
     153             : 
     154             :       ++aResult.numA;
     155             :       aResult.strB = kPre;
     156             :       aResult.strBlen = sizeof(kPre) - 1;
     157             :     } else {
     158             :       const wchar_t* numstart = wcspbrk(aResult.strB, L"0123456789+-");
     159             :       if (!numstart) {
     160             :         aResult.strBlen = wcslen(aResult.strB);
     161             :       } else {
     162             :         aResult.strBlen = numstart - aResult.strB;
     163             : 
     164             :         aResult.numC = wcstol(numstart, &aResult.extraD, 10);
     165             :         if (!*aResult.extraD) {
     166             :           aResult.extraD = nullptr;
     167             :         }
     168             :       }
     169             :     }
     170             :   }
     171             : 
     172             :   if (dot) {
     173             :     ++dot;
     174             : 
     175             :     if (!*dot) {
     176             :       dot = nullptr;
     177             :     }
     178             :   }
     179             : 
     180             :   return dot;
     181             : }
     182             : #endif
     183             : 
     184             : // compare two null-terminated strings, which may be null pointers
     185             : static int32_t
     186         548 : ns_strcmp(const char* aStr1, const char* aStr2)
     187             : {
     188             :   // any string is *before* no string
     189         548 :   if (!aStr1) {
     190         548 :     return aStr2 != 0;
     191             :   }
     192             : 
     193           0 :   if (!aStr2) {
     194           0 :     return -1;
     195             :   }
     196             : 
     197           0 :   return strcmp(aStr1, aStr2);
     198             : }
     199             : 
     200             : // compare two length-specified string, which may be null pointers
     201             : static int32_t
     202         548 : ns_strnncmp(const char* aStr1, uint32_t aLen1,
     203             :             const char* aStr2, uint32_t aLen2)
     204             : {
     205             :   // any string is *before* no string
     206         548 :   if (!aStr1) {
     207         274 :     return aStr2 != 0;
     208             :   }
     209             : 
     210         274 :   if (!aStr2) {
     211           0 :     return -1;
     212             :   }
     213             : 
     214         822 :   for (; aLen1 && aLen2; --aLen1, --aLen2, ++aStr1, ++aStr2) {
     215         274 :     if (*aStr1 < *aStr2) {
     216           0 :       return -1;
     217             :     }
     218             : 
     219         274 :     if (*aStr1 > *aStr2) {
     220           0 :       return 1;
     221             :     }
     222             :   }
     223             : 
     224         274 :   if (aLen1 == 0) {
     225         274 :     return aLen2 == 0 ? 0 : -1;
     226             :   }
     227             : 
     228           0 :   return 1;
     229             : }
     230             : 
     231             : // compare two int32_t
     232             : static int32_t
     233        3666 : ns_cmp(int32_t aNum1, int32_t aNum2)
     234             : {
     235        3666 :   if (aNum1 < aNum2) {
     236         804 :     return -1;
     237             :   }
     238             : 
     239        2862 :   return aNum1 != aNum2;
     240             : }
     241             : 
     242             : /**
     243             :  * Compares two VersionParts
     244             :  */
     245             : static int32_t
     246        3118 : CompareVP(VersionPart& aVer1, VersionPart& aVer2)
     247             : {
     248        3118 :   int32_t r = ns_cmp(aVer1.numA, aVer2.numA);
     249        3118 :   if (r) {
     250        2570 :     return r;
     251             :   }
     252             : 
     253         548 :   r = ns_strnncmp(aVer1.strB, aVer1.strBlen, aVer2.strB, aVer2.strBlen);
     254         548 :   if (r) {
     255           0 :     return r;
     256             :   }
     257             : 
     258         548 :   r = ns_cmp(aVer1.numC, aVer2.numC);
     259         548 :   if (r) {
     260           0 :     return r;
     261             :   }
     262             : 
     263         548 :   return ns_strcmp(aVer1.extraD, aVer2.extraD);
     264             : }
     265             : 
     266             : /**
     267             :  * Compares two VersionParts
     268             :  */
     269             : #ifdef XP_WIN
     270             : static int32_t
     271             : CompareVP(VersionPartW& aVer1, VersionPartW& aVer2)
     272             : {
     273             :   int32_t r = ns_cmp(aVer1.numA, aVer2.numA);
     274             :   if (r) {
     275             :     return r;
     276             :   }
     277             : 
     278             :   r = wcsncmp(aVer1.strB, aVer2.strB, XPCOM_MIN(aVer1.strBlen, aVer2.strBlen));
     279             :   if (r) {
     280             :     return r;
     281             :   }
     282             : 
     283             :   r = ns_cmp(aVer1.numC, aVer2.numC);
     284             :   if (r) {
     285             :     return r;
     286             :   }
     287             : 
     288             :   if (!aVer1.extraD) {
     289             :     return aVer2.extraD != 0;
     290             :   }
     291             : 
     292             :   if (!aVer2.extraD) {
     293             :     return -1;
     294             :   }
     295             : 
     296             :   return wcscmp(aVer1.extraD, aVer2.extraD);
     297             : }
     298             : #endif
     299             : 
     300             : namespace mozilla {
     301             : 
     302             : #ifdef XP_WIN
     303             : int32_t
     304             : CompareVersions(const char16_t* aStrA, const char16_t* aStrB)
     305             : {
     306             :   wchar_t* A2 = wcsdup(char16ptr_t(aStrA));
     307             :   if (!A2) {
     308             :     return 1;
     309             :   }
     310             : 
     311             :   wchar_t* B2 = wcsdup(char16ptr_t(aStrB));
     312             :   if (!B2) {
     313             :     free(A2);
     314             :     return 1;
     315             :   }
     316             : 
     317             :   int32_t result;
     318             :   wchar_t* a = A2;
     319             :   wchar_t* b = B2;
     320             : 
     321             :   do {
     322             :     VersionPartW va, vb;
     323             : 
     324             :     a = ParseVP(a, va);
     325             :     b = ParseVP(b, vb);
     326             : 
     327             :     result = CompareVP(va, vb);
     328             :     if (result) {
     329             :       break;
     330             :     }
     331             : 
     332             :   } while (a || b);
     333             : 
     334             :   free(A2);
     335             :   free(B2);
     336             : 
     337             :   return result;
     338             : }
     339             : #endif
     340             : 
     341             : int32_t
     342        2844 : CompareVersions(const char* aStrA, const char* aStrB)
     343             : {
     344        2844 :   char* A2 = strdup(aStrA);
     345        2844 :   if (!A2) {
     346           0 :     return 1;
     347             :   }
     348             : 
     349        2844 :   char* B2 = strdup(aStrB);
     350        2844 :   if (!B2) {
     351           0 :     free(A2);
     352           0 :     return 1;
     353             :   }
     354             : 
     355             :   int32_t result;
     356        2844 :   char* a = A2;
     357        2844 :   char* b = B2;
     358             : 
     359         274 :   do {
     360             :     VersionPart va, vb;
     361             : 
     362        3118 :     a = ParseVP(a, va);
     363        3118 :     b = ParseVP(b, vb);
     364             : 
     365        3118 :     result = CompareVP(va, vb);
     366        3118 :     if (result) {
     367        2570 :       break;
     368             :     }
     369             : 
     370         548 :   } while (a || b);
     371             : 
     372        2844 :   free(A2);
     373        2844 :   free(B2);
     374             : 
     375        2844 :   return result;
     376             : }
     377             : 
     378             : } // namespace mozilla
     379             : 

Generated by: LCOV version 1.13