PageRenderTime 176ms CodeModel.GetById 41ms app.highlight 77ms RepoModel.GetById 49ms app.codeStats 0ms

/XibParser.as

http://github.com/daoki2/xib2js
ActionScript | 1011 lines | 811 code | 39 blank | 161 comment | 187 complexity | 77ef255ba415f63fb4f5830910bb0f05 MD5 | raw file
   1/**
   2 * XIB parser for Titanium Mobile
   3 * @author Copyright (c) 2010-2012 daoki2
   4 * @version 2.0.0
   5 * 
   6 * Copyright (c) 2010-2012 daoki2
   7 *
   8 * Permission is hereby granted, free of charge, to any person obtaining a copy
   9 * of this software and associated documentation files (the "Software"), to deal
  10 * in the Software without restriction, including without limitation the rights
  11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12 * copies of the Software, and to permit persons to whom the Software is
  13 * furnished to do so, subject to the following conditions:
  14 *
  15 * The above copyright notice and this permission notice shall be included in
  16 * all copies or substantial portions of the Software.
  17 *
  18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24 * THE SOFTWARE.
  25 */
  26
  27package {
  28    import flash.display.*;
  29    import flash.errors.IllegalOperationError;
  30    import flash.filesystem.*;
  31    import flash.utils.*;
  32    import mx.controls.*;
  33    import mx.utils.*;
  34
  35    /**
  36     * This is a utility class to parse the .xib file for Titanium Mobile
  37     */
  38    public class XibParser {
  39
  40	private static const _TYPE:Array = [
  41					    "com.apple.InterfaceBuilder3.CocoaTouch.XIB",
  42					    "com.apple.InterfaceBuilder3.CocoaTouch.XIB",
  43					    "com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB",
  44					    "com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB"
  45					    ];
  46	private static const _VERSION:Array = [
  47					       "7.10",
  48					       "8.00",
  49					       "7.10",
  50					       "8.00"
  51					       ];
  52	private static var _xib:XML;
  53	private static var _rootObjects:Array = [];
  54	private static var _objRecords:Array = [];
  55
  56	/**
  57	 * XibParser class can not create instance
  58	 */
  59	public function XibParser() {
  60	    throw new IllegalOperationError("XibParser class can not create instance");
  61	}
  62
  63	/**
  64	 * parse the .xib file
  65	 */
  66	public static function exec(_file:File, _checkVersion:Boolean = true):void {
  67	    // read .xib file
  68	    var _fs:FileStream = new FileStream();
  69	    _fs.open(_file, FileMode.READ);
  70	    _xib = new XML(_fs.readUTFBytes(_fs.bytesAvailable));
  71	    _fs.close();
  72
  73	    if (_checkVersion) {
  74		if (!checkVersion()) {
  75		    Alert.show("This version of .xib file is not supported: " + _xib.@version.toString(), "ERROR");
  76		    trace("Version error");
  77		    return;
  78		}
  79	    }
  80
  81	    // parse the IBObjectContainer first because it is easy to get the name of the object
  82	    var children:XMLList;
  83	    var child:XML;
  84	    children = _xib.children();
  85	    for each (child in children) {
  86		switch (child.name().toString()) {
  87		case "data":
  88		    parseIBObjectContainerData(child);
  89		    break;
  90		default:
  91		    trace("Unknown XML list:", child.name());
  92		    break;
  93		}
  94	    }
  95
  96	    children = _xib.children();
  97	    for each (child in children) {
  98		switch (child.name().toString()) {
  99		case "data":
 100		    parseRootObjectsData(child);
 101		    break;
 102		default:
 103		    trace("Unknown XML list:", child.name());
 104		    break;
 105		}
 106	    }
 107	}
 108
 109	/**
 110	 * cleanup the parser
 111	 */
 112	public static function cleanup():void {
 113	    _rootObjects = new Array();
 114	    _objRecords = new Array();
 115	    _xib = null;
 116	}
 117
 118	/**
 119	 * Return the parsed data
 120	 */
 121	public static function getParsedData():Array {
 122	    return _rootObjects;
 123	}
 124
 125	/**
 126	 * parse IBObjectContainer of <data>
 127	 */
 128	private static function parseIBObjectContainerData(xml:XML):void {
 129	    var children:XMLList = xml.children();
 130	    for each (var child:XML in children) {
 131		switch (child.name().toString()) {
 132		case "object":
 133		    if (child.attribute("class").toString() == "IBObjectContainer" && child.@key.toString() == "IBDocument.Objects") {
 134			parseObjectContainer(child);
 135			break;
 136		    }
 137		    break;
 138		default:
 139		    // Do nothing
 140		    break;
 141		}
 142	    }
 143	}
 144
 145	/**
 146	 * parse RootObjects of <data>
 147	 */
 148	private static function parseRootObjectsData(xml:XML):void {
 149	    var children:XMLList = xml.children();
 150	    for each (var child:XML in children) {
 151		switch (child.name().toString()) {
 152		case "array":
 153		case "object":
 154		    if (child.attribute("class").toString() == "NSMutableArray" && child.@key.toString() == "IBDocument.RootObjects") {
 155			parseRootObject(child);
 156			break;
 157		    }
 158		    break;
 159		default:
 160		    // Do nothing
 161		    break;
 162		}
 163	    }
 164	}
 165
 166	/**
 167	 * parse RootObjects
 168	 */
 169	private static function parseRootObject(xml:XML):void {
 170	    var children:XMLList = xml.children();
 171	    for each (var child:XML in children) {
 172		switch (child.name().toString()) {
 173		case "object":
 174		    var _result:Object = null;
 175		    switch (child.attribute("class").toString()) {
 176		    case "IBUIWindow":
 177			_result = parseUIWindow(child);
 178			break;
 179		    case "IBUITabBarController":
 180			_result = parseUITabBarController(child);
 181			break;
 182		    case "IBUINavigationController":
 183			_result = parseUINavigationController(child);
 184			break;
 185		    case "IBUIViewController":
 186			_result = parseUIViewController(child);
 187			break;
 188		    case "IBUITableViewController":
 189			_result = parseUITableViewController(child);
 190			break;
 191		    case "IBUISplitViewController":
 192			_result = parseUISplitViewController(child);
 193			break;
 194		    case "IBUIImagePickerController":
 195			_result = parseUIImagePickerController(child);
 196			break;
 197		    case "IBUITableViewCell":
 198			_result = parseUITableViewCell(child);
 199			break;
 200		    case "IBUIView":
 201			_result = parseUIView(child);
 202			break;
 203		    default:
 204			// Do nothing
 205			trace("# skipped:1", child.attribute("class").toString());
 206			break;
 207		    }
 208		    if (_result != null) {
 209			_rootObjects.push(_result);
 210		    }
 211		    break;
 212		default:
 213		    // Do nothing
 214		    trace("# skipped:2", child.name().toString());
 215		    break;
 216		}
 217	    }
 218	}
 219
 220	/**
 221	 * parse UIWindow
 222	 */
 223	private static function parseUIWindow(xml:XML):Object {
 224	    trace("parse UIWindow", getObjectName(xml.@id.toString()), xml.@id);
 225	    return {obj:"IBUIWindow", name:getObjectName(xml.@id.toString()), id:xml.@id.toString(), subviews:getSubviews(xml), propertires:getProperties(xml)};
 226	}
 227	
 228	/**
 229	 * parse UITabBarController
 230	 */
 231	private static function parseUITabBarController(xml:XML):Object {
 232	    trace("parse IBUITabBarController", getObjectName(xml.@id.toString()), xml.@id);
 233	    var _viewControllers:Array = [];
 234	    var children:XMLList = xml.children();
 235	    for each (var child:XML in children) {
 236		switch (child.name().toString()) {
 237		case "object":
 238		    if (child.@key.toString() == "IBUISelectedViewController") {
 239			_viewControllers.push(parseViewController(child));
 240		    }
 241		    if (child.@key.toString() == "IBUIViewControllers") {
 242			var _result:Array = parseViewControllers(child);
 243			if (_result.length > 0)
 244			    _viewControllers = _viewControllers.concat(_result);
 245		    }
 246		    break;
 247		default:
 248		    // Do nothing
 249		    trace("# skipped:3", child.name().toString());
 250		    break;
 251		}
 252	    }
 253	    return {obj:"IBUITabBarController", name:getObjectName(xml.@id.toString()), id:xml.@id.toString(), views:_viewControllers};
 254	}
 255
 256	/**
 257	 * parse ViewControllers
 258	 */
 259	private static function parseViewControllers(xml:XML):Array {
 260	    trace("parseViewControllers");
 261	    var _views:Array = [];
 262	    var children:XMLList = xml.children();
 263	    for each (var child:XML in children) {
 264		var _result:Object = parseViewController(child);
 265		if (_result != null)
 266		    _views.push(_result);
 267	    }
 268	    return (_views.length > 0 ? _views : null);
 269	}
 270
 271	/**
 272	 * parse ViewController
 273	 */
 274	private static function parseViewController(xml:XML):Object {
 275	    switch (xml.name().toString()) {
 276	    case "object":
 277		if (xml.attribute("class").toString() == "IBUIViewController") {
 278		    return parseUIViewController(xml);
 279		}
 280		if (xml.attribute("class").toString() == "IBUINavigationController") {
 281		    return parseUINavigationController(xml);
 282		}
 283		if (xml.attribute("class").toString() == "IBUITableViewController") {
 284		    return parseUITableViewController(xml);
 285		}
 286		if (xml.attribute("class").toString() == "IBUIImagePickerController") {
 287		    return parseUIImagePickerController(xml);
 288		}
 289		break;
 290	    default:
 291		// do nothing
 292		trace("# skipped:4", xml.name().toString());
 293		break;
 294	    }
 295	    return null;
 296	}
 297
 298	/**
 299	 * parse UIViewController
 300	 */
 301	private static function parseUIViewController(xml:XML):Object {
 302	    trace("parse UIViewController", getObjectName(xml.@id.toString()), xml.@id);
 303	    var _tabItem:Object = null;
 304	    var _navItem:Object = null;
 305	    var _view:Object = null;
 306	    var children:XMLList = xml.children();
 307	    for each (var child:XML in children) {
 308		switch(child.name().toString()) {
 309		case "object":
 310		    switch(child.attribute("class").toString()) {
 311		    case "IBUINavigationItem":
 312			trace("UINavigationItem");
 313			_navItem = {title:getUITitle(child)};
 314			break;
 315		    case "IBUITabBarItem":
 316			trace("UITabBarItem");
 317			_tabItem = {title:getUITitle(child)};
 318			break;
 319		    case "IBUIView":
 320			_view = parseUIView(child);
 321			break;
 322		    case "IBUIScrollView":
 323			_view = parseUIScrollView(child);
 324			break;
 325		    case "IBUITextView":
 326			_view = parseUITextView(child);
 327			break;
 328		    case "IBUIImageView":
 329			_view = parseUIImageView(child);
 330			break;
 331		    case "IBUITableView":
 332			_view = parseUITableView(child);
 333			break;
 334		    case "IBUIWebView":
 335			_view = parseUIWebView(child);
 336			break;
 337		    case "IBMKMapView":
 338			_view = parseMKMapView(child);
 339			break;
 340		    default:
 341			//_view = parseControlls(child);
 342			break;
 343		    }
 344		    break;
 345		default:
 346		    // do nothing
 347		    trace("# skipped:5", child.name().toString());
 348		    break;
 349		}
 350	    }
 351	    return {obj:"IBUIViewController", name:getObjectName(xml.@id.toString()), id:xml.@id.toString(), view:_view, navItem:_navItem, tabItem:_tabItem};
 352	}
 353
 354	/**
 355	 * parse UINavigationController
 356	 */
 357	private static function parseUINavigationController(xml:XML):Object {
 358	    trace("parse UINavigationController", getObjectName(xml.@id.toString()), xml.@id);
 359	    var _views:Array = [];
 360	    var children:XMLList = xml.children();
 361	    var _tabItem:Object = null;
 362	    for each (var child:XML in children) {
 363		switch(child.name().toString()) {
 364		case "array":
 365		case "object":
 366		    //if (child.attribute("class").toString() == "NSMutableArray" && child.@key.toString() == "IBUIViewControllers") {
 367		    if (child.@key.toString() == "IBUIViewControllers") {
 368			_views = parseViewControllers(child);
 369		    }
 370		    if (child.attribute("class").toString() == "IBUITabBarItem") {
 371			trace("UITabBarItem");
 372			_tabItem = {title:getUITitle(child)};
 373		    }
 374		    break;
 375		default:
 376		    // do nothing
 377		    trace("# skipped:6", child.name().toString());
 378		    break;
 379		}
 380	    }
 381	    return {obj:"IBUINavigationController", name:getObjectName(xml.@id.toString()), id:xml.@id.toString(), views:_views, tabItem:_tabItem};
 382	}
 383
 384	/**
 385	 * parse UITableViewController
 386	 */
 387	private static function parseUITableViewController(xml:XML):Object {
 388	    trace("parse UITableViewController", getObjectName(xml.@id.toString()), xml.@id);
 389	    var _tabItem:Object = null;
 390	    var _navItem:Object = null;
 391	    var children:XMLList = xml.children();
 392	    for each (var child:XML in children) {
 393		switch(child.name().toString()) {
 394		case "object":
 395		    switch(child.attribute("class").toString()) {
 396		    case "IBUINavigationItem":
 397			trace("UINavigationItem");
 398			_navItem = {title:getUITitle(child)};
 399			break;
 400		    case "IBUITabBarItem":
 401			trace("UITabBarItem");
 402			_tabItem = {title:getUITitle(child)};
 403			break;
 404		    case "IBUITableView":
 405			trace("UITableView");
 406			break;
 407		    default:
 408			// do nothing
 409			break;
 410		    }
 411		default:
 412		    // do nothing
 413		    break;
 414		}
 415	    }
 416	    return {obj:"IBUITableViewController", name:getObjectName(xml.@id.toString()), id:xml.@id.toString(), navItem:_navItem, tabItem:_tabItem}
 417	}
 418
 419	/**
 420	 * parse UIImagePickerController
 421	 */
 422	private static function parseUIImagePickerController(xml:XML):Object {
 423	    trace("parse UIImagePickerController", getObjectName(xml.@id.toString()), xml.@id);
 424	    var _navBar:Object = null;
 425	    var _views:Array;
 426	    var children:XMLList = xml.children();
 427	    for each (var child:XML in children) {
 428		switch(child.name().toString()) {
 429		case "array":
 430		case "object":
 431		    if (child.attribute("class").toString() == "IBUINavigationBar") {
 432			// do nothing
 433		    }
 434		    if (child.attribute("class").toString() == "NSMutableArray" && child.@key.toString() == "IBUIViewControllers") {
 435			_views = parseViewControllers(child);
 436		    }
 437		    break;
 438		default:
 439		    // do nothing
 440		    trace("# skipped:7", child.name().toString());
 441		    break;
 442		}
 443	    }
 444	    return {obj:"IBUIImagePickerController", name:getObjectName(xml.@id.toString()), id:xml.@id.toString(), views:_views, navBar:_navBar};
 445	}
 446	/**
 447	 * parse UISplitViewController
 448	 */
 449	private static function parseUISplitViewController(xml:XML):Object {
 450	    trace("parse IBUISplitViewController", getObjectName(xml.@id.toString()), xml.@id);
 451	    var _viewControllers:Array = [];
 452	    var children:XMLList = xml.children();
 453	    for each (var child:XML in children) {
 454		switch (child.name().toString()) {
 455		case "object":
 456		    if (child.@key.toString() == "IBUIMasterViewController") {
 457			_viewControllers.push(parseUINavigationController(child));
 458		    }
 459		    if (child.@key.toString() == "IBUIDetailViewController") {
 460			if (child.attribute("class").toString() == "IBUIViewController")
 461			    _viewControllers.push(parseUIViewController(child));
 462			if (child.attribute("class").toString() == "IBUINavigationController")
 463			    _viewControllers.push(parseUINavigationController(child));			    
 464		    }
 465		    break;
 466		default:
 467		    // Do nothing
 468		    trace("# skipped:8", child.name().toString());
 469		    break;
 470		}
 471	    }
 472	    return {obj:"IBUISplitViewController", name:getObjectName(xml.@id.toString()), id:xml.@id.toString(), views:_viewControllers};
 473	}
 474
 475	/**
 476	 * parse UITableViewCell
 477	 */
 478	private static function parseUITableViewCell(xml:XML):Object {
 479	    trace("parse UITableViewCell", getObjectName(xml.@id.toString()), xml.@id);
 480	    var _subviews:Array = [];
 481	    var children:XMLList = xml.children();
 482	    for each (var child:XML in children) {
 483		switch(child.name().toString()) {
 484		case "array":
 485		case "object":
 486		    if (child.attribute("class").toString() == "NSMutableArray" && child.@key.toString() == "NSSubviews") {
 487			trace("NSSubviews");
 488			_subviews = getSubviews(child);
 489		    }
 490		    break;
 491		default:
 492		    // do nothing
 493		    trace("# skipped:9", child.name().toString());
 494		    break;
 495		}
 496	    }
 497	    return {obj:"IBUITableViewCell", name:getObjectName(xml.@id.toString()), id:xml.@id.toString, subviews:_subviews, properties:getProperties(xml)};
 498	}
 499
 500	/**
 501	 * parse UIView
 502	 */
 503	private static function parseUIView(xml:XML, scrollable:Boolean = false):Object {
 504	    trace("parse", (scrollable ? "IBUIScrollView" : "IBUIView"), xml.@id);
 505	    var _subviews:Array = [];
 506	    var children:XMLList = xml.children();
 507	    for each (var child:XML in children) {
 508		switch(child.name().toString()) {
 509		case "array":
 510		case "object":
 511		    if (child.attribute("class").toString() == "NSMutableArray" && child.@key.toString() == "NSSubviews") {
 512			trace("NSSubviews");
 513			_subviews = getSubviews(child);
 514		    }
 515		    break;
 516		default:
 517		    // do nothing
 518		    trace("# skipped:10", child.name().toString());
 519		    break;
 520		}
 521	    }
 522	    return {obj:(scrollable ? "IBUIScrollView" : "IBUIView"), name:getObjectName(xml.@id.toString()), id:xml.@id.toString, subviews:_subviews, properties:getProperties(xml)};
 523	}
 524
 525	/**
 526	 * parse UIScrollView
 527	 */
 528	private static function parseUIScrollView(xml:XML):Object {
 529	    return parseUIView(xml, true);
 530	}
 531
 532	/**
 533	 * parse UITextView
 534	 */
 535	private static function parseUITextView(xml:XML):Object {
 536	    trace("parse IBUITextView", getObjectName(xml.@id.toString()), xml.@id.toString());
 537	    return {obj:"IBUITextView", name:getObjectName(xml.@id.toString()), id:xml.@id.toString(), properties:getProperties(xml)};
 538	}
 539
 540	/**
 541	 * parse UIImageView
 542	 */
 543	private static function parseUIImageView(xml:XML):Object {
 544	    trace("parse IBUIImageView", getObjectName(xml.@id.toString()), xml.@id.toString());
 545	    return {obj:"IBUIImageView", name:getObjectName(xml.@id.toString()), id:xml.@id.toString(), properties:getProperties(xml)};
 546	}
 547
 548	/**
 549	 * parse UITableView
 550	 */
 551	private static function parseUITableView(xml:XML):Object {
 552	    trace("parse IBUITableView", getObjectName(xml.@id.toString()), xml.@id.toString());
 553	    return {obj:"IBUITableView", name:getObjectName(xml.@id.toString()), id:xml.@id.toString(), properties:getProperties(xml)};
 554	}
 555	
 556	/**
 557	 * parse UIWebView
 558	 */
 559	private static function parseUIWebView(xml:XML):Object {
 560	    trace("parse IBUIWebView", getObjectName(xml.@id.toString()), xml.@id.toString());
 561	    return {obj:"IBUIWebView", name:getObjectName(xml.@id.toString()), id:xml.@id.toString(), properties:getProperties(xml)};
 562	}
 563
 564	/**
 565	 * parse UIMKMapView
 566	 */
 567	private static function parseMKMapView(xml:XML):Object {
 568	    trace("parse IBMKMapView", getObjectName(xml.@id.toString()), xml.@id.toString());
 569	    return {obj:"IBMKMapView", name:getObjectName(xml.@id.toString()), id:xml.@id.toString(), properties:getProperties(xml)};
 570	}
 571
 572	/**
 573	 * parse Subviews
 574	 */
 575	private static function getSubviews(xml:XML):Array {
 576	    var result:Array = [];
 577	    var children:XMLList = xml.children();
 578	    for each (var child:XML in children) {
 579		switch (child.name().toString()) {
 580		case "array":
 581		case "object":
 582		    switch(child.attribute("class").toString()) {
 583		    case "NSMutableArray":
 584			if (child.@key.toString() == "NSSubviews") {
 585			    result.push({obj:"NSSubviews", subviews:getSubviews(child)});
 586			}
 587			break;
 588		    case "IBUIActivityIndicatorView":
 589		    case "IBUIButton":
 590		    case "IBUIDatePicker":
 591		    case "IBUIImageView":
 592		    case "IBUILabel":
 593		    case "IBUIPickerView":
 594		    case "IBUIProgressView":
 595		    case "IBUISearchBar":
 596		    case "IBUISegmentedControl":
 597		    case "IBUISlider":
 598		    case "IBUISwitch":
 599		    case "IBUITextField":
 600		    case "IBUITextView":
 601		    case "IBUIToolbar":
 602			trace("parse", child.attribute("class"), child.@id);
 603			result.push({obj:child.attribute("class").toString(), name:getObjectName(child.@id.toString()), id:child.@id.toString(), properties:getProperties(child)});
 604			break;
 605		    case "IBUIView":
 606			result.push(parseUIView(child));
 607			break;
 608		    case "IBUIScrollView":
 609			result.push(parseUIScrollView(child));
 610			break;
 611		    case "IBUITextView":
 612			result.push(parseUITextView(child));
 613			break;
 614		    case "IBUIImageView":
 615			result.push(parseUIImageView(child));
 616			break;
 617		    case "IBUITableView":
 618			result.push(parseUITableView(child));
 619			break;
 620		    case "IBUIWebView":
 621			result.push(parseUIWebView(child));
 622			break;
 623		    case "IBMKMapView":
 624			result.push(parseMKMapView(child));
 625			break;
 626		    default:
 627			// Do nothing;
 628			trace("# skipped:11", child.attribute("class").toString());
 629			break;
 630		    }
 631		    break;
 632		default:
 633		    // Do nothing
 634		    trace("# skipped:12", child.name().toString());
 635		    break;
 636		}
 637	    }
 638	    return result;
 639	}
 640
 641	/**
 642	 * parse property
 643	 */
 644	private static function getProperties(xml:XML):Array {
 645	    var result:Array = [];
 646	    var children:XMLList = xml.children();
 647	    var _children:XMLList;
 648	    var _child:XML;
 649	    for each (var child:XML in children) {
 650		switch (child.name().toString()) {
 651		case "string":
 652		    if (child.@key.toString() == "NSFrame") {
 653			trace("parse NSFrame", child.toString());
 654			result.push({type:"frame", value:child.toString()});
 655			break;
 656		    }
 657		    if (child.@key.toString() == "NSFrameSize") {
 658			trace("parse NSFrameSize", child.toString());
 659			result.push({type:"framesize", value:child.toString()});
 660			break;
 661		    }
 662		    if (child.@key.toString() == "IBUIText") {
 663			trace("parse IBUIText", child.toString());
 664			if (xml.attribute("class").toString() == "IBUITextField" || xml.attribute("class").toString() == "IBUITextView") {
 665			    result.push({type:"value", value:"'" + child.toString() + "'"});
 666			} else {
 667			    result.push({type:"text", value:child.toString()});
 668			}
 669			break;
 670		    }
 671		    if (child.@key.toString() == "IBUINormalTitle") {
 672			trace("parse IBUINormalTitle", child.toString());
 673			result.push({type:"title", value:child.toString()});
 674			break;
 675		    }
 676		    break;
 677		case "bool":
 678		    if (child.@key.toString() == "IBUIOn") {
 679			trace("parse IBUIOn", child.toString());
 680			result.push({type:"value", value:(child.toString() == "YES" ? "true" : "false")});			
 681		    }
 682		    break;
 683		case "float":
 684		    if (child.@key.toString() == "IBUIValue" || child.@key.toString() == "IBUIProgress") {
 685			trace("parse IBUIValue", child.toString());
 686			result.push({type:"value", value:child.toString()});
 687			break;
 688		    }
 689		    if (child.@key.toString() == "IBUIMinValue") {
 690			trace("parse IBUIMinValue", child.toString());
 691			result.push({type:"min", value:child.toString()});
 692			break;
 693		    }
 694		    if (child.@key.toString() == "IBUIMaxValue") {
 695			trace("parse IBUIMaxValue", child.toString());
 696			result.push({type:"max", value:child.toString()});
 697			break;
 698		    }
 699		    break;
 700		case "object":
 701		    // parse Font
 702		    if (child.@key.toString() == "IBUIFont") {
 703			trace("parse IBUIFont", child.toString());
 704			_children = child.children();
 705			var _fontName:String = "";
 706			var _fontSize:String = "";
 707			for each (_child in _children) {
 708			    switch(_child.name().toString()) {
 709			    case "string":
 710				if (_child.@key.toString() == "NSName") {
 711				    _fontName = _child.toString();
 712				}
 713				break;
 714			    case "double":
 715				if (_child.@key.toString() == "NSSize") {
 716				    _fontSize = _child.toString();
 717				}
 718				break;
 719			    default:
 720				trace("# skipped:13", _child.name().toString());
 721				break;
 722			    }
 723			}
 724			result.push({type:"font", value:_fontName + "," + _fontSize});			
 725			break;
 726		    }
 727		    // parse Segement
 728		    if (child.@key.toString() == "IBSegmentTitles") {
 729			trace("parse IBSegmentTitles", child.toString());
 730			_children = child.children();
 731			var _labels:String = "";
 732			for each (_child in _children) {
 733			    if (_child.name().toString() == "string") {
 734				_labels += "'" + _child.toString() + "', ";
 735			    }
 736			}
 737			result.push({type:"labels", value:"[" + _labels.substring(0, _labels.length - 2) + "]"});
 738			break;
 739		    }
 740		    // parse Toolbar
 741		    if (child.@key.toString() == "IBUIItems") {
 742			_children = child.children();
 743			var _toolbar:String = "";
 744			for each (_child in _children) {			   
 745			    if (_child.attribute("class").toString() == "IBUIBarButtonItem") {
 746				trace("parse IBUIBarButtonItem", _child.toString());
 747				var __children:XMLList = _child.children();
 748				var _title:String = "";
 749				var _id:String = "";
 750				var _width:String = "";
 751				for each(var __child:XML in __children) {
 752				    switch (__child.name().toString()) {
 753				    case "string":
 754					if (__child.@key.toString() == "IBUITitle") {
 755					    _title = __child.toString();
 756					}
 757					break;
 758				    case "int":
 759					if (__child.@key.toString() == "IBUISystemItemIdentifier") {
 760					    _id = __child.toString();
 761					}
 762					break;
 763				    case "float":
 764					if (__child.@key.toString() == "IBUIWidth") {
 765					    _width = __child.toString();
 766					}
 767					break;
 768				    default:
 769					trace("# skipped:14", __child.name().toString());
 770					break;
 771				    }						
 772				}
 773				_toolbar += "{title: " + _title + ", id: " + _id + ", width: " + _width + "}, ";
 774			    }
 775			}
 776			result.push({type:"toolbar", value:"[" + _toolbar.substring(0, _toolbar.length - 2) + "]"});
 777			break;
 778		    }
 779		    // parse NSColor
 780		    if (child.attribute("class").toString() == "NSColor") {
 781			_children = child.children();
 782			var _colorSpace:int = -1;
 783			var _bytes:Array = [];
 784			var _color:String = "";
 785			for each (_child in _children) {
 786			    switch (_child.name().toString()) {
 787			    case "int":
 788				if (_child.@key.toString() == "NSColorSpace") {
 789				    _colorSpace = _child.toString();
 790				}
 791				break;
 792			    case "bytes":
 793				_color = convertToColor(_child.toString(), _colorSpace, _child.@key.toString());
 794				break;
 795			    default:
 796				// do nothing
 797				break;
 798			    }
 799			}
 800			if (_color != "") {
 801			    var _colorType:String = "color";
 802			    switch(child.@key.toString()) {
 803			    case "IBUIBackgroundColor":
 804				result.push({type:"backgroundColor", value:_color});
 805				break;
 806			    case "IBUINormalTitleColor":
 807			    case "IBUITextColor":
 808				result.push({type:"color", value:_color});
 809				break;
 810			    default:
 811				trace("# skipped:15", child.@key.toString());
 812				break;
 813			    }
 814			}
 815			break;
 816		    }
 817		    break;
 818		default:
 819		    // Do nothing
 820		    trace("# skipped:16", child.name().toString());
 821		    break;
 822		}
 823	    }
 824	    return result;
 825	}
 826	
 827	/**
 828	 * parse ObjectContainer
 829	 */
 830	private static function parseObjectContainer(xml:XML):void {
 831	    trace("parse ObjectContainer");
 832	    var children:XMLList = xml.children();
 833	    for each (var child:XML in children) {
 834		switch (child.name().toString()) {
 835		case "object":
 836		    if (child.attribute("class").toString() == "IBMutableOrderedSet" && child.@key.toString() == "objectRecords") {
 837			parseObjectRecords(child);
 838			break;
 839		    }
 840		    break;
 841		default:
 842		    // Do nothing
 843		    trace("# skipped:17", child.name().toString());
 844		    break;
 845		}
 846	    }
 847	}
 848
 849	/**
 850	 * parse ObjectRecords
 851	 */
 852	private static function parseObjectRecords(xml:XML):void {
 853	    trace("parse ObjectRecords");
 854	    var children:XMLList = xml.children();
 855	    for each (var child:XML in children) {
 856		switch (child.name().toString()) {
 857		case "array":
 858		case "object":
 859		    //if (child.attribute("class").toString() == "NSArray" && child.@key.toString() == "orderedObjects") {
 860		    if (child.@key.toString() == "orderedObjects") {
 861			parseOrderedObject(child);
 862			break;
 863		    }
 864		    break;
 865		default:
 866		    // do nothing
 867		    break;
 868		}
 869	    }
 870	}
 871
 872	/**
 873	 * parse OrderedObjects
 874	 */
 875	private static function parseOrderedObject(xml:XML):void {
 876	    var children:XMLList = xml.children();
 877	    for each (var child:XML in children) {
 878		switch (child.name().toString()) {
 879		case "object":
 880		    if (child.attribute("class").toString() == "IBObjectRecord") {
 881			if (child.string.toString() != "") {
 882			    for (var i:uint = 0; i < child.reference.length(); i++) {
 883				if (child.reference[i].@key.toString() == "object") {
 884				    trace("add id:", child.reference[i].@ref.toString(), "name:", child.string.toString());			    
 885				    _objRecords.push({id:child.reference[i].@ref.toString(), name:child.string.toString()});
 886				}
 887			    }
 888			    break;
 889			}
 890		    }
 891		    break;
 892		default:
 893		    // do nothing
 894		    trace("# skipped:18", child.name().toString());
 895		    break;
 896		}
 897	    }
 898	}
 899
 900	/**
 901	 * convert base64 encoded value to color value
 902	 */
 903	private static function convertToColor(_code:String, type:int, key:String):String {
 904	    //trace("convertToColor", _code, type, key);
 905	    var result:String = "";
 906
 907	    // The _code is not just Base64 encoded data
 908	    // It seems the padding character is "AA" not "=". Why?
 909	    if (_code.length <=3) {
 910		if (_code == "MAA") {
 911		    return "#000000";
 912		} else {
 913		    _code = _code.substring(0, _code.length -1) + "==";
 914		}
 915	    } else {
 916		var _padding:String = _code.substring(_code.length - 2, _code.length);
 917		if (_padding == "AA") {
 918		    _code = _code.substring(0, _code.length - 2);
 919		}
 920	    }
 921	    var _padNum:int = _code.length % 4;
 922	    if (_padNum != 0) {
 923		while(_padNum != 4) {
 924		    _code += "=";
 925		    _padNum++;
 926		}
 927	    }
 928	    var decoder:Base64Decoder = new Base64Decoder();
 929	    decoder.decode(_code);
 930	    var _bytes:ByteArray = decoder.toByteArray();
 931	    var i:int;
 932	    var _r:String;
 933	    var _g:String;
 934	    var _b:String;
 935	    var _color:Array;
 936	    switch(key) {
 937	    case "NSRGB":
 938		_color = _bytes.readUTFBytes(_bytes.length).split(" ");
 939		_r = uint(parseFloat(_color[0])*255).toString(16);
 940		_g = uint(parseFloat(_color[1])*255).toString(16);
 941		_b = uint(parseFloat(_color[2])*255).toString(16);
 942		result = "#" + (_r.length < 2 ? "0" + _r : _r) + (_g.length < 2 ? "0" + _g : _g) + (_b.length < 2 ? "0" + _b : _b);
 943		if (_color.length == 4)
 944		    result += ":" + parseFloat(_color[3]);
 945		break;
 946	    case "NSCMYK": 
 947		_color = _bytes.readUTFBytes(_bytes.length).split(" ");
 948		var _c:float = parseFloat(_color[0]);
 949		var _m:float = parseFloat(_color[1]);
 950		var _y:float = parseFloat(_color[2]);
 951		var _k:float = parseFloat(_color[3]);
 952		_r = uint((1 - Math.min(1, _c * (1 - _k) + _k)) * 255).toString(16);
 953		_g = uint((1 - Math.min(1, _m * (1 - _k) + _k)) * 255).toString(16);
 954		_b = uint((1 - Math.min(1, _y * (1 - _k) + _k)) * 255).toString(16);
 955		result = "#" + (_r.length < 2 ? "0" + _r : _r) + (_g.length < 2 ? "0" + _g : _g) + (_b.length < 2 ? "0" + _b : _b);
 956		if (_color.length == 5)
 957		    result += ":" + parseFloat(_color[4]);
 958		break;
 959	    case "NSWhite": // Grayscale
 960		_color = _bytes.readUTFBytes(_bytes.length).split(" ");
 961		_r = uint(parseFloat(_color[0])*255).toString(16);
 962		result = "#" + (_r.length < 2 ? "0" + _r : _r) + (_r.length < 2 ? "0" + _r : _r) + (_r.length < 2 ? "0" + _r : _r);
 963		if (_color.length == 2)
 964		    result += ":" + parseFloat(_color[1]);
 965		break;
 966	    default:
 967		trace("# skipped:19", key, type);
 968		break;
 969	    }
 970	    return result;
 971	}
 972
 973	/**
 974	 * get IBUITitle
 975	 */
 976	private static function getUITitle(xml:XML):String {
 977	    var children:XMLList = xml.children();
 978	    for each (var child:XML in children) {
 979		if (child.@key.toString() == "IBUITitle")
 980		    return child.toString();
 981	    }
 982	    return "";
 983	}
 984
 985	/**
 986	 * get the name of the object
 987	 */
 988	private static function getObjectName(id:String):String {
 989	    for each (var val:* in _objRecords) {
 990		if (val.id == id) {
 991		    return val.name;
 992		}
 993	    }
 994	    return "";
 995	}
 996
 997	/**
 998	 * Check version
 999	 */
1000	private static function checkVersion():Boolean {
1001	    if (_xib.name().toString() == "archive") {
1002		trace(_xib.@type, _xib.@version);
1003		for (var i:uint = 0; i < _TYPE.length; i++) {
1004		    if (_xib.@type.toString() == _TYPE[i] && _xib.@version.toString() == _VERSION[i])
1005			return true;
1006		}
1007	    }
1008	    return false;
1009	}
1010    }
1011}