зеркало из https://github.com/mozilla/gecko-dev.git
196 строки
5.5 KiB
C++
196 строки
5.5 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=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 "mozilla/dom/LSValue.h"
|
|
|
|
#include "mozIStorageStatement.h"
|
|
#include "mozilla/dom/SnappyUtils.h"
|
|
#include "mozilla/fallible.h"
|
|
#include "mozilla/TextUtils.h"
|
|
#include "nsDebug.h"
|
|
#include "nsError.h"
|
|
|
|
namespace mozilla::dom {
|
|
|
|
namespace {
|
|
|
|
bool PutStringBytesToCString(const nsAString& aSrc, nsCString& aDest) {
|
|
const char16_t* bufferData;
|
|
const size_t byteLength = sizeof(char16_t) * aSrc.GetData(&bufferData);
|
|
|
|
char* destDataPtr;
|
|
const auto newLength = aDest.GetMutableData(&destDataPtr, byteLength);
|
|
if (newLength != byteLength) {
|
|
return false;
|
|
}
|
|
std::memcpy(static_cast<void*>(destDataPtr),
|
|
static_cast<const void*>(bufferData), byteLength);
|
|
|
|
return true;
|
|
}
|
|
|
|
template <class T>
|
|
using TypeBufferResult = Result<std::pair<T, nsCString>, nsresult>;
|
|
|
|
} // namespace
|
|
|
|
bool PutCStringBytesToString(const nsACString& aSrc, nsString& aDest) {
|
|
const char* bufferData;
|
|
const size_t byteLength = aSrc.GetData(&bufferData);
|
|
const size_t shortLength = byteLength / sizeof(char16_t);
|
|
|
|
char16_t* destDataPtr;
|
|
const auto newLength = aDest.GetMutableData(&destDataPtr, shortLength);
|
|
if (newLength != shortLength) {
|
|
return false;
|
|
}
|
|
|
|
std::memcpy(static_cast<void*>(destDataPtr),
|
|
static_cast<const void*>(bufferData), byteLength);
|
|
return true;
|
|
}
|
|
|
|
LSValue::Converter::Converter(const LSValue& aValue) {
|
|
using ConversionType = LSValue::ConversionType;
|
|
using CompressionType = LSValue::CompressionType;
|
|
|
|
if (aValue.mBuffer.IsVoid()) {
|
|
mBuffer.SetIsVoid(true);
|
|
return;
|
|
}
|
|
|
|
const CompressionType compressionType = aValue.GetCompressionType();
|
|
const ConversionType conversionType = aValue.GetConversionType();
|
|
|
|
const nsCString uncompressed = [compressionType, &aValue]() {
|
|
if (CompressionType::UNCOMPRESSED != compressionType) {
|
|
nsCString buffer;
|
|
MOZ_ASSERT(CompressionType::SNAPPY == compressionType);
|
|
MOZ_ALWAYS_TRUE(SnappyUncompress(aValue.mBuffer, buffer));
|
|
return buffer;
|
|
}
|
|
return aValue.mBuffer;
|
|
}();
|
|
|
|
if (ConversionType::NONE != conversionType) {
|
|
MOZ_ASSERT(ConversionType::UTF16_UTF8 == conversionType);
|
|
MOZ_ALWAYS_TRUE(CopyUTF8toUTF16(uncompressed, mBuffer, fallible));
|
|
return;
|
|
}
|
|
|
|
MOZ_ALWAYS_TRUE(PutCStringBytesToString(uncompressed, mBuffer));
|
|
}
|
|
|
|
bool LSValue::InitFromString(const nsAString& aBuffer) {
|
|
MOZ_ASSERT(mBuffer.IsVoid());
|
|
MOZ_ASSERT(!mUTF16Length);
|
|
MOZ_ASSERT(ConversionType::NONE == mConversionType);
|
|
MOZ_ASSERT(CompressionType::UNCOMPRESSED == mCompressionType);
|
|
|
|
if (aBuffer.IsVoid()) {
|
|
return true;
|
|
}
|
|
|
|
const uint32_t utf16Length = aBuffer.Length();
|
|
|
|
const auto conversionRes = [&aBuffer]() -> TypeBufferResult<ConversionType> {
|
|
nsCString converted;
|
|
|
|
if (Utf16ValidUpTo(aBuffer) == aBuffer.Length()) {
|
|
if (NS_WARN_IF(!CopyUTF16toUTF8(aBuffer, converted, fallible))) {
|
|
return Err(NS_ERROR_OUT_OF_MEMORY);
|
|
}
|
|
return std::pair{ConversionType::UTF16_UTF8, std::move(converted)};
|
|
}
|
|
|
|
if (NS_WARN_IF(!PutStringBytesToCString(aBuffer, converted))) {
|
|
return Err(NS_ERROR_OUT_OF_MEMORY);
|
|
}
|
|
return std::pair{ConversionType::NONE, std::move(converted)};
|
|
}();
|
|
|
|
if (conversionRes.isErr()) {
|
|
return false;
|
|
}
|
|
|
|
const auto& [conversionType, converted] = conversionRes.inspect();
|
|
|
|
const auto compressionRes =
|
|
[&converted = converted]() -> TypeBufferResult<CompressionType> {
|
|
nsCString compressed;
|
|
if (NS_WARN_IF(!SnappyCompress(converted, compressed))) {
|
|
return Err(NS_ERROR_OUT_OF_MEMORY);
|
|
}
|
|
if (!compressed.IsVoid()) {
|
|
return std::pair{CompressionType::SNAPPY, std::move(compressed)};
|
|
}
|
|
|
|
compressed = converted;
|
|
return std::pair{CompressionType::UNCOMPRESSED, std::move(compressed)};
|
|
}();
|
|
|
|
if (compressionRes.isErr()) {
|
|
return false;
|
|
}
|
|
|
|
const auto& [compressionType, compressed] = compressionRes.inspect();
|
|
|
|
mBuffer = compressed;
|
|
mUTF16Length = utf16Length;
|
|
mConversionType = conversionType;
|
|
mCompressionType = compressionType;
|
|
|
|
return true;
|
|
}
|
|
|
|
nsresult LSValue::InitFromStatement(mozIStorageStatement* aStatement,
|
|
uint32_t aIndex) {
|
|
MOZ_ASSERT(aStatement);
|
|
MOZ_ASSERT(mBuffer.IsVoid());
|
|
MOZ_ASSERT(!mUTF16Length);
|
|
MOZ_ASSERT(ConversionType::NONE == mConversionType);
|
|
MOZ_ASSERT(CompressionType::UNCOMPRESSED == mCompressionType);
|
|
|
|
int32_t utf16Length;
|
|
nsresult rv = aStatement->GetInt32(aIndex, &utf16Length);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
int32_t conversionType;
|
|
rv = aStatement->GetInt32(aIndex + 1, &conversionType);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
int32_t compressionType;
|
|
rv = aStatement->GetInt32(aIndex + 2, &compressionType);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
nsCString buffer;
|
|
rv = aStatement->GetBlobAsUTF8String(aIndex + 3, buffer);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
|
|
mBuffer = buffer;
|
|
mUTF16Length = static_cast<uint32_t>(utf16Length);
|
|
mConversionType = static_cast<decltype(mConversionType)>(conversionType);
|
|
mCompressionType = static_cast<decltype(mCompressionType)>(compressionType);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
const LSValue& VoidLSValue() {
|
|
static const LSValue sVoidLSValue;
|
|
|
|
return sVoidLSValue;
|
|
}
|
|
|
|
} // namespace mozilla::dom
|