tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

LSValue.cpp (5768B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=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 file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/dom/LSValue.h"
      8 
      9 #include "mozIStorageStatement.h"
     10 #include "mozilla/Assertions.h"
     11 #include "mozilla/TextUtils.h"
     12 #include "mozilla/dom/SnappyUtils.h"
     13 #include "mozilla/fallible.h"
     14 #include "nsDebug.h"
     15 #include "nsError.h"
     16 
     17 namespace mozilla::dom {
     18 
     19 namespace {
     20 
     21 bool PutStringBytesToCString(const nsAString& aSrc, nsCString& aDest) {
     22  const char16_t* bufferData;
     23  const size_t byteLength = sizeof(char16_t) * aSrc.GetData(&bufferData);
     24 
     25  char* destDataPtr;
     26  const auto newLength = aDest.GetMutableData(&destDataPtr, byteLength);
     27  if (newLength != byteLength) {
     28    return false;
     29  }
     30  std::memcpy(static_cast<void*>(destDataPtr),
     31              static_cast<const void*>(bufferData), byteLength);
     32 
     33  return true;
     34 }
     35 
     36 template <class T>
     37 using TypeBufferResult = Result<std::pair<T, nsCString>, nsresult>;
     38 
     39 }  // namespace
     40 
     41 bool PutCStringBytesToString(const nsACString& aSrc, nsString& aDest) {
     42  const char* bufferData;
     43  const size_t byteLength = aSrc.GetData(&bufferData);
     44  const size_t shortLength = byteLength / sizeof(char16_t);
     45 
     46  char16_t* destDataPtr;
     47  const auto newLength = aDest.GetMutableData(&destDataPtr, shortLength);
     48  if (newLength != shortLength) {
     49    return false;
     50  }
     51 
     52  std::memcpy(static_cast<void*>(destDataPtr),
     53              static_cast<const void*>(bufferData), byteLength);
     54  return true;
     55 }
     56 
     57 LSValue::Converter::Converter(const LSValue& aValue) {
     58  using ConversionType = LSValue::ConversionType;
     59  using CompressionType = LSValue::CompressionType;
     60 
     61  if (aValue.mBuffer.IsVoid()) {
     62    mBuffer.SetIsVoid(true);
     63    return;
     64  }
     65 
     66  const CompressionType compressionType = aValue.GetCompressionType();
     67  const ConversionType conversionType = aValue.GetConversionType();
     68 
     69  const nsCString uncompressed = [compressionType, &aValue]() {
     70    if (CompressionType::UNCOMPRESSED != compressionType) {
     71      nsCString buffer;
     72      MOZ_ASSERT(CompressionType::SNAPPY == compressionType);
     73      if (NS_WARN_IF(!SnappyUncompress(aValue.mBuffer, buffer))) {
     74        buffer.Truncate();
     75      }
     76      return buffer;
     77    }
     78 
     79    return aValue.mBuffer;
     80  }();
     81 
     82  if (ConversionType::NONE != conversionType) {
     83    MOZ_ASSERT(ConversionType::UTF16_UTF8 == conversionType);
     84    if (NS_WARN_IF(!CopyUTF8toUTF16(uncompressed, mBuffer, fallible))) {
     85      mBuffer.SetIsVoid(true);
     86    }
     87    return;
     88  }
     89 
     90  if (NS_WARN_IF(!PutCStringBytesToString(uncompressed, mBuffer))) {
     91    mBuffer.SetIsVoid(true);
     92  }
     93 }
     94 
     95 bool LSValue::InitFromString(const nsAString& aBuffer) {
     96  MOZ_ASSERT(mBuffer.IsVoid());
     97  MOZ_ASSERT(!mUTF16Length);
     98  MOZ_ASSERT(ConversionType::NONE == mConversionType);
     99  MOZ_ASSERT(CompressionType::UNCOMPRESSED == mCompressionType);
    100 
    101  if (aBuffer.IsVoid()) {
    102    return true;
    103  }
    104 
    105  const uint32_t utf16Length = aBuffer.Length();
    106 
    107  const auto conversionRes = [&aBuffer]() -> TypeBufferResult<ConversionType> {
    108    nsCString converted;
    109 
    110    if (Utf16ValidUpTo(aBuffer) == aBuffer.Length()) {
    111      if (NS_WARN_IF(!CopyUTF16toUTF8(aBuffer, converted, fallible))) {
    112        return Err(NS_ERROR_OUT_OF_MEMORY);
    113      }
    114      return std::pair{ConversionType::UTF16_UTF8, std::move(converted)};
    115    }
    116 
    117    if (NS_WARN_IF(!PutStringBytesToCString(aBuffer, converted))) {
    118      return Err(NS_ERROR_OUT_OF_MEMORY);
    119    }
    120    return std::pair{ConversionType::NONE, std::move(converted)};
    121  }();
    122 
    123  if (conversionRes.isErr()) {
    124    return false;
    125  }
    126 
    127  const auto& [conversionType, converted] = conversionRes.inspect();
    128 
    129  const auto compressionRes =
    130      [&converted = converted]() -> TypeBufferResult<CompressionType> {
    131    nsCString compressed;
    132    if (NS_WARN_IF(!SnappyCompress(converted, compressed))) {
    133      return Err(NS_ERROR_OUT_OF_MEMORY);
    134    }
    135    if (!compressed.IsVoid()) {
    136      return std::pair{CompressionType::SNAPPY, std::move(compressed)};
    137    }
    138 
    139    compressed = converted;
    140    return std::pair{CompressionType::UNCOMPRESSED, std::move(compressed)};
    141  }();
    142 
    143  if (compressionRes.isErr()) {
    144    return false;
    145  }
    146 
    147  const auto& [compressionType, compressed] = compressionRes.inspect();
    148 
    149  mBuffer = compressed;
    150  mUTF16Length = utf16Length;
    151  mConversionType = conversionType;
    152  mCompressionType = compressionType;
    153 
    154  return true;
    155 }
    156 
    157 nsresult LSValue::InitFromStatement(mozIStorageStatement* aStatement,
    158                                    uint32_t aIndex) {
    159  MOZ_ASSERT(aStatement);
    160  MOZ_ASSERT(mBuffer.IsVoid());
    161  MOZ_ASSERT(!mUTF16Length);
    162  MOZ_ASSERT(ConversionType::NONE == mConversionType);
    163  MOZ_ASSERT(CompressionType::UNCOMPRESSED == mCompressionType);
    164 
    165  int32_t utf16Length;
    166  nsresult rv = aStatement->GetInt32(aIndex, &utf16Length);
    167  if (NS_WARN_IF(NS_FAILED(rv))) {
    168    return rv;
    169  }
    170 
    171  int32_t conversionType;
    172  rv = aStatement->GetInt32(aIndex + 1, &conversionType);
    173  if (NS_WARN_IF(NS_FAILED(rv))) {
    174    return rv;
    175  }
    176 
    177  int32_t compressionType;
    178  rv = aStatement->GetInt32(aIndex + 2, &compressionType);
    179  if (NS_WARN_IF(NS_FAILED(rv))) {
    180    return rv;
    181  }
    182 
    183  nsCString buffer;
    184  rv = aStatement->GetBlobAsUTF8String(aIndex + 3, buffer);
    185  if (NS_WARN_IF(NS_FAILED(rv))) {
    186    return rv;
    187  }
    188 
    189  mBuffer = buffer;
    190  mUTF16Length = static_cast<uint32_t>(utf16Length);
    191  mConversionType = static_cast<decltype(mConversionType)>(conversionType);
    192  mCompressionType = static_cast<decltype(mCompressionType)>(compressionType);
    193 
    194  return NS_OK;
    195 }
    196 
    197 const LSValue& VoidLSValue() {
    198  static const LSValue sVoidLSValue;
    199 
    200  return sVoidLSValue;
    201 }
    202 
    203 }  // namespace mozilla::dom