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