misc/libphysfs/lzma/CPP/7zip/Archive/Common/ParseProperties.cpp
author nemo
Mon, 10 Apr 2017 12:06:43 -0400
changeset 12213 bb5522e88ab2
permissions -rw-r--r--
bulk copy of latest physfs to our misc/libphysfs since this seems to fix an off-by-1 error reliably hit in readln read of 1 byte probably introduced in the addition of the buffered read. Whether this is excessive or whether libphysfs should even be maintained by us is another matter. But at least we shouldn't crash

// ParseProperties.cpp

#include "StdAfx.h"

#include "ParseProperties.h"

#include "Common/StringToInt.h"
#include "Common/MyCom.h"

HRESULT ParsePropValue(const UString &name, const PROPVARIANT &prop, UInt32 &resValue)
{
  if (prop.vt == VT_UI4)
  {
    if (!name.IsEmpty())
      return E_INVALIDARG;
    resValue = prop.ulVal;
  }
  else if (prop.vt == VT_EMPTY)
  {
    if(!name.IsEmpty())
    {
      const wchar_t *start = name;
      const wchar_t *end;
      UInt64 v = ConvertStringToUInt64(start, &end);
      if (end - start != name.Length())
        return E_INVALIDARG;
      resValue = (UInt32)v;
    }
  }
  else
    return E_INVALIDARG;
  return S_OK;
}

static const int kLogarithmicSizeLimit = 32;
static const wchar_t kByteSymbol = L'B';
static const wchar_t kKiloByteSymbol = L'K';
static const wchar_t kMegaByteSymbol = L'M';

HRESULT ParsePropDictionaryValue(const UString &srcStringSpec, UInt32 &dicSize)
{
  UString srcString = srcStringSpec;
  srcString.MakeUpper();

  const wchar_t *start = srcString;
  const wchar_t *end;
  UInt64 number = ConvertStringToUInt64(start, &end);
  int numDigits = (int)(end - start);
  if (numDigits == 0 || srcString.Length() > numDigits + 1)
    return E_INVALIDARG;
  if (srcString.Length() == numDigits)
  {
    if (number >= kLogarithmicSizeLimit)
      return E_INVALIDARG;
    dicSize = (UInt32)1 << (int)number;
    return S_OK;
  }
  switch (srcString[numDigits])
  {
    case kByteSymbol:
      if (number >= ((UInt64)1 << kLogarithmicSizeLimit))
        return E_INVALIDARG;
      dicSize = (UInt32)number;
      break;
    case kKiloByteSymbol:
      if (number >= ((UInt64)1 << (kLogarithmicSizeLimit - 10)))
        return E_INVALIDARG;
      dicSize = (UInt32)(number << 10);
      break;
    case kMegaByteSymbol:
      if (number >= ((UInt64)1 << (kLogarithmicSizeLimit - 20)))
        return E_INVALIDARG;
      dicSize = (UInt32)(number << 20);
      break;
    default:
      return E_INVALIDARG;
  }
  return S_OK;
}

HRESULT ParsePropDictionaryValue(const UString &name, const PROPVARIANT &prop, UInt32 &resValue)
{
  if (name.IsEmpty())
  {
    if (prop.vt == VT_UI4)
    {
      UInt32 logDicSize = prop.ulVal;
      if (logDicSize >= 32)
        return E_INVALIDARG;
      resValue = (UInt32)1 << logDicSize;
      return S_OK;
    }
    if (prop.vt == VT_BSTR)
      return ParsePropDictionaryValue(prop.bstrVal, resValue);
    return E_INVALIDARG;
  }
  return ParsePropDictionaryValue(name, resValue);
}

bool StringToBool(const UString &s, bool &res)
{
  if (s.IsEmpty() || s.CompareNoCase(L"ON") == 0)
  {
    res = true;
    return true;
  }
  if (s.CompareNoCase(L"OFF") == 0)
  {
    res = false;
    return true;
  }
  return false;
}

HRESULT SetBoolProperty(bool &dest, const PROPVARIANT &value)
{
  switch(value.vt)
  {
    case VT_EMPTY:
      dest = true;
      return S_OK;
    /*
    case VT_UI4:
      dest = (value.ulVal != 0);
      break;
    */
    case VT_BSTR:
      return StringToBool(value.bstrVal, dest) ?  S_OK : E_INVALIDARG;
  }
  return E_INVALIDARG;
}

int ParseStringToUInt32(const UString &srcString, UInt32 &number)
{
  const wchar_t *start = srcString;
  const wchar_t *end;
  UInt64 number64 = ConvertStringToUInt64(start, &end);
  if (number64 > 0xFFFFFFFF) 
  {
    number = 0;
    return 0;
  }
  number = (UInt32)number64;
  return (int)(end - start);
}

HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads)
{
  if (name.IsEmpty())
  {
    switch(prop.vt)
    {
      case VT_UI4:
        numThreads = prop.ulVal;
        break;
      default:
      {
        bool val; 
        RINOK(SetBoolProperty(val, prop));
        numThreads = (val ? defaultNumThreads : 1);
        break;
      }
    }
  }
  else
  {
    UInt32 number;
    int index = ParseStringToUInt32(name, number);
    if (index != name.Length())
      return E_INVALIDARG;
    numThreads = number;
  }
  return S_OK;
}