Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/xpcom/base/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 7 kB image not shown  

Quelle  nsVersionComparator.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "nsVersionComparator.h"

#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include "mozilla/CheckedInt.h"
#if defined(XP_WIN)
#  if !defined(UPDATER_NO_STRING_GLUE_STL)
#    include <wchar.h>
#    include "nsString.h"
#  endif
#  include "nsAlgorithm.h"
#endif

struct VersionPart {
  int32_t numA;

  const char* strB;  // NOT null-terminated, can be a null pointer
  uint32_t strBlen;

  int32_t numC;

  char* extraD;  // null-terminated
};

#ifdef XP_WIN
struct VersionPartW {
  int32_t numA;

  wchar_t* strB;  // NOT null-terminated, can be a null pointer
  uint32_t strBlen;

  int32_t numC;

  wchar_t* extraD;  // null-terminated
};
#endif

static int32_t ns_strtol(const char* aPart, char** aNext) {
  errno = 0;
  long result_long = strtol(aPart, aNext, 10);

  // Different platforms seem to disagree on what to return when the value
  // is out of range so we ensure that it is always what we want it to be.
  // We choose 0 firstly because that is the default when the number doesn't
  // exist at all and also because it would be easier to recover from should
  // you somehow end up in a situation where an old version is invalid. It is
  // much easier to create a version either larger or smaller than 0, much
  // harder to do the same with INT_MAX.
  if (errno != 0) {
    return 0;
  }

  mozilla::CheckedInt<int32_t> result = result_long;
  if (!result.isValid()) {
    return 0;
  }

  return result.value();
}

/**
 * Parse a version part into a number and "extra text".
 *
 * @returns A pointer to the next versionpart, or null if none.
 */

static char* ParseVP(char* aPart, VersionPart& aResult) {
  char* dot;

  aResult.numA = 0;
  aResult.strB = nullptr;
  aResult.strBlen = 0;
  aResult.numC = 0;
  aResult.extraD = nullptr;

  if (!aPart) {
    return aPart;
  }

  dot = strchr(aPart, '.');
  if (dot) {
    *dot = '\0';
  }

  if (aPart[0] == '*' && aPart[1] == '\0') {
    aResult.numA = INT32_MAX;
    aResult.strB = "";
  } else {
    aResult.numA = ns_strtol(aPart, const_cast<char**>(&aResult.strB));
  }

  if (!*aResult.strB) {
    aResult.strB = nullptr;
    aResult.strBlen = 0;
  } else {
    if (aResult.strB[0] == '+') {
      static const char kPre[] = "pre";

      ++aResult.numA;
      aResult.strB = kPre;
      aResult.strBlen = sizeof(kPre) - 1;
    } else {
      const char* numstart = strpbrk(aResult.strB, "0123456789+-");
      if (!numstart) {
        aResult.strBlen = strlen(aResult.strB);
      } else {
        aResult.strBlen = numstart - aResult.strB;
        aResult.numC = ns_strtol(numstart, const_cast<char**>(&aResult.extraD));

        if (!*aResult.extraD) {
          aResult.extraD = nullptr;
        }
      }
    }
  }

  if (dot) {
    ++dot;

    if (!*dot) {
      dot = nullptr;
    }
  }

  return dot;
}

/**
 * Parse a version part into a number and "extra text".
 *
 * @returns A pointer to the next versionpart, or null if none.
 */

#ifdef XP_WIN

static int32_t ns_wcstol(const wchar_t* aPart, wchar_t** aNext) {
  errno = 0;
  long result_long = wcstol(aPart, aNext, 10);

  // See above for the rationale for using 0 here.
  if (errno != 0) {
    return 0;
  }

  mozilla::CheckedInt<int32_t> result = result_long;
  if (!result.isValid()) {
    return 0;
  }

  return result.value();
}

static wchar_t* ParseVP(wchar_t* aPart, VersionPartW& aResult) {
  wchar_t* dot;

  aResult.numA = 0;
  aResult.strB = nullptr;
  aResult.strBlen = 0;
  aResult.numC = 0;
  aResult.extraD = nullptr;

  if (!aPart) {
    return aPart;
  }

  dot = wcschr(aPart, '.');
  if (dot) {
    *dot = '\0';
  }

  if (aPart[0] == '*' && aPart[1] == '\0') {
    static wchar_t kEmpty[] = L"";

    aResult.numA = INT32_MAX;
    aResult.strB = kEmpty;
  } else {
    aResult.numA = ns_wcstol(aPart, const_cast<wchar_t**>(&aResult.strB));
  }

  if (!*aResult.strB) {
    aResult.strB = nullptr;
    aResult.strBlen = 0;
  } else {
    if (aResult.strB[0] == '+') {
      static wchar_t kPre[] = L"pre";

      ++aResult.numA;
      aResult.strB = kPre;
      aResult.strBlen = sizeof(kPre) - 1;
    } else {
      const wchar_t* numstart = wcspbrk(aResult.strB, L"0123456789+-");
      if (!numstart) {
        aResult.strBlen = wcslen(aResult.strB);
      } else {
        aResult.strBlen = numstart - aResult.strB;
        aResult.numC =
            ns_wcstol(numstart, const_cast<wchar_t**>(&aResult.extraD));

        if (!*aResult.extraD) {
          aResult.extraD = nullptr;
        }
      }
    }
  }

  if (dot) {
    ++dot;

    if (!*dot) {
      dot = nullptr;
    }
  }

  return dot;
}
#endif

