From 6853f9a3e6f21f7e03f8165a90bd8f42520e04d9 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Wed, 6 Sep 2017 14:26:29 +0930 Subject: [PATCH] Treat all IOExceptions and all Runtime exceptions after closing as EOF --- .../org/servalproject/json/JSONTokeniser.java | 138 ++++++++++-------- 1 file changed, 76 insertions(+), 62 deletions(-) diff --git a/java-api/src/org/servalproject/json/JSONTokeniser.java b/java-api/src/org/servalproject/json/JSONTokeniser.java index 06e915ad..73935a8d 100644 --- a/java-api/src/org/servalproject/json/JSONTokeniser.java +++ b/java-api/src/org/servalproject/json/JSONTokeniser.java @@ -20,20 +20,19 @@ package org.servalproject.json; -import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.io.PushbackReader; import java.io.UnsupportedEncodingException; import java.util.Collection; public class JSONTokeniser { - final InputStream underlyingStream; - final PushbackReader reader; + private final InputStream underlyingStream; + private final InputStreamReader reader; private boolean closed = false; - Object pushedToken; + private int pushedChar=-1; + private Object pushedToken; private static final boolean DUMP_JSON_TO_STDERR = false; @@ -53,6 +52,9 @@ public class JSONTokeniser { public SyntaxException(String message) { super(message); } + public SyntaxException(String message, Throwable e) { + super(message, e); + } } public static class UnexpectedException extends JSONInputException @@ -101,39 +103,51 @@ public class JSONTokeniser { public JSONTokeniser(InputStream stream) throws UnsupportedEncodingException { underlyingStream = stream; - reader = new PushbackReader(new InputStreamReader(stream, "UTF-8")); + reader = new InputStreamReader(stream, "UTF-8"); } - private int _read() throws IOException + private int _read() { + int p = pushedChar; + pushedChar = -1; + if (p!=-1) + return p; try { int n = this.reader.read(); if (DUMP_JSON_TO_STDERR && n != -1) System.err.print((char) n); return n; - }catch (IllegalStateException e){ - if (closed) { - EOFException eof = new EOFException(); - eof.initCause(e); - throw eof; - } + }catch (IOException e){ + return -1; + }catch (RuntimeException e){ + if (closed) + return -1; throw e; } } - private int _read(char[] buf, int offset, int length) throws IOException + private int _read(char[] buf, int offset, int length) { + if (length==0) + return 0; + + int p = pushedChar; + pushedChar = -1; + if (p!=-1){ + buf[offset] = (char) p; + return 1; + } + try { int n = this.reader.read(buf, offset, length); if (DUMP_JSON_TO_STDERR && n != -1) System.err.print(new String(buf, offset, n)); return n; - }catch (IllegalStateException e){ - if (closed) { - EOFException eof = new EOFException(); - eof.initCause(e); - throw eof; - } + }catch (IOException e){ + return -1; + }catch (RuntimeException e){ + if (closed) + return -1; throw e; } } @@ -149,7 +163,7 @@ public class JSONTokeniser { throw new SyntaxException("JSON syntax error: expecting " + exactly + ", got " + jsonTokenDescription(tok)); } - public void consume(Token exactly) throws SyntaxException, UnexpectedException, IOException + public void consume(Token exactly) throws SyntaxException, UnexpectedException { match(nextToken(), exactly); } @@ -197,37 +211,37 @@ public class JSONTokeniser { // Float --> Double // Double --> Float if (cls == Double.class && (tok instanceof Float || tok instanceof Long || tok instanceof Integer)) - tok = new Double(((Number)tok).doubleValue()); + tok = ((Number)tok).doubleValue(); else if (cls == Float.class && (tok instanceof Double || tok instanceof Long || tok instanceof Integer)) - tok = new Float(((Number)tok).floatValue()); + tok = ((Number)tok).floatValue(); else if (cls == Long.class && tok instanceof Integer) - tok = new Long(((Number)tok).longValue()); + tok = ((Number)tok).longValue(); if (cls.isInstance(tok)) return (T)tok; // unchecked cast throw new UnexpectedTokenException(tok, cls); } - public T consume(Class cls) throws SyntaxException, UnexpectedException, IOException + public T consume(Class cls) throws SyntaxException, UnexpectedException { return consume(cls, Narrow.NO_NULL); } - public T consume(Class cls, Narrow opts) throws SyntaxException, UnexpectedException, IOException + public T consume(Class cls, Narrow opts) throws SyntaxException, UnexpectedException { return narrow(nextToken(), cls, opts); } - public Object consume() throws SyntaxException, UnexpectedException, IOException + public Object consume() throws SyntaxException, UnexpectedException { return consume(Object.class, Narrow.NO_NULL); } - public Object consume(Narrow opts) throws SyntaxException, UnexpectedException, IOException + public Object consume(Narrow opts) throws SyntaxException, UnexpectedException { return consume(Object.class, opts); } - public String consume(String exactly) throws SyntaxException, UnexpectedException, IOException + public String consume(String exactly) throws SyntaxException, UnexpectedException { String tok = consume(String.class); if (tok.equals(exactly)) @@ -235,17 +249,17 @@ public class JSONTokeniser { throw new UnexpectedTokenException(tok, exactly); } - public int consumeArray(Collection collection, Narrow opts) throws SyntaxException, UnexpectedException, IOException + public int consumeArray(Collection collection, Narrow opts) throws SyntaxException, UnexpectedException { return consumeArray(collection, Object.class, opts); } - public int consumeArray(Collection collection, Class cls) throws SyntaxException, UnexpectedException, IOException + public int consumeArray(Collection collection, Class cls) throws SyntaxException, UnexpectedException { return consumeArray(collection, cls, Narrow.NO_NULL); } - public int consumeArray(Collection collection, Class cls, Narrow opts) throws SyntaxException, UnexpectedException, IOException + public int consumeArray(Collection collection, Class cls, Narrow opts) throws SyntaxException, UnexpectedException { int added = 0; consume(Token.START_ARRAY); @@ -264,17 +278,17 @@ public class JSONTokeniser { return added; } - public void consumeArray(Object[] array) throws SyntaxException, UnexpectedException, IOException + public void consumeArray(Object[] array) throws SyntaxException, UnexpectedException { consumeArray(array, Object.class, Narrow.NO_NULL); } - public void consumeArray(Object[] array, Narrow opts) throws SyntaxException, UnexpectedException, IOException + public void consumeArray(Object[] array, Narrow opts) throws SyntaxException, UnexpectedException { consumeArray(array, Object.class, opts); } - public void consumeArray(T[] array, Class cls, Narrow opts) throws SyntaxException, UnexpectedException, IOException + public void consumeArray(T[] array, Class cls, Narrow opts) throws SyntaxException, UnexpectedException { consume(Token.START_ARRAY); for (int i = 0; i < array.length; ++i) { @@ -309,38 +323,38 @@ public class JSONTokeniser { return tok.toString(); } - private void readWord(String word) throws SyntaxException, IOException - { - int len = 0; - while (len < word.length()) { - char[] buf = new char[word.length() - len]; - int n = _read(buf, 0, buf.length); - if (n == -1) - throw new SyntaxException("EOF in middle of \"" + word + "\""); - for (int i = 0; i < n; ++i) - if (buf[i] != word.charAt(len++)) - throw new SyntaxException("expecting \"" + word + "\""); - } - } - - private int readHex(int digits) throws SyntaxException, IOException - { - assert digits <= 8; - char[] buf = new char[digits]; + private void readAll(char[] buf) throws SyntaxException { int len = 0; while (len < buf.length) { int n = _read(buf, len, buf.length - len); if (n == -1) - throw new SyntaxException("EOF in middle of " + digits + " hex digits"); + throw new SyntaxException("EOF in middle of read"); len += n; } + } + + private void readWord(String word) throws SyntaxException + { + int len = word.length(); + char[] buf = new char[len]; + readAll(buf); + for (int i = 0; i < len; ++i) + if (buf[i] != word.charAt(i)) + throw new SyntaxException("expecting \"" + word + "\""); + } + + private int readHex(int digits) throws SyntaxException + { + assert digits <= 8; + char[] buf = new char[digits]; + readAll(buf); String hex = new String(buf); try { return Integer.valueOf(hex, 16); } catch (NumberFormatException e) { + throw new SyntaxException("expecting " + digits + " hex digits, got \"" + hex + "\"", e); } - throw new SyntaxException("expecting " + digits + " hex digits, got \"" + hex + "\""); } public void pushToken(Object tok) @@ -350,10 +364,10 @@ public class JSONTokeniser { pushedToken = tok; } - public Object nextToken() throws SyntaxException, IOException + public Object nextToken() throws SyntaxException { - if (pushedToken != null) { - Object tok = pushedToken; + Object tok = pushedToken; + if (tok != null) { pushedToken = null; return tok; } @@ -380,15 +394,15 @@ public class JSONTokeniser { case ':': return Token.COLON; case 't': - this.reader.unread(c); + pushedChar=c; readWord("true"); return Boolean.TRUE; case 'f': - this.reader.unread(c); + pushedChar=c; readWord("false"); return Boolean.FALSE; case 'n': - this.reader.unread(c); + pushedChar=c; readWord("null"); return Token.NULL; case '"': { @@ -487,7 +501,7 @@ public class JSONTokeniser { } while (Character.isDigit(c)); } - this.reader.unread(c); + pushedChar=c; String number = sb.toString(); try { if (isfloat)