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"
16 namespace mozilla::dom
{
20 bool PutStringBytesToCString(const nsAString
& aSrc
, nsCString
& aDest
) {
21 const char16_t
* bufferData
;
22 const size_t byteLength
= sizeof(char16_t
) * aSrc
.GetData(&bufferData
);
25 const auto newLength
= aDest
.GetMutableData(&destDataPtr
, byteLength
);
26 if (newLength
!= byteLength
) {
29 std::memcpy(static_cast<void*>(destDataPtr
),
30 static_cast<const void*>(bufferData
), byteLength
);
36 using TypeBufferResult
= Result
<std::pair
<T
, nsCString
>, nsresult
>;
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
) {
51 std::memcpy(static_cast<void*>(destDataPtr
),
52 static_cast<const void*>(bufferData
), byteLength
);
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);
65 const CompressionType compressionType
= aValue
.GetCompressionType();
66 const ConversionType conversionType
= aValue
.GetConversionType();
68 const nsCString uncompressed
= [compressionType
, &aValue
]() {
69 if (CompressionType::UNCOMPRESSED
!= compressionType
) {
71 MOZ_ASSERT(CompressionType::SNAPPY
== compressionType
);
72 if (NS_WARN_IF(!SnappyUncompress(aValue
.mBuffer
, buffer
))) {
78 return aValue
.mBuffer
;
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);
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()) {
104 const uint32_t utf16Length
= aBuffer
.Length();
106 const auto conversionRes
= [&aBuffer
]() -> TypeBufferResult
<ConversionType
> {
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
)};
122 if (conversionRes
.isErr()) {
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
)};
142 if (compressionRes
.isErr()) {
146 const auto& [compressionType
, compressed
] = compressionRes
.inspect();
148 mBuffer
= compressed
;
149 mUTF16Length
= utf16Length
;
150 mConversionType
= conversionType
;
151 mCompressionType
= compressionType
;
156 nsresult
LSValue::InitFromStatement(mozIStorageStatement
* aStatement
,
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
);
165 nsresult rv
= aStatement
->GetInt32(aIndex
, &utf16Length
);
166 if (NS_WARN_IF(NS_FAILED(rv
))) {
170 int32_t conversionType
;
171 rv
= aStatement
->GetInt32(aIndex
+ 1, &conversionType
);
172 if (NS_WARN_IF(NS_FAILED(rv
))) {
176 int32_t compressionType
;
177 rv
= aStatement
->GetInt32(aIndex
+ 2, &compressionType
);
178 if (NS_WARN_IF(NS_FAILED(rv
))) {
183 rv
= aStatement
->GetBlobAsUTF8String(aIndex
+ 3, buffer
);
184 if (NS_WARN_IF(NS_FAILED(rv
))) {
189 mUTF16Length
= static_cast<uint32_t>(utf16Length
);
190 mConversionType
= static_cast<decltype(mConversionType
)>(conversionType
);
191 mCompressionType
= static_cast<decltype(mCompressionType
)>(compressionType
);
196 const LSValue
& VoidLSValue() {
197 static const LSValue sVoidLSValue
;
202 } // namespace mozilla::dom