OSDN Git Service

改行コード指定
[jindolf/Jindolf.git] / src / main / java / jp / sourceforge / jindolf / json / Json.java
1 /*
2  * JSON utilities
3  *
4  * License : The MIT License
5  * Copyright(c) 2009 olyutorskii
6  */
7
8 package jp.sourceforge.jindolf.json;
9
10 import java.io.IOException;
11 import java.io.Reader;
12
13 /**
14  * JSON各種共通ユーティリティ。
15  */
16 public final class Json{
17
18     /**
19      * 隠しコンストラクタ。
20      */
21     private Json(){
22         assert false;
23         throw new AssertionError();
24     }
25
26
27     /**
28      * JSON最上位構造から文字出力を開始する。
29      * @param appout 出力先
30      * @param value JSONのObjectかArray
31      * @throws IOException 出力エラー
32      * @throws IllegalArgumentException 出力対象がObjectでもArrayでもない。
33      */
34     public static void writeJsonTop(Appendable appout, JsValue value)
35             throws IOException,
36                    IllegalArgumentException {
37         if( ! (value instanceof JsObject) && ! (value instanceof JsArray) ){
38             throw new IllegalArgumentException();
39         }
40
41         JsonAppender appender = new JsonAppender(appout);
42
43         try{
44             value.traverse(appender);
45         }catch(JsVisitException e){
46             Throwable cause = e.getCause();
47             if(cause instanceof IOException){
48                 throw (IOException) cause;
49             }else if(cause instanceof RuntimeException){
50                 throw (RuntimeException) cause;
51             }else if(cause instanceof Error){
52                 throw (Error) cause;
53             }else{
54                 assert false;
55                 return;
56             }
57         }
58
59         appender.flush();
60
61         return;
62     }
63
64     /**
65      * JSON規格のwhitespace文字を判定する。
66      * @param ch 判定対象文字
67      * @return whitespaceならtrue
68      */
69     public static boolean isWhitespace(char ch){
70         if(ch == '\t'    ) return true;
71         if(ch == '\r'    ) return true;
72         if(ch == '\n'    ) return true;
73         if(ch == '\u0020') return true;
74         return false;
75     }
76
77     /**
78      * whitespace文字を読み飛ばす。
79      * @param reader 文字入力
80      * @throws IOException 入力エラー
81      */
82     static void skipWhiteSpace(JsonReader reader)
83             throws IOException{
84         for(;;){
85             int chData = reader.read();
86             if(chData < '\u0000') break;
87             if( ! isWhitespace((char)chData) ){
88                 reader.unread(chData);
89                 break;
90             }
91         }
92         return;
93     }
94
95     /**
96      * 各種定数(true,false,null)を文字ストリームから読み取る。
97      * 長さ0の文字定数には無条件でfalseを返す。
98      * @param reader 文字入力
99      * @param text 文字定数
100      * @return 文字定数が文字入力に現れればtrue。
101      * 見つからないもしくはストリームの終わりに達したときはfalse
102      * @throws IOException 入力エラー
103      * @throws IllegalArgumentException 文字定数が長すぎる
104      */
105     static boolean parseConst(JsonReader reader,
106                                CharSequence text)
107             throws IOException,
108                    IllegalArgumentException {
109         int textLength = text.length();
110         if(textLength <= 0) return false;
111         if(textLength >= JsonReader.PUSHBACK_TOKENS){
112             throw new IllegalArgumentException();
113         }
114
115         int[] backData = new int[textLength - 1];
116         int readed = 0;
117
118         for(;;){
119             int chData = reader.read();
120             if(chData != text.charAt(readed)){
121                 if(chData >= '\u0000') reader.unread(chData);
122                 for(int pos = readed - 1; pos >= 0; pos--){
123                     reader.unread(backData[pos]);
124                 }
125                 break;
126             }
127
128             if(readed >= backData.length) return true;
129
130             backData[readed++] = chData;
131         }
132
133         return false;
134     }
135
136     /**
137      * JSONの各種Valueを文字ストリームから読み取る。
138      * @param reader 文字入力
139      * @return 各種Value
140      * @throws IOException 入力エラー
141      * @throws JsParseException パースエラー
142      */
143     public static JsValue parseValue(Reader reader)
144             throws IOException, JsParseException{
145         JsonReader jsreader;
146         if(reader instanceof JsonReader){
147             jsreader = (JsonReader) reader;
148         }else{
149             jsreader = new JsonReader(reader);
150         }
151
152         return parseValue(jsreader);
153     }
154
155     /**
156      * JSONの各種Valueを文字ストリームから読み取る。
157      * @param reader 文字入力
158      * @return 各種Value。ストリームの終わりに達したときはnull
159      * @throws IOException 入力エラー
160      * @throws JsParseException パースエラー
161      */
162     static JsValue parseValue(JsonReader reader)
163             throws IOException, JsParseException{
164         skipWhiteSpace(reader);
165
166         if(parseConst(reader, JsNull.NULL.toString())){
167             return JsNull.NULL;
168         }else if(parseConst(reader, JsBoolean.TRUE.toString())){
169             return JsBoolean.TRUE;
170         }else if(parseConst(reader, JsBoolean.FALSE.toString())){
171             return JsBoolean.FALSE;
172         }
173
174         int head = reader.read();
175         if(head < '\u0000') return null;
176
177         if( head == '-' || ('0' <= head && head <= '9') ){
178             reader.unread(head);
179             return JsNumber.parseNumber(reader);
180         }else if(head == '{'){
181             reader.unread(head);
182             return JsObject.parseObject(reader);
183         }else if(head == '['){
184             reader.unread(head);
185             return JsArray.parseArray(reader);
186         }else if(head == '"'){
187             reader.unread(head);
188             return JsString.parseString(reader);
189         }
190
191         throw new JsParseException();
192     }
193
194 }