1 /* Copyright (c) 2007 Derek Wischusen
3 * Permission is hereby granted, free of charge, to any person obtaining a copy of
4 * this software and associated documentation files (the "Software"), to deal in
5 * the Software without restriction, including without limitation the rights to
6 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7 * of the Software, and to permit persons to whom the Software is furnished to do
8 * so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in all
11 * copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 import flash.utils.Dictionary;
25 import flash.utils.getDefinitionByName;
26 import flash.utils.getQualifiedClassName;
28 import mx.utils.Base64Decoder;
29 import mx.utils.ObjectUtil;
31 import org.as3yaml.nodes.Node;
32 import org.idmedia.as3commons.util.ArrayList;
33 import org.idmedia.as3commons.util.Collection;
34 import org.idmedia.as3commons.util.HashMap;
35 import org.idmedia.as3commons.util.Map;
36 import org.as3yaml.util.StringUtils;
38 public class SafeConstructor extends BaseConstructor {
39 private static var yamlConstructors : Dictionary = new Dictionary();
40 private static var yamlMultiConstructors : Dictionary = new Dictionary();
41 private static var yamlMultiRegexps : Map = new HashMap();
43 override public function getYamlConstructor(key:Object) : Function {
45 var ctor : Function = yamlConstructors[key];
48 ctor = super.getYamlConstructor(key);
53 override public function getYamlMultiConstructor(key : Object) : Function {
55 var ctor : Function = yamlMultiConstructors[key];
58 ctor = super.getYamlMultiConstructor(key);
64 override public function getYamlMultiRegexp(key : Object) : RegExp {
65 var mine : RegExp = yamlMultiRegexps.get(key);
67 mine = super.getYamlMultiRegexp(key);
72 override public function getYamlMultiRegexps() : Map {
73 var all : Map = new HashMap();
74 all.putAll(super.getYamlMultiRegexps());
75 all.putAll(yamlMultiRegexps);
79 public static function addConstructor(tag : String, ctor : Function) : void {
80 yamlConstructors[tag] = ctor;
83 public static function addMultiConstructor(tagPrefix : String, ctor : Function) : void {
84 yamlMultiConstructors[tagPrefix] = ctor;
85 yamlMultiRegexps.put(tagPrefix, new RegExp("^"+tagPrefix));
88 public function SafeConstructor(composer : Composer) {
92 private static var BOOL_VALUES : Object = {
101 public static function constructYamlNull(ctor : Constructor, node : Node) : Object {
105 public static function constructYamlBool(ctor : Constructor, node : Node) : Object {
106 var val : String = ctor.constructScalar(node) as String;
107 return BOOL_VALUES[val.toLowerCase()];
110 public static function constructYamlOmap(ctor : Constructor, node : Node) : Object {
111 return ctor.constructOmap(node);
114 public static function constructYamlPairs(ctor : Constructor, node : Node) : Object {
115 return ctor.constructPairs(node);
118 public static function constructYamlSet(ctor : Constructor, node : Node) : Object {
119 return Map(ctor.constructMapping(node)).keySet();
122 public static function constructYamlStr(ctor : Constructor, node : Node) : Object {
123 var value : String = ctor.constructScalar(node) as String;
124 return value.length == 0 ? null : value;
127 public static function constructYamlSeq(ctor : Constructor, node : Node) : Object {
128 return ctor.constructSequence(node);
131 public static function constructYamlMap(ctor : Constructor, node : Node) : Object {
132 return ctor.constructMapping(node);
135 public static function constructUndefined(ctor : Constructor, node : Node) : Object {
136 throw new ConstructorException(null,"could not determine a constructor for the tag " + node.getTag(),null);
139 private static var TIMESTAMP_REGEXP : RegExp = new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:(?:[Tt]|[ \t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \t]*(?:Z|([-+][0-9][0-9]?)(?::([0-9][0-9])?)?))?)?$");
140 private static var YMD_REGEXP : RegExp = new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)$");
141 public static function constructYamlTimestamp(ctor : Constructor, node : Node) : Object {
142 var match : Object = YMD_REGEXP.exec(String(node.getValue()));
145 var month_s : String;
147 var time : Date = null;
154 if(year_s == null || month_s == null || day_s == null) {
155 throw new ConstructorException(null, "bad date value: " + node.getValue(), null);
158 return new Date(year_s,int(month_s)-1,day_s);
160 match = TIMESTAMP_REGEXP.exec(String(node.getValue()));
162 return ctor.constructPrivateType(node);
169 var hour_s: String = match[4];
170 var min_s: String = match[5];
171 var sec_s: String = match[6];
172 var fract_s: String = match[7];
173 var timezoneh_s: String = match[8];
174 var timezonem_s: String = match[9];
177 if(fract_s != null) {
180 while(10*usec < 1000) {
188 if(month_s != null && day_s != null) {
189 time.setMonth(int(month_s)-1, day_s);
192 time.setFullYear(year_s);
195 time.setHours(hour_s);
198 time.setMinutes(min_s);
201 time.setSeconds(sec_s);
203 time.setMilliseconds(usec);
204 if(timezoneh_s != null || timezonem_s != null) {
207 if(timezoneh_s != null) {
208 if(timezoneh_s.charAt(0) == ("-")) {
211 zone += int(timezoneh_s.substring(1))*3600000;
213 if(timezonem_s != null) {
214 zone += int(timezonem_s)*60000;
220 public static function constructYamlInt(ctor : Constructor, node : Node) : Object {
221 var value : String = String(ctor.constructScalar(node)).replace(/_/g,"");
223 var first : String = value.charAt(0);
226 value = value.substring(1);
227 } else if(first == '+') {
228 value = value.substring(1);
233 } else if(StringUtils.startsWith(value, "0b")) {
234 value = value.substring(2);
236 } else if(StringUtils.startsWith(value, "0x")) {
237 value = value.substring(2);
239 } else if(value.charAt(0) == ("0")) {
240 value = value.substring(1);
242 } else if(value.indexOf(':') != -1) {
243 var digits : Array = value.split(":");
246 for(var i:int=0,j:int=digits.length;i<j;i++) {
247 val += (Number(digits[(j-i)-1])*bes);
250 return new int(sign*val);
252 return sign * parseInt(value, base);//new Number(sign * int(value));
254 return (sign * parseInt(value, base));
257 private static var INF_VALUE_POS : Number = new Number(Number.POSITIVE_INFINITY);
258 private static var INF_VALUE_NEG : Number = new Number(Number.NEGATIVE_INFINITY);
259 private static var NAN_VALUE : Number = new Number(Number.NaN);
261 public static function constructYamlFloat(ctor : Constructor, node : Node) : Object {
262 var value : String = String(ctor.constructScalar(node).toString()).replace(/'_'/g,"");
264 var first : String = value.charAt(0);
267 value = value.substring(1);
268 } else if(first == '+') {
269 value = value.substring(1);
271 var valLower : String = value.toLowerCase();
272 if(valLower == (".inf")) {
273 return sign == -1 ? INF_VALUE_NEG : INF_VALUE_POS;
274 } else if(valLower == (".nan")) {
276 } else if(value.indexOf(':') != -1) {
277 var digits : Array = value.split(":");
279 var val : Number = 0.0;
280 for(var i:int=0,j:int=digits.length;i<j;i++) {
281 val += (Number(digits[(j-i)-1])*bes);
284 return new Number(sign*val);
286 return Number(value) * sign;
290 public static function constructYamlBinary(ctor : Constructor, node : Node) : Object {
291 var values : Array = ctor.constructScalar(node).toString().split("[\n\u0085]|(?:\r[^\n])");
292 var vals : String = new String();
293 for(var i:int=0,j:int=values.length;i<j;i++) {
296 var decoder : Base64Decoder = new Base64Decoder();
297 decoder.decode(vals);
298 return decoder.flush();
301 public static function constructSpecializedSequence(ctor : Constructor, pref : String, node : Node) : Object {
302 var outp : ArrayList = null;
304 var seqClass : Object = getDefinitionByName(pref) as Class;
305 outp = new seqClass() as ArrayList;
307 throw new YAMLException("Can't construct a sequence from class " + pref + ": " + e.toString());
309 var coll : Collection = ctor.constructSequence(node) as Collection;
314 public static function constructSpecializedMap(ctor : Constructor, pref : String, node : Node) : Object {
315 var outp : Map = null;
317 var mapClass : Class = getDefinitionByName(pref) as Class;
318 outp = new mapClass();
320 throw new YAMLException("Can't construct a mapping from class " + pref + ": " + e.toString());
322 var coll : Map = ctor.constructMapping(node) as Map;
327 private static function fixValue(inp : Object, outp : Class) : Object {
331 var inClass : Class = getDefinitionByName(getQualifiedClassName(inp)) as Class;
332 if(outp is inClass) {
335 if(inClass == Number && (outp == int)) {
339 if(inClass == Number && (outp == String)) {
340 return new String(inp);
346 public static function constructActionscript(ctor : Constructor, pref : String, node : Node) : Object {
347 var outp : Object = null;
349 var cl : Class = getDefinitionByName(pref) as Class;
351 var values : Dictionary = Dictionary(ctor.constructMapping(node));
352 var props : Array = ObjectUtil.getClassInfo(outp).properties;
353 for(var key : Object in values) {
354 var value : Object = values[key];
358 throw new YAMLException("Can't construct actionscript object from class " + pref + ": " + e.toString());
364 BaseConstructor.addConstructor("tag:yaml.org,2002:null", function call(self : Constructor, node : Node) : Object {
365 return constructYamlNull(self,node);
367 addConstructor("tag:yaml.org,2002:bool", function call(self : Constructor, node : Node) : Object {
368 return constructYamlBool(self,node);
370 addConstructor("tag:yaml.org,2002:omap", function call(self : Constructor, node : Node) : Object {
371 return constructYamlOmap(self,node);
373 addConstructor("tag:yaml.org,2002:pairs", function call(self : Constructor, node : Node) : Object {
374 return constructYamlPairs(self,node);
376 addConstructor("tag:yaml.org,2002:set", function call(self : Constructor, node : Node) : Object {
377 return constructYamlSet(self,node);
379 addConstructor("tag:yaml.org,2002:int", function call(self : Constructor, node : Node) : Object {
380 return constructYamlInt(self,node);
382 addConstructor("tag:yaml.org,2002:float", function call(self : Constructor, node : Node) : Object {
383 return constructYamlFloat(self,node);
385 addConstructor("tag:yaml.org,2002:timestamp", function call(self : Constructor, node : Node) : Object {
386 return constructYamlTimestamp(self,node);
388 addConstructor("tag:yaml.org,2002:timestamp#ymd", function call(self : Constructor, node : Node) : Object {
389 return constructYamlTimestamp(self,node);
391 addConstructor("tag:yaml.org,2002:str", function call(self : Constructor, node : Node) : Object {
392 return constructYamlStr(self,node);
394 addConstructor("tag:yaml.org,2002:binary", function call(self : Constructor, node : Node) : Object {
395 return constructYamlBinary(self,node);
397 addConstructor("tag:yaml.org,2002:seq", function call(self : Constructor, node : Node) : Object {
398 return constructYamlSeq(self,node);
400 addConstructor("tag:yaml.org,2002:map", function call(self : Constructor, node : Node) : Object {
401 return constructYamlMap(self,node);
403 addConstructor(null, function call(self : Constructor, node : Node) : Object {
404 return self.constructPrivateType(node);
407 addMultiConstructor("tag:yaml.org,2002:seq:", function call(self : Constructor, pref : String, node : Node) : Object {
408 return constructSpecializedSequence(self,pref,node);
410 addMultiConstructor("tag:yaml.org,2002:map:", function call(self : Constructor, pref : String, node : Node) : Object {
411 return constructSpecializedMap(self,pref,node);
413 addMultiConstructor("!actionscript/object:", function call(self : Constructor, pref : String, node : Node) : Object {
414 return constructActionscript(self,pref,node);