diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llmessage/llmime.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to '')
-rw-r--r-- | linden/indra/llmessage/llmime.cpp | 632 |
1 files changed, 632 insertions, 0 deletions
diff --git a/linden/indra/llmessage/llmime.cpp b/linden/indra/llmessage/llmime.cpp new file mode 100644 index 0000000..2786ea8 --- /dev/null +++ b/linden/indra/llmessage/llmime.cpp | |||
@@ -0,0 +1,632 @@ | |||
1 | /** | ||
2 | * @file llmime.cpp | ||
3 | * @author Phoenix | ||
4 | * @date 2006-12-20 | ||
5 | * @brief Implementation of mime tools. | ||
6 | * | ||
7 | * Copyright (c) 2006-2007, Linden Research, Inc. | ||
8 | * | ||
9 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
10 | * to you under the terms of the GNU General Public License, version 2.0 | ||
11 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
12 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
13 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
14 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
15 | * | ||
16 | * There are special exceptions to the terms and conditions of the GPL as | ||
17 | * it is applied to this Source Code. View the full text of the exception | ||
18 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
19 | * online at http://secondlife.com/developers/opensource/flossexception | ||
20 | * | ||
21 | * By copying, modifying or distributing this software, you acknowledge | ||
22 | * that you have read and understood your obligations described above, | ||
23 | * and agree to abide by those obligations. | ||
24 | * | ||
25 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
26 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
27 | * COMPLETENESS OR PERFORMANCE. | ||
28 | */ | ||
29 | |||
30 | #include "linden_common.h" | ||
31 | #include "llmime.h" | ||
32 | |||
33 | #include <vector> | ||
34 | |||
35 | #include "llmemorystream.h" | ||
36 | |||
37 | /** | ||
38 | * Useful constants. | ||
39 | */ | ||
40 | // Headers specified in rfc-2045 will be canonicalized below. | ||
41 | static const std::string CONTENT_LENGTH("Content-Length"); | ||
42 | static const std::string CONTENT_TYPE("Content-Type"); | ||
43 | static const S32 KNOWN_HEADER_COUNT = 6; | ||
44 | static const std::string KNOWN_HEADER[KNOWN_HEADER_COUNT] = | ||
45 | { | ||
46 | CONTENT_LENGTH, | ||
47 | CONTENT_TYPE, | ||
48 | std::string("MIME-Version"), | ||
49 | std::string("Content-Transfer-Encoding"), | ||
50 | std::string("Content-ID"), | ||
51 | std::string("Content-Description"), | ||
52 | }; | ||
53 | |||
54 | // parser helpers | ||
55 | static const std::string MULTIPART("multipart"); | ||
56 | static const std::string BOUNDARY("boundary"); | ||
57 | static const std::string END_OF_CONTENT_PARAMETER("\r\n ;\t"); | ||
58 | static const std::string SEPARATOR_PREFIX("--"); | ||
59 | //static const std::string SEPARATOR_SUFFIX("\r\n"); | ||
60 | |||
61 | /* | ||
62 | Content-Type: multipart/mixed; boundary="segment" | ||
63 | Content-Length: 24832 | ||
64 | |||
65 | --segment | ||
66 | Content-Type: image/j2c | ||
67 | Content-Length: 23715 | ||
68 | |||
69 | <data> | ||
70 | |||
71 | --segment | ||
72 | Content-Type: text/xml; charset=UTF-8 | ||
73 | |||
74 | <meta data> | ||
75 | EOF | ||
76 | |||
77 | */ | ||
78 | |||
79 | /** | ||
80 | * LLMimeIndex | ||
81 | */ | ||
82 | |||
83 | /** | ||
84 | * @class LLMimeIndex::Impl | ||
85 | * @brief Implementation details of the mime index class. | ||
86 | * @see LLMimeIndex | ||
87 | */ | ||
88 | class LLMimeIndex::Impl | ||
89 | { | ||
90 | public: | ||
91 | Impl() : mOffset(-1), mUseCount(1) | ||
92 | {} | ||
93 | Impl(LLSD headers, S32 offset) : | ||
94 | mHeaders(headers), mOffset(offset), mUseCount(1) | ||
95 | {} | ||
96 | public: | ||
97 | LLSD mHeaders; | ||
98 | S32 mOffset; | ||
99 | S32 mUseCount; | ||
100 | |||
101 | typedef std::vector<LLMimeIndex> sub_part_t; | ||
102 | sub_part_t mAttachments; | ||
103 | }; | ||
104 | |||
105 | LLSD LLMimeIndex::headers() const | ||
106 | { | ||
107 | return mImpl->mHeaders; | ||
108 | } | ||
109 | |||
110 | S32 LLMimeIndex::offset() const | ||
111 | { | ||
112 | return mImpl->mOffset; | ||
113 | } | ||
114 | |||
115 | S32 LLMimeIndex::contentLength() const | ||
116 | { | ||
117 | // Find the content length in the headers. | ||
118 | S32 length = -1; | ||
119 | LLSD content_length = mImpl->mHeaders[CONTENT_LENGTH]; | ||
120 | if(content_length.isDefined()) | ||
121 | { | ||
122 | length = content_length.asInteger(); | ||
123 | } | ||
124 | return length; | ||
125 | } | ||
126 | |||
127 | std::string LLMimeIndex::contentType() const | ||
128 | { | ||
129 | std::string type; | ||
130 | LLSD content_type = mImpl->mHeaders[CONTENT_TYPE]; | ||
131 | if(content_type.isDefined()) | ||
132 | { | ||
133 | type = content_type.asString(); | ||
134 | } | ||
135 | return type; | ||
136 | } | ||
137 | |||
138 | bool LLMimeIndex::isMultipart() const | ||
139 | { | ||
140 | bool multipart = false; | ||
141 | LLSD content_type = mImpl->mHeaders[CONTENT_TYPE]; | ||
142 | if(content_type.isDefined()) | ||
143 | { | ||
144 | std::string type = content_type.asString(); | ||
145 | int comp = type.compare(0, MULTIPART.size(), MULTIPART); | ||
146 | if(0 == comp) | ||
147 | { | ||
148 | multipart = true; | ||
149 | } | ||
150 | } | ||
151 | return multipart; | ||
152 | } | ||
153 | |||
154 | S32 LLMimeIndex::subPartCount() const | ||
155 | { | ||
156 | return mImpl->mAttachments.size(); | ||
157 | } | ||
158 | |||
159 | LLMimeIndex LLMimeIndex::subPart(S32 index) const | ||
160 | { | ||
161 | LLMimeIndex part; | ||
162 | if((index >= 0) && (index < (S32)mImpl->mAttachments.size())) | ||
163 | { | ||
164 | part = mImpl->mAttachments[index]; | ||
165 | } | ||
166 | return part; | ||
167 | } | ||
168 | |||
169 | LLMimeIndex::LLMimeIndex() : mImpl(new LLMimeIndex::Impl) | ||
170 | { | ||
171 | } | ||
172 | |||
173 | LLMimeIndex::LLMimeIndex(LLSD headers, S32 content_offset) : | ||
174 | mImpl(new LLMimeIndex::Impl(headers, content_offset)) | ||
175 | { | ||
176 | } | ||
177 | |||
178 | LLMimeIndex::LLMimeIndex(const LLMimeIndex& mime) : | ||
179 | mImpl(mime.mImpl) | ||
180 | { | ||
181 | ++mImpl->mUseCount; | ||
182 | } | ||
183 | |||
184 | LLMimeIndex::~LLMimeIndex() | ||
185 | { | ||
186 | if(0 == --mImpl->mUseCount) | ||
187 | { | ||
188 | delete mImpl; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | LLMimeIndex& LLMimeIndex::operator=(const LLMimeIndex& mime) | ||
193 | { | ||
194 | // Increment use count first so that we handle self assignment | ||
195 | // automatically. | ||
196 | ++mime.mImpl->mUseCount; | ||
197 | if(0 == --mImpl->mUseCount) | ||
198 | { | ||
199 | delete mImpl; | ||
200 | } | ||
201 | mImpl = mime.mImpl; | ||
202 | return *this; | ||
203 | } | ||
204 | |||
205 | bool LLMimeIndex::attachSubPart(LLMimeIndex sub_part) | ||
206 | { | ||
207 | // *FIX: Should we check for multi-part? | ||
208 | if(mImpl->mAttachments.size() < S32_MAX) | ||
209 | { | ||
210 | mImpl->mAttachments.push_back(sub_part); | ||
211 | return true; | ||
212 | } | ||
213 | return false; | ||
214 | } | ||
215 | |||
216 | /** | ||
217 | * LLMimeParser | ||
218 | */ | ||
219 | /** | ||
220 | * @class LLMimeParser::Impl | ||
221 | * @brief Implementation details of the mime parser class. | ||
222 | * @see LLMimeParser | ||
223 | */ | ||
224 | class LLMimeParser::Impl | ||
225 | { | ||
226 | public: | ||
227 | // @brief Constructor. | ||
228 | Impl(); | ||
229 | |||
230 | // @brief Reset this for a new parse. | ||
231 | void reset(); | ||
232 | |||
233 | /** | ||
234 | * @brief Parse a mime entity to find the index information. | ||
235 | * | ||
236 | * This method will scan the istr until a single complete mime | ||
237 | * entity is read, an EOF, or limit bytes have been scanned. The | ||
238 | * istr will be modified by this parsing, so pass in a temporary | ||
239 | * stream or rewind/reset the stream after this call. | ||
240 | * @param istr An istream which contains a mime entity. | ||
241 | * @param limit The maximum number of bytes to scan. | ||
242 | * @param separator The multipart separator if it is known. | ||
243 | * @param is_subpart Set true if parsing a multipart sub part. | ||
244 | * @param index[out] The parsed output. | ||
245 | * @return Returns true if an index was parsed and no errors occurred. | ||
246 | */ | ||
247 | bool parseIndex( | ||
248 | std::istream& istr, | ||
249 | S32 limit, | ||
250 | const std::string& separator, | ||
251 | bool is_subpart, | ||
252 | LLMimeIndex& index); | ||
253 | |||
254 | protected: | ||
255 | /** | ||
256 | * @brief parse the headers. | ||
257 | * | ||
258 | * At the end of a successful parse, mScanCount will be at the | ||
259 | * start of the content. | ||
260 | * @param istr The input stream. | ||
261 | * @param limit maximum number of bytes to process | ||
262 | * @param headers[out] A map of the headers found. | ||
263 | * @return Returns true if the parse was successful. | ||
264 | */ | ||
265 | bool parseHeaders(std::istream& istr, S32 limit, LLSD& headers); | ||
266 | |||
267 | /** | ||
268 | * @brief Figure out the separator string from a content type header. | ||
269 | * | ||
270 | * @param multipart_content_type The content type value from the headers. | ||
271 | * @return Returns the separator string. | ||
272 | */ | ||
273 | std::string findSeparator(std::string multipart_content_type); | ||
274 | |||
275 | /** | ||
276 | * @brief Scan through istr past the separator. | ||
277 | * | ||
278 | * @param istr The input stream. | ||
279 | * @param limit Maximum number of bytes to scan. | ||
280 | * @param separator The multipart separator. | ||
281 | */ | ||
282 | void scanPastSeparator( | ||
283 | std::istream& istr, | ||
284 | S32 limit, | ||
285 | const std::string& separator); | ||
286 | |||
287 | /** | ||
288 | * @brief Scan through istr past the content of the current mime part. | ||
289 | * | ||
290 | * @param istr The input stream. | ||
291 | * @param limit Maximum number of bytes to scan. | ||
292 | * @param headers The headers for this mime part. | ||
293 | * @param separator The multipart separator if known. | ||
294 | */ | ||
295 | void scanPastContent( | ||
296 | std::istream& istr, | ||
297 | S32 limit, | ||
298 | LLSD headers, | ||
299 | const std::string separator); | ||
300 | |||
301 | /** | ||
302 | * @brief Eat CRLF. | ||
303 | * | ||
304 | * This method has no concept of the limit, so ensure you have at | ||
305 | * least 2 characters left to eat before hitting the limit. This | ||
306 | * method will increment mScanCount as it goes. | ||
307 | * @param istr The input stream. | ||
308 | * @return Returns true if CRLF was found and consumed off of istr. | ||
309 | */ | ||
310 | bool eatCRLF(std::istream& istr); | ||
311 | |||
312 | // @brief Returns true if parsing should continue. | ||
313 | bool continueParse() const { return (!mError && mContinue); } | ||
314 | |||
315 | // @brief anonymous enumeration for parse buffer size. | ||
316 | enum | ||
317 | { | ||
318 | LINE_BUFFER_LENGTH = 1024 | ||
319 | }; | ||
320 | |||
321 | protected: | ||
322 | S32 mScanCount; | ||
323 | bool mContinue; | ||
324 | bool mError; | ||
325 | char mBuffer[LINE_BUFFER_LENGTH]; | ||
326 | }; | ||
327 | |||
328 | LLMimeParser::Impl::Impl() | ||
329 | { | ||
330 | reset(); | ||
331 | } | ||
332 | |||
333 | void LLMimeParser::Impl::reset() | ||
334 | { | ||
335 | mScanCount = 0; | ||
336 | mContinue = true; | ||
337 | mError = false; | ||
338 | mBuffer[0] = '\0'; | ||
339 | } | ||
340 | |||
341 | bool LLMimeParser::Impl::parseIndex( | ||
342 | std::istream& istr, | ||
343 | S32 limit, | ||
344 | const std::string& separator, | ||
345 | bool is_subpart, | ||
346 | LLMimeIndex& index) | ||
347 | { | ||
348 | LLSD headers; | ||
349 | bool parsed_something = false; | ||
350 | if(parseHeaders(istr, limit, headers)) | ||
351 | { | ||
352 | parsed_something = true; | ||
353 | LLMimeIndex mime(headers, mScanCount); | ||
354 | index = mime; | ||
355 | if(index.isMultipart()) | ||
356 | { | ||
357 | // Figure out the separator, scan past it, and recurse. | ||
358 | std::string ct = headers[CONTENT_TYPE].asString(); | ||
359 | std::string sep = findSeparator(ct); | ||
360 | scanPastSeparator(istr, limit, sep); | ||
361 | while(continueParse() && parseIndex(istr, limit, sep, true, mime)) | ||
362 | { | ||
363 | index.attachSubPart(mime); | ||
364 | } | ||
365 | } | ||
366 | else | ||
367 | { | ||
368 | // Scan to the end of content. | ||
369 | scanPastContent(istr, limit, headers, separator); | ||
370 | if(is_subpart) | ||
371 | { | ||
372 | scanPastSeparator(istr, limit, separator); | ||
373 | } | ||
374 | } | ||
375 | } | ||
376 | if(mError) return false; | ||
377 | return parsed_something; | ||
378 | } | ||
379 | |||
380 | bool LLMimeParser::Impl::parseHeaders( | ||
381 | std::istream& istr, | ||
382 | S32 limit, | ||
383 | LLSD& headers) | ||
384 | { | ||
385 | while(continueParse()) | ||
386 | { | ||
387 | // Get the next line. | ||
388 | // We subtract 1 from the limit so that we make sure | ||
389 | // not to read past limit when we get() the newline. | ||
390 | S32 max_get = llmin((S32)LINE_BUFFER_LENGTH, limit - mScanCount - 1); | ||
391 | istr.getline(mBuffer, max_get, '\r'); | ||
392 | mScanCount += istr.gcount(); | ||
393 | int c = istr.get(); | ||
394 | if(EOF == c) | ||
395 | { | ||
396 | mContinue = false; | ||
397 | return false; | ||
398 | } | ||
399 | ++mScanCount; | ||
400 | if(c != '\n') | ||
401 | { | ||
402 | mError = true; | ||
403 | return false; | ||
404 | } | ||
405 | if(mScanCount >= limit) | ||
406 | { | ||
407 | mContinue = false; | ||
408 | } | ||
409 | |||
410 | // Check if that's the end of headers. | ||
411 | if('\0' == mBuffer[0]) | ||
412 | { | ||
413 | break; | ||
414 | } | ||
415 | |||
416 | // Split out the name and value. | ||
417 | // *NOTE: The use of strchr() here is safe since mBuffer is | ||
418 | // guaranteed to be NULL terminated from the call to getline() | ||
419 | // above. | ||
420 | char* colon = strchr(mBuffer, ':'); | ||
421 | if(!colon) | ||
422 | { | ||
423 | mError = true; | ||
424 | return false; | ||
425 | } | ||
426 | |||
427 | // Cononicalize the name part, and store the name: value in | ||
428 | // the headers structure. We do this by iterating through | ||
429 | // 'known' headers and replacing the value found with the | ||
430 | // correct one. | ||
431 | // *NOTE: Not so efficient, but iterating through a small | ||
432 | // subset should not be too much of an issue. | ||
433 | std::string name(mBuffer, colon++ - mBuffer); | ||
434 | while(isspace(*colon)) ++colon; | ||
435 | std::string value(colon); | ||
436 | for(S32 ii = 0; ii < KNOWN_HEADER_COUNT; ++ii) | ||
437 | { | ||
438 | if(0 == LLString::compareInsensitive( | ||
439 | name.c_str(), | ||
440 | KNOWN_HEADER[ii].c_str())) | ||
441 | { | ||
442 | name = KNOWN_HEADER[ii]; | ||
443 | break; | ||
444 | } | ||
445 | } | ||
446 | headers[name] = value; | ||
447 | } | ||
448 | if(headers.isUndefined()) return false; | ||
449 | return true; | ||
450 | } | ||
451 | |||
452 | std::string LLMimeParser::Impl::findSeparator(std::string header) | ||
453 | { | ||
454 | // 01234567890 | ||
455 | //Content-Type: multipart/mixed; boundary="segment" | ||
456 | std::string separator; | ||
457 | std::string::size_type pos = header.find(BOUNDARY); | ||
458 | if(std::string::npos == pos) return separator; | ||
459 | pos += BOUNDARY.size() + 1; | ||
460 | std::string::size_type end; | ||
461 | if(header[pos] == '"') | ||
462 | { | ||
463 | // the boundary is quoted, find the end from pos, and take the | ||
464 | // substring. | ||
465 | end = header.find('"', ++pos); | ||
466 | if(std::string::npos == end) | ||
467 | { | ||
468 | // poorly formed boundary. | ||
469 | mError = true; | ||
470 | } | ||
471 | } | ||
472 | else | ||
473 | { | ||
474 | // otherwise, it's every character until a whitespace, end of | ||
475 | // line, or another parameter begins. | ||
476 | end = header.find_first_of(END_OF_CONTENT_PARAMETER, pos); | ||
477 | if(std::string::npos == end) | ||
478 | { | ||
479 | // it goes to the end of the string. | ||
480 | end = header.size(); | ||
481 | } | ||
482 | } | ||
483 | if(!mError) separator = header.substr(pos, end - pos); | ||
484 | return separator; | ||
485 | } | ||
486 | |||
487 | void LLMimeParser::Impl::scanPastSeparator( | ||
488 | std::istream& istr, | ||
489 | S32 limit, | ||
490 | const std::string& sep) | ||
491 | { | ||
492 | std::ostringstream ostr; | ||
493 | ostr << SEPARATOR_PREFIX << sep; | ||
494 | std::string separator = ostr.str(); | ||
495 | bool found_separator = false; | ||
496 | while(!found_separator && continueParse()) | ||
497 | { | ||
498 | // Subtract 1 from the limit so that we make sure not to read | ||
499 | // past limit when we get() the newline. | ||
500 | S32 max_get = llmin((S32)LINE_BUFFER_LENGTH, limit - mScanCount - 1); | ||
501 | istr.getline(mBuffer, max_get, '\r'); | ||
502 | mScanCount += istr.gcount(); | ||
503 | if(istr.gcount() >= LINE_BUFFER_LENGTH - 1) | ||
504 | { | ||
505 | // that's way too long to be a separator, so ignore it. | ||
506 | continue; | ||
507 | } | ||
508 | int c = istr.get(); | ||
509 | if(EOF == c) | ||
510 | { | ||
511 | mContinue = false; | ||
512 | return; | ||
513 | } | ||
514 | ++mScanCount; | ||
515 | if(c != '\n') | ||
516 | { | ||
517 | mError = true; | ||
518 | return; | ||
519 | } | ||
520 | if(mScanCount >= limit) | ||
521 | { | ||
522 | mContinue = false; | ||
523 | } | ||
524 | if(0 == LLString::compareStrings(mBuffer, separator.c_str())) | ||
525 | { | ||
526 | found_separator = true; | ||
527 | } | ||
528 | } | ||
529 | } | ||
530 | |||
531 | void LLMimeParser::Impl::scanPastContent( | ||
532 | std::istream& istr, | ||
533 | S32 limit, | ||
534 | LLSD headers, | ||
535 | const std::string separator) | ||
536 | { | ||
537 | if(headers.has(CONTENT_LENGTH)) | ||
538 | { | ||
539 | S32 content_length = headers[CONTENT_LENGTH].asInteger(); | ||
540 | // Subtract 2 here for the \r\n after the content. | ||
541 | S32 max_skip = llmin(content_length, limit - mScanCount - 2); | ||
542 | istr.ignore(max_skip); | ||
543 | mScanCount += max_skip; | ||
544 | |||
545 | // *NOTE: Check for hitting the limit and eof here before | ||
546 | // checking for the trailing EOF, because our mime parser has | ||
547 | // to gracefully handle incomplete mime entites. | ||
548 | if((mScanCount >= limit) || istr.eof()) | ||
549 | { | ||
550 | mContinue = false; | ||
551 | } | ||
552 | else if(!eatCRLF(istr)) | ||
553 | { | ||
554 | mError = true; | ||
555 | return; | ||
556 | } | ||
557 | } | ||
558 | } | ||
559 | |||
560 | bool LLMimeParser::Impl::eatCRLF(std::istream& istr) | ||
561 | { | ||
562 | int c = istr.get(); | ||
563 | ++mScanCount; | ||
564 | if(c != '\r') | ||
565 | { | ||
566 | return false; | ||
567 | } | ||
568 | c = istr.get(); | ||
569 | ++mScanCount; | ||
570 | if(c != '\n') | ||
571 | { | ||
572 | return false; | ||
573 | } | ||
574 | return true; | ||
575 | } | ||
576 | |||
577 | |||
578 | LLMimeParser::LLMimeParser() : mImpl(* new LLMimeParser::Impl) | ||
579 | { | ||
580 | } | ||
581 | |||
582 | LLMimeParser::~LLMimeParser() | ||
583 | { | ||
584 | delete & mImpl; | ||
585 | } | ||
586 | |||
587 | void LLMimeParser::reset() | ||
588 | { | ||
589 | mImpl.reset(); | ||
590 | } | ||
591 | |||
592 | bool LLMimeParser::parseIndex(std::istream& istr, LLMimeIndex& index) | ||
593 | { | ||
594 | std::string separator; | ||
595 | return mImpl.parseIndex(istr, S32_MAX, separator, false, index); | ||
596 | } | ||
597 | |||
598 | bool LLMimeParser::parseIndex( | ||
599 | const std::vector<U8>& buffer, | ||
600 | LLMimeIndex& index) | ||
601 | { | ||
602 | LLMemoryStream mstr(&buffer[0], buffer.size()); | ||
603 | return parseIndex(mstr, buffer.size() + 1, index); | ||
604 | } | ||
605 | |||
606 | bool LLMimeParser::parseIndex( | ||
607 | std::istream& istr, | ||
608 | S32 limit, | ||
609 | LLMimeIndex& index) | ||
610 | { | ||
611 | std::string separator; | ||
612 | return mImpl.parseIndex(istr, limit, separator, false, index); | ||
613 | } | ||
614 | |||
615 | bool LLMimeParser::parseIndex(const U8* buffer, S32 length, LLMimeIndex& index) | ||
616 | { | ||
617 | LLMemoryStream mstr(buffer, length); | ||
618 | return parseIndex(mstr, length + 1, index); | ||
619 | } | ||
620 | |||
621 | /* | ||
622 | bool LLMimeParser::verify(std::istream& isr, LLMimeIndex& index) const | ||
623 | { | ||
624 | return false; | ||
625 | } | ||
626 | |||
627 | bool LLMimeParser::verify(U8* buffer, S32 length, LLMimeIndex& index) const | ||
628 | { | ||
629 | LLMemoryStream mstr(buffer, length); | ||
630 | return verify(mstr, index); | ||
631 | } | ||
632 | */ | ||