1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.qedeq.base.io;
17
18 import java.io.File;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.Reader;
22 import java.math.BigInteger;
23
24 import org.qedeq.base.utility.StringUtility;
25
26
27
28
29
30
31
32 public class TextInput extends InputStream {
33
34
35 public static final int EOF = -1;
36
37
38
39 public static final char CR = '\012';
40
41
42 private static final String MARKER = "#####";
43
44
45 private final StringBuffer source;
46
47
48 private int lineNumber = 0;
49
50
51 private int column = 0;
52
53
54 private int position = 0;
55
56
57 private BigInteger maxIntValue = BigInteger.valueOf(Integer.MAX_VALUE);
58
59
60
61
62
63
64
65
66 public TextInput(final Reader reader) throws IOException {
67 try {
68 if (reader == null) {
69 throw new NullPointerException(
70 "no null pointer as argument accepted");
71 }
72 this.source = new StringBuffer();
73
74 int c;
75 while (-1 != (c = reader.read())) {
76 this.source.append((char) c);
77 }
78 } finally {
79 IoUtility.close(reader);
80 }
81 }
82
83
84
85
86
87
88
89 public TextInput(final StringBuffer source) {
90 if (source == null) {
91 throw new NullPointerException(
92 "no null pointer as argument accepted");
93 }
94 this.source = source;
95 }
96
97
98
99
100
101
102
103 public TextInput(final String source) {
104 if (source == null) {
105 throw new NullPointerException(
106 "no null pointer as argument accepted");
107 }
108 this.source = new StringBuffer(source);
109 }
110
111
112
113
114
115
116
117
118
119
120 public TextInput(final File file, final String encoding) throws IOException {
121 if (file == null) {
122 throw new NullPointerException(
123 "no null pointer as argument accepted");
124 }
125 this.source = new StringBuffer();
126 IoUtility.loadFile(file, source, encoding);
127 }
128
129
130
131
132
133
134
135
136
137 public final int read() {
138 if (position >= source.length()) {
139 return EOF;
140 }
141 if (getChar() == CR) {
142 lineNumber++;
143 column = 0;
144 } else {
145 column++;
146 }
147 return source.charAt(position++);
148 }
149
150
151
152
153
154
155
156
157
158 public final int readInverse() {
159 if (position <= 0) {
160 return -1;
161 }
162 final char c = source.charAt(--position);
163 if (c == CR) {
164 lineNumber--;
165 int pos = source.lastIndexOf("" + CR, position - 1);
166 if (pos < 0) {
167 column = position;
168 } else {
169 column = position - 1 - pos;
170 }
171 } else {
172 column--;
173 if (column < 0) {
174 throw new IllegalStateException("column less then 0");
175 }
176 }
177 return c;
178 }
179
180
181
182
183
184
185
186
187 public final String readString(final int number) {
188 final StringBuffer result = new StringBuffer(number);
189 for (int i = 0; i < number; i++) {
190 final int c = read();
191 if (c != -1) {
192 result.append((char) c);
193 } else {
194 break;
195 }
196 }
197 return result.toString();
198 }
199
200
201
202
203
204
205
206 public final void forward(final int number) {
207 for (int i = 0; i < number; i++) {
208 final int c = read();
209 if (c == -1) {
210 break;
211 }
212 }
213 }
214
215
216
217
218
219
220
221
222 public final boolean forward(final String search) {
223 final int pos = source.indexOf(search, position);
224 if (pos < 0) {
225 setPosition(getMaximumPosition());
226 return false;
227 }
228 setPosition(pos);
229 return true;
230 }
231
232
233
234
235
236
237
238
239
240 public final int getChar() {
241 if (position >= source.length()) {
242 return -1;
243 }
244 return source.charAt(position);
245 }
246
247
248
249
250
251
252
253
254
255
256
257 public final int getChar(final int skip) {
258 if (position + skip < 0 || position + skip >= source.length()) {
259 return -1;
260 }
261 return source.charAt(position + skip);
262 }
263
264
265
266
267
268
269
270
271
272 public final String getSubstring(final int from, final int to) {
273 if (from >= to) {
274 return "";
275 }
276 final int l = source.length();
277 final int f = (from < 0 ? 0 : (from > l ? l : from));
278 final int t = (to < 0 ? 0 : (to > l ? l : to));
279 return source.substring(f, t);
280 }
281
282
283
284
285
286
287 public final String asString() {
288 return source.toString();
289 }
290
291
292
293
294
295
296
297
298
299
300 public final void replace(final int from, final int to, final String replacement) {
301 source.replace(from, to, replacement);
302 if (position > from && position < to) {
303 setPosition(from + replacement.length());
304 } else if (position > from) {
305 setPosition(position - to + from + replacement.length());
306 }
307 }
308
309
310
311
312
313
314 public final void skipWhiteSpace() {
315 while (!isEmpty() && Character.isWhitespace((char) getChar())) {
316 read();
317 }
318 }
319
320
321
322
323
324
325 public final void skipWhiteSpaceInverse() {
326 while (getPosition() > 0 && Character.isWhitespace((char) getChar(-1))) {
327 readInverse();
328 }
329 }
330
331
332
333
334
335
336
337 public final void skipBackToBeginOfXmlTag() {
338 if ('<' == getChar()) {
339 return;
340 }
341 boolean quoted = false;
342 do {
343 if (-1 == readInverse()) {
344 throw new IllegalArgumentException("begin of xml tag not found");
345 }
346 if ('\"' == getChar()) {
347 quoted = !quoted;
348 }
349 } while (quoted || '<' != getChar());
350 }
351
352
353
354
355 public final void skipToEndOfLine() {
356 int c = 0;
357 do {
358 c = read();
359 } while (!isEmpty() && c != CR);
360 }
361
362
363
364
365
366
367
368 public final void skipForwardToEndOfXmlTag() {
369 if ('>' == getChar()) {
370 return;
371 }
372 boolean quoted = false;
373 while (!isEmpty() && (quoted || '>' != getChar())) {
374 int c = read();
375 if ('\"' == c) {
376 quoted = !quoted;
377 }
378 }
379 if (isEmpty()) {
380 throw new IllegalArgumentException("end of xml tag not found");
381 }
382 read();
383 }
384
385
386
387
388
389
390
391
392
393
394 public final String readNextXmlName() {
395 skipWhiteSpace();
396 if (isEmpty() || '=' == getChar() || '>' == getChar() || '<' == getChar()) {
397 throw new IllegalArgumentException(
398 "begin of attribute or tag expected");
399 }
400 StringBuffer buffer = new StringBuffer();
401 while (!isEmpty() && '=' != getChar() && '>' != getChar() && '<' != getChar()
402 && !Character.isWhitespace((char) getChar())) {
403 buffer.append((char) read());
404 }
405 return buffer.toString();
406 }
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423 public final String readNextAttributeValue() {
424 skipWhiteSpace();
425 if (isEmpty() || '=' != getChar()) {
426 throw new IllegalArgumentException(
427 "\"=\" expected");
428 }
429 read();
430 skipWhiteSpace();
431 if (isEmpty() || '>' == getChar()) {
432 throw new IllegalArgumentException(
433 "attribute value expected");
434 }
435 StringBuffer buffer = new StringBuffer();
436 if ('\"' == getChar()) {
437 read();
438 while (!isEmpty() && '\"' != getChar()) {
439 buffer.append((char) read());
440 }
441 if ('\"' != getChar()) {
442 throw new IllegalArgumentException("\" expected");
443 }
444 read();
445 } else {
446 while (!isEmpty() && '>' != getChar()
447 && !Character.isWhitespace((char) getChar())) {
448 buffer.append((char) read());
449 }
450 }
451 return StringUtility.unescapeXml(buffer.toString());
452 }
453
454
455
456
457
458
459 public final boolean isEmpty() {
460 return position >= source.length();
461 }
462
463
464
465
466
467
468
469 public final boolean isEmpty(final int skip) {
470 return position + skip >= source.length();
471 }
472
473
474
475
476
477
478
479
480
481
482 public final String readLetterDigitString() {
483 skipWhiteSpace();
484 if (isEmpty() || !Character.isLetterOrDigit((char) getChar())) {
485 read();
486 throw new IllegalArgumentException(
487 "letter or digit expected");
488 }
489 StringBuffer buffer = new StringBuffer();
490 while (!isEmpty() && Character.isLetterOrDigit((char) getChar())) {
491 buffer.append((char) read());
492 }
493 return buffer.toString();
494 }
495
496
497
498
499
500
501
502
503 public final String readStringTilWhitespace() {
504 skipWhiteSpace();
505 StringBuffer buffer = new StringBuffer();
506 while (!isEmpty() && !Character.isWhitespace((char) getChar())) {
507 buffer.append((char) read());
508 }
509 return buffer.toString();
510 }
511
512
513
514
515
516
517
518
519
520
521 public final int readNonNegativeInt() {
522 skipWhiteSpace();
523 if (isEmpty() || !Character.isDigit((char) getChar())) {
524 read();
525 throw new IllegalArgumentException(
526 "digit expected");
527 }
528 StringBuffer buffer = new StringBuffer();
529 while (!isEmpty() && Character.isDigit((char) getChar())) {
530 buffer.append((char) read());
531 }
532 final BigInteger big = new BigInteger(buffer.toString());
533 if (1 == big.compareTo(maxIntValue)) {
534 throw new IllegalArgumentException("this integer is to large! Maximum possible value is "
535 + maxIntValue);
536 }
537 return big.intValue();
538 }
539
540
541
542
543
544
545
546
547
548
549
550 public final String readCounter() {
551 skipWhiteSpace();
552 if (isEmpty()) {
553 throw new IllegalArgumentException("integer expected");
554 }
555 StringBuffer buffer = new StringBuffer();
556 if (getChar() == '-') {
557 buffer.append(read());
558 }
559 final int begin = getPosition();
560 if (!Character.isDigit((char) getChar())) {
561 throw new IllegalArgumentException("digit expected");
562 }
563 while (!isEmpty() && Character.isDigit((char) getChar())) {
564 buffer.append((char) read());
565 }
566 if (buffer.length() >= 2 && ('0' == buffer.charAt(0)
567 || '-' == buffer.charAt(0) && '0' == buffer.charAt(1))) {
568 setPosition(begin);
569 throw new IllegalArgumentException("no leading zeros allowed");
570 }
571 return buffer.toString();
572 }
573
574
575
576
577
578
579
580
581
582
583
584 public final String readQuoted() {
585 skipWhiteSpace();
586 if (isEmpty() || read() != '\"') {
587 throw new IllegalArgumentException(
588 "\" expected");
589 }
590 StringBuffer unquoted = new StringBuffer();
591 char c;
592 do {
593 if (isEmpty()) {
594 throw new IllegalArgumentException(
595 "ending \" expected");
596 }
597 c = (char) read();
598 if (c != '\"') {
599 unquoted.append(c);
600 } else {
601 if (isEmpty() || getChar() != '\"') {
602 break;
603 }
604 unquoted.append((char) read());
605 }
606 } while (true);
607 return unquoted.toString();
608 }
609
610
611
612
613
614
615 public final int getRow() {
616 return lineNumber + 1;
617 }
618
619
620
621
622
623
624 public final int getColumn() {
625 return column + 1;
626 }
627
628
629
630
631
632
633 public final String getLine() {
634 int min = position - 1;
635 while (min >= 0 && source.charAt(min) != CR) {
636 min--;
637 }
638 int max = position;
639 while (max < source.length()
640 && source.charAt(max) != CR) {
641 max++;
642 }
643 if (min + 1 >= max) {
644 return "";
645 }
646 return source.substring(min + 1, max);
647 }
648
649
650
651
652
653
654
655 public final int getPosition() {
656 return position;
657 }
658
659
660
661
662
663
664 public final SourcePosition getSourcePosition() {
665 return new SourcePosition(getRow(), getColumn());
666 }
667
668
669
670
671
672
673
674 public final int getMaximumPosition() {
675 return source.length();
676 }
677
678
679
680
681
682
683 public final void setPosition(final int position) {
684 if (position >= source.length()) {
685 this.position = source.length();
686 } else if (this.position != position) {
687 if (position < this.position) {
688 this.position = 0;
689 this.lineNumber = 0;
690 this.column = 0;
691 for (int i = 0; i < position; i++) {
692 read();
693 }
694 } else {
695 for (int i = this.position; i < position; i++) {
696 read();
697 }
698 }
699 }
700 }
701
702
703
704
705
706
707 public final void setPosition(final SourcePosition position) {
708 setRow(position.getRow());
709 setColumn(position.getColumn());
710 }
711
712
713
714
715
716
717
718 public final void addPosition(final SourcePosition delta) {
719 addRow(delta.getRow() - 1);
720 addColumn(delta.getColumn() - 1);
721 }
722
723
724
725
726
727
728 public final void setRow(final int row) {
729 int r = row;
730
731 if (r <= 0) {
732 r = 1;
733 }
734
735 if (getRow() == r) {
736 return;
737 }
738
739 if (getPosition() >= source.length() && getRow() >= r) {
740 return;
741 }
742 if (getRow() > r) {
743
744 this.position = 0;
745 this.lineNumber = 0;
746 this.column = 0;
747 }
748 while (getRow() < r) {
749 if (EOF == read()) {
750 return;
751 }
752 }
753 }
754
755
756
757
758
759
760
761 public final SourcePosition getPosition(final int find) {
762 int r = 0;
763 int c = 0;
764 int i = 0;
765 while (i < source.length() && i < find) {
766 if (CR == source.charAt(i)) {
767 r++;
768 c = 0;
769 } else {
770 c++;
771 }
772 i++;
773 }
774 return new SourcePosition(r + 1, c + 1);
775 }
776
777
778
779
780
781
782
783 public final int getPosition(final SourcePosition position) {
784 int find = 0;
785 int r = 0;
786
787 while (++r < position.getRow()) {
788 find = source.indexOf("" + CR, find);
789 if (-1 == find) {
790 break;
791 }
792 }
793 if (find < 0) {
794 find = source.length();
795 }
796 find += position.getColumn();
797 if (find > source.length()) {
798 find = source.length();
799 }
800 return find;
801 }
802
803
804
805
806
807
808
809 public final String getSourceArea(final SourceArea area) {
810 return source.substring(getPosition(area.getStartPosition()),
811 getPosition(area.getEndPosition()));
812 }
813
814
815
816
817
818
819 public final void addRow(final int number) {
820 setRow(getRow() + number);
821 }
822
823
824
825
826
827
828
829
830 public final void setColumn(final int column) {
831 int c = column;
832
833 if (c <= 0) {
834 c = 1;
835 }
836
837 if (getColumn() == c) {
838 return;
839 }
840 if (getColumn() > c) {
841 do {
842 this.position--;
843 this.column--;
844 } while (getColumn() > c);
845 return;
846 }
847 while (getChar() != CR && getChar() != EOF && getColumn() < c) {
848 read();
849 }
850 }
851
852
853
854
855
856
857 public final void addColumn(final int number) {
858 setColumn(getColumn() + number);
859 }
860
861
862
863
864
865
866 public final String showLinePosition() {
867 final String line = getLine();
868 final StringBuffer buffer = new StringBuffer();
869 final int col = getColumn() - 1;
870 if (col > 0) {
871 if (col < line.length()) {
872 buffer.append(line.substring(0, col));
873 } else {
874 buffer.append(line);
875 }
876 }
877 buffer.append(MARKER);
878 if (col < line.length()) {
879 buffer.append(line.substring(col));
880 }
881 return buffer.toString();
882 }
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907 }