/src/resiprocate/rutil/ParseBuffer.hxx
Line | Count | Source (jump to first uncovered line) |
1 | | #if !defined(RESIP_PARSEBUFFER_HXX) |
2 | | #define RESIP_PARSEBUFFER_HXX |
3 | | |
4 | | #include "rutil/Data.hxx" |
5 | | #include "rutil/ParseException.hxx" |
6 | | |
7 | | namespace resip |
8 | | { |
9 | | |
10 | | /** |
11 | | @brief Provides string-parsing functionality with protection from buffer |
12 | | overflow. |
13 | | |
14 | | Throws ParseException when parse failures occur. |
15 | | @ingroup text_proc |
16 | | */ |
17 | | class ParseBuffer |
18 | | { |
19 | | public: |
20 | | // does NOT OWN the buffer memory |
21 | | ParseBuffer(const char* buff, size_t len, |
22 | | const Data& errorContext = Data::Empty); |
23 | | |
24 | | explicit ParseBuffer(const char* buff, |
25 | | const Data& errorContext = Data::Empty); |
26 | | |
27 | | explicit ParseBuffer(const Data& data, |
28 | | const Data& errorContext = Data::Empty); |
29 | | |
30 | | ParseBuffer(const ParseBuffer& other); |
31 | | |
32 | | ///@cond |
33 | | // .bwc. Backwards-compatibility hack; ParseException used to be |
34 | | // a full inner class of ParseBuffer, and we also had a separate |
35 | | // ParseException class that other things used. For consistency, we have |
36 | | // moved everything over to use ParseException, but there is app-code |
37 | | // out there that still expects ParseException to exist. |
38 | | typedef ParseException Exception; |
39 | | ///@endcond |
40 | | |
41 | | private: |
42 | | /** |
43 | | @internal |
44 | | @brief Provides some access to the current position of a ParseBuffer, |
45 | | which guards against invalid accesses. Just a wrapper around a |
46 | | ParseBuffer&, so is very cheap to initialize/copy. |
47 | | */ |
48 | | class CurrentPosition |
49 | | { |
50 | | public: |
51 | | inline explicit CurrentPosition(const ParseBuffer& pb) : |
52 | 44.3M | mPb(pb) |
53 | 44.3M | {} |
54 | | |
55 | | operator const char*() const |
56 | 16.4M | { |
57 | 16.4M | return mPb.mPosition; |
58 | 16.4M | } |
59 | | |
60 | | const char& operator*() const |
61 | 7.83M | { |
62 | 7.83M | mPb.assertNotEof(); |
63 | 7.83M | return *mPb.mPosition; |
64 | 7.83M | } |
65 | | |
66 | | const ParseBuffer& mPb; |
67 | | }; |
68 | | |
69 | | /** |
70 | | @internal |
71 | | @brief Similar to CurrentPosition, but does not move depending on the |
72 | | state of the ParseBuffer. Initializing one of these is more expensive. |
73 | | */ |
74 | | class Pointer |
75 | | { |
76 | | public: |
77 | | Pointer(const ParseBuffer& pb, |
78 | | const char* position, |
79 | | bool atEof); |
80 | | Pointer(const CurrentPosition& pos); |
81 | | |
82 | | operator const char*() const |
83 | 5.54k | { |
84 | 5.54k | return mPosition; |
85 | 5.54k | } |
86 | | |
87 | | const char& operator*() const; |
88 | | private: |
89 | | const ParseBuffer& mPb; |
90 | | const char* mPosition; |
91 | | const bool mIsValid; |
92 | | static const Data msg; |
93 | | }; |
94 | | |
95 | | public: |
96 | 6.26k | const Data& getContext() const {return mErrorContext;} |
97 | | |
98 | | // allow the buffer to be rolled back |
99 | | ParseBuffer& operator=(const ParseBuffer& other); |
100 | | void reset(const char* pos) |
101 | 38.8k | { |
102 | 38.8k | resip_assert( mBuff <= mEnd); |
103 | 38.8k | resip_assert( (pos >= mBuff) && (pos <= mEnd) ); |
104 | 38.8k | mPosition = pos; |
105 | 38.8k | } resip::ParseBuffer::reset(char const*) Line | Count | Source | 101 | 38.8k | { | 102 | 38.8k | resip_assert( mBuff <= mEnd); | 103 | 38.8k | resip_assert( (pos >= mBuff) && (pos <= mEnd) ); | 104 | 38.8k | mPosition = pos; | 105 | 38.8k | } |
Unexecuted instantiation: resip::ParseBuffer::reset(char const*) |
106 | | |
107 | | // abcdef |
108 | | // ^ ^ |
109 | | // begin end |
110 | 32.0M | bool eof() const { return mPosition >= mEnd;} |
111 | 1.12k | bool bof() const { return mPosition <= mBuff;} |
112 | 0 | bool valid() const {return (!eof()) && (!bof());} |
113 | 5.54k | Pointer start() const { return Pointer(*this, mBuff, eof()); } |
114 | 15.0M | CurrentPosition position() const { return CurrentPosition(*this); } |
115 | 0 | Pointer end() const { return Pointer(*this, mEnd, true); } |
116 | 0 | size_t lengthRemaining() { return mEnd - mPosition; } |
117 | | |
118 | | CurrentPosition skipChar() |
119 | 3.76M | { |
120 | 3.76M | if (eof()) |
121 | 114 | { |
122 | 114 | fail(__FILE__, __LINE__,"skipped over eof"); |
123 | 114 | } |
124 | 3.76M | ++mPosition; |
125 | 3.76M | return CurrentPosition(*this); |
126 | 3.76M | } |
127 | | |
128 | | CurrentPosition skipChar(char c); |
129 | | CurrentPosition skipChars(const char* cs); |
130 | | CurrentPosition skipChars(const Data& cs); |
131 | | CurrentPosition skipNonWhitespace(); |
132 | | CurrentPosition skipWhitespace(); |
133 | | CurrentPosition skipLWS(); |
134 | | CurrentPosition skipToTermCRLF(); |
135 | | CurrentPosition skipToChar(char c) |
136 | 3.55M | { |
137 | 3.55M | mPosition = (const char*)memchr(mPosition, c, mEnd-mPosition); |
138 | 3.55M | if(!mPosition) |
139 | 12.4k | { |
140 | 12.4k | mPosition=mEnd; |
141 | 12.4k | } |
142 | 3.55M | return CurrentPosition(*this); |
143 | 3.55M | } |
144 | | CurrentPosition skipToChars(const char* cs); |
145 | | CurrentPosition skipToChars(const Data& cs); // ?dlb? case sensitivity arg? |
146 | | CurrentPosition skipToOneOf(const char* cs); |
147 | | CurrentPosition skipToOneOf(const char* cs1, const char* cs2); |
148 | | CurrentPosition skipToOneOf(const Data& cs); |
149 | | CurrentPosition skipToOneOf(const Data& cs1, const Data& cs2); |
150 | | |
151 | | // std::bitset based parse function |
152 | | CurrentPosition skipChars(const std::bitset<256>& cs) |
153 | 0 | { |
154 | 0 | while (mPosition < mEnd) |
155 | 0 | { |
156 | 0 | if (cs.test((unsigned char)(*mPosition))) |
157 | 0 | { |
158 | 0 | mPosition++; |
159 | 0 | } |
160 | 0 | else |
161 | 0 | { |
162 | 0 | return CurrentPosition(*this); |
163 | 0 | } |
164 | 0 | } |
165 | 0 | return CurrentPosition(*this); |
166 | 0 | } |
167 | | |
168 | | CurrentPosition skipToOneOf(const std::bitset<256>& cs) |
169 | 3.74M | { |
170 | 250M | while (mPosition < mEnd) |
171 | 250M | { |
172 | 250M | if (cs.test((unsigned char)(*mPosition))) |
173 | 3.72M | { |
174 | 3.72M | return CurrentPosition(*this); |
175 | 3.72M | } |
176 | 247M | else |
177 | 247M | { |
178 | 247M | mPosition++; |
179 | 247M | } |
180 | 250M | } |
181 | 17.4k | return CurrentPosition(*this); |
182 | 3.74M | } |
183 | | |
184 | | const char* skipToEndQuote(char quote = '"'); |
185 | | CurrentPosition skipN(size_t count) |
186 | 6.29k | { |
187 | 6.29k | mPosition += count; |
188 | 6.29k | if (mPosition > mEnd) |
189 | 6.29k | { |
190 | 6.29k | fail(__FILE__, __LINE__, "skipped eof"); |
191 | 6.29k | } |
192 | 6.29k | return CurrentPosition(*this); |
193 | 6.29k | } |
194 | | |
195 | | CurrentPosition skipToEnd() |
196 | 44.0k | { |
197 | 44.0k | mPosition = mEnd; |
198 | 44.0k | return CurrentPosition(*this); |
199 | 44.0k | } |
200 | | |
201 | | // inverse of skipChar() -- end up at char not before it |
202 | | const char* skipBackChar(); |
203 | | const char* skipBackWhitespace(); |
204 | | const char* skipBackN(int count) |
205 | 0 | { |
206 | 0 | mPosition -= count; |
207 | 0 | if (bof()) |
208 | 0 | { |
209 | 0 | fail(__FILE__, __LINE__,"backed over beginning of buffer"); |
210 | 0 | } |
211 | 0 | return mPosition; |
212 | 0 | } |
213 | | |
214 | | const char* skipBackChar(char c); |
215 | | const char* skipBackToChar(char c); |
216 | | const char* skipBackToOneOf(const char* cs); |
217 | | |
218 | | void assertEof() const |
219 | 2 | { |
220 | 2 | if (!eof()) |
221 | 1 | { |
222 | 1 | fail(__FILE__, __LINE__,"expected eof"); |
223 | 1 | } |
224 | 2 | } |
225 | | |
226 | | void assertNotEof() const |
227 | 7.87M | { |
228 | 7.87M | if (eof()) |
229 | 12.3k | { |
230 | 12.3k | fail(__FILE__, __LINE__,"unexpected eof"); |
231 | 12.3k | } |
232 | 7.87M | } |
233 | | |
234 | | void fail(const char* file, unsigned int line, |
235 | | const Data& errmsg = Data::Empty) const; |
236 | | |
237 | | /// make the passed in data share memory with the buffer (uses Data::Share) |
238 | | void data(Data& data, const char* start) const; |
239 | | |
240 | | Data data(const char* start) const; |
241 | | |
242 | | void dataUnescaped(Data& data, const char* start) const; |
243 | | |
244 | | int integer(); |
245 | | |
246 | | |
247 | | uint8_t uInt8(); |
248 | | uint32_t uInt32(); |
249 | | uint64_t uInt64(); |
250 | | |
251 | 0 | RESIP_DEPRECATED(uint64_t unsignedLongLong()){return uInt64();} |
252 | 0 | RESIP_DEPRECATED(unsigned long unsignedInteger()){return uInt32();} |
253 | | |
254 | | #ifndef RESIP_FIXED_POINT |
255 | | float floatVal(); |
256 | | #endif |
257 | | int qVal(); |
258 | | |
259 | | static bool oneOf(char c, const char* cs); |
260 | | static bool oneOf(char c, const Data& cs); |
261 | | static const char* Whitespace; |
262 | | static const char* ParamTerm; |
263 | | private: |
264 | | friend class ParseBuffer::CurrentPosition; |
265 | | const char* mBuff; |
266 | | const char* mPosition; |
267 | | const char* mEnd; |
268 | | const Data& mErrorContext; |
269 | | }; |
270 | | |
271 | | } |
272 | | |
273 | | #endif |
274 | | |
275 | | /* ==================================================================== |
276 | | * The Vovida Software License, Version 1.0 |
277 | | * |
278 | | * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. |
279 | | * |
280 | | * Redistribution and use in source and binary forms, with or without |
281 | | * modification, are permitted provided that the following conditions |
282 | | * are met: |
283 | | * |
284 | | * 1. Redistributions of source code must retain the above copyright |
285 | | * notice, this list of conditions and the following disclaimer. |
286 | | * |
287 | | * 2. Redistributions in binary form must reproduce the above copyright |
288 | | * notice, this list of conditions and the following disclaimer in |
289 | | * the documentation and/or other materials provided with the |
290 | | * distribution. |
291 | | * |
292 | | * 3. The names "VOCAL", "Vovida Open Communication Application Library", |
293 | | * and "Vovida Open Communication Application Library (VOCAL)" must |
294 | | * not be used to endorse or promote products derived from this |
295 | | * software without prior written permission. For written |
296 | | * permission, please contact vocal@vovida.org. |
297 | | * |
298 | | * 4. Products derived from this software may not be called "VOCAL", nor |
299 | | * may "VOCAL" appear in their name, without prior written |
300 | | * permission of Vovida Networks, Inc. |
301 | | * |
302 | | * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED |
303 | | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
304 | | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND |
305 | | * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA |
306 | | * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES |
307 | | * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, |
308 | | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
309 | | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
310 | | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
311 | | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
312 | | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
313 | | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
314 | | * DAMAGE. |
315 | | * |
316 | | * ==================================================================== |
317 | | * |
318 | | * This software consists of voluntary contributions made by Vovida |
319 | | * Networks, Inc. and many individuals on behalf of Vovida Networks, |
320 | | * Inc. For more information on Vovida Networks, Inc., please see |
321 | | * <http://www.vovida.org/>. |
322 | | * |
323 | | */ |