1/*
2 * Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25package sun.jvm.hotspot.debugger;
26
27import java.io.*;
28
29/** InputLexer is the lexer through which the current set of debuggers
30    see the debug server. It provides the ability to read all of the
31    types the debuggers are interested in. All read operations are
32    blocking. */
33
34public class InputLexer {
35  public InputLexer(BufferedInputStream in) throws IOException {
36    this.in = in;
37    pushedBack = false;
38  }
39
40  public void close() throws IOException {
41    in.close();
42  }
43
44  /** Parses a boolean (really either a 0 or 1 integer in US-ASCII
45      encoding) on the input stream */
46  public boolean parseBoolean() throws IOException {
47    int val = parseInt();
48    return (val != 0);
49  }
50
51  /** Parses an int in US-ASCII encoding on the input stream */
52  public int parseInt() throws IOException {
53    long l = parseLong();
54    long mask = 0xFFFFFFFF00000000L;
55    if ((l & mask) != 0) {
56      throw new IOException("Overflow error reading int from debug server (read " + l + ")");
57    }
58    return (int) l;
59  }
60
61  /** Parses a long in US-ASCII encoding on the input stream */
62  public long parseLong() throws IOException {
63    skipWhitespace();
64    byte b = readByte();
65    if (!Character.isDigit((char) b)) {
66      error();
67    }
68    long l = 0;
69    while (Character.isDigit((char) b)) {
70      l *= 10;
71      l += (b - '0');
72      b = readByte();
73    }
74    pushBack(b);
75    return l;
76  }
77
78  /** Parses an address in the form 0x12345678 in US-ASCII encoding on
79      the input stream */
80  public long parseAddress() throws IOException {
81    skipWhitespace();
82    byte b;
83    if ((b = readByte()) != '0') {
84      error();
85    }
86    b = readByte();
87    if (b != 'x') {
88      error();
89    }
90    long val = 0;
91    while (isHexDigit((char) (b = readByte()))) {
92      val *= 16;
93      val += Character.digit((char) b, 16);
94    }
95    pushBack(b);
96    return val;
97  }
98
99  public void skipByte() throws IOException {
100    readByte();
101  }
102
103  /** Reads binary data; one byte */
104  public byte readByte() throws IOException {
105    if (pushedBack) {
106      pushedBack = false;
107      return backBuf;
108    }
109    return readByteInternal();
110  }
111
112  /** Reads a block of binary data in BLOCKING fashion */
113  public void readBytes(byte[] buf, int off, int len) throws IOException {
114    int startIdx = off;
115    int numRead = 0;
116    if (pushedBack) {
117      buf[startIdx] = backBuf;
118      pushedBack = false;
119      ++startIdx;
120      ++numRead;
121    }
122    while (numRead < len) {
123      numRead += in.read(buf, startIdx + numRead, len - numRead);
124    }
125    //    if (numRead != len) {
126    //      throw new IOException("Only read " + numRead + " out of " +
127    //                            len + " bytes requested");
128    //    }
129  }
130
131  /** Reads binary data; one 16-bit character in big-endian format */
132  public char readChar() throws IOException {
133    int hi = ((int) readByte()) & 0xFF;
134    int lo = ((int) readByte()) & 0xFF;
135    return (char) ((hi << 8) | lo);
136  }
137
138  /** Reads binary data; one 32-bit unsigned int in big-endian format.
139      Returned as a long. */
140  public long readUnsignedInt() throws IOException {
141    long b1 = ((long) readByte()) & 0xFF;
142    long b2 = ((long) readByte()) & 0xFF;
143    long b3 = ((long) readByte()) & 0xFF;
144    long b4 = ((long) readByte()) & 0xFF;
145
146    return ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4);
147  }
148
149  /** Reads binary data; a US-ASCII string of the specified length */
150  public String readByteString(int len) throws IOException {
151    byte[] b = new byte[len];
152    for (int i = 0; i < len; i++) {
153      b[i] = readByte();
154    }
155    try {
156      return new String(b, "US-ASCII");
157    }
158    catch (UnsupportedEncodingException e) {
159      throw new IOException(e.toString());
160    }
161  }
162
163  /** Reads binary data; a Unicode string of the specified length */
164  public String readCharString(int len) throws IOException {
165    char[] c = new char[len];
166    for (int i = 0; i < len; i++) {
167      c[i] = readChar();
168    }
169    return new String(c);
170  }
171
172  //----------------------------------------------------------------------
173  // Internals only below this point
174  //
175
176  private void skipWhitespace() throws IOException {
177    byte b;
178    while (Character.isWhitespace((char) (b = readByte()))) {
179    }
180    pushBack(b);
181  }
182
183  private boolean isHexDigit(char c) {
184    return (('0' <= c && c <= '9') ||
185            ('a' <= c && c <= 'f') ||
186            ('A' <= c && c <= 'F'));
187  }
188
189  private void pushBack(byte b) {
190    if (pushedBack) {
191      throw new InternalError("Only one character pushback supported");
192    }
193    backBuf = b;
194    pushedBack = true;
195  }
196
197  private byte readByteInternal() throws IOException {
198    int i = in.read();
199    if (i == -1) {
200      throw new IOException("End-of-file reached while reading from server");
201    }
202    return (byte) i;
203  }
204
205  private void error() throws IOException {
206    throw new IOException("Error parsing output of debug server");
207  }
208
209  private BufferedInputStream in;
210  private boolean pushedBack;
211  private byte backBuf;
212}
213