1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
10 #include "nsIInputStream.h"
11 #include "mozilla/Likely.h"
15 * Functions to read complete lines from an input stream.
17 * To properly use the helper function in here (NS_ReadLine) the caller should
18 * create a nsLineBuffer<T> with new, and pass it to NS_ReadLine every time it
21 * When done, the object should be deleted.
26 * Buffer size. This many bytes will be buffered. If a line is longer than this,
27 * the partial line will be appended to the out parameter of NS_ReadLine and the
28 * buffer will be emptied.
29 * Note: if you change this constant, please update the regression test in
30 * netwerk/test/unit/test_readline.js accordingly (bug 397850).
32 #define kLineBufferSize 4096
36 * Line buffer structure, buffers data from an input stream.
37 * The buffer is empty when |start| == |end|.
38 * Invariant: |start| <= |end|
40 template <typename CharT
>
43 nsLineBuffer() : start(buf
), end(buf
) {}
45 CharT buf
[kLineBufferSize
+ 1];
51 * Read a line from an input stream. Lines are separated by '\r' (0x0D) or '\n'
52 * (0x0A), or "\r\n" or "\n\r".
55 * The stream to read from
57 * The line buffer to use. A single line buffer must not be used with
58 * different input streams.
60 * The string where the line will be stored.
62 * Whether more data is available in the buffer. If true, NS_ReadLine may
63 * be called again to read further lines. Otherwise, further calls to
64 * NS_ReadLine will return an error.
69 * Input stream returned an error upon read. See
70 * nsIInputStream::read.
72 template <typename CharT
, class StreamType
, class StringType
>
73 nsresult
NS_ReadLine(StreamType
* aStream
, nsLineBuffer
<CharT
>* aBuffer
,
74 StringType
& aLine
, bool* more
) {
75 CharT eolchar
= 0; // the first eol char or 1 after \r\n or \n\r is found
79 while (true) { // will be returning out of this loop on eol or eof
80 if (aBuffer
->start
== aBuffer
->end
) { // buffer is empty. Read into it.
82 nsresult rv
= aStream
->Read(aBuffer
->buf
, kLineBufferSize
, &bytesRead
);
83 if (NS_FAILED(rv
) || MOZ_UNLIKELY(bytesRead
== 0)) {
87 aBuffer
->start
= aBuffer
->buf
;
88 aBuffer
->end
= aBuffer
->buf
+ bytesRead
;
89 *(aBuffer
->end
) = '\0';
93 * Walk the buffer looking for an end-of-line.
94 * There are 3 cases to consider:
95 * 1. the eol char is the last char in the buffer
96 * 2. the eol char + one more char at the end of the buffer
97 * 3. the eol char + two or more chars at the end of the buffer
98 * we need at least one char after the first eol char to determine if
99 * it's a \r\n or \n\r sequence (and skip over it), and we need one
100 * more char after the end-of-line to set |more| correctly.
102 CharT
* current
= aBuffer
->start
;
103 if (MOZ_LIKELY(eolchar
== 0)) {
104 for (; current
< aBuffer
->end
; ++current
) {
105 if (*current
== '\n' || *current
== '\r') {
108 aLine
.Append(aBuffer
->start
);
113 if (MOZ_LIKELY(eolchar
!= 0)) {
114 for (; current
< aBuffer
->end
; ++current
) {
115 if ((eolchar
== '\r' && *current
== '\n') ||
116 (eolchar
== '\n' && *current
== '\r')) {
120 aBuffer
->start
= current
;
126 if (eolchar
== 0) aLine
.Append(aBuffer
->start
);
127 aBuffer
->start
= aBuffer
->end
; // mark the buffer empty
131 #endif // nsReadLine_h__