annotate bindings/as3/ext/com/adobe/serialization/json/JSONDecoder.as @ 770:c54bc2ffbf92 tip

update tags
author convert-repo
date Fri, 16 Dec 2011 11:34:01 +0000
parents 3a0b9700b3d2
children
rev   line source
mas01mj@732 1 /*
mas01mj@732 2 Copyright (c) 2008, Adobe Systems Incorporated
mas01mj@732 3 All rights reserved.
mas01mj@732 4
mas01mj@732 5 Redistribution and use in source and binary forms, with or without
mas01mj@732 6 modification, are permitted provided that the following conditions are
mas01mj@732 7 met:
mas01mj@732 8
mas01mj@732 9 * Redistributions of source code must retain the above copyright notice,
mas01mj@732 10 this list of conditions and the following disclaimer.
mas01mj@732 11
mas01mj@732 12 * Redistributions in binary form must reproduce the above copyright
mas01mj@732 13 notice, this list of conditions and the following disclaimer in the
mas01mj@732 14 documentation and/or other materials provided with the distribution.
mas01mj@732 15
mas01mj@732 16 * Neither the name of Adobe Systems Incorporated nor the names of its
mas01mj@732 17 contributors may be used to endorse or promote products derived from
mas01mj@732 18 this software without specific prior written permission.
mas01mj@732 19
mas01mj@732 20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
mas01mj@732 21 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
mas01mj@732 22 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
mas01mj@732 23 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
mas01mj@732 24 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
mas01mj@732 25 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
mas01mj@732 26 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
mas01mj@732 27 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
mas01mj@732 28 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
mas01mj@732 29 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
mas01mj@732 30 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
mas01mj@732 31 */
mas01mj@732 32
mas01mj@732 33 package com.adobe.serialization.json
mas01mj@732 34 {
mas01mj@732 35
mas01mj@732 36 public class JSONDecoder
mas01mj@732 37 {
mas01mj@732 38
mas01mj@732 39 /**
mas01mj@732 40 * Flag indicating if the parser should be strict about the format
mas01mj@732 41 * of the JSON string it is attempting to decode.
mas01mj@732 42 */
mas01mj@732 43 private var strict:Boolean;
mas01mj@732 44
mas01mj@732 45 /** The value that will get parsed from the JSON string */
mas01mj@732 46 private var value:*;
mas01mj@732 47
mas01mj@732 48 /** The tokenizer designated to read the JSON string */
mas01mj@732 49 private var tokenizer:JSONTokenizer;
mas01mj@732 50
mas01mj@732 51 /** The current token from the tokenizer */
mas01mj@732 52 private var token:JSONToken;
mas01mj@732 53
mas01mj@732 54 /**
mas01mj@732 55 * Constructs a new JSONDecoder to parse a JSON string
mas01mj@732 56 * into a native object.
mas01mj@732 57 *
mas01mj@732 58 * @param s The JSON string to be converted
mas01mj@732 59 * into a native object
mas01mj@732 60 * @param strict Flag indicating if the JSON string needs to
mas01mj@732 61 * strictly match the JSON standard or not.
mas01mj@732 62 * @langversion ActionScript 3.0
mas01mj@732 63 * @playerversion Flash 9.0
mas01mj@732 64 * @tiptext
mas01mj@732 65 */
mas01mj@732 66 public function JSONDecoder( s:String, strict:Boolean )
mas01mj@732 67 {
mas01mj@732 68 this.strict = strict;
mas01mj@732 69 tokenizer = new JSONTokenizer( s, strict );
mas01mj@732 70
mas01mj@732 71 nextToken();
mas01mj@732 72 value = parseValue();
mas01mj@732 73
mas01mj@732 74 // Make sure the input stream is empty
mas01mj@732 75 if ( strict && nextToken() != null )
mas01mj@732 76 {
mas01mj@732 77 tokenizer.parseError( "Unexpected characters left in input stream" );
mas01mj@732 78 }
mas01mj@732 79 }
mas01mj@732 80
mas01mj@732 81 /**
mas01mj@732 82 * Gets the internal object that was created by parsing
mas01mj@732 83 * the JSON string passed to the constructor.
mas01mj@732 84 *
mas01mj@732 85 * @return The internal object representation of the JSON
mas01mj@732 86 * string that was passed to the constructor
mas01mj@732 87 * @langversion ActionScript 3.0
mas01mj@732 88 * @playerversion Flash 9.0
mas01mj@732 89 * @tiptext
mas01mj@732 90 */
mas01mj@732 91 public function getValue():*
mas01mj@732 92 {
mas01mj@732 93 return value;
mas01mj@732 94 }
mas01mj@732 95
mas01mj@732 96 /**
mas01mj@732 97 * Returns the next token from the tokenzier reading
mas01mj@732 98 * the JSON string
mas01mj@732 99 */
mas01mj@732 100 private function nextToken():JSONToken
mas01mj@732 101 {
mas01mj@732 102 return token = tokenizer.getNextToken();
mas01mj@732 103 }
mas01mj@732 104
mas01mj@732 105 /**
mas01mj@732 106 * Attempt to parse an array.
mas01mj@732 107 */
mas01mj@732 108 private function parseArray():Array
mas01mj@732 109 {
mas01mj@732 110 // create an array internally that we're going to attempt
mas01mj@732 111 // to parse from the tokenizer
mas01mj@732 112 var a:Array = new Array();
mas01mj@732 113
mas01mj@732 114 // grab the next token from the tokenizer to move
mas01mj@732 115 // past the opening [
mas01mj@732 116 nextToken();
mas01mj@732 117
mas01mj@732 118 // check to see if we have an empty array
mas01mj@732 119 if ( token.type == JSONTokenType.RIGHT_BRACKET )
mas01mj@732 120 {
mas01mj@732 121 // we're done reading the array, so return it
mas01mj@732 122 return a;
mas01mj@732 123 }
mas01mj@732 124 // in non-strict mode an empty array is also a comma
mas01mj@732 125 // followed by a right bracket
mas01mj@732 126 else if ( !strict && token.type == JSONTokenType.COMMA )
mas01mj@732 127 {
mas01mj@732 128 // move past the comma
mas01mj@732 129 nextToken();
mas01mj@732 130
mas01mj@732 131 // check to see if we're reached the end of the array
mas01mj@732 132 if ( token.type == JSONTokenType.RIGHT_BRACKET )
mas01mj@732 133 {
mas01mj@732 134 return a;
mas01mj@732 135 }
mas01mj@732 136 else
mas01mj@732 137 {
mas01mj@732 138 tokenizer.parseError( "Leading commas are not supported. Expecting ']' but found " + token.value );
mas01mj@732 139 }
mas01mj@732 140 }
mas01mj@732 141
mas01mj@732 142 // deal with elements of the array, and use an "infinite"
mas01mj@732 143 // loop because we could have any amount of elements
mas01mj@732 144 while ( true )
mas01mj@732 145 {
mas01mj@732 146 // read in the value and add it to the array
mas01mj@732 147 a.push( parseValue() );
mas01mj@732 148
mas01mj@732 149 // after the value there should be a ] or a ,
mas01mj@732 150 nextToken();
mas01mj@732 151
mas01mj@732 152 if ( token.type == JSONTokenType.RIGHT_BRACKET )
mas01mj@732 153 {
mas01mj@732 154 // we're done reading the array, so return it
mas01mj@732 155 return a;
mas01mj@732 156 }
mas01mj@732 157 else if ( token.type == JSONTokenType.COMMA )
mas01mj@732 158 {
mas01mj@732 159 // move past the comma and read another value
mas01mj@732 160 nextToken();
mas01mj@732 161
mas01mj@732 162 // Allow arrays to have a comma after the last element
mas01mj@732 163 // if the decoder is not in strict mode
mas01mj@732 164 if ( !strict )
mas01mj@732 165 {
mas01mj@732 166 // Reached ",]" as the end of the array, so return it
mas01mj@732 167 if ( token.type == JSONTokenType.RIGHT_BRACKET )
mas01mj@732 168 {
mas01mj@732 169 return a;
mas01mj@732 170 }
mas01mj@732 171 }
mas01mj@732 172 }
mas01mj@732 173 else
mas01mj@732 174 {
mas01mj@732 175 tokenizer.parseError( "Expecting ] or , but found " + token.value );
mas01mj@732 176 }
mas01mj@732 177 }
mas01mj@732 178 return null;
mas01mj@732 179 }
mas01mj@732 180
mas01mj@732 181 /**
mas01mj@732 182 * Attempt to parse an object.
mas01mj@732 183 */
mas01mj@732 184 private function parseObject():Object
mas01mj@732 185 {
mas01mj@732 186 // create the object internally that we're going to
mas01mj@732 187 // attempt to parse from the tokenizer
mas01mj@732 188 var o:Object = new Object();
mas01mj@732 189
mas01mj@732 190 // store the string part of an object member so
mas01mj@732 191 // that we can assign it a value in the object
mas01mj@732 192 var key:String
mas01mj@732 193
mas01mj@732 194 // grab the next token from the tokenizer
mas01mj@732 195 nextToken();
mas01mj@732 196
mas01mj@732 197 // check to see if we have an empty object
mas01mj@732 198 if ( token.type == JSONTokenType.RIGHT_BRACE )
mas01mj@732 199 {
mas01mj@732 200 // we're done reading the object, so return it
mas01mj@732 201 return o;
mas01mj@732 202 }
mas01mj@732 203 // in non-strict mode an empty object is also a comma
mas01mj@732 204 // followed by a right bracket
mas01mj@732 205 else if ( !strict && token.type == JSONTokenType.COMMA )
mas01mj@732 206 {
mas01mj@732 207 // move past the comma
mas01mj@732 208 nextToken();
mas01mj@732 209
mas01mj@732 210 // check to see if we're reached the end of the object
mas01mj@732 211 if ( token.type == JSONTokenType.RIGHT_BRACE )
mas01mj@732 212 {
mas01mj@732 213 return o;
mas01mj@732 214 }
mas01mj@732 215 else
mas01mj@732 216 {
mas01mj@732 217 tokenizer.parseError( "Leading commas are not supported. Expecting '}' but found " + token.value );
mas01mj@732 218 }
mas01mj@732 219 }
mas01mj@732 220
mas01mj@732 221 // deal with members of the object, and use an "infinite"
mas01mj@732 222 // loop because we could have any amount of members
mas01mj@732 223 while ( true )
mas01mj@732 224 {
mas01mj@732 225 if ( token.type == JSONTokenType.STRING )
mas01mj@732 226 {
mas01mj@732 227 // the string value we read is the key for the object
mas01mj@732 228 key = String( token.value );
mas01mj@732 229
mas01mj@732 230 // move past the string to see what's next
mas01mj@732 231 nextToken();
mas01mj@732 232
mas01mj@732 233 // after the string there should be a :
mas01mj@732 234 if ( token.type == JSONTokenType.COLON )
mas01mj@732 235 {
mas01mj@732 236 // move past the : and read/assign a value for the key
mas01mj@732 237 nextToken();
mas01mj@732 238 o[key] = parseValue();
mas01mj@732 239
mas01mj@732 240 // move past the value to see what's next
mas01mj@732 241 nextToken();
mas01mj@732 242
mas01mj@732 243 // after the value there's either a } or a ,
mas01mj@732 244 if ( token.type == JSONTokenType.RIGHT_BRACE )
mas01mj@732 245 {
mas01mj@732 246 // we're done reading the object, so return it
mas01mj@732 247 return o;
mas01mj@732 248 }
mas01mj@732 249 else if ( token.type == JSONTokenType.COMMA )
mas01mj@732 250 {
mas01mj@732 251 // skip past the comma and read another member
mas01mj@732 252 nextToken();
mas01mj@732 253
mas01mj@732 254 // Allow objects to have a comma after the last member
mas01mj@732 255 // if the decoder is not in strict mode
mas01mj@732 256 if ( !strict )
mas01mj@732 257 {
mas01mj@732 258 // Reached ",}" as the end of the object, so return it
mas01mj@732 259 if ( token.type == JSONTokenType.RIGHT_BRACE )
mas01mj@732 260 {
mas01mj@732 261 return o;
mas01mj@732 262 }
mas01mj@732 263 }
mas01mj@732 264 }
mas01mj@732 265 else
mas01mj@732 266 {
mas01mj@732 267 tokenizer.parseError( "Expecting } or , but found " + token.value );
mas01mj@732 268 }
mas01mj@732 269 }
mas01mj@732 270 else
mas01mj@732 271 {
mas01mj@732 272 tokenizer.parseError( "Expecting : but found " + token.value );
mas01mj@732 273 }
mas01mj@732 274 }
mas01mj@732 275 else
mas01mj@732 276 {
mas01mj@732 277 tokenizer.parseError( "Expecting string but found " + token.value );
mas01mj@732 278 }
mas01mj@732 279 }
mas01mj@732 280 return null;
mas01mj@732 281 }
mas01mj@732 282
mas01mj@732 283 /**
mas01mj@732 284 * Attempt to parse a value
mas01mj@732 285 */
mas01mj@732 286 private function parseValue():Object
mas01mj@732 287 {
mas01mj@732 288 // Catch errors when the input stream ends abruptly
mas01mj@732 289 if ( token == null )
mas01mj@732 290 {
mas01mj@732 291 tokenizer.parseError( "Unexpected end of input" );
mas01mj@732 292 }
mas01mj@732 293
mas01mj@732 294 switch ( token.type )
mas01mj@732 295 {
mas01mj@732 296 case JSONTokenType.LEFT_BRACE:
mas01mj@732 297 return parseObject();
mas01mj@732 298
mas01mj@732 299 case JSONTokenType.LEFT_BRACKET:
mas01mj@732 300 return parseArray();
mas01mj@732 301
mas01mj@732 302 case JSONTokenType.STRING:
mas01mj@732 303 case JSONTokenType.NUMBER:
mas01mj@732 304 case JSONTokenType.TRUE:
mas01mj@732 305 case JSONTokenType.FALSE:
mas01mj@732 306 case JSONTokenType.NULL:
mas01mj@732 307 return token.value;
mas01mj@732 308
mas01mj@732 309 case JSONTokenType.NAN:
mas01mj@732 310 if ( !strict )
mas01mj@732 311 {
mas01mj@732 312 return token.value;
mas01mj@732 313 }
mas01mj@732 314 else
mas01mj@732 315 {
mas01mj@732 316 tokenizer.parseError( "Unexpected " + token.value );
mas01mj@732 317 }
mas01mj@732 318
mas01mj@732 319 default:
mas01mj@732 320 tokenizer.parseError( "Unexpected " + token.value );
mas01mj@732 321
mas01mj@732 322 }
mas01mj@732 323
mas01mj@732 324 return null;
mas01mj@732 325 }
mas01mj@732 326 }
mas01mj@732 327 }