1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #ifndef _nsMsgLineBuffer_H
6 #define _nsMsgLineBuffer_H
7 
8 #include "msgCore.h"  // precompiled header...
9 
10 // I can't believe I have to have this stupid class, but I can't find
11 // anything suitable (nsStrImpl might be, when it's done). nsIByteBuffer
12 // would do, if I had a stream for input, which I don't.
13 
14 class nsByteArray {
15  public:
16   nsByteArray();
17   virtual ~nsByteArray();
GetSize()18   uint32_t GetSize() { return m_bufferSize; }
GetBufferPos()19   uint32_t GetBufferPos() { return m_bufferPos; }
20   nsresult GrowBuffer(uint32_t desired_size, uint32_t quantum = 1024);
21   nsresult AppendString(const char* string);
22   nsresult AppendBuffer(const char* buffer, uint32_t length);
ResetWritePos()23   void ResetWritePos() { m_bufferPos = 0; }
GetBuffer()24   char* GetBuffer() { return m_buffer; }
25 
26  protected:
27   char* m_buffer;
28   uint32_t m_bufferSize;
29   uint32_t
30       m_bufferPos;  // write Pos in m_buffer - where the next byte should go.
31 };
32 
33 /**
34  * nsMsgLineBuffer breaks up incoming data into lines.
35  * It accepts CRLF, CR or LF line endings.
36  *
37  * Data is fed in via BufferInput(). The virtual HandleLine() will be
38  * invoked for each line. The data passed to HandleLine() is verbatim,
39  * and will include whatever line endings were in the source data.
40  *
41  * Flush() should be called when the data is exhausted, to handle any
42  * leftover bytes in the buffer (e.g. if the data doesn't end with an EOL).
43  */
44 class nsMsgLineBuffer : private nsByteArray {
45  public:
46   nsMsgLineBuffer();
47   virtual ~nsMsgLineBuffer();
48   nsresult BufferInput(const char* net_buffer, int32_t net_buffer_size);
49 
50   /**
51    * HandleLine should be implemented by derived classes, to handle a line.
52    * The line will have whatever end-of-line characters were present in the
53    * source data (potentially none, if the data ends mid-line).
54    */
55   virtual nsresult HandleLine(const char* line, uint32_t line_length) = 0;
56 
57   /**
58    * Flush processes any unprocessed data currently in the buffer. Should
59    * be called when the source data is exhausted.
60    */
61   nsresult Flush();
62 };
63 
64 // I'm adding this utility class here for lack of a better place. This utility
65 // class is similar to nsMsgLineBuffer except it works from an input stream. It
66 // is geared towards efficiently parsing new lines out of a stream by storing
67 // read but unprocessed bytes in a buffer. I envision the primary use of this to
68 // be our mail protocols such as imap, news and pop which need to process line
69 // by line data being returned in the form of a proxied stream from the server.
70 
71 class nsIInputStream;
72 
73 class nsMsgLineStreamBuffer {
74  public:
75   NS_INLINE_DECL_REFCOUNTING(nsMsgLineStreamBuffer)
76 
77   // aBufferSize -- size of the buffer you want us to use for buffering stream
78   //                data
79   // aEndOfLinetoken -- The delimiter string to be used for determining the end
80   //                of line. This allows us to parse platform specific end of
81   //                line endings by making it a parameter.
82   // aAllocateNewLines -- true if you want calls to ReadNextLine to allocate new
83   //                memory for the line.
84   //                if false, the char * returned is just a ptr into the buffer.
85   //                Subsequent calls to ReadNextLine will alter the data so your
86   //                ptr only has a life time of a per call.
87   // aEatCRLFs --   true if you don't want to see the CRLFs on the lines
88   //                returned by ReadNextLine.
89   //                false if you do want to see them.
90   // aLineToken --  Specify the line token to look for, by default is LF ('\n')
91   //                which cover as well CRLF. If lines are terminated with a CR
92   //                only, you need to set aLineToken to CR ('\r')
93   nsMsgLineStreamBuffer(
94       uint32_t aBufferSize, bool aAllocateNewLines, bool aEatCRLFs = true,
95       char aLineToken = '\n');  // specify the size of the buffer you want the
96                                 // class to use....
97 
98   // Caller must free the line returned using PR_Free
99   // aEndOfLinetoken   -- delimiter used to denote the end of a line.
100   // aNumBytesInLine   -- The number of bytes in the line returned
101   // aPauseForMoreData -- There is not enough data in the stream to make a line
102   //                      at this time...
103   char* ReadNextLine(nsIInputStream* aInputStream, uint32_t& aNumBytesInLine,
104                      bool& aPauseForMoreData, nsresult* rv = nullptr,
105                      bool addLineTerminator = false);
106   nsresult GrowBuffer(uint32_t desiredSize);
107   void ClearBuffer();
108   bool NextLineAvailable();
109 
110  private:
111   virtual ~nsMsgLineStreamBuffer();
112 
113  protected:
114   bool m_eatCRLFs;
115   bool m_allocateNewLines;
116   char* m_dataBuffer;
117   uint32_t m_dataBufferSize;
118   uint32_t m_startPos;
119   uint32_t m_numBytesInBuffer;
120   char m_lineToken;
121 };
122 
123 #endif
124