• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.io;
18 
19 import java.io.IOException;
20 
21 /**
22  * Package-protected abstract class that implements the line reading
23  * algorithm used by {@link LineReader}. Line separators are per {@link
24  * java.io.BufferedReader}: line feed, carriage return, or carriage
25  * return followed immediately by a linefeed.
26  *
27  * <p>Subclasses must implement {@link #handleLine}, call {@link #add}
28  * to pass character data, and call {@link #finish} at the end of stream.
29  *
30  * @author Chris Nokleberg
31  * @since 2009.09.15 <b>tentative</b>
32  */
33 abstract class LineBuffer {
34   /** Holds partial line contents. */
35   private StringBuilder line = new StringBuilder();
36   /** Whether a line ending with a CR is pending processing. */
37   private boolean sawReturn;
38 
39   /**
40    * Process additional characters from the stream. When a line separator
41    * is found the contents of the line and the line separator itself
42    * are passed to the abstract {@link #handleLine} method.
43    *
44    * @param cbuf the character buffer to process
45    * @param off the offset into the buffer
46    * @param len the number of characters to process
47    * @throws IOException if an I/O error occurs
48    * @see #finish
49    */
50   @SuppressWarnings("fallthrough")
add(char[] cbuf, int off, int len)51   protected void add(char[] cbuf, int off, int len) throws IOException {
52     int pos = off;
53     if (sawReturn && len > 0) {
54       // Last call to add ended with a CR; we can handle the line now.
55       if (finishLine(cbuf[pos] == '\n')) {
56         pos++;
57       }
58     }
59 
60     int start = pos;
61     for (int end = off + len; pos < end; pos++) {
62       switch (cbuf[pos]) {
63         case '\r':
64           line.append(cbuf, start, pos - start);
65           sawReturn = true;
66           if (pos + 1 < end) {
67             if (finishLine(cbuf[pos + 1] == '\n')) {
68               pos++;
69             }
70           }
71           start = pos + 1;
72           break;
73 
74         case '\n':
75           line.append(cbuf, start, pos - start);
76           finishLine(true);
77           start = pos + 1;
78           break;
79       }
80     }
81     line.append(cbuf, start, off + len - start);
82   }
83 
84   /** Called when a line is complete. */
finishLine(boolean sawNewline)85   private boolean finishLine(boolean sawNewline) throws IOException {
86     handleLine(line.toString(), sawReturn
87         ? (sawNewline ? "\r\n" : "\r")
88         : (sawNewline ? "\n" : ""));
89     line = new StringBuilder();
90     sawReturn = false;
91     return sawNewline;
92   }
93 
94   /**
95    * Subclasses must call this method after finishing character processing,
96    * in order to ensure that any unterminated line in the buffer is
97    * passed to {@link #handleLine}.
98    *
99    * @throws IOException if an I/O error occurs
100    */
finish()101   protected void finish() throws IOException {
102     if (sawReturn || line.length() > 0) {
103       finishLine(false);
104     }
105   }
106 
107   /**
108    * Called for each line found in the character data passed to
109    * {@link #add}.
110    *
111    * @param line a line of text (possibly empty), without any line separators
112    * @param end the line separator; one of {@code "\r"}, {@code "\n"},
113    *     {@code "\r\n"}, or {@code ""}
114    * @throws IOException if an I/O error occurs
115    */
handleLine(String line, String end)116   protected abstract void handleLine(String line, String end)
117       throws IOException;
118 }
119