KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > quercus > lib > json > JsonModule


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Nam Nguyen
28  */

29
30 package com.caucho.quercus.lib.json;
31
32 import com.caucho.quercus.annotation.Optional;
33 import com.caucho.quercus.env.*;
34 import com.caucho.quercus.module.AbstractQuercusModule;
35 import com.caucho.util.L10N;
36
37 import java.util.Map JavaDoc;
38 import java.util.logging.Logger JavaDoc;
39
40 public class JsonModule
41     extends AbstractQuercusModule
42 {
43   private static final Logger JavaDoc log
44     = Logger.getLogger(JsonModule.class.getName());
45   private static final L10N L = new L10N(JsonModule.class);
46
47   public String JavaDoc []getLoadedExtensions()
48   {
49     return new String JavaDoc[] { "json" };
50   }
51
52   /**
53    * Returns a JSON-encoded String.
54    *
55    * JSON strings can be in any Unicode format (UTF-8, UTF-16, UTF-32).
56    * Therefore need to pay special attention to multi-char characters.
57    *
58    * @param env
59    * @param val to encode into json format
60    * @return String JSON-encoded String
61    */

62   public StringValue json_encode(Env env, Value val)
63   {
64     StringBuilderValue sb = new StringBuilderValue();
65
66     jsonEncodeImpl(env, sb, val);
67     return sb;
68   }
69
70   private void jsonEncodeImpl(Env env, StringBuilderValue sb, Value val)
71   {
72     if (val instanceof StringValue) {
73       sb.append('"');
74       encodeString(sb, (StringValue)val);
75       sb.append('"');
76     }
77
78     else if (val == BooleanValue.TRUE)
79       sb.append("true");
80     else if (val == BooleanValue.FALSE)
81       sb.append("false");
82
83     else if (val instanceof NumberValue)
84       sb.append(val.toStringValue());
85
86     else if (val instanceof ArrayValue)
87       encodeArray(env, sb, (ArrayValue)val);
88
89     else if (val instanceof ObjectValue)
90       encodeObject(env, sb, (ObjectValue)val);
91
92     else if (val == NullValue.NULL || val == null)
93       sb.append("null");
94
95     else {
96       env.warning(L.l("type is unsupported; encoded as null"));
97     }
98   }
99
100   private void encodeArray(Env env, StringBuilderValue sb, ArrayValue val)
101   {
102     long length = 0;
103     for (Value key : val.keySet()) {
104       if ((! key.isLongConvertible()) || key.toLong() != length) {
105         encodeArrayToObject(env, sb, val);
106         return;
107       }
108       length++;
109     }
110
111     sb.append('[');
112
113     length = 0;
114     for (Value value : ((ArrayValue)val).values()) {
115       if (length > 0)
116         sb.append(',');
117       jsonEncodeImpl(env, sb, value);
118       length++;
119     }
120
121     sb.append(']');
122   }
123
124   /**
125    * Encodes an associative array into a JSON object.
126    */

127   private void encodeArrayToObject(Env env, StringBuilderValue sb, ArrayValue val)
128   {
129       sb.append('{');
130
131       int length = 0;
132       for (Map.Entry JavaDoc<Value,Value> entry : val.entrySet()) {
133         if (length > 0)
134           sb.append(',');
135
136         jsonEncodeImpl(env, sb, entry.getKey().toStringValue());
137         sb.append(':');
138         jsonEncodeImpl(env, sb, entry.getValue());
139         length++;
140       }
141
142       sb.append('}');
143   }
144
145   /**
146    * Encodes an PHP object into a JSON object.
147    */

148   private void encodeObject(Env env, StringBuilderValue sb, ObjectValue val)
149   {
150       sb.append('{');
151
152       int length = 0;
153       for (Map.Entry JavaDoc<String JavaDoc,Value> entry : val.entrySet()) {
154         if (length > 0)
155           sb.append(',');
156
157         jsonEncodeImpl(env, sb, new StringValueImpl(entry.getKey()));
158         sb.append(':');
159         jsonEncodeImpl(env, sb, entry.getValue());
160         length++;
161       }
162
163       sb.append('}');
164   }
165
166   /**
167    * Escapes special/control characters.
168    */

169   private void encodeString(StringBuilderValue sb, StringValue val)
170   {
171     int len = val.length();
172     for (int i = 0; i < len; i++) {
173       char c = val.charAt(i);
174
175       switch (c) {
176         case '\b':
177           sb.append('\\');
178           sb.append('b');
179           break;
180         case '\f':
181           sb.append('\\');
182           sb.append('f');
183           break;
184         case '\n':
185           sb.append('\\');
186           sb.append('n');
187           break;
188         case '\r':
189           sb.append('\\');
190           sb.append('r');
191           break;
192         case '\t':
193           sb.append('\\');
194           sb.append('t');
195           break;
196         case '\\':
197           sb.append('\\');
198           sb.append('\\');
199           break;
200         case '"':
201           sb.append('\\');
202           sb.append('"');
203           break;
204         case '/':
205           sb.append('\\');
206           sb.append('/');
207           break;
208         default:
209           if (c > 0x1F) {
210             sb.append(c);
211             break;
212           }
213
214           // Need to escape control chars in range 0-0x1F
215
sb.append('\\');
216           sb.append('u');
217           sb.append('0');
218           sb.append('0');
219
220           if (c <= 0x0F)
221             sb.append('0');
222           else {
223             sb.append('1');
224             c &= 0x0F;
225           }
226
227           if (c <= 0x09)
228             c += '0';
229           else
230             c += 'a' - 10;
231
232           sb.append(c);
233       }
234     }
235   }
236
237   /**
238    * Takes a JSON-encoded string and returns a PHP value.
239    *
240    * @param env
241    * @param s JSON-encoded string.
242    * @param assoc determines whether a generic PHP object or PHP associative
243    * array should be returned when decoding json objects.
244    * @return decoded PHP value.
245    */

246   public Value json_decode(Env env,
247                           StringValue s,
248                           @Optional("false") boolean assoc)
249   {
250     return (new JsonDecoder()).jsonDecode(env, s, assoc);
251   }
252
253 }
254
Popular Tags