LCOV - code coverage report
Current view: directory - objdir/xpcom/build - nsVersionComparator.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 86 79 91.9 %
Date: 2012-06-02 Functions: 6 6 100.0 %

       1                 : /* ***** BEGIN LICENSE BLOCK *****
       2                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       3                 :  *
       4                 :  * The contents of this file are subject to the Mozilla Public License Version
       5                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       6                 :  * the License. You may obtain a copy of the License at
       7                 :  * http://www.mozilla.org/MPL/
       8                 :  *
       9                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      10                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      11                 :  * for the specific language governing rights and limitations under the
      12                 :  * License.
      13                 :  *
      14                 :  * The Original Code is Mozilla XPCOM.
      15                 :  *
      16                 :  * The Initial Developer of the Original Code is
      17                 :  * Benjamin Smedberg <benjamin@smedbergs.us>.
      18                 :  *
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2005
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "nsVersionComparator.h"
      39                 : 
      40                 : #include <stdlib.h>
      41                 : #include <string.h>
      42                 : #if defined(XP_WIN) && !defined(UPDATER_NO_STRING_GLUE_STL)
      43                 : #include <wchar.h>
      44                 : #include "nsStringGlue.h"
      45                 : #endif
      46                 : 
      47                 : struct VersionPart {
      48                 :   PRInt32     numA;
      49                 : 
      50                 :   const char *strB;    // NOT null-terminated, can be a null pointer
      51                 :   PRUint32    strBlen;
      52                 : 
      53                 :   PRInt32     numC;
      54                 : 
      55                 :   char       *extraD;  // null-terminated
      56                 : };
      57                 : 
      58                 : #ifdef XP_WIN
      59                 : struct VersionPartW {
      60                 :   PRInt32     numA;
      61                 : 
      62                 :   const PRUnichar *strB;    // NOT null-terminated, can be a null pointer
      63                 :   PRUint32    strBlen;
      64                 : 
      65                 :   PRInt32     numC;
      66                 : 
      67                 :   PRUnichar       *extraD;  // null-terminated
      68                 : 
      69                 : };
      70                 : #endif
      71                 : 
      72                 : /**
      73                 :  * Parse a version part into a number and "extra text".
      74                 :  *
      75                 :  * @returns A pointer to the next versionpart, or null if none.
      76                 :  */
      77                 : static char*
      78           39172 : ParseVP(char *part, VersionPart &result)
      79                 : {
      80                 :   char *dot;
      81                 : 
      82           39172 :   result.numA = 0;
      83           39172 :   result.strB = nsnull;
      84           39172 :   result.strBlen = 0;
      85           39172 :   result.numC = 0;
      86           39172 :   result.extraD = nsnull;
      87                 : 
      88           39172 :   if (!part)
      89            1082 :     return part;
      90                 : 
      91           38090 :   dot = strchr(part, '.');
      92           38090 :   if (dot)
      93            9038 :     *dot = '\0';
      94                 : 
      95           38090 :   if (part[0] == '*' && part[1] == '\0') {
      96             408 :     result.numA = PR_INT32_MAX;
      97             408 :     result.strB = "";
      98                 :   }
      99                 :   else {
     100           37682 :     result.numA = strtol(part, const_cast<char**>(&result.strB), 10);
     101                 :   }
     102                 : 
     103           38090 :   if (!*result.strB) {
     104           37875 :     result.strB = nsnull;
     105           37875 :     result.strBlen = 0;
     106                 :   }
     107                 :   else {
     108             215 :     if (result.strB[0] == '+') {
     109                 :       static const char kPre[] = "pre";
     110                 : 
     111              10 :       ++result.numA;
     112              10 :       result.strB = kPre;
     113              10 :       result.strBlen = sizeof(kPre) - 1;
     114                 :     }
     115                 :     else {
     116             205 :       const char *numstart = strpbrk(result.strB, "0123456789+-");
     117             205 :       if (!numstart) {
     118              42 :         result.strBlen = strlen(result.strB);
     119                 :       }
     120                 :       else {
     121             163 :         result.strBlen = numstart - result.strB;
     122                 : 
     123             163 :         result.numC = strtol(numstart, &result.extraD, 10);
     124             163 :         if (!*result.extraD)
     125             110 :           result.extraD = nsnull;
     126                 :       }
     127                 :     }
     128                 :   }
     129                 : 
     130           38090 :   if (dot) {
     131            9038 :     ++dot;
     132                 : 
     133            9038 :     if (!*dot)
     134               0 :       dot = nsnull;
     135                 :   }
     136                 : 
     137           38090 :   return dot;
     138                 : }
     139                 : 
     140                 : 
     141                 : /**
     142                 :  * Parse a version part into a number and "extra text".
     143                 :  *
     144                 :  * @returns A pointer to the next versionpart, or null if none.
     145                 :  */
     146                 : #ifdef XP_WIN
     147                 : static PRUnichar*
     148                 : ParseVP(PRUnichar *part, VersionPartW &result)
     149                 : {
     150                 : 
     151                 :   PRUnichar *dot;
     152                 : 
     153                 :   result.numA = 0;
     154                 :   result.strB = nsnull;
     155                 :   result.strBlen = 0;
     156                 :   result.numC = 0;
     157                 :   result.extraD = nsnull;
     158                 : 
     159                 :   if (!part)
     160                 :     return part;
     161                 : 
     162                 :   dot = wcschr(part, '.');
     163                 :   if (dot)
     164                 :     *dot = '\0';
     165                 : 
     166                 :   if (part[0] == '*' && part[1] == '\0') {
     167                 :     result.numA = PR_INT32_MAX;
     168                 :     result.strB = L"";
     169                 :   }
     170                 :   else {
     171                 :     result.numA = wcstol(part, const_cast<PRUnichar**>(&result.strB), 10);
     172                 :   }
     173                 : 
     174                 :   if (!*result.strB) {
     175                 :     result.strB = nsnull;
     176                 :     result.strBlen = 0;
     177                 :   }
     178                 :   else {
     179                 :     if (result.strB[0] == '+') {
     180                 :       static const PRUnichar kPre[] = L"pre";
     181                 : 
     182                 :       ++result.numA;
     183                 :       result.strB = kPre;
     184                 :       result.strBlen = sizeof(kPre) - 1;
     185                 :     }
     186                 :     else {
     187                 :       const PRUnichar *numstart = wcspbrk(result.strB, L"0123456789+-");
     188                 :       if (!numstart) {
     189                 :         result.strBlen = wcslen(result.strB);
     190                 :       }
     191                 :       else {
     192                 :         result.strBlen = numstart - result.strB;
     193                 : 
     194                 :         result.numC = wcstol(numstart, &result.extraD, 10);
     195                 :         if (!*result.extraD)
     196                 :           result.extraD = nsnull;
     197                 :       }
     198                 :     }
     199                 :   }
     200                 : 
     201                 :   if (dot) {
     202                 :     ++dot;
     203                 : 
     204                 :     if (!*dot)
     205                 :       dot = nsnull;
     206                 :   }
     207                 : 
     208                 :   return dot;
     209                 : }
     210                 : #endif
     211                 : 
     212                 : // compare two null-terminated strings, which may be null pointers
     213                 : static PRInt32
     214            8856 : ns_strcmp(const char *str1, const char *str2)
     215                 : {
     216                 :   // any string is *before* no string
     217            8856 :   if (!str1)
     218            8852 :     return str2 != 0;
     219                 : 
     220               4 :   if (!str2)
     221               2 :     return -1;
     222                 : 
     223               2 :   return strcmp(str1, str2);
     224                 : }
     225                 : 
     226                 : // compare two length-specified string, which may be null pointers
     227                 : static PRInt32
     228            8920 : ns_strnncmp(const char *str1, PRUint32 len1, const char *str2, PRUint32 len2)
     229                 : {
     230                 :   // any string is *before* no string
     231            8920 :   if (!str1)
     232            8858 :     return str2 != 0;
     233                 : 
     234              62 :   if (!str2)
     235              24 :     return -1;
     236                 : 
     237             152 :   for (; len1 && len2; --len1, --len2, ++str1, ++str2) {
     238             114 :     if (*str1 < *str2)
     239               0 :       return -1;
     240                 : 
     241             114 :     if (*str1 > *str2)
     242               0 :       return 1;
     243                 :   }
     244                 : 
     245              38 :   if (len1 == 0)
     246              38 :     return len2 == 0 ? 0 : -1;
     247                 : 
     248               0 :   return 1;
     249                 : }
     250                 : 
     251                 : // compare two PRInt32
     252                 : static PRInt32
     253           28460 : ns_cmp(PRInt32 n1, PRInt32 n2)
     254                 : {
     255           28460 :   if (n1 < n2)
     256            7012 :     return -1;
     257                 : 
     258           21448 :   return n1 != n2;
     259                 : }
     260                 : 
     261                 : /**
     262                 :  * Compares two VersionParts
     263                 :  */
     264                 : static PRInt32
     265           19586 : CompareVP(VersionPart &v1, VersionPart &v2)
     266                 : {
     267           19586 :   PRInt32 r = ns_cmp(v1.numA, v2.numA);
     268           19586 :   if (r)
     269           10666 :     return r;
     270                 : 
     271            8920 :   r = ns_strnncmp(v1.strB, v1.strBlen, v2.strB, v2.strBlen);
     272            8920 :   if (r)
     273              46 :     return r;
     274                 : 
     275            8874 :   r = ns_cmp(v1.numC, v2.numC);
     276            8874 :   if (r)
     277              18 :     return r;
     278                 : 
     279            8856 :   return ns_strcmp(v1.extraD, v2.extraD);
     280                 : }
     281                 : 
     282                 : /**
     283                 :  * Compares two VersionParts
     284                 :  */
     285                 : #ifdef XP_WIN
     286                 : static PRInt32
     287                 : CompareVP(VersionPartW &v1, VersionPartW &v2)
     288                 : {
     289                 :   PRInt32 r = ns_cmp(v1.numA, v2.numA);
     290                 :   if (r)
     291                 :     return r;
     292                 : 
     293                 :   r = wcsncmp(v1.strB, v2.strB, NS_MIN(v1.strBlen,v2.strBlen));
     294                 :   if (r)
     295                 :     return r;
     296                 : 
     297                 :   r = ns_cmp(v1.numC, v2.numC);
     298                 :   if (r)
     299                 :     return r;
     300                 : 
     301                 :   if (!v1.extraD)
     302                 :     return v2.extraD != 0;
     303                 : 
     304                 :   if (!v2.extraD)
     305                 :     return -1;
     306                 : 
     307                 :   return wcscmp(v1.extraD, v2.extraD);
     308                 : }
     309                 : 
     310                 : 
     311                 : PRInt32
     312                 : NS_CompareVersions(const PRUnichar *A, const PRUnichar *B)
     313                 : {
     314                 :   PRUnichar *A2 = wcsdup(A);
     315                 :   if (!A2)
     316                 :     return 1;
     317                 : 
     318                 :   PRUnichar *B2 = wcsdup(B);
     319                 :   if (!B2) {
     320                 :     free(A2);
     321                 :     return 1;
     322                 :   }
     323                 : 
     324                 :   PRInt32 result;
     325                 :   PRUnichar *a = A2, *b = B2;
     326                 : 
     327                 :   do {
     328                 :     VersionPartW va, vb;
     329                 : 
     330                 :     a = ParseVP(a, va);
     331                 :     b = ParseVP(b, vb);
     332                 : 
     333                 :     result = CompareVP(va, vb);
     334                 :     if (result)
     335                 :       break;
     336                 : 
     337                 :   } while (a || b);
     338                 : 
     339                 :   free(A2);
     340                 :   free(B2);
     341                 : 
     342                 :   return result;
     343                 : }
     344                 : #endif
     345                 : 
     346                 : PRInt32
     347           17603 : NS_CompareVersions(const char *A, const char *B)
     348                 : {
     349           17603 :   char *A2 = strdup(A);
     350           17603 :   if (!A2)
     351               0 :     return 1;
     352                 : 
     353           17603 :   char *B2 = strdup(B);
     354           17603 :   if (!B2) {
     355               0 :     free(A2);
     356               0 :     return 1;
     357                 :   }
     358                 : 
     359                 :   PRInt32 result;
     360           17603 :   char *a = A2, *b = B2;
     361                 : 
     362            8852 :   do {
     363                 :     VersionPart va, vb;
     364                 : 
     365           19586 :     a = ParseVP(a, va);
     366           19586 :     b = ParseVP(b, vb);
     367                 : 
     368           19586 :     result = CompareVP(va, vb);
     369           19586 :     if (result)
     370           10734 :       break;
     371                 : 
     372                 :   } while (a || b);
     373                 : 
     374           17603 :   free(A2);
     375           17603 :   free(B2);
     376                 : 
     377           17603 :   return result;
     378                 : }
     379                 : 

Generated by: LCOV version 1.7