]> git.mjollnir.org Git - moodle.git/blob
c1b1ca1bde5fa2a3d99df25fba3666bb6e161bab
[moodle.git] /
1 /*
2 Adobe Systems Incorporated(r) Source Code License Agreement
3 Copyright(c) 2005 Adobe Systems Incorporated. All rights reserved.
4         
5 Please read this Source Code License Agreement carefully before using
6 the source code.
7         
8 Adobe Systems Incorporated grants to you a perpetual, worldwide, non-exclusive,
9 no-charge, royalty-free, irrevocable copyright license, to reproduce,
10 prepare derivative works of, publicly display, publicly perform, and
11 distribute this source code and such derivative works in source or
12 object code form without any attribution requirements.
13         
14 The name "Adobe Systems Incorporated" must not be used to endorse or promote products
15 derived from the source code without prior written permission.
16         
17 You agree to indemnify, hold harmless and defend Adobe Systems Incorporated from and
18 against any loss, damage, claims or lawsuits, including attorney's
19 fees that arise or result from your use or distribution of the source
20 code.
21         
22 THIS SOURCE CODE IS PROVIDED "AS IS" AND "WITH ALL FAULTS", WITHOUT
23 ANY TECHNICAL SUPPORT OR ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
24 BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ALSO, THERE IS NO WARRANTY OF
26 NON-INFRINGEMENT, TITLE OR QUIET ENJOYMENT. IN NO EVENT SHALL MACROMEDIA
27 OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
30 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOURCE CODE, EVEN IF
33 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 package com.adobe.serialization.json {
37
38       /**
39        * @private
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 8.5
52                  * @tiptext
53                  */
54                 public function JSONEncoder( o:Object ) {
55                         jsonString = convertToString( o );
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 8.5
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:Object ):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                         // the value of o[key] in the loop below - store this 
245                         // as a variable so we don't have to keep looking up o[key]
246                         // when testing for valid values to convert
247                         var value:Object;
248                         
249                         // loop over the keys in the object and add their converted
250                         // values to the string
251                         for ( var key:String in o ) {
252                                 // assign value to a variable for quick lookup
253                                 value = o[key];
254                                 
255                                 // don't add function's to the JSON string
256                                 if ( value is Function ) {
257                                         // skip this key and try another
258                                         continue;
259                                 }
260                                 
261                                 // when the length is 0 we're adding the first item so
262                                 // no comma is necessary
263                                 if ( s.length > 0 ) {
264                                         // we've already added an item, so add the comma separator
265                                         s += ","
266                                 }
267                                 
268                                 s += escapeString( key ) + ":" + convertToString( value );
269                         }
270                         
271                         return "{" + s + "}";
272                 }
273                 
274         }
275         
276 }