Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / dom / localstorage / LSValue.cpp
blob03637fdebaf93a093c72e1dbbed45cb2416b8035
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/. */
7 #include "mozilla/dom/LSValue.h"
9 #include "mozIStorageStatement.h"
10 #include "mozilla/dom/SnappyUtils.h"
11 #include "mozilla/fallible.h"
12 #include "mozilla/TextUtils.h"
13 #include "nsDebug.h"
14 #include "nsError.h"
16 namespace mozilla::dom {
18 namespace {
20 bool PutStringBytesToCString(const nsAString& aSrc, nsCString& aDest) {
21 const char16_t* bufferData;
22 const size_t byteLength = sizeof(char16_t) * aSrc.GetData(&bufferData);
24 char* destDataPtr;
25 const auto newLength = aDest.GetMutableData(&destDataPtr, byteLength);
26 if (newLength != byteLength) {
27 return false;
29 std::memcpy(static_cast<void*>(destDataPtr),
30 static_cast<const void*>(bufferData), byteLength);
32 return true;
35 template <class T>
36 using TypeBufferResult = Result<std::pair<T, nsCString>, nsresult>;
38 } // namespace
40 bool PutCStringBytesToString(const nsACString& aSrc, nsString& aDest) {
41 const char* bufferData;
42 const size_t byteLength = aSrc.GetData(&bufferData);
43 const size_t shortLength = byteLength / sizeof(char16_t);
45 char16_t* destDataPtr;
46 const auto newLength = aDest.GetMutableData(&destDataPtr, shortLength);
47 if (newLength != shortLength) {
48 return false;
51 std::memcpy(static_cast<void*>(destDataPtr),
52 static_cast<const void*>(bufferData), byteLength);
53 return true;
56 LSValue::Converter::Converter(const LSValue& aValue) {
57 using ConversionType = LSValue::ConversionType;
58 using CompressionType = LSValue::CompressionType;
60 if (aValue.mBuffer.IsVoid()) {
61 mBuffer.SetIsVoid(true);
62 return;
65 const CompressionType compressionType = aValue.GetCompressionType();
66 const ConversionType conversionType = aValue.GetConversionType();
68 const nsCString uncompressed = [compressionType, &aValue]() {
69 if (CompressionType::UNCOMPRESSED != compressionType) {
70 nsCString buffer;
71 MOZ_ASSERT(CompressionType::SNAPPY == compressionType);
72 if (NS_WARN_IF(!SnappyUncompress(aValue.mBuffer, buffer))) {
73 buffer.Truncate();
75 return buffer;
78 return aValue.mBuffer;
79 }();
81 if (ConversionType::NONE != conversionType) {
82 MOZ_ASSERT(ConversionType::UTF16_UTF8 == conversionType);
83 if (NS_WARN_IF(!CopyUTF8toUTF16(uncompressed, mBuffer, fallible))) {
84 mBuffer.SetIsVoid(true);
86 return;
89 if (NS_WARN_IF(!PutCStringBytesToString(uncompressed, mBuffer))) {
90 mBuffer.SetIsVoid(true);
94 bool LSValue::InitFromString(const nsAString& aBuffer) {
95 MOZ_ASSERT(mBuffer.IsVoid());
96 MOZ_ASSERT(!mUTF16Length);
97 MOZ_ASSERT(ConversionType::NONE == mConversionType);
98 MOZ_ASSERT(CompressionType::UNCOMPRESSED == mCompressionType);
100 if (aBuffer.IsVoid()) {
101 return true;
104 const uint32_t utf16Length = aBuffer.Length();
106 const auto conversionRes = [&aBuffer]() -> TypeBufferResult<ConversionType> {
107 nsCString converted;
109 if (Utf16ValidUpTo(aBuffer) == aBuffer.Length()) {
110 if (NS_WARN_IF(!CopyUTF16toUTF8(aBuffer, converted, fallible))) {
111 return Err(NS_ERROR_OUT_OF_MEMORY);
113 return std::pair{ConversionType::UTF16_UTF8, std::move(converted)};
116 if (NS_WARN_IF(!PutStringBytesToCString(aBuffer, converted))) {
117 return Err(NS_ERROR_OUT_OF_MEMORY);
119 return std::pair{ConversionType::NONE, std::move(converted)};
120 }();
122 if (conversionRes.isErr()) {
123 return false;
126 const auto& [conversionType, converted] = conversionRes.inspect();
128 const auto compressionRes =
129 [&converted = converted]() -> TypeBufferResult<CompressionType> {
130 nsCString compressed;
131 if (NS_WARN_IF(!SnappyCompress(converted, compressed))) {
132 return Err(NS_ERROR_OUT_OF_MEMORY);
134 if (!compressed.IsVoid()) {
135 return std::pair{CompressionType::SNAPPY, std::move(compressed)};
138 compressed = converted;
139 return std::pair{CompressionType::UNCOMPRESSED, std::move(compressed)};
140 }();
142 if (compressionRes.isErr()) {
143 return false;
146 const auto& [compressionType, compressed] = compressionRes.inspect();
148 mBuffer = compressed;
149 mUTF16Length = utf16Length;
150 mConversionType = conversionType;
151 mCompressionType = compressionType;
153 return true;
156 nsresult LSValue::InitFromStatement(mozIStorageStatement* aStatement,
157 uint32_t aIndex) {
158 MOZ_ASSERT(aStatement);
159 MOZ_ASSERT(mBuffer.IsVoid());
160 MOZ_ASSERT(!mUTF16Length);
161 MOZ_ASSERT(ConversionType::NONE == mConversionType);
162 MOZ_ASSERT(CompressionType::UNCOMPRESSED == mCompressionType);
164 int32_t utf16Length;
165 nsresult rv = aStatement->GetInt32(aIndex, &utf16Length);
166 if (NS_WARN_IF(NS_FAILED(rv))) {
167 return rv;
170 int32_t conversionType;
171 rv = aStatement->GetInt32(aIndex + 1, &conversionType);
172 if (NS_WARN_IF(NS_FAILED(rv))) {
173 return rv;
176 int32_t compressionType;
177 rv = aStatement->GetInt32(aIndex + 2, &compressionType);
178 if (NS_WARN_IF(NS_FAILED(rv))) {
179 return rv;
182 nsCString buffer;
183 rv = aStatement->GetBlobAsUTF8String(aIndex + 3, buffer);
184 if (NS_WARN_IF(NS_FAILED(rv))) {
185 return rv;
188 mBuffer = buffer;
189 mUTF16Length = static_cast<uint32_t>(utf16Length);
190 mConversionType = static_cast<decltype(mConversionType)>(conversionType);
191 mCompressionType = static_cast<decltype(mCompressionType)>(compressionType);
193 return NS_OK;
196 const LSValue& VoidLSValue() {
197 static const LSValue sVoidLSValue;
199 return sVoidLSValue;
202 } // namespace mozilla::dom