View Javadoc
1   /**
2    * Redistribution and use of this software and associated documentation
3    * ("Software"), with or without modification, are permitted provided
4    * that the following conditions are met:
5    *
6    * 1. Redistributions of source code must retain copyright
7    *    statements and notices.  Redistributions must also contain a
8    *    copy of this document.
9    *
10   * 2. Redistributions in binary form must reproduce the
11   *    above copyright notice, this list of conditions and the
12   *    following disclaimer in the documentation and/or other
13   *    materials provided with the distribution.
14   *
15   * 3. The name "Exolab" must not be used to endorse or promote
16   *    products derived from this Software without prior written
17   *    permission of Intalio, Inc.  For written permission,
18   *    please contact info@exolab.org.
19   *
20   * 4. Products derived from this Software may not be called "Exolab"
21   *    nor may "Exolab" appear in their names without prior written
22   *    permission of Intalio, Inc. Exolab is a registered
23   *    trademark of Intalio, Inc.
24   *
25   * 5. Due credit should be given to the Exolab Project
26   *    (http://www.exolab.org/).
27   *
28   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
29   * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
32   * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39   * OF THE POSSIBILITY OF SUCH DAMAGE.
40   *
41   * Copyright 2000 (C) Intalio Inc. All Rights Reserved.
42   *
43   * $Id$
44   */
45  
46  package org.exolab.castor.xml.dtd.parser;
47  
48  /**
49   * An implementation of interface
50   * {@link org.exolab.castor.xml.dtd.parser.CharStream CharStream}.
51   * Implements input character stream
52   * that maintains line and column number positions of the characters.
53   * It also has the capability to backup the stream to some extent.<br>
54   * The object of this class is constructed using
55   * {@link java.io.Reader java.io.Reader} <tt>reader</tt> and it is left to
56   * constructor of the <tt>reader</tt> to set up character encoding correctly.
57   * This means that method <u><font color="blue">read</font></u> of
58   * the <tt>reader</tt> is used to get next characters, assuming it returns
59   * appropriate values. It is recommended to use class
60   * {@link java.io.InputStreamReader java.io.InputStreamReader}
61   * as a <tt>reader</tt>, which allows to set desired character encoding.
62   * This class is an intermediate component between input
63   * character reader and the parser.<br>
64   * The code of this class is based on the class <b>ASCII_CharStream</b> - implementation
65   * of interface
66   * {@link org.exolab.castor.xml.dtd.parser.CharStream CharStream},
67   * that JavaCC would have generated with
68   * the following options set in a JavaCC grammar file: <pre>
69   *    JAVA_UNICODE_ESCAPE = false;
70   *    UNICODE_INPUT = false;
71   *    USER_CHAR_STREAM = false; </pre>
72   * Note that this class is not fully JavaCC generated.<br>
73   * @author <b>JavaCC</b>, <a href="mailto:totok@intalio.com">Alexander Totok</a>
74   * @version $Revision$ $Date: 2003-03-03 00:05:44 -0700 (Mon, 03 Mar 2003) $
75   */
76  public final class InputCharStream implements CharStream {
77  
78     public static final boolean staticFlag = false;
79     int bufsize;
80     int available;
81     int tokenBegin;
82     public int bufpos = -1;
83     private int bufline[];
84     private int bufcolumn[];
85  
86     private int column = 0;
87     private int line = 1;
88  
89     private boolean prevCharIsCR = false;
90     private boolean prevCharIsLF = false;
91  
92     private java.io.Reader inputStream;
93  
94     private char[] buffer;
95     private int maxNextCharInd = 0;
96     private int inBuf = 0;
97  
98     private final void ExpandBuff(boolean wrapAround) {
99  
100       char[] newbuffer = new char[bufsize + 2048];
101       int newbufline[] = new int[bufsize + 2048];
102       int newbufcolumn[] = new int[bufsize + 2048];
103 
104       try {
105          if (wrapAround) {
106             System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
107             System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
108             buffer = newbuffer;
109 
110             System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
111             System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
112             bufline = newbufline;
113 
114             System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
115             System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
116             bufcolumn = newbufcolumn;
117 
118             maxNextCharInd = (bufpos += (bufsize - tokenBegin));
119 
120          } else {
121 
122             System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
123             buffer = newbuffer;
124 
125             System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
126             bufline = newbufline;
127 
128             System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
129             bufcolumn = newbufcolumn;
130 
131             maxNextCharInd = (bufpos -= tokenBegin);
132          }
133       }
134       catch (Throwable t) {
135          throw new Error(t.getMessage());
136       }
137 
138       bufsize += 2048;
139       available = bufsize;
140       tokenBegin = 0;
141    }
142 
143    private final void FillBuff() throws java.io.IOException {
144       if (maxNextCharInd == available) {
145          if (available == bufsize) {
146             if (tokenBegin > 2048) {
147                bufpos = maxNextCharInd = 0;
148                available = tokenBegin;
149             } else if (tokenBegin < 0) bufpos = maxNextCharInd = 0;
150             else ExpandBuff(false);
151          } else if (available > tokenBegin) available = bufsize;
152          else if ((tokenBegin - available) < 2048) ExpandBuff(true);
153          else available = tokenBegin;
154       }
155 
156       int i;
157 
158       try {
159          if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1) {
160             inputStream.close();
161             throw new java.io.IOException();
162          }
163          maxNextCharInd += i;
164          return;
165       } catch(java.io.IOException e) {
166          --bufpos;
167          backup(0);
168          if (tokenBegin == -1) tokenBegin = bufpos;
169          throw e;
170       }
171    }
172 
173    public final char BeginToken() throws java.io.IOException {
174 
175       tokenBegin = -1;
176       char c = readChar();
177       tokenBegin = bufpos;
178       return c;
179    }
180 
181    private final void UpdateLineColumn(char c) {
182 
183       column++;
184       if (prevCharIsLF) {
185          prevCharIsLF = false;
186          line += (column = 1);
187       } else if (prevCharIsCR) {
188          prevCharIsCR = false;
189          if (c == '\n') prevCharIsLF = true;
190          else line += (column = 1);
191       }
192 
193       switch (c) {
194          case '\r' :
195             prevCharIsCR = true;
196             break;
197          case '\n' :
198             prevCharIsLF = true;
199             break;
200          case '\t' :
201             column--;
202             column += (8 - (column & 07));
203             break;
204          default :
205             break;
206       }
207 
208       bufline[bufpos] = line;
209       bufcolumn[bufpos] = column;
210    }
211 
212    /**
213     * Returns the next character from the input stream. The only method whose
214     * implementation is different from its original in the ASCII_CharStream class.
215     */
216    public final char readChar() throws java.io.IOException {
217 
218       if (inBuf > 0) {
219          --inBuf;
220 
221          //----------------------------------------------------------------------
222          // the next line was changed, the original line generated by JavaCC was:
223          // return (char)((char)0xff & buffer[(bufpos == bufsize - 1) ? (bufpos = 0) : ++bufpos]);
224          //----------------------------------------------------------------------
225          return buffer[(bufpos == bufsize - 1) ? (bufpos = 0) : ++bufpos];
226       }
227       if (++bufpos >= maxNextCharInd) FillBuff();
228 
229       //----------------------------------------------------------------------
230       // the next line was changed, the original line generated by JavaCC was:
231       // char c = (char)((char)0xff & buffer[bufpos]);
232       //----------------------------------------------------------------------
233       char c = buffer[bufpos];
234 
235       UpdateLineColumn(c);
236       return (c);
237     }
238 
239    /**
240     * @deprecated
241     * @see #getEndColumn
242     */
243    public final int getColumn() {
244       return bufcolumn[bufpos];
245    }
246 
247    /**
248     * @deprecated
249     * @see #getEndLine
250     */
251    public final int getLine() {
252       return bufline[bufpos];
253    }
254 
255    public final int getEndColumn() {
256       return bufcolumn[bufpos];
257    }
258 
259    public final int getEndLine() {
260       return bufline[bufpos];
261    }
262 
263    public final int getBeginColumn() {
264       return bufcolumn[tokenBegin];
265    }
266 
267    public final int getBeginLine() {
268       return bufline[tokenBegin];
269    }
270 
271    public final void backup(int amount) {
272       inBuf += amount;
273       if ((bufpos -= amount) < 0) bufpos += bufsize;
274    }
275 
276    /**
277     * Constructor, allowing to specify start line and start column of the char
278     * stream, and buffer size as well.
279     */
280    public InputCharStream(java.io.Reader dstream, int startline,
281                            int startcolumn, int buffersize) {
282       inputStream = dstream;
283       line = startline;
284       column = startcolumn - 1;
285       available = bufsize = buffersize;
286       buffer = new char[buffersize];
287       bufline = new int[buffersize];
288       bufcolumn = new int[buffersize];
289    }
290 
291    /**
292     * Constructor, allowing to specify start line and start column
293     * of the char stream.
294     */
295    public InputCharStream(java.io.Reader dstream, int startline,
296                                                    int startcolumn) {
297       this(dstream, startline, startcolumn, 4096);
298    }
299 
300    /**
301     * Constructor, instantiating the char stream to begin at 1-st line and
302     * 1-st column of <tt>dstream</tt>.
303     */
304    public InputCharStream(java.io.Reader dstream) {
305       this(dstream, 1, 1);
306    }
307 
308    /**
309     * Reinitialization of the char stream, allowing to specify start line
310     * and start column of the char stream, and buffer size as well.
311     */
312    public void ReInit(java.io.Reader dstream, int startline,
313                              int startcolumn, int buffersize) {
314       inputStream = dstream;
315       line = startline;
316       column = startcolumn - 1;
317 
318       if (buffer == null || buffersize != buffer.length) {
319          available = bufsize = buffersize;
320          buffer = new char[buffersize];
321          bufline = new int[buffersize];
322          bufcolumn = new int[buffersize];
323       }
324       prevCharIsLF = prevCharIsCR = false;
325       tokenBegin = inBuf = maxNextCharInd = 0;
326       bufpos = -1;
327    }
328 
329    /**
330     * Reinitialization of the char stream, allowing to specify start line
331     * and start column of the char stream.
332     */
333    public void ReInit(java.io.Reader dstream, int startline,
334                                               int startcolumn) {
335       ReInit(dstream, startline, startcolumn, 4096);
336    }
337 
338    /**
339     * Reinitialization of the char stream, instantiating the char stream
340     * to begin at 1-st line and 1-st column of <tt>dstream</tt>.
341     */
342    public void ReInit(java.io.Reader dstream) {
343       ReInit(dstream, 1, 1);
344    }
345 
346    public final String GetImage() {
347       if (bufpos >= tokenBegin) {
348           return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
349       }
350       return new String(buffer, tokenBegin, bufsize - tokenBegin) + new String(buffer, 0, bufpos + 1);
351    }
352 
353    public final char[] GetSuffix(int len) {
354       char[] ret = new char[len];
355 
356       if ((bufpos + 1) >= len)
357          System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
358       else {
359          System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
360                                   len - bufpos - 1);
361          System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
362       }
363       return ret;
364    }
365 
366    public void Done() {
367       buffer = null;
368       bufline = null;
369       bufcolumn = null;
370    }
371 
372    /**
373     * Method to adjust line and column numbers for the start of a token.
374     */
375    public void adjustBeginLineColumn(int newLine, int newCol) {
376       int start = tokenBegin;
377       int len;
378 
379       if (bufpos >= tokenBegin) {
380          len = bufpos - tokenBegin + inBuf + 1;
381       } else {
382          len = bufsize - tokenBegin + bufpos + 1 + inBuf;
383       }
384 
385       int i = 0, j = 0, k = 0;
386       int nextColDiff = 0, columnDiff = 0;
387 
388       while (i < len &&
389              bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) {
390          bufline[j] = newLine;
391          nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
392          bufcolumn[j] = newCol + columnDiff;
393          columnDiff = nextColDiff;
394          i++;
395       }
396 
397       if (i < len) {
398          bufline[j] = newLine++;
399          bufcolumn[j] = newCol + columnDiff;
400 
401          while (i++ < len) {
402             if (bufline[j = start % bufsize] != bufline[++start % bufsize])
403                bufline[j] = newLine++;
404             else
405                bufline[j] = newLine;
406          }
407       }
408 
409       line = bufline[j];
410       column = bufcolumn[j];
411    }
412 }