OSDN Git Service

JDK1.7対応
[jovsonz/Jovsonz.git] / src / main / java / jp / sourceforge / jovsonz / JsonSource.java
1 /*
2  * JSON stream source
3  *
4  * License : The MIT License
5  * Copyright(c) 2009 olyutorskii
6  */
7
8 package jp.sourceforge.jovsonz;
9
10 import java.io.Closeable;
11 import java.io.IOException;
12 import java.io.Reader;
13 import java.io.StringReader;
14
15 /**
16  * JSONデータ用入力ソース。
17  * 先読みした文字のプッシュバック機能と行番号のカウント機能を有する。
18  * 行番号は1から始まる。
19  * 行と行はLF('\n')で区切られるものとする。(※CRは無視)
20  * @see java.io.PushbackReader
21  * @see java.io.LineNumberReader
22  */
23 class JsonSource implements Closeable {
24
25     /** プッシュバック可能な文字数。 */
26     private static final int PUSHBACK_TOKENS = 10;
27
28     private static final char LINEFEED = '\n';  // LF(0x0a)
29
30     private static final String ERRMSG_OVERFLOW =
31             "Pushback buffer overflow";
32     private static final String ERRMSG_CLOSED =
33             "Stream closed";
34
35     static{
36         assert "\\uXXXX".length() < PUSHBACK_TOKENS;
37     }
38
39     private final Reader reader;
40
41     // プッシュバック用文字スタック構造。
42     private final char[] charStack = new char[PUSHBACK_TOKENS];
43     private int stackPt = 0;
44
45     private int lineNumber = 1;
46
47     private boolean closed = false;
48
49     /**
50      * コンストラクタ。
51      * @param reader 文字入力リーダー
52      * @throws NullPointerException 引数がnull
53      */
54     public JsonSource(Reader reader) throws NullPointerException{
55         super();
56         if(reader == null) throw new NullPointerException();
57         this.reader = reader;
58         return;
59     }
60
61     /**
62      * コンストラクタ。
63      * 任意の文字列を入力ソースとする。
64      * @param text 文字列
65      * @see java.io.StringReader
66      */
67     public JsonSource(CharSequence text){
68         this(new StringReader(text.toString()));
69         return;
70     }
71
72     /**
73      * JSON規格のwhitespace文字を判定する。
74      * @param ch 判定対象文字
75      * @return whitespaceならtrue
76      */
77     public static boolean isWhitespace(char ch){
78         switch(ch){
79         case '\u0020':
80         case '\t':
81         case '\r':
82         case '\n':
83             return true;
84         default:
85             break;
86         }
87         return false;
88     }
89
90     /**
91      * JSON規格のwhitespace文字を判定する。
92      * @param ch 判定対象文字。
93      * 上位16bitがゼロでなければwhitespaceと判定されない。
94      * @return whitespaceならtrue。引数が負の場合はfalse。
95      */
96     public static boolean isWhitespace(int ch){
97         if((int)Character.MIN_VALUE > ch) return false;
98         if((int)Character.MAX_VALUE < ch) return false;
99         return isWhitespace((char)ch);
100     }
101
102     /**
103      * プッシュバック可能な残り文字数を返す。
104      * @return プッシュバック可能な残り文字数
105      */
106     public int getPushBackSpared(){
107         return PUSHBACK_TOKENS - this.stackPt;
108     }
109
110     /**
111      * 現時点での行番号を返す。
112      * @return 1から始まる行番号
113      */
114     public int getLineNumber(){
115         return this.lineNumber;
116     }
117
118     /**
119      * 1文字読み込む。
120      * @return 読み込んだ文字。入力が終わっている場合は負の値。
121      * @throws IOException 入力エラー
122      * @see java.io.Reader#read()
123      */
124     public int read() throws IOException{
125         if(this.closed) throw new IOException(ERRMSG_CLOSED);
126
127         int chData;
128         if(this.stackPt > 0){
129             chData = (int) this.charStack[--this.stackPt];
130         }else{
131             chData = this.reader.read();
132         }
133
134         if(chData == (int)LINEFEED) this.lineNumber++;
135
136         return chData;
137     }
138
139     /**
140      * 入力末端ではないと仮定して1文字読み込む。
141      * @return 読み込んだ文字。
142      * @throws IOException 入力エラー
143      * @throws JsParseException 入力が終わっている
144      */
145     public char readOrDie() throws IOException, JsParseException{
146         int chData = read();
147         if(chData < 0){
148             throw new JsParseException(JsParseException.ERRMSG_NODATA,
149                                        this.lineNumber);
150         }
151         return (char)chData;
152     }
153
154     /**
155      * 入力が文字列とマッチするか判定する。
156      * 失敗しても読み戻しは行われない。
157      * 長さ0の文字列は必ずマッチに成功する。
158      * @param seq マッチ対象文字列
159      * @return マッチすればtrue
160      * @throws IOException 入力エラー
161      * @throws JsParseException 入力が終わっている。
162      */
163     public boolean matchOrDie(CharSequence seq)
164             throws IOException, JsParseException{
165         int length = seq.length();
166         for(int pt = 0; pt < length; pt++){
167             if(readOrDie() != seq.charAt(pt)) return false;
168         }
169         return true;
170     }
171
172     /**
173      * 1文字読み戻す。
174      * 行数カウントへも反映される。
175      * @param ch 読み戻す文字
176      * @throws IOException バッファあふれもしくはクローズ済み
177      */
178     public void unread(char ch) throws IOException{
179         if(this.closed) throw new IOException(ERRMSG_CLOSED);
180
181         if(this.stackPt >= PUSHBACK_TOKENS){
182             throw new IOException(ERRMSG_OVERFLOW);
183         }
184
185         this.charStack[this.stackPt++] = ch;
186
187         if(ch == LINEFEED) this.lineNumber--;
188
189         return;
190     }
191
192     /**
193      * 1文字読み戻す。
194      * char型にキャストした引数が次回読み込まれる。
195      * 行数カウントへも反映される。
196      * @param ch 読み戻す文字。負の符号を含む上位16bitは無視される。
197      * @throws IOException バッファあふれもしくはクローズ済み
198      */
199     public void unread(int ch) throws IOException{
200         unread((char) ch);
201         return;
202     }
203
204     /**
205      * whitespace文字を読み飛ばす。
206      * @throws IOException 入力エラー
207      */
208     public void skipWhiteSpace() throws IOException{
209         for(;;){
210             int chData = read();
211             if(chData < 0) break;
212             if( ! isWhitespace(chData) ){
213                 unread(chData);
214                 break;
215             }
216         }
217
218         return;
219     }
220
221     /**
222      * まだ読み込めるデータがあるか判定する。
223      * @return まだ読めるデータがあればtrue
224      * @throws IOException IO入力エラー
225      */
226     public boolean hasMore() throws IOException{
227         int chData = read();
228         if(chData < 0) return false;
229         unread(chData);
230         return true;
231     }
232
233     /**
234      * コンストラクタで指定されたReaderを閉じる。
235      * クローズ後の読み込みおよび読み戻し動作は全て例外を投げる。
236      * @throws IOException 入出力エラー
237      * @see java.io.Closeable
238      */
239     @Override
240     public void close() throws IOException{
241         this.closed = true;
242         this.stackPt = 0;
243         this.reader.close();
244         return;
245     }
246
247 }