1
2
3 package org.apache.commons.jexl3.parser;
4
5
6
7
8
9
10 public
11 abstract class AbstractCharStream
12 implements CharStream
13 {
14
15 public static final int DEFAULT_BUF_SIZE = 4096;
16
17 static final int hexval (final char c) throws java.io.IOException
18 {
19 switch (c)
20 {
21 case '0':
22 return 0;
23 case '1':
24 return 1;
25 case '2':
26 return 2;
27 case '3':
28 return 3;
29 case '4':
30 return 4;
31 case '5':
32 return 5;
33 case '6':
34 return 6;
35 case '7':
36 return 7;
37 case '8':
38 return 8;
39 case '9':
40 return 9;
41 case 'a':
42 case 'A':
43 return 10;
44 case 'b':
45 case 'B':
46 return 11;
47 case 'c':
48 case 'C':
49 return 12;
50 case 'd':
51 case 'D':
52 return 13;
53 case 'e':
54 case 'E':
55 return 14;
56 case 'f':
57 case 'F':
58 return 15;
59 default:
60 throw new java.io.IOException ("Invalid hex char '" + c + "' (=" + (int) c + ") provided!");
61 }
62 }
63
64
65 private int m_nTabSize = 1;
66
67
68 protected char[] buffer;
69
70
71 protected int bufsize;
72
73
74 protected int bufpos;
75
76
77 protected int available;
78
79
80 protected int tokenBegin;
81
82
83 protected int inBuf;
84 protected int maxNextCharInd;
85
86 private int[] m_aBufLine;
87 private int[] m_aBufColumn;
88
89
90 private int m_nLineNo;
91
92 private int m_nColumnNo;
93
94
95 private boolean m_bPrevCharIsCR;
96
97 private boolean m_bPrevCharIsLF;
98
99
100 private boolean m_bTrackLineColumn = true;
101
102
103
104 public AbstractCharStream(final int nStartLine,
105 final int nStartColumn,
106 final int nBufferSize)
107 {
108 reInit (nStartLine, nStartColumn, nBufferSize);
109 }
110
111
112 public final void reInit(final int nStartLine,
113 final int nStartColumn,
114 final int nBufferSize)
115 {
116 m_nLineNo = nStartLine;
117 m_nColumnNo = nStartColumn - 1;
118 m_bPrevCharIsCR = false;
119 m_bPrevCharIsLF = false;
120 if (buffer == null || nBufferSize != buffer.length)
121 {
122 bufsize = nBufferSize;
123 available = nBufferSize;
124 buffer = new char[nBufferSize];
125 m_aBufLine = new int[nBufferSize];
126 m_aBufColumn = new int[nBufferSize];
127 }
128 maxNextCharInd = 0;
129 inBuf = 0;
130 tokenBegin = 0;
131 bufpos = -1;
132 }
133
134
135
136
137
138
139
140
141 protected abstract int streamRead (char[] aBuf, int nOfs, int nLen) throws java.io.IOException;
142
143
144
145
146
147 protected abstract void streamClose () throws java.io.IOException;
148
149
150 protected int getBufSizeAfterExpansion ()
151 {
152
153 return bufsize * 2;
154 }
155
156 protected void expandBuff (final boolean bWrapAround)
157 {
158
159 final int nNewBufSize = getBufSizeAfterExpansion ();
160
161 final char[] newbuffer = new char[nNewBufSize];
162 final int[] newbufline = new int[nNewBufSize];
163 final int[] newbufcolumn = new int[nNewBufSize];
164
165
166 final int nPreservedChars = bufsize - tokenBegin;
167
168 if (bWrapAround)
169 {
170
171
172
173
174 System.arraycopy(buffer, tokenBegin, newbuffer, 0, nPreservedChars);
175
176
177 System.arraycopy(buffer, 0, newbuffer, nPreservedChars, bufpos);
178
179
180 buffer = newbuffer;
181
182 System.arraycopy(m_aBufLine, tokenBegin, newbufline, 0, nPreservedChars);
183 System.arraycopy(m_aBufLine, 0, newbufline, nPreservedChars, bufpos);
184 m_aBufLine = newbufline;
185
186 System.arraycopy(m_aBufColumn, tokenBegin, newbufcolumn, 0, nPreservedChars);
187 System.arraycopy(m_aBufColumn, 0, newbufcolumn, nPreservedChars, bufpos);
188 m_aBufColumn = newbufcolumn;
189
190 bufpos += nPreservedChars;
191 maxNextCharInd = bufpos;
192 }
193 else
194 {
195
196
197 System.arraycopy(buffer, tokenBegin, newbuffer, 0, nPreservedChars);
198 buffer = newbuffer;
199
200 System.arraycopy(m_aBufLine, tokenBegin, newbufline, 0, nPreservedChars);
201 m_aBufLine = newbufline;
202
203 System.arraycopy(m_aBufColumn, tokenBegin, newbufcolumn, 0, nPreservedChars);
204 m_aBufColumn = newbufcolumn;
205
206 bufpos -= tokenBegin;
207 maxNextCharInd = bufpos;
208 }
209
210
211 bufsize = nNewBufSize;
212 available = nNewBufSize;
213 tokenBegin = 0;
214 }
215
216 protected final void internalAdjustBuffSize()
217 {
218 final int nHalfBufferSize = bufsize / 2;
219 if (available == bufsize)
220 {
221 if (tokenBegin < 0)
222 {
223
224
225 bufpos = 0;
226 maxNextCharInd = 0;
227 }
228 else
229 if (tokenBegin > nHalfBufferSize)
230 {
231
232 bufpos = 0;
233 maxNextCharInd = 0;
234
235
236 available = tokenBegin;
237 }
238 else
239 {
240
241
242 expandBuff (false);
243 }
244 }
245 else
246 {
247
248 if (available > tokenBegin)
249 {
250 available = bufsize;
251 }
252 else
253 if ((tokenBegin - available) < nHalfBufferSize)
254 {
255 expandBuff (true);
256 }
257 else
258 {
259 available = tokenBegin;
260 }
261 }
262 }
263
264 protected void fillBuff() throws java.io.IOException
265 {
266 if (maxNextCharInd == available)
267 internalAdjustBuffSize();
268
269 try
270 {
271
272 final int nCharsRead = streamRead (buffer, maxNextCharInd, available - maxNextCharInd);
273 if (nCharsRead == -1)
274 {
275
276 streamClose ();
277
278
279 throw new java.io.IOException("PGCC end of stream");
280 }
281 maxNextCharInd += nCharsRead;
282 }
283 catch (final java.io.IOException ex)
284 {
285 --bufpos;
286
287 backup (0);
288 if (tokenBegin == -1)
289 {
290
291 tokenBegin = bufpos;
292 }
293 throw ex;
294 }
295 }
296
297 protected final void internalSetBufLineColumn (final int nLine, final int nColumn)
298 {
299 m_aBufLine[bufpos] = nLine;
300 m_aBufColumn[bufpos] = nColumn;
301 }
302
303 protected final void internalUpdateLineColumn(final char c)
304 {
305 m_nColumnNo++;
306
307 if (m_bPrevCharIsLF)
308 {
309
310
311 m_bPrevCharIsLF = false;
312 m_nColumnNo = 1;
313 m_nLineNo++;
314 }
315 else
316 if (m_bPrevCharIsCR)
317 {
318 m_bPrevCharIsCR = false;
319 if (c == '\n')
320 {
321
322 m_bPrevCharIsLF = true;
323 }
324 else
325 {
326
327 m_nColumnNo = 1;
328 m_nLineNo++;
329 }
330 }
331
332 switch (c)
333 {
334 case '\r':
335 m_bPrevCharIsCR = true;
336 break;
337 case '\n':
338 m_bPrevCharIsLF = true;
339 break;
340 case '\t':
341 m_nColumnNo--;
342 m_nColumnNo += (m_nTabSize - (m_nColumnNo % m_nTabSize));
343 break;
344 }
345
346 internalSetBufLineColumn (m_nLineNo, m_nColumnNo);
347 }
348
349 public char readChar() throws java.io.IOException
350 {
351 if (inBuf > 0)
352 {
353
354 --inBuf;
355
356 ++bufpos;
357 if (bufpos == bufsize)
358 {
359
360 bufpos = 0;
361 }
362
363 return buffer[bufpos];
364 }
365
366 ++bufpos;
367 if (bufpos >= maxNextCharInd)
368 fillBuff();
369
370 final char c = buffer[bufpos];
371
372 if (m_bTrackLineColumn)
373 internalUpdateLineColumn(c);
374 return c;
375 }
376
377 public char beginToken() throws java.io.IOException
378 {
379 tokenBegin = -1;
380 final char c = readChar();
381 tokenBegin = bufpos;
382 return c;
383 }
384
385 public int getBeginColumn ()
386 {
387 return m_aBufColumn[tokenBegin];
388 }
389
390 public int getBeginLine ()
391 {
392 return m_aBufLine[tokenBegin];
393 }
394
395 public int getEndColumn ()
396 {
397 return m_aBufColumn[bufpos];
398 }
399
400 public int getEndLine ()
401 {
402 return m_aBufLine[bufpos];
403 }
404
405 public void backup (final int nAmount)
406 {
407 if (nAmount > bufsize)
408 throw new IllegalStateException ("Cannot back " + nAmount + " chars which is larger than the internal buffer size (" + bufsize + ")");
409
410 inBuf += nAmount;
411 bufpos -= nAmount;
412 if (bufpos < 0)
413 {
414
415 bufpos += bufsize;
416 }
417 }
418
419 public String getImage()
420 {
421 if (bufpos >= tokenBegin)
422 {
423
424 return new String (buffer, tokenBegin, bufpos - tokenBegin + 1);
425 }
426
427
428 return new String (buffer, tokenBegin, bufsize - tokenBegin) +
429 new String (buffer, 0, bufpos + 1);
430 }
431
432 public char[] getSuffix (final int len)
433 {
434 char[] ret = new char[len];
435 if ((bufpos + 1) >= len)
436 {
437
438 System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
439 }
440 else
441 {
442
443 final int nPart1 = len - bufpos - 1;
444 System.arraycopy(buffer, bufsize - nPart1, ret, 0, nPart1);
445 System.arraycopy(buffer, 0, ret, nPart1, bufpos + 1);
446 }
447 return ret;
448 }
449
450 public void done()
451 {
452 buffer = null;
453 m_aBufLine = null;
454 m_aBufColumn = null;
455 }
456
457 public final int getTabSize()
458 {
459 return m_nTabSize;
460 }
461
462 public final void setTabSize (final int nTabSize)
463 {
464 m_nTabSize = nTabSize;
465 }
466
467
468
469
470
471 public final void adjustBeginLineColumn(final int nNewLine, final int newCol)
472 {
473 int start = tokenBegin;
474 int newLine = nNewLine;
475
476 int len;
477 if (bufpos >= tokenBegin)
478 {
479 len = bufpos - tokenBegin + inBuf + 1;
480 }
481 else
482 {
483 len = bufsize - tokenBegin + bufpos + 1 + inBuf;
484 }
485
486 int i = 0;
487 int j = 0;
488 int k = 0;
489 int nextColDiff = 0;
490 int columnDiff = 0;
491
492
493 while (i < len && m_aBufLine[j = start % bufsize] == m_aBufLine[k = ++start % bufsize])
494 {
495 m_aBufLine[j] = newLine;
496 nextColDiff = columnDiff + m_aBufColumn[k] - m_aBufColumn[j];
497 m_aBufColumn[j] = newCol + columnDiff;
498 columnDiff = nextColDiff;
499 i++;
500 }
501
502 if (i < len)
503 {
504 m_aBufLine[j] = newLine++;
505 m_aBufColumn[j] = newCol + columnDiff;
506
507 while (i++ < len)
508 {
509
510 if (m_aBufLine[j = start % bufsize] != m_aBufLine[++start % bufsize])
511 m_aBufLine[j] = newLine++;
512 else
513 m_aBufLine[j] = newLine;
514 }
515 }
516
517 m_nLineNo = m_aBufLine[j];
518 m_nColumnNo = m_aBufColumn[j];
519 }
520
521
522
523
524 protected final int getLine ()
525 {
526 return m_nLineNo;
527 }
528
529
530
531
532 protected final int getColumn ()
533 {
534 return m_nColumnNo;
535 }
536
537 public final boolean isTrackLineColumn ()
538 {
539 return m_bTrackLineColumn;
540 }
541
542 public final void setTrackLineColumn (final boolean bTrackLineColumn)
543 {
544 m_bTrackLineColumn = bTrackLineColumn;
545 }
546 }
547