001: /*
002: * CONFIDENTIAL AND PROPRIETARY SOURCE CODE OF
003: * NETSCAPE COMMUNICATIONS CORPORATION
004: *
005: * Copyright (c) 1996 Netscape Communications Corporation.
006: * All Rights Reserved.
007: * Use of this Source Code is subject to the terms of the applicable
008: * license agreement from Netscape Communications Corporation.
009: */
010:
011: package soif;
012:
013: import util.ReportError;
014: import java.io.*;
015:
016: /**
017: * SOIF parser class. Reads SOIF instances from an input stream.
018: */
019: public class SOIFParser {
020: /**
021: * Raw SOIF string.
022: */
023: private InputStream sis;
024:
025: /**
026: * Head of SOIF list.
027: */
028: private SOIF soifList;
029:
030: /**
031: * Did the SOIF parse correctly?
032: */
033: private boolean valid;
034:
035: /**
036: * End of stream reached
037: */
038: private boolean EOS;
039:
040: /**
041: * debug
042: */
043: public boolean debug;
044:
045: /* XXX this should be a static function - parse(String) */
046: /**
047: * Constructor.
048: * @param s target string to convert to SOIF
049: */
050: public SOIFParser(String str) {
051: this (new StringBufferInputStream(str));
052: try {
053: soifList = parse();
054: SOIF s = soifList;
055: while (!EOS && (s.next = parse()) != null)
056: s = s.next;
057: } catch (IOException e) {
058: valid = false;
059: }
060: }
061:
062: public SOIFParser(InputStream is) {
063: valid = false;
064: sis = is;
065: soifList = null;
066: }
067:
068: /* internal buffering - not thread safe, but speeds things up a lot */
069: private int bufferIndex = 0, dataLen = 0;
070: private final static int IO_BUFFER_SIZE = 5000;
071: private final byte[] ioBuffer = new byte[IO_BUFFER_SIZE];
072:
073: private final char getChar() throws IOException {
074: char c;
075: if (bufferIndex >= dataLen) {
076: dataLen = sis.read(ioBuffer);
077: bufferIndex = 0;
078: }
079: ;
080: if (dataLen == -1)
081: throw new EOFException();
082: else
083: c = (char) ioBuffer[bufferIndex++];
084: //System.out.print("."+c);
085: return c;
086: }
087:
088: /** This is a bit closer to the mark than StreamTokenizer */
089: char getToken(String skip, String stop, String ok, String bad,
090: StringBuffer sb) throws Exception {
091: char c = getChar();
092: if (skip != null) {
093: while (skip.indexOf(c) != -1) {
094: c = getChar();
095: }
096: }
097: while (true) {
098: if (stop != null && stop.indexOf(c) != -1)
099: break;
100: if (ok != null && ok.indexOf(c) == -1)
101: throw new Exception();
102: if (bad != null && bad.indexOf(c) != -1)
103: throw new Exception();
104: sb.append(c);
105: c = getChar();
106: }
107: return c;
108: }
109:
110: public SOIF parse() throws IOException {
111: String sa;
112: String sv;
113: StringBuffer sb = new StringBuffer(32);
114: SOIF nSOIF = new SOIF();
115: char c, c1;
116: //debug = true;
117:
118: if (EOS)
119: throw new EOFException();
120:
121: if (debug)
122: System.out.println("\nSOIF Parser...");
123:
124: try {
125:
126: // "@SCHEMA { url\n" (skip over leading junk)
127: c = '\n';
128: do {
129: c1 = c;
130: c = getChar();
131: } while (!(c == '@' && (c1 == '\n' || c1 == '\r')));
132:
133: c = getToken(null, " ", null, "\r\n", sb);
134: nSOIF.schemaName = new String(sb);
135:
136: if (debug)
137: System.out.println("schemaName = [" + nSOIF.schemaName
138: + "]");
139:
140: // " { url\n"
141: c = getToken(" ", "{", " ", "\r\n", sb);
142:
143: sb.setLength(0);
144: c = getToken(" ", "\r\n", null, null, sb);
145: nSOIF.URL = new String(sb);
146:
147: if (nSOIF.URL.compareTo("-") != 0)
148: nSOIF.addAVPairs("URL", nSOIF.URL); /* XXX get rid of this??? */
149:
150: if (debug)
151: System.out.println("URL = [" + nSOIF.URL + "]");
152:
153: // parse the attributes
154: while (true) {
155:
156: // "attr{n}:\tval" OR "}"
157:
158: sb.setLength(0);
159: c = getToken("\r\n", "{}", null, "\r\n", sb);
160:
161: if (c == '}') {
162: if (debug)
163: System.out.println("End of SOIF");
164: nSOIF.valid = true;
165: valid = true;
166: return nSOIF;
167: }
168:
169: sa = new String(sb);
170:
171: if (debug)
172: System.out.println(sa);
173:
174: // "nn}:\t..."
175:
176: // this is a bit slow ...
177: //sb.setLength(0);
178: //c = getToken(null, "}", "0123456789", null, sb);
179: //int nn = Integer.parseInt(new String(sb));
180:
181: // ... try this instead
182: int nn = -1;
183: while (true) {
184: c = getChar();
185: if ('0' <= c && c <= '9') {
186: if (nn == -1)
187: nn = 0;
188: nn = nn * 10 + c - '0';
189: } else
190: break;
191: }
192:
193: if (c != '}' || nn == -1)
194: throw new Exception();
195:
196: int sal = nn;
197: if (debug)
198: System.out.println("" + sal);
199:
200: // ":\t..."
201:
202: if (getChar() != ':' || getChar() != '\t')
203: throw new Exception();
204:
205: byte ba[] = new byte[sal];
206:
207: /* sis.readFully(ba); */
208: int nc = Math.min(sal, dataLen - bufferIndex);
209: System.arraycopy(ioBuffer, bufferIndex, ba, 0, nc);
210: bufferIndex += nc;
211: if (nc < sal) {
212: // we didn't get all the chars
213: for (int i = nc; i < sal; ++i)
214: ba[i] = (byte) getChar();
215:
216: /* this is very slow if the input stream is a BIS ... */
217: /* for(int d = nc; d < sal; d += sis.read(ba, d, sal - d)); */
218: }
219:
220: sv = new String(ba, 0, 0, ba.length);
221:
222: if (debug)
223: System.out.println("AV Pair: " + sa + " " + sv);
224:
225: if (!sa.equalsIgnoreCase("URL")) // avoid problem caused by adding the real url above
226: nSOIF.addAVPairs(sa, sv);
227: }
228: } catch (Exception e) {
229: if (e instanceof EOFException) {
230: if (debug)
231: System.out.println("End of stream reached");
232: EOS = true;
233: return null;
234: }
235: ReportError.reportError(util.ReportError.INTERNAL, "SOIF",
236: "parseSOIF", Messages.INVALIDSOIF);
237: System.out.println(toRawSOIFString());
238: throw new IOException(Messages.INVALIDSOIF);
239: }
240: }
241:
242: /**
243: * Whether the SOIF is valid.
244: */
245: public boolean isValid() {
246: return valid;
247: }
248:
249: /**
250: * Whether the SOIF is valid.
251: */
252: public boolean isEOS() {
253: return EOS;
254: }
255:
256: /**
257: * Return head of list.
258: */
259: public SOIF getSOIFHead() {
260: return soifList;
261: }
262:
263: /**
264: * Return root of SOIF list.
265: */
266: public SOIF getSOIF() {
267: return valid ? soifList : null;
268: }
269:
270: /**
271: * Return original SOIF string.
272: */
273: public String toRawSOIFString() {
274: return "---< SOIF beg >---\n" + "[" + sis + "]\n"
275: + "---< SOIF end >---\n";
276: }
277:
278: public String toString() {
279: return "SOIFParser instance:\n" + "\tvalid = [" + valid
280: + "]\n" + toRawSOIFString() + soifList.toStringList();
281: }
282:
283: }
|