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 "nsHtml5TreeBuilder.h"
8 #include "nsUTF8Utils.h"
9 
ToString(nsAString & aString)10 void nsHtml5String::ToString(nsAString& aString) {
11   switch (GetKind()) {
12     case eStringBuffer:
13       return AsStringBuffer()->ToString(Length(), aString);
14     case eAtom:
15       return AsAtom()->ToString(aString);
16     case eEmpty:
17       aString.Truncate();
18       return;
19     default:
20       aString.Truncate();
21       aString.SetIsVoid(true);
22       return;
23   }
24 }
25 
CopyToBuffer(char16_t * aBuffer) const26 void nsHtml5String::CopyToBuffer(char16_t* aBuffer) const {
27   memcpy(aBuffer, AsPtr(), Length() * sizeof(char16_t));
28 }
29 
LowerCaseEqualsASCII(const char * aLowerCaseLiteral) const30 bool nsHtml5String::LowerCaseEqualsASCII(const char* aLowerCaseLiteral) const {
31   return !nsCharTraits<char16_t>::compareLowerCaseToASCIINullTerminated(
32       AsPtr(), Length(), aLowerCaseLiteral);
33 }
34 
EqualsASCII(const char * aLiteral) const35 bool nsHtml5String::EqualsASCII(const char* aLiteral) const {
36   return !nsCharTraits<char16_t>::compareASCIINullTerminated(AsPtr(), Length(),
37                                                              aLiteral);
38 }
39 
LowerCaseStartsWithASCII(const char * aLowerCaseLiteral) const40 bool nsHtml5String::LowerCaseStartsWithASCII(
41     const char* aLowerCaseLiteral) const {
42   const char* litPtr = aLowerCaseLiteral;
43   const char16_t* strPtr = AsPtr();
44   const char16_t* end = strPtr + Length();
45   char16_t litChar;
46   while ((litChar = *litPtr)) {
47     MOZ_ASSERT(!(litChar >= 'A' && litChar <= 'Z'),
48                "Literal isn't in lower case.");
49     if (strPtr == end) {
50       return false;
51     }
52     char16_t strChar = *strPtr;
53     if (strChar >= 'A' && strChar <= 'Z') {
54       strChar += 0x20;
55     }
56     if (litChar != strChar) {
57       return false;
58     }
59     ++litPtr;
60     ++strPtr;
61   }
62   return true;
63 }
64 
Equals(nsHtml5String aOther) const65 bool nsHtml5String::Equals(nsHtml5String aOther) const {
66   MOZ_ASSERT(operator bool());
67   MOZ_ASSERT(aOther);
68   if (Length() != aOther.Length()) {
69     return false;
70   }
71   return !memcmp(AsPtr(), aOther.AsPtr(), Length() * sizeof(char16_t));
72 }
73 
Clone()74 nsHtml5String nsHtml5String::Clone() {
75   switch (GetKind()) {
76     case eStringBuffer:
77       AsStringBuffer()->AddRef();
78       break;
79     case eAtom:
80       AsAtom()->AddRef();
81       break;
82     default:
83       break;
84   }
85   return nsHtml5String(mBits);
86 }
87 
Release()88 void nsHtml5String::Release() {
89   switch (GetKind()) {
90     case eStringBuffer:
91       AsStringBuffer()->Release();
92       break;
93     case eAtom:
94       AsAtom()->Release();
95       break;
96     default:
97       break;
98   }
99   mBits = eNull;
100 }
101 
102 // static
FromBuffer(char16_t * aBuffer,int32_t aLength,nsHtml5TreeBuilder * aTreeBuilder)103 nsHtml5String nsHtml5String::FromBuffer(char16_t* aBuffer, int32_t aLength,
104                                         nsHtml5TreeBuilder* aTreeBuilder) {
105   if (!aLength) {
106     return nsHtml5String(eEmpty);
107   }
108   // Work with nsStringBuffer directly to make sure that storage is actually
109   // nsStringBuffer and to make sure the allocation strategy matches
110   // nsAttrValue::GetStringBuffer, so that it doesn't need to reallocate and
111   // copy.
112   RefPtr<nsStringBuffer> buffer(
113       nsStringBuffer::Alloc((aLength + 1) * sizeof(char16_t)));
114   if (!buffer) {
115     if (!aTreeBuilder) {
116       MOZ_CRASH("Out of memory.");
117     }
118     aTreeBuilder->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
119     buffer = nsStringBuffer::Alloc(2 * sizeof(char16_t));
120     if (!buffer) {
121       MOZ_CRASH(
122           "Out of memory so badly that couldn't even allocate placeholder.");
123     }
124     char16_t* data = reinterpret_cast<char16_t*>(buffer->Data());
125     data[0] = 0xFFFD;
126     data[1] = 0;
127     return nsHtml5String(reinterpret_cast<uintptr_t>(buffer.forget().take()) |
128                          eStringBuffer);
129   }
130   char16_t* data = reinterpret_cast<char16_t*>(buffer->Data());
131   memcpy(data, aBuffer, aLength * sizeof(char16_t));
132   data[aLength] = 0;
133   return nsHtml5String(reinterpret_cast<uintptr_t>(buffer.forget().take()) |
134                        eStringBuffer);
135 }
136 
137 // static
FromLiteral(const char * aLiteral)138 nsHtml5String nsHtml5String::FromLiteral(const char* aLiteral) {
139   size_t length = std::strlen(aLiteral);
140   if (!length) {
141     return nsHtml5String(eEmpty);
142   }
143   // Work with nsStringBuffer directly to make sure that storage is actually
144   // nsStringBuffer and to make sure the allocation strategy matches
145   // nsAttrValue::GetStringBuffer, so that it doesn't need to reallocate and
146   // copy.
147   RefPtr<nsStringBuffer> buffer(
148       nsStringBuffer::Alloc((length + 1) * sizeof(char16_t)));
149   if (!buffer) {
150     MOZ_CRASH("Out of memory.");
151   }
152   char16_t* data = reinterpret_cast<char16_t*>(buffer->Data());
153   ConvertAsciitoUtf16(Span(aLiteral, length), Span(data, length));
154   data[length] = 0;
155   return nsHtml5String(reinterpret_cast<uintptr_t>(buffer.forget().take()) |
156                        eStringBuffer);
157 }
158 
159 // static
FromString(const nsAString & aString)160 nsHtml5String nsHtml5String::FromString(const nsAString& aString) {
161   auto length = aString.Length();
162   if (!length) {
163     return nsHtml5String(eEmpty);
164   }
165   RefPtr<nsStringBuffer> buffer = nsStringBuffer::FromString(aString);
166   if (buffer && (length == buffer->StorageSize() / sizeof(char16_t) - 1)) {
167     return nsHtml5String(reinterpret_cast<uintptr_t>(buffer.forget().take()) |
168                          eStringBuffer);
169   }
170   buffer = nsStringBuffer::Alloc((length + 1) * sizeof(char16_t));
171   if (!buffer) {
172     MOZ_CRASH("Out of memory.");
173   }
174   char16_t* data = reinterpret_cast<char16_t*>(buffer->Data());
175   memcpy(data, aString.BeginReading(), length * sizeof(char16_t));
176   data[length] = 0;
177   return nsHtml5String(reinterpret_cast<uintptr_t>(buffer.forget().take()) |
178                        eStringBuffer);
179 }
180 
181 // static
FromAtom(already_AddRefed<nsAtom> aAtom)182 nsHtml5String nsHtml5String::FromAtom(already_AddRefed<nsAtom> aAtom) {
183   return nsHtml5String(reinterpret_cast<uintptr_t>(aAtom.take()) | eAtom);
184 }
185 
186 // static
EmptyString()187 nsHtml5String nsHtml5String::EmptyString() { return nsHtml5String(eEmpty); }
188