initial import
[vuplus_webkit] / Source / WebCore / storage / IDBKeyPath.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
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 AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "IDBKeyPath.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include <wtf/ASCIICType.h>
32 #include <wtf/dtoa.h>
33
34 namespace WebCore {
35
36 class IDBKeyPathLexer {
37 public:
38     enum TokenType {
39         TokenIdentifier,
40         TokenDot,
41         TokenEnd,
42         TokenError
43     };
44
45     explicit IDBKeyPathLexer(const String& s)
46         : m_string(s)
47         , m_ptr(s.characters())
48         , m_end(s.characters() + s.length())
49         , m_currentTokenType(TokenError)
50     {
51     }
52
53     TokenType currentTokenType() const { return m_currentTokenType; }
54
55     TokenType nextTokenType()
56     {
57         m_currentTokenType = lex(m_currentElement);
58         return m_currentTokenType;
59     }
60
61     const String& currentElement() { return m_currentElement; }
62
63 private:
64     TokenType lex(String&);
65     TokenType lexIdentifier(String&);
66     String m_currentElement;
67     String m_string;
68     const UChar* m_ptr;
69     const UChar* m_end;
70     TokenType m_currentTokenType;
71 };
72
73 IDBKeyPathLexer::TokenType IDBKeyPathLexer::lex(String& element)
74 {
75     if (m_ptr >= m_end)
76         return TokenEnd;
77     ASSERT(m_ptr < m_end);
78
79     if (*m_ptr == '.') {
80         ++m_ptr;
81         return TokenDot;
82     }
83     return lexIdentifier(element);
84 }
85
86 static inline bool isSafeIdentifierStartCharacter(UChar c)
87 {
88     return isASCIIAlpha(c) || (c == '_') || (c == '$');
89 }
90
91 static inline bool isSafeIdentifierCharacter(UChar c)
92 {
93     return isASCIIAlphanumeric(c) || (c == '_') || (c == '$');
94 }
95
96 IDBKeyPathLexer::TokenType IDBKeyPathLexer::lexIdentifier(String& element)
97 {
98     const UChar* start = m_ptr;
99     if (m_ptr < m_end && isSafeIdentifierStartCharacter(*m_ptr))
100         ++m_ptr;
101     else
102         return TokenError;
103
104     while (m_ptr < m_end && isSafeIdentifierCharacter(*m_ptr))
105         ++m_ptr;
106
107     element = String(start, m_ptr - start);
108     return TokenIdentifier;
109 }
110
111 bool IDBIsValidKeyPath(const String& keyPath)
112 {
113     IDBKeyPathParseError error;
114     Vector<String> keyPathElements;
115     IDBParseKeyPath(keyPath, keyPathElements, error);
116     return error == IDBKeyPathParseErrorNone;
117 }
118
119 void IDBParseKeyPath(const String& keyPath, Vector<String>& elements, IDBKeyPathParseError& error)
120 {
121     // IDBKeyPath ::= EMPTY_STRING | identifier ('.' identifier)*
122     // The basic state machine is:
123     //   Start => {Identifier, End}
124     //   Identifier => {Dot, End}
125     //   Dot => {Identifier}
126     // It bails out as soon as it finds an error, but doesn't discard the bits it managed to parse.
127     enum ParserState { Identifier, Dot, End };
128
129     IDBKeyPathLexer lexer(keyPath);
130     IDBKeyPathLexer::TokenType tokenType = lexer.nextTokenType();
131     ParserState state;
132     if (tokenType == IDBKeyPathLexer::TokenIdentifier)
133         state = Identifier;
134     else if (tokenType == IDBKeyPathLexer::TokenEnd)
135         state = End;
136     else {
137         error = IDBKeyPathParseErrorStart;
138         return;
139     }
140
141     while (1) {
142         switch (state) {
143         case Identifier : {
144             IDBKeyPathLexer::TokenType tokenType = lexer.currentTokenType();
145             ASSERT(tokenType == IDBKeyPathLexer::TokenIdentifier);
146
147             String element = lexer.currentElement();
148             elements.append(element);
149
150             tokenType = lexer.nextTokenType();
151             if (tokenType == IDBKeyPathLexer::TokenDot)
152                 state = Dot;
153             else if (tokenType == IDBKeyPathLexer::TokenEnd)
154                 state = End;
155             else {
156                 error = IDBKeyPathParseErrorIdentifier;
157                 return;
158             }
159             break;
160         }
161         case Dot: {
162             IDBKeyPathLexer::TokenType tokenType = lexer.currentTokenType();
163             ASSERT(tokenType == IDBKeyPathLexer::TokenDot);
164
165             tokenType = lexer.nextTokenType();
166             if (tokenType == IDBKeyPathLexer::TokenIdentifier)
167                 state = Identifier;
168             else {
169                 error = IDBKeyPathParseErrorDot;
170                 return;
171             }
172             break;
173         }
174         case End: {
175             error = IDBKeyPathParseErrorNone;
176             return;
177         }
178         }
179     }
180 }
181
182 } // namespace WebCore
183
184 #endif // ENABLE(INDEXED_DATABASE)