Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this
3 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #include "nsHtml5String.h"
6 : #include "nsCharTraits.h"
7 : #include "nsUTF8Utils.h"
8 : #include "nsHtml5TreeBuilder.h"
9 :
10 20 : nsHtml5String::nsHtml5String(already_AddRefed<nsStringBuffer> aBuffer,
11 20 : uint32_t aLength)
12 20 : : mBuffer(aBuffer.take())
13 20 : , mLength(aLength)
14 : {
15 20 : if (mBuffer) {
16 19 : MOZ_ASSERT(aLength);
17 : } else {
18 1 : MOZ_ASSERT(!aLength || aLength == UINT32_MAX);
19 : }
20 20 : }
21 :
22 : void
23 44 : nsHtml5String::ToString(nsAString& aString)
24 : {
25 44 : if (mBuffer) {
26 29 : mBuffer->ToString(mLength, aString);
27 : } else {
28 15 : aString.Truncate();
29 15 : if (mLength) {
30 14 : aString.SetIsVoid(true);
31 : }
32 : }
33 44 : }
34 :
35 : void
36 0 : nsHtml5String::CopyToBuffer(char16_t* aBuffer)
37 : {
38 0 : if (mBuffer) {
39 0 : memcpy(aBuffer, mBuffer->Data(), mLength * sizeof(char16_t));
40 : }
41 0 : }
42 :
43 : bool
44 8 : nsHtml5String::LowerCaseEqualsASCII(const char* aLowerCaseLiteral)
45 : {
46 8 : if (!mBuffer) {
47 4 : if (mLength) {
48 : // This string is null
49 4 : return false;
50 : }
51 : // this string is empty
52 0 : return !(*aLowerCaseLiteral);
53 : }
54 8 : return !nsCharTraits<char16_t>::compareLowerCaseToASCIINullTerminated(
55 12 : reinterpret_cast<char16_t*>(mBuffer->Data()), Length(), aLowerCaseLiteral);
56 : }
57 :
58 : bool
59 0 : nsHtml5String::EqualsASCII(const char* aLiteral)
60 : {
61 0 : if (!mBuffer) {
62 0 : if (mLength) {
63 : // This string is null
64 0 : return false;
65 : }
66 : // this string is empty
67 0 : return !(*aLiteral);
68 : }
69 0 : return !nsCharTraits<char16_t>::compareASCIINullTerminated(
70 0 : reinterpret_cast<char16_t*>(mBuffer->Data()), Length(), aLiteral);
71 : }
72 :
73 : bool
74 55 : nsHtml5String::LowerCaseStartsWithASCII(const char* aLowerCaseLiteral)
75 : {
76 55 : if (!mBuffer) {
77 0 : if (mLength) {
78 : // This string is null
79 0 : return false;
80 : }
81 : // this string is empty
82 0 : return !(*aLowerCaseLiteral);
83 : }
84 55 : const char* litPtr = aLowerCaseLiteral;
85 55 : const char16_t* strPtr = reinterpret_cast<char16_t*>(mBuffer->Data());
86 55 : const char16_t* end = strPtr + Length();
87 : char16_t litChar;
88 669 : while ((litChar = *litPtr) && (strPtr != end)) {
89 362 : MOZ_ASSERT(!(litChar >= 'A' && litChar <= 'Z'),
90 : "Literal isn't in lower case.");
91 362 : char16_t strChar = *strPtr;
92 362 : if (strChar >= 'A' && strChar <= 'Z') {
93 132 : strChar += 0x20;
94 : }
95 362 : if (litChar != strChar) {
96 55 : return false;
97 : }
98 307 : ++litPtr;
99 307 : ++strPtr;
100 : }
101 0 : return true;
102 : }
103 :
104 : bool
105 0 : nsHtml5String::Equals(nsHtml5String aOther)
106 : {
107 0 : MOZ_ASSERT(operator bool());
108 0 : MOZ_ASSERT(aOther);
109 0 : if (mLength != aOther.mLength) {
110 0 : return false;
111 : }
112 0 : if (!mBuffer) {
113 0 : return true;
114 : }
115 0 : MOZ_ASSERT(aOther.mBuffer);
116 0 : return !memcmp(
117 0 : mBuffer->Data(), aOther.mBuffer->Data(), Length() * sizeof(char16_t));
118 : }
119 :
120 : nsHtml5String
121 0 : nsHtml5String::Clone()
122 : {
123 0 : MOZ_ASSERT(operator bool());
124 0 : RefPtr<nsStringBuffer> ref(mBuffer);
125 0 : return nsHtml5String(ref.forget(), mLength);
126 : }
127 :
128 : void
129 27 : nsHtml5String::Release()
130 : {
131 27 : if (mBuffer) {
132 19 : mBuffer->Release();
133 19 : mBuffer = nullptr;
134 : }
135 27 : mLength = UINT32_MAX;
136 27 : }
137 :
138 : // static
139 : nsHtml5String
140 19 : nsHtml5String::FromBuffer(char16_t* aBuffer,
141 : int32_t aLength,
142 : nsHtml5TreeBuilder* aTreeBuilder)
143 : {
144 19 : if (!aLength) {
145 0 : return nsHtml5String(nullptr, 0U);
146 : }
147 : // Work with nsStringBuffer directly to make sure that storage is actually
148 : // nsStringBuffer and to make sure the allocation strategy matches
149 : // nsAttrValue::GetStringBuffer, so that it doesn't need to reallocate and
150 : // copy.
151 : RefPtr<nsStringBuffer> buffer(
152 38 : nsStringBuffer::Alloc((aLength + 1) * sizeof(char16_t)));
153 19 : if (!buffer) {
154 0 : if (!aTreeBuilder) {
155 0 : MOZ_CRASH("Out of memory.");
156 : }
157 0 : aTreeBuilder->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
158 0 : buffer = nsStringBuffer::Alloc(2 * sizeof(char16_t));
159 0 : if (!buffer) {
160 0 : MOZ_CRASH(
161 : "Out of memory so badly that couldn't even allocate placeholder.");
162 : }
163 0 : char16_t* data = reinterpret_cast<char16_t*>(buffer->Data());
164 0 : data[0] = 0xFFFD;
165 0 : data[1] = 0;
166 0 : return nsHtml5String(buffer.forget(), 1);
167 : }
168 19 : char16_t* data = reinterpret_cast<char16_t*>(buffer->Data());
169 19 : memcpy(data, aBuffer, aLength * sizeof(char16_t));
170 19 : data[aLength] = 0;
171 19 : return nsHtml5String(buffer.forget(), aLength);
172 : }
173 :
174 : // static
175 : nsHtml5String
176 0 : nsHtml5String::FromLiteral(const char* aLiteral)
177 : {
178 0 : size_t length = std::strlen(aLiteral);
179 0 : if (!length) {
180 0 : return nsHtml5String(nullptr, 0U);
181 : }
182 : // Work with nsStringBuffer directly to make sure that storage is actually
183 : // nsStringBuffer and to make sure the allocation strategy matches
184 : // nsAttrValue::GetStringBuffer, so that it doesn't need to reallocate and
185 : // copy.
186 : RefPtr<nsStringBuffer> buffer(
187 0 : nsStringBuffer::Alloc((length + 1) * sizeof(char16_t)));
188 0 : if (!buffer) {
189 0 : MOZ_CRASH("Out of memory.");
190 : }
191 0 : char16_t* data = reinterpret_cast<char16_t*>(buffer->Data());
192 0 : LossyConvertEncoding8to16 converter(data);
193 0 : converter.write(aLiteral, length);
194 0 : data[length] = 0;
195 0 : return nsHtml5String(buffer.forget(), length);
196 : }
197 :
198 : // static
199 : nsHtml5String
200 0 : nsHtml5String::FromString(const nsAString& aString)
201 : {
202 0 : auto length = aString.Length();
203 0 : if (!length) {
204 0 : return nsHtml5String(nullptr, 0U);
205 : }
206 0 : RefPtr<nsStringBuffer> buffer = nsStringBuffer::FromString(aString);
207 0 : if (buffer) {
208 0 : return nsHtml5String(buffer.forget(), length);
209 : }
210 0 : buffer = nsStringBuffer::Alloc((length + 1) * sizeof(char16_t));
211 0 : if (!buffer) {
212 0 : MOZ_CRASH("Out of memory.");
213 : }
214 0 : char16_t* data = reinterpret_cast<char16_t*>(buffer->Data());
215 0 : memcpy(data, aString.BeginReading(), length * sizeof(char16_t));
216 0 : data[length] = 0;
217 0 : return nsHtml5String(buffer.forget(), length);
218 : }
219 :
220 : // static
221 : nsHtml5String
222 1 : nsHtml5String::EmptyString()
223 : {
224 1 : return nsHtml5String(nullptr, 0U);
225 : }
|