001: /*
002: * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.jcr.svn;
031:
032: import com.caucho.util.L10N;
033: import com.caucho.vfs.ReadStream;
034:
035: import java.io.IOException;
036: import java.util.ArrayList;
037: import java.util.logging.Logger;
038:
039: /**
040: * Subversion input class.
041: */
042: public class SubversionInput {
043: private final L10N L = new L10N(SubversionInput.class);
044: private final Logger log = Logger.getLogger(SubversionInput.class
045: .getName());
046:
047: private ReadStream _is;
048: private int _peek;
049:
050: public SubversionInput(ReadStream is) {
051: _is = is;
052: }
053:
054: /**
055: * Reads a string.
056: */
057: public String readString() throws IOException {
058: skipWhitespace();
059:
060: long length = readLong();
061:
062: expect(':');
063:
064: StringBuilder sb = new StringBuilder();
065:
066: for (int i = 0; i < length; i++) {
067: sb.append((char) read());
068: }
069:
070: return sb.toString();
071: }
072:
073: /**
074: * Reads a string literal.
075: */
076: public String readLiteral() throws IOException {
077: skipWhitespace();
078:
079: StringBuilder sb = new StringBuilder();
080:
081: int ch;
082:
083: while (isStringChar((ch = read()))) {
084: sb.append((char) ch);
085: }
086:
087: _peek = ch;
088:
089: return sb.toString();
090: }
091:
092: /**
093: * Reads a long.
094: */
095: public long readLong() throws IOException {
096: skipWhitespace();
097:
098: int sign = 1;
099: long value = 0;
100:
101: int ch = read();
102:
103: if (ch == '-') {
104: sign = -1;
105: ch = read();
106: } else if (ch == '+') {
107: sign = -1;
108: ch = read();
109: }
110:
111: if (!('0' <= ch && ch <= '9'))
112: throw error(L.l("expected digit (0-9) at '{0}' (0x{1})",
113: String.valueOf((char) ch), Integer.toHexString(ch)));
114:
115: for (; '0' <= ch && ch <= '9'; ch = read()) {
116: value = 10 * value + ch - '0';
117: }
118:
119: _peek = ch;
120:
121: return sign * value;
122: }
123:
124: /**
125: * Reads a s-exp
126: */
127: public Object readSexp() throws IOException {
128: int ch;
129:
130: while ((ch = read()) >= 0) {
131: switch (ch) {
132: case ' ':
133: case '\t':
134: case '\r':
135: case '\n':
136: break;
137:
138: case '(': {
139: ArrayList array = new ArrayList();
140:
141: Object value;
142:
143: while ((value = readSexp()) != null) {
144: array.add(value);
145: }
146:
147: expect(')');
148:
149: return array;
150: }
151: case ')':
152: _peek = ch;
153: return null;
154:
155: case '0':
156: case '1':
157: case '2':
158: case '3':
159: case '4':
160: case '5':
161: case '6':
162: case '7':
163: case '8':
164: case '9': {
165: _peek = ch;
166:
167: long value = readLong();
168:
169: ch = read();
170:
171: if (ch == ':') {
172: StringBuilder sb = new StringBuilder();
173: for (int i = 0; i < value; i++)
174: sb.append((char) read());
175: return sb.toString();
176: } else {
177: _peek = ch;
178:
179: return new Long(value);
180: }
181: }
182:
183: default:
184: if (isStringChar((char) ch)) {
185: StringBuilder sb = new StringBuilder();
186:
187: sb.append((char) ch);
188: while (isStringChar(ch = read())) {
189: sb.append((char) ch);
190: }
191:
192: _peek = ch;
193:
194: return sb.toString();
195: } else
196: throw error(L.l("Unexpected character"));
197: }
198: }
199:
200: return null;
201: }
202:
203: /**
204: * Skips whitespace
205: */
206: public boolean skipWhitespace() throws IOException {
207: int ch;
208:
209: while (Character.isWhitespace(ch = read())) {
210: }
211:
212: _peek = ch;
213:
214: return ch >= 0;
215: }
216:
217: /**
218: * Reads until an open brace.
219: */
220: public void expect(char expect) throws IOException {
221: int ch;
222:
223: while ((ch = read()) >= 0) {
224: if (ch == expect)
225: return;
226: else if (Character.isWhitespace(ch)) {
227: } else
228: throw error(L.l("Expected '{0}' at '{1}' (0x{2})",
229: String.valueOf((char) expect), String
230: .valueOf((char) ch), Integer
231: .toHexString(ch)));
232: }
233:
234: throw error(L.l("Expected '{0}' at end of file", String
235: .valueOf((char) expect)));
236: }
237:
238: private boolean isStringChar(int ch) {
239: switch (ch) {
240: case ' ':
241: case '\t':
242: case '\n':
243: case '\r':
244: return false;
245: case -1:
246: return false;
247: case '(':
248: case ')':
249: return false;
250: default:
251: return true;
252: }
253: }
254:
255: private IOException error(String msg) {
256: return new IOException(msg);
257: }
258:
259: public int read() throws IOException {
260: if (_peek > 0) {
261: int peek = _peek;
262: _peek = 0;
263: return peek;
264: }
265:
266: int ch = _is.read();
267:
268: if (ch >= 0)
269: System.out.print((char) ch);
270:
271: return ch;
272: }
273:
274: public void close() {
275: ReadStream is = _is;
276: _is = null;
277:
278: if (is != null) {
279: is.close();
280: }
281: }
282: }
|