tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsReadLine.h (4229B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      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/. */
      6 
      7 #ifndef nsReadLine_h__
      8 #define nsReadLine_h__
      9 
     10 #include "nsIInputStream.h"
     11 #include "mozilla/Likely.h"
     12 
     13 /**
     14 * @file
     15 * Functions to read complete lines from an input stream.
     16 *
     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
     19 * wants a line out.
     20 *
     21 * When done, the object should be deleted.
     22 */
     23 
     24 /**
     25 * @internal
     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).
     31 */
     32 #define kLineBufferSize 4096
     33 
     34 /**
     35 * @internal
     36 * Line buffer structure, buffers data from an input stream.
     37 * The buffer is empty when |start| == |end|.
     38 * Invariant: |start| <= |end|
     39 */
     40 template <typename CharT>
     41 class nsLineBuffer {
     42 public:
     43  nsLineBuffer() : start(buf), end(buf) {}
     44 
     45  CharT buf[kLineBufferSize + 1];
     46  CharT* start;
     47  CharT* end;
     48 };
     49 
     50 /**
     51 * Read a line from an input stream. Lines are separated by '\r' (0x0D) or '\n'
     52 * (0x0A), or "\r\n" or "\n\r".
     53 *
     54 * @param aStream
     55 *        The stream to read from
     56 * @param aBuffer
     57 *        The line buffer to use.  A single line buffer must not be used with
     58 *        different input streams.
     59 * @param aLine [out]
     60 *        The string where the line will be stored.
     61 * @param more [out]
     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.
     65 *
     66 * @retval NS_OK
     67 *         Read successful
     68 * @retval error
     69 *         Input stream returned an error upon read. See
     70 *         nsIInputStream::read.
     71 */
     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
     76 
     77  aLine.Truncate();
     78 
     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.
     81      uint32_t bytesRead;
     82      nsresult rv = aStream->Read(aBuffer->buf, kLineBufferSize, &bytesRead);
     83      if (NS_FAILED(rv) || MOZ_UNLIKELY(bytesRead == 0)) {
     84        *more = false;
     85        return rv;
     86      }
     87      aBuffer->start = aBuffer->buf;
     88      aBuffer->end = aBuffer->buf + bytesRead;
     89      *(aBuffer->end) = '\0';
     90    }
     91 
     92    /*
     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.
    101     */
    102    CharT* current = aBuffer->start;
    103    if (MOZ_LIKELY(eolchar == 0)) {
    104      for (; current < aBuffer->end; ++current) {
    105        if (*current == '\n' || *current == '\r') {
    106          eolchar = *current;
    107          *current++ = '\0';
    108          aLine.Append(aBuffer->start);
    109          break;
    110        }
    111      }
    112    }
    113    if (MOZ_LIKELY(eolchar != 0)) {
    114      for (; current < aBuffer->end; ++current) {
    115        if ((eolchar == '\r' && *current == '\n') ||
    116            (eolchar == '\n' && *current == '\r')) {
    117          eolchar = 1;
    118          continue;
    119        }
    120        aBuffer->start = current;
    121        *more = true;
    122        return NS_OK;
    123      }
    124    }
    125 
    126    if (eolchar == 0) aLine.Append(aBuffer->start);
    127    aBuffer->start = aBuffer->end;  // mark the buffer empty
    128  }
    129 }
    130 
    131 #endif  // nsReadLine_h__