source: code/Website/open-flash-chart/com/adobe/serialization/json/JSONEncoder.as@ 7849

Last change on this file since 7849 was 7849, checked in by dennisw, 15 years ago
File size: 9.2 KB
Line 
1/*
2Adobe Systems Incorporated(r) Source Code License Agreement
3Copyright(c) 2005 Adobe Systems Incorporated. All rights reserved.
4
5Please read this Source Code License Agreement carefully before using
6the source code.
7
8Adobe Systems Incorporated grants to you a perpetual, worldwide, non-exclusive,
9no-charge, royalty-free, irrevocable copyright license, to reproduce,
10prepare derivative works of, publicly display, publicly perform, and
11distribute this source code and such derivative works in source or
12object code form without any attribution requirements.
13
14The name "Adobe Systems Incorporated" must not be used to endorse or promote products
15derived from the source code without prior written permission.
16
17You agree to indemnify, hold harmless and defend Adobe Systems Incorporated from and
18against any loss, damage, claims or lawsuits, including attorney's
19fees that arise or result from your use or distribution of the source
20code.
21
22THIS SOURCE CODE IS PROVIDED "AS IS" AND "WITH ALL FAULTS", WITHOUT
23ANY TECHNICAL SUPPORT OR ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
24BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ALSO, THERE IS NO WARRANTY OF
26NON-INFRINGEMENT, TITLE OR QUIET ENJOYMENT. IN NO EVENT SHALL MACROMEDIA
27OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
30OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOURCE CODE, EVEN IF
33ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34*/
35
36package com.adobe.serialization.json
37{
38
39 import flash.utils.describeType;
40
41 public class JSONEncoder {
42
43 /** The string that is going to represent the object we're encoding */
44 private var jsonString:String;
45
46 /**
47 * Creates a new JSONEncoder.
48 *
49 * @param o The object to encode as a JSON string
50 * @langversion ActionScript 3.0
51 * @playerversion Flash 9.0
52 * @tiptext
53 */
54 public function JSONEncoder( value:* ) {
55 jsonString = convertToString( value );
56
57 }
58
59 /**
60 * Gets the JSON string from the encoder.
61 *
62 * @return The JSON string representation of the object
63 * that was passed to the constructor
64 * @langversion ActionScript 3.0
65 * @playerversion Flash 9.0
66 * @tiptext
67 */
68 public function getString():String {
69 return jsonString;
70 }
71
72 /**
73 * Converts a value to it's JSON string equivalent.
74 *
75 * @param value The value to convert. Could be any
76 * type (object, number, array, etc)
77 */
78 private function convertToString( value:* ):String {
79
80 // determine what value is and convert it based on it's type
81 if ( value is String ) {
82
83 // escape the string so it's formatted correctly
84 return escapeString( value as String );
85
86 } else if ( value is Number ) {
87
88 // only encode numbers that finate
89 return isFinite( value as Number) ? value.toString() : "null";
90
91 } else if ( value is Boolean ) {
92
93 // convert boolean to string easily
94 return value ? "true" : "false";
95
96 } else if ( value is Array ) {
97
98 // call the helper method to convert an array
99 return arrayToString( value as Array );
100
101 } else if ( value is Object && value != null ) {
102
103 // call the helper method to convert an object
104 return objectToString( value );
105 }
106 return "null";
107 }
108
109 /**
110 * Escapes a string accoding to the JSON specification.
111 *
112 * @param str The string to be escaped
113 * @return The string with escaped special characters
114 * according to the JSON specification
115 */
116 private function escapeString( str:String ):String {
117 // create a string to store the string's jsonstring value
118 var s:String = "";
119 // current character in the string we're processing
120 var ch:String;
121 // store the length in a local variable to reduce lookups
122 var len:Number = str.length;
123
124 // loop over all of the characters in the string
125 for ( var i:int = 0; i < len; i++ ) {
126
127 // examine the character to determine if we have to escape it
128 ch = str.charAt( i );
129 switch ( ch ) {
130
131 case '"': // quotation mark
132 s += "\\\"";
133 break;
134
135 //case '/': // solidus
136 // s += "\\/";
137 // break;
138
139 case '\\': // reverse solidus
140 s += "\\\\";
141 break;
142
143 case '\b': // bell
144 s += "\\b";
145 break;
146
147 case '\f': // form feed
148 s += "\\f";
149 break;
150
151 case '\n': // newline
152 s += "\\n";
153 break;
154
155 case '\r': // carriage return
156 s += "\\r";
157 break;
158
159 case '\t': // horizontal tab
160 s += "\\t";
161 break;
162
163 default: // everything else
164
165 // check for a control character and escape as unicode
166 if ( ch < ' ' ) {
167 // get the hex digit(s) of the character (either 1 or 2 digits)
168 var hexCode:String = ch.charCodeAt( 0 ).toString( 16 );
169
170 // ensure that there are 4 digits by adjusting
171 // the # of zeros accordingly.
172 var zeroPad:String = hexCode.length == 2 ? "00" : "000";
173
174 // create the unicode escape sequence with 4 hex digits
175 s += "\\u" + zeroPad + hexCode;
176 } else {
177
178 // no need to do any special encoding, just pass-through
179 s += ch;
180
181 }
182 } // end switch
183
184 } // end for loop
185
186 return "\"" + s + "\"";
187 }
188
189 /**
190 * Converts an array to it's JSON string equivalent
191 *
192 * @param a The array to convert
193 * @return The JSON string representation of <code>a</code>
194 */
195 private function arrayToString( a:Array ):String {
196 // create a string to store the array's jsonstring value
197 var s:String = "";
198
199 // loop over the elements in the array and add their converted
200 // values to the string
201 for ( var i:int = 0; i < a.length; i++ ) {
202 // when the length is 0 we're adding the first element so
203 // no comma is necessary
204 if ( s.length > 0 ) {
205 // we've already added an element, so add the comma separator
206 s += ","
207 }
208
209 // convert the value to a string
210 s += convertToString( a[i] );
211 }
212
213 // KNOWN ISSUE: In ActionScript, Arrays can also be associative
214 // objects and you can put anything in them, ie:
215 // myArray["foo"] = "bar";
216 //
217 // These properties aren't picked up in the for loop above because
218 // the properties don't correspond to indexes. However, we're
219 // sort of out luck because the JSON specification doesn't allow
220 // these types of array properties.
221 //
222 // So, if the array was also used as an associative object, there
223 // may be some values in the array that don't get properly encoded.
224 //
225 // A possible solution is to instead encode the Array as an Object
226 // but then it won't get decoded correctly (and won't be an
227 // Array instance)
228
229 // close the array and return it's string value
230 return "[" + s + "]";
231 }
232
233 /**
234 * Converts an object to it's JSON string equivalent
235 *
236 * @param o The object to convert
237 * @return The JSON string representation of <code>o</code>
238 */
239 private function objectToString( o:Object ):String
240 {
241 // create a string to store the object's jsonstring value
242 var s:String = "";
243
244 // determine if o is a class instance or a plain object
245 var classInfo:XML = describeType( o );
246 if ( classInfo.@name.toString() == "Object" )
247 {
248 // the value of o[key] in the loop below - store this
249 // as a variable so we don't have to keep looking up o[key]
250 // when testing for valid values to convert
251 var value:Object;
252
253 // loop over the keys in the object and add their converted
254 // values to the string
255 for ( var key:String in o )
256 {
257 // assign value to a variable for quick lookup
258 value = o[key];
259
260 // don't add function's to the JSON string
261 if ( value is Function )
262 {
263 // skip this key and try another
264 continue;
265 }
266
267 // when the length is 0 we're adding the first item so
268 // no comma is necessary
269 if ( s.length > 0 ) {
270 // we've already added an item, so add the comma separator
271 s += ","
272 }
273
274 s += escapeString( key ) + ":" + convertToString( value );
275 }
276 }
277 else // o is a class instance
278 {
279 // Loop over all of the variables and accessors in the class and
280 // serialize them along with their values.
281 for each ( var v:XML in classInfo..*.( name() == "variable" || name() == "accessor" ) )
282 {
283 // When the length is 0 we're adding the first item so
284 // no comma is necessary
285 if ( s.length > 0 ) {
286 // We've already added an item, so add the comma separator
287 s += ","
288 }
289
290 s += escapeString( v.@name.toString() ) + ":"
291 + convertToString( o[ v.@name ] );
292 }
293
294 }
295
296 return "{" + s + "}";
297 }
298
299
300 }
301
302}
Note: See TracBrowser for help on using the repository browser.