// compare two null-terminated strings, which may be null pointers
static int32_t ns_strcmp(const char* aStr1, const char* aStr2) {
  // any string is *before* no string
  if (!aStr1) {
    return aStr2 != 0;
  }

  if (!aStr2) {
    return -1;
  }

  return strcmp(aStr1, aStr2);
}

// compare two length-specified string, which may be null pointers
static int32_t ns_strnncmp(const char* aStr1, uint32_t aLen1, const char* aStr2,
                           uint32_t aLen2) {
  // any string is *before* no string
  if (!aStr1) {
    return aStr2 != 0;
  }

  if (!aStr2) {
    return -1;
  }

  for (; aLen1 && aLen2; --aLen1, --aLen2, ++aStr1, ++aStr2) {
    if (*aStr1 < *aStr2) {
      return -1;
    }

    if (*aStr1 > *aStr2) {
      return 1;
    }
  }

  if (aLen1 == 0) {
    return aLen2 == 0 ? 0 : -1;
  }

  return 1;
}

// compare two int32_t
static int32_t ns_cmp(int32_t aNum1, int32_t aNum2) {
  if (aNum1 < aNum2) {
    return -1;
  }

  return aNum1 != aNum2;
}

/**
 * Compares two VersionParts
 */

static int32_t CompareVP(VersionPart& aVer1, VersionPart& aVer2) {
  int32_t r = ns_cmp(aVer1.numA, aVer2.numA);
  if (r) {
    return r;
  }

  r = ns_strnncmp(aVer1.strB, aVer1.strBlen, aVer2.strB, aVer2.strBlen);
  if (r) {
    return r;
  }

  r = ns_cmp(aVer1.numC, aVer2.numC);
  if (r) {
    return r;
  }

  return ns_strcmp(aVer1.extraD, aVer2.extraD);
}

/**
 * Compares two VersionParts
 */

#ifdef XP_WIN
static int32_t CompareVP(VersionPartW& aVer1, VersionPartW& aVer2) {
  int32_t r = ns_cmp(aVer1.numA, aVer2.numA);
  if (r) {
    return r;
  }

  r = wcsncmp(aVer1.strB, aVer2.strB, XPCOM_MIN(aVer1.strBlen, aVer2.strBlen));
  if (r) {
    return r;
  }

  r = ns_cmp(aVer1.numC, aVer2.numC);
  if (r) {
    return r;
  }

  if (!aVer1.extraD) {
    return aVer2.extraD != 0;
  }

  if (!aVer2.extraD) {
    return -1;
  }

  return wcscmp(aVer1.extraD, aVer2.extraD);
}
#endif

namespace mozilla {

#ifdef XP_WIN
int32_t CompareVersions(const char16_t* aStrA, const char16_t* aStrB) {
  wchar_t* A2 = wcsdup(char16ptr_t(aStrA));
  if (!A2) {
    return 1;
  }

  wchar_t* B2 = wcsdup(char16ptr_t(aStrB));
  if (!B2) {
    free(A2);
    return 1;
  }

  int32_t result;
  wchar_t* a = A2;
  wchar_t* b = B2;

  do {
    VersionPartW va, vb;

    a = ParseVP(a, va);
    b = ParseVP(b, vb);

    result = CompareVP(va, vb);
    if (result) {
      break;
    }

  } while (a || b);

  free(A2);
  free(B2);

  return result;
}
#endif

int32_t CompareVersions(const char* aStrA, const char* aStrB) {
  char* A2 = strdup(aStrA);
  if (!A2) {
    return 1;
  }

  char* B2 = strdup(aStrB);
  if (!B2) {
    free(A2);
    return 1;
  }

  int32_t result;
  char* a = A2;
  char* b = B2;

  do {
    VersionPart va, vb;

    a = ParseVP(a, va);
    b = ParseVP(b, vb);

    result = CompareVP(va, vb);
    if (result) {
      break;
    }

  } while (a || b);

  free(A2);
  free(B2);

  return result;
}

}  // namespace mozilla

95%


¤ Dauer der Verarbeitung: 0.36 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.