Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / html / parser / HTMLToken.h
1 /*
2  * Copyright (C) 2013 Google, Inc. All Rights Reserved.
3  * Copyright (C) 2015 Apple Inc. All Rights Reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
25  */
26
27 #ifndef HTMLToken_h
28 #define HTMLToken_h
29
30 #include "Attribute.h"
31
32 namespace WebCore {
33
34 struct DoctypeData {
35     bool hasPublicIdentifier { false };
36     bool hasSystemIdentifier { false };
37     Vector<UChar> publicIdentifier;
38     Vector<UChar> systemIdentifier;
39     bool forceQuirks { false };
40 };
41
42 class HTMLToken {
43     WTF_MAKE_FAST_ALLOCATED;
44 public:
45     enum Type {
46         Uninitialized,
47         DOCTYPE,
48         StartTag,
49         EndTag,
50         Comment,
51         Character,
52         EndOfFile,
53     };
54
55     struct Attribute {
56         Vector<UChar, 32> name;
57         Vector<UChar, 32> value;
58
59         // Used by HTMLSourceTracker.
60         unsigned startOffset;
61         unsigned endOffset;
62     };
63
64     typedef Vector<Attribute, 10> AttributeList;
65     typedef Vector<UChar, 256> DataVector;
66
67     HTMLToken();
68
69     void clear();
70
71     Type type() const;
72
73     // EndOfFile
74
75     void makeEndOfFile();
76
77     // StartTag, EndTag, DOCTYPE.
78
79     const DataVector& name() const;
80
81     void appendToName(UChar);
82
83     // DOCTYPE.
84
85     void beginDOCTYPE();
86     void beginDOCTYPE(UChar);
87
88     void setForceQuirks();
89
90     void setPublicIdentifierToEmptyString();
91     void setSystemIdentifierToEmptyString();
92
93     void appendToPublicIdentifier(UChar);
94     void appendToSystemIdentifier(UChar);
95
96     std::unique_ptr<DoctypeData> releaseDoctypeData();
97
98     // StartTag, EndTag.
99
100     bool selfClosing() const;
101     const AttributeList& attributes() const;
102
103     void beginStartTag(UChar);
104
105     void beginEndTag(LChar);
106     void beginEndTag(const Vector<LChar, 32>&);
107
108     void beginAttribute(unsigned offset);
109     void appendToAttributeName(UChar);
110     void appendToAttributeValue(UChar);
111     void endAttribute(unsigned offset);
112
113     void setSelfClosing();
114
115 public:
116     // Used by the XSSAuditor to nuke XSS-laden attributes.
117     void eraseValueOfAttribute(unsigned index);
118     void appendToAttributeValue(unsigned index, StringView value);
119
120     // Character.
121
122     // Starting a character token works slightly differently than starting
123     // other types of tokens because we want to save a per-character branch.
124     // There is no beginCharacters, and appending a character sets the type.
125
126     const DataVector& characters() const;
127     bool charactersIsAll8BitData() const;
128
129     void appendToCharacter(LChar);
130     void appendToCharacter(UChar);
131     void appendToCharacter(const Vector<LChar, 32>&);
132
133     // Comment.
134
135     const DataVector& comment() const;
136     bool commentIsAll8BitData() const;
137
138     void beginComment();
139     void appendToComment(UChar);
140
141 private:
142     Type m_type;
143
144     DataVector m_data;
145     UChar m_data8BitCheck;
146
147     // For StartTag and EndTag
148     bool m_selfClosing;
149     AttributeList m_attributes;
150     Attribute* m_currentAttribute;
151
152     // For DOCTYPE
153     std::unique_ptr<DoctypeData> m_doctypeData;
154 };
155
156 const HTMLToken::Attribute* findAttribute(const Vector<HTMLToken::Attribute>&, StringView name);
157
158 inline HTMLToken::HTMLToken()
159     : m_type(Uninitialized)
160     , m_data8BitCheck(0)
161 {
162 }
163
164 inline void HTMLToken::clear()
165 {
166     m_type = Uninitialized;
167     m_data.clear();
168     m_data8BitCheck = 0;
169 }
170
171 inline HTMLToken::Type HTMLToken::type() const
172 {
173     return m_type;
174 }
175
176 inline void HTMLToken::makeEndOfFile()
177 {
178     ASSERT(m_type == Uninitialized);
179     m_type = EndOfFile;
180 }
181
182 inline const HTMLToken::DataVector& HTMLToken::name() const
183 {
184     ASSERT(m_type == StartTag || m_type == EndTag || m_type == DOCTYPE);
185     return m_data;
186 }
187
188 inline void HTMLToken::appendToName(UChar character)
189 {
190     ASSERT(m_type == StartTag || m_type == EndTag || m_type == DOCTYPE);
191     ASSERT(character);
192     m_data.append(character);
193     m_data8BitCheck |= character;
194 }
195
196 inline void HTMLToken::setForceQuirks()
197 {
198     ASSERT(m_type == DOCTYPE);
199     m_doctypeData->forceQuirks = true;
200 }
201
202 inline void HTMLToken::beginDOCTYPE()
203 {
204     ASSERT(m_type == Uninitialized);
205     m_type = DOCTYPE;
206     m_doctypeData = std::make_unique<DoctypeData>();
207 }
208
209 inline void HTMLToken::beginDOCTYPE(UChar character)
210 {
211     ASSERT(character);
212     beginDOCTYPE();
213     m_data.append(character);
214     m_data8BitCheck |= character;
215 }
216
217 inline void HTMLToken::setPublicIdentifierToEmptyString()
218 {
219     ASSERT(m_type == DOCTYPE);
220     m_doctypeData->hasPublicIdentifier = true;
221     m_doctypeData->publicIdentifier.clear();
222 }
223
224 inline void HTMLToken::setSystemIdentifierToEmptyString()
225 {
226     ASSERT(m_type == DOCTYPE);
227     m_doctypeData->hasSystemIdentifier = true;
228     m_doctypeData->systemIdentifier.clear();
229 }
230
231 inline void HTMLToken::appendToPublicIdentifier(UChar character)
232 {
233     ASSERT(character);
234     ASSERT(m_type == DOCTYPE);
235     ASSERT(m_doctypeData->hasPublicIdentifier);
236     m_doctypeData->publicIdentifier.append(character);
237 }
238
239 inline void HTMLToken::appendToSystemIdentifier(UChar character)
240 {
241     ASSERT(character);
242     ASSERT(m_type == DOCTYPE);
243     ASSERT(m_doctypeData->hasSystemIdentifier);
244     m_doctypeData->systemIdentifier.append(character);
245 }
246
247 inline std::unique_ptr<DoctypeData> HTMLToken::releaseDoctypeData()
248 {
249     return WTFMove(m_doctypeData);
250 }
251
252 inline bool HTMLToken::selfClosing() const
253 {
254     ASSERT(m_type == StartTag || m_type == EndTag);
255     return m_selfClosing;
256 }
257
258 inline void HTMLToken::setSelfClosing()
259 {
260     ASSERT(m_type == StartTag || m_type == EndTag);
261     m_selfClosing = true;
262 }
263
264 inline void HTMLToken::beginStartTag(UChar character)
265 {
266     ASSERT(character);
267     ASSERT(m_type == Uninitialized);
268     m_type = StartTag;
269     m_selfClosing = false;
270     m_attributes.clear();
271
272 #if !ASSERT_DISABLED
273     m_currentAttribute = nullptr;
274 #endif
275
276     m_data.append(character);
277     m_data8BitCheck = character;
278 }
279
280 inline void HTMLToken::beginEndTag(LChar character)
281 {
282     ASSERT(m_type == Uninitialized);
283     m_type = EndTag;
284     m_selfClosing = false;
285     m_attributes.clear();
286
287 #if !ASSERT_DISABLED
288     m_currentAttribute = nullptr;
289 #endif
290
291     m_data.append(character);
292 }
293
294 inline void HTMLToken::beginEndTag(const Vector<LChar, 32>& characters)
295 {
296     ASSERT(m_type == Uninitialized);
297     m_type = EndTag;
298     m_selfClosing = false;
299     m_attributes.clear();
300
301 #if !ASSERT_DISABLED
302     m_currentAttribute = nullptr;
303 #endif
304
305     m_data.appendVector(characters);
306 }
307
308 inline void HTMLToken::beginAttribute(unsigned offset)
309 {
310     ASSERT(m_type == StartTag || m_type == EndTag);
311     ASSERT(offset);
312
313     m_attributes.grow(m_attributes.size() + 1);
314     m_currentAttribute = &m_attributes.last();
315
316     m_currentAttribute->startOffset = offset;
317 }
318
319 inline void HTMLToken::endAttribute(unsigned offset)
320 {
321     ASSERT(offset);
322     ASSERT(m_currentAttribute);
323     m_currentAttribute->endOffset = offset;
324 #if !ASSERT_DISABLED
325     m_currentAttribute = nullptr;
326 #endif
327 }
328
329 inline void HTMLToken::appendToAttributeName(UChar character)
330 {
331     ASSERT(character);
332     ASSERT(m_type == StartTag || m_type == EndTag);
333     ASSERT(m_currentAttribute);
334     m_currentAttribute->name.append(character);
335 }
336
337 inline void HTMLToken::appendToAttributeValue(UChar character)
338 {
339     ASSERT(character);
340     ASSERT(m_type == StartTag || m_type == EndTag);
341     ASSERT(m_currentAttribute);
342     m_currentAttribute->value.append(character);
343 }
344
345 inline void HTMLToken::appendToAttributeValue(unsigned i, StringView value)
346 {
347     ASSERT(!value.isEmpty());
348     ASSERT(m_type == StartTag || m_type == EndTag);
349     append(m_attributes[i].value, value);
350 }
351
352 inline const HTMLToken::AttributeList& HTMLToken::attributes() const
353 {
354     ASSERT(m_type == StartTag || m_type == EndTag);
355     return m_attributes;
356 }
357
358 // Used by the XSSAuditor to nuke XSS-laden attributes.
359 inline void HTMLToken::eraseValueOfAttribute(unsigned i)
360 {
361     ASSERT(m_type == StartTag || m_type == EndTag);
362     ASSERT(i < m_attributes.size());
363     m_attributes[i].value.clear();
364 }
365
366 inline const HTMLToken::DataVector& HTMLToken::characters() const
367 {
368     ASSERT(m_type == Character);
369     return m_data;
370 }
371
372 inline bool HTMLToken::charactersIsAll8BitData() const
373 {
374     ASSERT(m_type == Character);
375     return m_data8BitCheck <= 0xFF;
376 }
377
378 inline void HTMLToken::appendToCharacter(LChar character)
379 {
380     ASSERT(m_type == Uninitialized || m_type == Character);
381     m_type = Character;
382     m_data.append(character);
383 }
384
385 inline void HTMLToken::appendToCharacter(UChar character)
386 {
387     ASSERT(m_type == Uninitialized || m_type == Character);
388     m_type = Character;
389     m_data.append(character);
390     m_data8BitCheck |= character;
391 }
392
393 inline void HTMLToken::appendToCharacter(const Vector<LChar, 32>& characters)
394 {
395     ASSERT(m_type == Uninitialized || m_type == Character);
396     m_type = Character;
397     m_data.appendVector(characters);
398 }
399
400 inline const HTMLToken::DataVector& HTMLToken::comment() const
401 {
402     ASSERT(m_type == Comment);
403     return m_data;
404 }
405
406 inline bool HTMLToken::commentIsAll8BitData() const
407 {
408     ASSERT(m_type == Comment);
409     return m_data8BitCheck <= 0xFF;
410 }
411
412 inline void HTMLToken::beginComment()
413 {
414     ASSERT(m_type == Uninitialized);
415     m_type = Comment;
416 }
417
418 inline void HTMLToken::appendToComment(UChar character)
419 {
420     ASSERT(character);
421     ASSERT(m_type == Comment);
422     m_data.append(character);
423     m_data8BitCheck |= character;
424 }
425
426 inline bool nameMatches(const HTMLToken::Attribute& attribute, StringView name)
427 {
428     unsigned size = name.length();
429     if (attribute.name.size() != size)
430         return false;
431     for (unsigned i = 0; i < size; ++i) {
432         // FIXME: The one caller that uses this probably wants to ignore letter case.
433         if (attribute.name[i] != name[i])
434             return false;
435     }
436     return true;
437 }
438
439 inline const HTMLToken::Attribute* findAttribute(const HTMLToken::AttributeList& attributes, StringView name)
440 {
441     for (auto& attribute : attributes) {
442         if (nameMatches(attribute, name))
443             return &attribute;
444     }
445     return nullptr;
446 }
447
448 }
449
450 #endif