1 /****************************************************************************
  2  Copyright (c) 2008-2010 Ricardo Quesada
  3  Copyright (c) 2011-2012 cocos2d-x.org
  4  Copyright (c) 2013-2014 Chukong Technologies Inc.
  5 
  6  http://www.cocos2d-x.org
  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 
 27 /**
 28  * @constant
 29  * @type Number
 30  */
 31 cc.TMX_PROPERTY_NONE = 0;
 32 
 33 /**
 34  * @constant
 35  * @type Number
 36  */
 37 cc.TMX_PROPERTY_MAP = 1;
 38 
 39 /**
 40  * @constant
 41  * @type Number
 42  */
 43 cc.TMX_PROPERTY_LAYER = 2;
 44 
 45 /**
 46  * @constant
 47  * @type Number
 48  */
 49 cc.TMX_PROPERTY_OBJECTGROUP = 3;
 50 
 51 /**
 52  * @constant
 53  * @type Number
 54  */
 55 cc.TMX_PROPERTY_OBJECT = 4;
 56 
 57 /**
 58  * @constant
 59  * @type Number
 60  */
 61 cc.TMX_PROPERTY_TILE = 5;
 62 
 63 /**
 64  * @constant
 65  * @type Number
 66  */
 67 cc.TMX_TILE_HORIZONTAL_FLAG = 0x80000000;
 68 
 69 
 70 /**
 71  * @constant
 72  * @type Number
 73  */
 74 cc.TMX_TILE_VERTICAL_FLAG = 0x40000000;
 75 
 76 /**
 77  * @constant
 78  * @type Number
 79  */
 80 cc.TMX_TILE_DIAGONAL_FLAG = 0x20000000;
 81 
 82 /**
 83  * @constant
 84  * @type Number
 85  */
 86 cc.TMX_TILE_FLIPPED_ALL = (cc.TMX_TILE_HORIZONTAL_FLAG | cc.TMX_TILE_VERTICAL_FLAG | cc.TMX_TILE_DIAGONAL_FLAG) >>> 0;
 87 
 88 /**
 89  * @constant
 90  * @type Number
 91  */
 92 cc.TMX_TILE_FLIPPED_MASK = (~(cc.TMX_TILE_FLIPPED_ALL)) >>> 0;
 93 
 94 // Bits on the far end of the 32-bit global tile ID (GID's) are used for tile flags
 95 
 96 /**
 97  * <p>cc.TMXLayerInfo contains the information about the layers like: <br />
 98  * - Layer name<br />
 99  * - Layer size <br />
100  * - Layer opacity at creation time (it can be modified at runtime)  <br />
101  * - Whether the layer is visible (if it's not visible, then the CocosNode won't be created) <br />
102  *  <br />
103  * This information is obtained from the TMX file.</p>
104  * @class
105  * @extends cc.Class
106  *
107  * @property {Array}    properties  - Properties of the layer info.
108  */
109 cc.TMXLayerInfo = cc.Class.extend(/** @lends cc.TMXLayerInfo# */{
110     properties:null,
111 
112 	name:"",
113     _layerSize:null,
114     _tiles:null,
115     visible:null,
116     _opacity:null,
117     ownTiles:true,
118     _minGID:100000,
119     _maxGID:0,
120     offset:null,
121 
122     ctor:function () {
123         this.properties = [];
124         this.name = "";
125         this._layerSize = null;
126         this._tiles = [];
127         this.visible = true;
128         this._opacity = 0;
129         this.ownTiles = true;
130         this._minGID = 100000;
131         this._maxGID = 0;
132         this.offset = cc.p(0,0);
133     },
134 
135     /**
136      * @return {Array}
137      */
138     getProperties:function () {
139         return this.properties;
140     },
141 
142     /**
143      * @param {object} value
144      */
145     setProperties:function (value) {
146         this.properties = value;
147     }
148 });
149 
150 /**
151  * <p>cc.TMXTilesetInfo contains the information about the tilesets like: <br />
152  * - Tileset name<br />
153  * - Tileset spacing<br />
154  * - Tileset margin<br />
155  * - size of the tiles<br />
156  * - Image used for the tiles<br />
157  * - Image size<br />
158  *
159  * This information is obtained from the TMX file. </p>
160  * @class
161  * @extends cc.Class
162  */
163 cc.TMXTilesetInfo = cc.Class.extend(/** @lends cc.TMXTilesetInfo# */{
164 
165     /**
166      * Tileset name
167      */
168     name:"",
169 
170     /**
171      * First grid
172      */
173     firstGid:0,
174     _tileSize:null,
175 
176     /**
177      * Spacing
178      */
179     spacing:0,
180 
181     /**
182      *  Margin
183      */
184     margin:0,
185 
186     /**
187      * Filename containing the tiles (should be sprite sheet / texture atlas)
188      */
189     sourceImage:"",
190 
191     /**
192      * Size in pixels of the image
193      */
194     imageSize:null,
195 
196     ctor:function () {
197         this._tileSize = cc.size(0, 0);
198         this.imageSize = cc.size(0, 0);
199     },
200 
201     /**
202      * @param {Number} gid
203      * @return {cc.Rect}
204      */
205     rectForGID:function (gid) {
206         var rect = cc.rect(0, 0, 0, 0);
207         rect.width = this._tileSize.width;
208         rect.height = this._tileSize.height;
209         gid &= cc.TMX_TILE_FLIPPED_MASK;
210         gid = gid - parseInt(this.firstGid, 10);
211         var max_x = parseInt((this.imageSize.width - this.margin * 2 + this.spacing) / (this._tileSize.width + this.spacing), 10);
212         rect.x = parseInt((gid % max_x) * (this._tileSize.width + this.spacing) + this.margin, 10);
213         rect.y = parseInt(parseInt(gid / max_x, 10) * (this._tileSize.height + this.spacing) + this.margin, 10);
214         return rect;
215     }
216 });
217 
218 /**
219  * <p>cc.TMXMapInfo contains the information about the map like: <br/>
220  *- Map orientation (hexagonal, isometric or orthogonal)<br/>
221  *- Tile size<br/>
222  *- Map size</p>
223  *
224  * <p>And it also contains: <br/>
225  * - Layers (an array of TMXLayerInfo objects)<br/>
226  * - Tilesets (an array of TMXTilesetInfo objects) <br/>
227  * - ObjectGroups (an array of TMXObjectGroupInfo objects) </p>
228  *
229  * <p>This information is obtained from the TMX file. </p>
230  * @class
231  * @extends cc.saxParser
232  *
233  * @property {Array}    properties          - Properties of the map info.
234  * @property {Number}   orientation         - Map orientation.
235  * @property {Object}   parentElement       - Parent element.
236  * @property {Number}   parentGID           - Parent GID.
237  * @property {Object}   layerAttrs        - Layer attributes.
238  * @property {Boolean}  storingCharacters   - Is reading storing characters stream.
239  * @property {String}   tmxFileName         - TMX file name.
240  * @property {String}   currentString       - Current string stored from characters stream.
241  * @property {Number}   mapWidth            - Width of the map
242  * @property {Number}   mapHeight           - Height of the map
243  * @property {Number}   tileWidth           - Width of a tile
244  * @property {Number}   tileHeight          - Height of a tile
245  */
246 cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{
247 	properties:null,
248     orientation:null,
249 	parentElement:null,
250 	parentGID:null,
251 	layerAttrs:0,
252 	storingCharacters:false,
253 	tmxFileName:null,
254 	currentString:null,
255 
256 	_objectGroups:null,
257     _mapSize:null,
258     _tileSize:null,
259     _layers:null,
260     _tilesets:null,
261     // tile properties
262     _tileProperties:null,
263     _resources:"",
264     _currentFirstGID:0,
265 
266     /**
267      * Creates a TMX Format with a tmx file or content string                           <br/>
268      * Constructor of cc.TMXMapInfo
269      * @param {String} tmxFile fileName or content string
270      * @param {String} resourcePath  If tmxFile is a file name ,it is not required.If tmxFile is content string ,it is must required.
271      * @example
272      * 1.
273      * //create a TMXMapInfo with file name
274      * var tmxMapInfo = cc.TMXMapInfo.create("res/orthogonal-test1.tmx");
275      * 2.
276      * //create a TMXMapInfo with content string and resource path
277      * var resources = "res/TileMaps";
278      * var filePath = "res/TileMaps/orthogonal-test1.tmx";
279      * var xmlStr = cc.loader.getRes(filePath);
280      * var tmxMapInfo = cc.TMXMapInfo.create(xmlStr, resources);
281      */
282     ctor:function (tmxFile, resourcePath) {
283         cc.SAXParser.prototype.ctor.apply(this);
284         this._mapSize = cc.size(0, 0);
285         this._tileSize = cc.size(0, 0);
286         this._layers = [];
287         this._tilesets = [];
288         this._objectGroups = [];
289         this.properties = [];
290         this._tileProperties = {};
291 
292         this._currentFirstGID = 0;
293 
294         if (resourcePath !== undefined) {
295             this.initWithXML(tmxFile,resourcePath);
296         } else if(tmxFile !== undefined){
297             this.initWithTMXFile(tmxFile);
298         }
299     },
300     /**
301      * @return {Number}
302      */
303     getOrientation:function () {
304         return this.orientation;
305     },
306 
307     /**
308      * @param {Number} value
309      */
310     setOrientation:function (value) {
311         this.orientation = value;
312     },
313 
314     /**
315      * Map width & height
316      * @return {cc.Size}
317      */
318     getMapSize:function () {
319         return cc.size(this._mapSize.width,this._mapSize.height);
320     },
321 
322     /**
323      * @param {cc.Size} value
324      */
325     setMapSize:function (value) {
326         this._mapSize.width = value.width;
327         this._mapSize.height = value.height;
328     },
329 
330 	_getMapWidth: function () {
331 		return this._mapSize.width;
332 	},
333 	_setMapWidth: function (width) {
334 		this._mapSize.width = width;
335 	},
336 	_getMapHeight: function () {
337 		return this._mapSize.height;
338 	},
339 	_setMapHeight: function (height) {
340 		this._mapSize.height = height;
341 	},
342 
343     /**
344      * Tiles width & height
345      * @return {cc.Size}
346      */
347     getTileSize:function () {
348         return cc.size(this._tileSize.width, this._tileSize.height);
349     },
350 
351     /**
352      * @param {cc.Size} value
353      */
354     setTileSize:function (value) {
355         this._tileSize.width = value.width;
356         this._tileSize.height = value.height;
357     },
358 
359 	_getTileWidth: function () {
360 		return this._tileSize.width;
361 	},
362 	_setTileWidth: function (width) {
363 		this._tileSize.width = width;
364 	},
365 	_getTileHeight: function () {
366 		return this._tileSize.height;
367 	},
368 	_setTileHeight: function (height) {
369 		this._tileSize.height = height;
370 	},
371 
372     /**
373      * Layers
374      * @return {Array}
375      */
376     getLayers:function () {
377         return this._layers;
378     },
379 
380     /**
381      * @param {cc.TMXLayerInfo} value
382      */
383     setLayers:function (value) {
384         this._layers.push(value);
385     },
386 
387     /**
388      * tilesets
389      * @return {Array}
390      */
391     getTilesets:function () {
392         return this._tilesets;
393     },
394 
395     /**
396      * @param {cc.TMXTilesetInfo} value
397      */
398     setTilesets:function (value) {
399         this._tilesets.push(value);
400     },
401 
402     /**
403      * ObjectGroups
404      * @return {Array}
405      */
406     getObjectGroups:function () {
407         return this._objectGroups;
408     },
409 
410     /**
411      * @param {cc.TMXObjectGroup} value
412      */
413     setObjectGroups:function (value) {
414         this._objectGroups.push(value);
415     },
416 
417     /**
418      * parent element
419      * @return {Object}
420      */
421     getParentElement:function () {
422         return this.parentElement;
423     },
424 
425     /**
426      * @param {Object} value
427      */
428     setParentElement:function (value) {
429         this.parentElement = value;
430     },
431 
432     /**
433      * parent GID
434      * @return {Number}
435      */
436     getParentGID:function () {
437         return this.parentGID;
438     },
439 
440     /**
441      * @param {Number} value
442      */
443     setParentGID:function (value) {
444         this.parentGID = value;
445     },
446 
447     /**
448      * Layer attribute
449      * @return {Object}
450      */
451     getLayerAttribs:function () {
452         return this.layerAttrs;
453     },
454 
455     /**
456      * @param {Object} value
457      */
458     setLayerAttribs:function (value) {
459         this.layerAttrs = value;
460     },
461 
462     /**
463      * Is reading storing characters stream
464      * @return {Boolean}
465      */
466     getStoringCharacters:function () {
467         return this.storingCharacters;
468     },
469 
470     /**
471      * @param {Boolean} value
472      */
473     setStoringCharacters:function (value) {
474         this.storingCharacters = value;
475     },
476 
477     /**
478      * Properties
479      * @return {Array}
480      */
481     getProperties:function () {
482         return this.properties;
483     },
484 
485     /**
486      * @param {object} value
487      */
488     setProperties:function (value) {
489         this.properties = value;
490     },
491 
492     /**
493      * Initializes a TMX format with a  tmx file
494      * @param {String} tmxFile
495      * @return {Element}
496      */
497     initWithTMXFile:function (tmxFile) {
498         this._internalInit(tmxFile, null);
499         return this.parseXMLFile(tmxFile);
500     },
501 
502     /**
503      * initializes a TMX format with an XML string and a TMX resource path
504      * @param {String} tmxString
505      * @param {String} resourcePath
506      * @return {Boolean}
507      */
508     initWithXML:function (tmxString, resourcePath) {
509         this._internalInit(null, resourcePath);
510         return this.parseXMLString(tmxString);
511     },
512 
513     /** Initalises parsing of an XML file, either a tmx (Map) file or tsx (Tileset) file
514      * @param {String} tmxFile
515      * @param {boolean} [isXmlString=false]
516      * @return {Element}
517      */
518     parseXMLFile:function (tmxFile, isXmlString) {
519         isXmlString = isXmlString || false;
520 	    var xmlStr = isXmlString ? tmxFile : cc.loader.getRes(tmxFile);
521         if(!xmlStr) throw "Please load the resource first : " + tmxFile;
522 
523         var mapXML = this._parseXML(xmlStr);
524         var i, j;
525 
526         // PARSE <map>
527         var map = mapXML.documentElement;
528 
529         var version = map.getAttribute('version');
530         var orientationStr = map.getAttribute('orientation');
531 
532         if (map.nodeName == "map") {
533             if (version != "1.0" && version !== null)
534                 cc.log("cocos2d: TMXFormat: Unsupported TMX version:" + version);
535 
536             if (orientationStr == "orthogonal")
537                 this.orientation = cc.TMX_ORIENTATION_ORTHO;
538             else if (orientationStr == "isometric")
539                 this.orientation = cc.TMX_ORIENTATION_ISO;
540             else if (orientationStr == "hexagonal")
541                 this.orientation = cc.TMX_ORIENTATION_HEX;
542             else if (orientationStr !== null)
543                 cc.log("cocos2d: TMXFomat: Unsupported orientation:" + orientationStr);
544 
545             var mapSize = cc.size(0, 0);
546             mapSize.width = parseFloat(map.getAttribute('width'));
547             mapSize.height = parseFloat(map.getAttribute('height'));
548             this.setMapSize(mapSize);
549 
550             mapSize = cc.size(0, 0);
551             mapSize.width = parseFloat(map.getAttribute('tilewidth'));
552             mapSize.height = parseFloat(map.getAttribute('tileheight'));
553             this.setTileSize(mapSize);
554 
555             // The parent element is the map
556             var propertyArr = map.querySelectorAll("map > properties >  property");
557             if (propertyArr) {
558                 var aPropertyDict = {};
559                 for (i = 0; i < propertyArr.length; i++) {
560                     aPropertyDict[propertyArr[i].getAttribute('name')] = propertyArr[i].getAttribute('value');
561                 }
562                 this.properties = aPropertyDict;
563             }
564         }
565 
566         // PARSE <tileset>
567         var tilesets = map.getElementsByTagName('tileset');
568         if (map.nodeName !== "map") {
569             tilesets = [];
570             tilesets.push(map);
571         }
572 
573         for (i = 0; i < tilesets.length; i++) {
574             var selTileset = tilesets[i];
575             // If this is an external tileset then start parsing that
576             var tsxName = selTileset.getAttribute('source');
577             if (tsxName) {
578                 //this._currentFirstGID = parseInt(selTileset.getAttribute('firstgid'));
579                 var tsxPath = isXmlString ? cc.path.join(this._resources, tsxName) : cc.path.changeBasename(tmxFile, tsxName);
580                 this.parseXMLFile(tsxPath);
581             } else {
582                 var tileset = new cc.TMXTilesetInfo();
583                 tileset.name = selTileset.getAttribute('name') || "";
584                 //TODO need fix
585                 //if(this._currentFirstGID === 0){
586                 tileset.firstGid = parseInt(selTileset.getAttribute('firstgid')) || 0;
587                 //}else{
588                 //    tileset.firstGid = this._currentFirstGID;
589                 //    this._currentFirstGID = 0;
590                 //}
591 
592                 tileset.spacing = parseInt(selTileset.getAttribute('spacing')) || 0;
593                 tileset.margin = parseInt(selTileset.getAttribute('margin')) || 0;
594 
595                 var tilesetSize = cc.size(0, 0);
596                 tilesetSize.width = parseFloat(selTileset.getAttribute('tilewidth'));
597                 tilesetSize.height = parseFloat(selTileset.getAttribute('tileheight'));
598                 tileset._tileSize = tilesetSize;
599 
600                 var image = selTileset.getElementsByTagName('image')[0];
601                 var imagename = image.getAttribute('source');
602                 var num = -1;
603                 if(this.tmxFileName)
604                     num  = this.tmxFileName.lastIndexOf("/");
605                 if (num !== -1) {
606                     var dir = this.tmxFileName.substr(0, num + 1);
607                     tileset.sourceImage = dir + imagename;
608                 } else {
609                     tileset.sourceImage = this._resources + (this._resources ? "/" : "") + imagename;
610                 }
611                 this.setTilesets(tileset);
612 
613                 // PARSE  <tile>
614                 var tiles = selTileset.getElementsByTagName('tile');
615                 if (tiles) {
616                     for (var tIdx = 0; tIdx < tiles.length; tIdx++) {
617                         var t = tiles[tIdx];
618                         this.parentGID = parseInt(tileset.firstGid) + parseInt(t.getAttribute('id') || 0);
619                         var tp = t.querySelectorAll("properties > property");
620                         if (tp) {
621                             var dict = {};
622                             for (j = 0; j < tp.length; j++) {
623                                 var name = tp[j].getAttribute('name');
624                                 dict[name] = tp[j].getAttribute('value');
625                             }
626                             this._tileProperties[this.parentGID] = dict;
627                         }
628                     }
629                 }
630             }
631         }
632 
633         // PARSE  <layer>
634         var layers = map.getElementsByTagName('layer');
635         if (layers) {
636             for (i = 0; i < layers.length; i++) {
637                 var selLayer = layers[i];
638                 var data = selLayer.getElementsByTagName('data')[0];
639 
640                 var layer = new cc.TMXLayerInfo();
641                 layer.name = selLayer.getAttribute('name');
642 
643                 var layerSize = cc.size(0, 0);
644                 layerSize.width = parseFloat(selLayer.getAttribute('width'));
645                 layerSize.height = parseFloat(selLayer.getAttribute('height'));
646                 layer._layerSize = layerSize;
647 
648                 var visible = selLayer.getAttribute('visible');
649                 layer.visible = !(visible == "0");
650 
651                 var opacity = selLayer.getAttribute('opacity') || 1;
652 
653                 if (opacity)
654                     layer._opacity = parseInt(255 * parseFloat(opacity));
655                 else
656                     layer._opacity = 255;
657                 layer.offset = cc.p(parseFloat(selLayer.getAttribute('x')) || 0, parseFloat(selLayer.getAttribute('y')) || 0);
658 
659                 var nodeValue = '';
660                 for (j = 0; j < data.childNodes.length; j++) {
661                     nodeValue += data.childNodes[j].nodeValue
662                 }
663                 nodeValue = nodeValue.trim();
664 
665                 // Unpack the tilemap data
666                 var compression = data.getAttribute('compression');
667                 var encoding = data.getAttribute('encoding');
668                 if(compression && compression !== "gzip" && compression !== "zlib"){
669                     cc.log("cc.TMXMapInfo.parseXMLFile(): unsupported compression method");
670                     return null;
671                 }
672                 switch (compression) {
673                     case 'gzip':
674                         layer._tiles = cc.unzipBase64AsArray(nodeValue, 4);
675                         break;
676                     case 'zlib':
677                         var inflator = new Zlib.Inflate(cc.Codec.Base64.decodeAsArray(nodeValue, 1));
678                         layer._tiles = cc.uint8ArrayToUint32Array(inflator.decompress());
679                         break;
680                     case null:
681                     case '':
682                         // Uncompressed
683                         if (encoding == "base64")
684                             layer._tiles = cc.Codec.Base64.decodeAsArray(nodeValue, 4);
685                         else if (encoding === "csv") {
686                             layer._tiles = [];
687                             var csvTiles = nodeValue.split(',');
688                             for (var csvIdx = 0; csvIdx < csvTiles.length; csvIdx++)
689                                 layer._tiles.push(parseInt(csvTiles[csvIdx]));
690                         } else {
691                             //XML format
692                             var selDataTiles = data.getElementsByTagName("tile");
693                             layer._tiles = [];
694                             for (var xmlIdx = 0; xmlIdx < selDataTiles.length; xmlIdx++)
695                                 layer._tiles.push(parseInt(selDataTiles[xmlIdx].getAttribute("gid")));
696                         }
697                         break;
698                     default:
699                         if(this.layerAttrs == cc.TMXLayerInfo.ATTRIB_NONE)
700                             cc.log("cc.TMXMapInfo.parseXMLFile(): Only base64 and/or gzip/zlib maps are supported");
701                         break;
702                 }
703 
704                 // The parent element is the last layer
705                 var layerProps = selLayer.querySelectorAll("properties > property");
706                 if (layerProps) {
707                     var layerProp = {};
708                     for (j = 0; j < layerProps.length; j++) {
709                         layerProp[layerProps[j].getAttribute('name')] = layerProps[j].getAttribute('value');
710                     }
711                     layer.properties = layerProp;
712                 }
713                 this.setLayers(layer);
714             }
715         }
716 
717         // PARSE <objectgroup>
718         var objectGroups = map.getElementsByTagName('objectgroup');
719         if (objectGroups) {
720             for (i = 0; i < objectGroups.length; i++) {
721                 var selGroup = objectGroups[i];
722                 var objectGroup = new cc.TMXObjectGroup();
723                 objectGroup.groupName = selGroup.getAttribute('name');
724                 objectGroup.setPositionOffset(cc.p(parseFloat(selGroup.getAttribute('x')) * this.getTileSize().width || 0,
725                     parseFloat(selGroup.getAttribute('y')) * this.getTileSize().height || 0));
726 
727                 var groupProps = selGroup.querySelectorAll("objectgroup > properties > property");
728                 if (groupProps) {
729                     for (j = 0; j < groupProps.length; j++) {
730                         var groupProp = {};
731                         groupProp[groupProps[j].getAttribute('name')] = groupProps[j].getAttribute('value');
732                         // Add the property to the layer
733                         objectGroup.properties = groupProp;
734                     }
735                 }
736 
737                 var objects = selGroup.querySelectorAll('object');
738                 if (objects) {
739                     for (j = 0; j < objects.length; j++) {
740                         var selObj = objects[j];
741                         // The value for "type" was blank or not a valid class name
742                         // Create an instance of TMXObjectInfo to store the object and its properties
743                         var objectProp = {};
744 
745                         // Set the name of the object to the value for "name"
746                         objectProp["name"] = selObj.getAttribute('name') || "";
747 
748                         // Assign all the attributes as key/name pairs in the properties dictionary
749                         objectProp["type"] = selObj.getAttribute('type') || "";
750 
751                         objectProp["x"] = parseInt(selObj.getAttribute('x') || 0) + objectGroup.getPositionOffset().x;
752                         var y = parseInt(selObj.getAttribute('y') || 0) + objectGroup.getPositionOffset().y;
753 
754                         objectProp["width"] = parseInt(selObj.getAttribute('width')) || 0;
755                         objectProp["height"] = parseInt(selObj.getAttribute('height')) || 0;
756 
757                         // Correct y position. (Tiled uses Flipped, cocos2d uses Standard)
758                         objectProp["y"] = parseInt(this.getMapSize().height * this.getTileSize().height) - y - objectProp["height"];
759 
760                         var docObjProps = selObj.querySelectorAll("properties > property");
761                         if (docObjProps) {
762                             for (var k = 0; k < docObjProps.length; k++)
763                                 objectProp[docObjProps[k].getAttribute('name')] = docObjProps[k].getAttribute('value');
764                         }
765 
766                         //polygon
767                         var polygonProps = selObj.querySelectorAll("polygon");
768                         if(polygonProps && polygonProps.length > 0) {
769                             var selPgPointStr = polygonProps[0].getAttribute('points');
770                             if(selPgPointStr)
771                                 objectProp["polygonPoints"] = this._parsePointsString(selPgPointStr);
772                         }
773 
774                         //polyline
775                         var polylineProps = selObj.querySelectorAll("polyline");
776                         if(polylineProps && polylineProps.length > 0) {
777                             var selPlPointStr = polylineProps[0].getAttribute('points');
778                             if(selPlPointStr)
779                                 objectProp["polylinePoints"] = this._parsePointsString(selPlPointStr);
780                         }
781 
782                         // Add the object to the objectGroup
783                         objectGroup.setObjects(objectProp);
784                     }
785                 }
786 
787                 this.setObjectGroups(objectGroup);
788             }
789         }
790         return map;
791     },
792 
793     _parsePointsString:function(pointsString){
794          if(!pointsString)
795             return null;
796 
797         var points = [];
798         var pointsStr = pointsString.split(' ');
799         for(var i = 0; i < pointsStr.length; i++){
800             var selPointStr = pointsStr[i].split(',');
801             points.push({'x':selPointStr[0], 'y':selPointStr[1]});
802         }
803         return points;
804     },
805 
806     /**
807      * initializes parsing of an XML string, either a tmx (Map) string or tsx (Tileset) string
808      * @param {String} xmlString
809      * @return {Boolean}
810      */
811     parseXMLString:function (xmlString) {
812         return this.parseXMLFile(xmlString, true);
813     },
814 
815     /**
816      * @return {object}
817      */
818     getTileProperties:function () {
819         return this._tileProperties;
820     },
821 
822     /**
823      * @param {object} tileProperties
824      */
825     setTileProperties:function (tileProperties) {
826         this._tileProperties.push(tileProperties);
827     },
828 
829     /**
830      * @return {String}
831      */
832     getCurrentString:function () {
833         return this.currentString;
834     },
835 
836     /**
837      * @param {String} currentString
838      */
839     setCurrentString:function (currentString) {
840         this.currentString = currentString;
841     },
842 
843     /**
844      * @return {String}
845      */
846     getTMXFileName:function () {
847         return this.tmxFileName;
848     },
849 
850     /**
851      * @param {String} fileName
852      */
853     setTMXFileName:function (fileName) {
854         this.tmxFileName = fileName;
855     },
856 
857     _internalInit:function (tmxFileName, resourcePath) {
858         this._tilesets.length = 0;
859         this._layers.length = 0;
860 
861         this.tmxFileName = tmxFileName;
862         if (resourcePath)
863             this._resources = resourcePath;
864 
865         this._objectGroups.length = 0;
866         this.properties.length = 0;
867         this._tileProperties.length = 0;
868 
869         // tmp vars
870         this.currentString = "";
871         this.storingCharacters = false;
872         this.layerAttrs = cc.TMXLayerInfo.ATTRIB_NONE;
873         this.parentElement = cc.TMX_PROPERTY_NONE;
874         this._currentFirstGID = 0;
875     }
876 });
877 
878 var _p = cc.TMXMapInfo.prototype;
879 
880 // Extended properties
881 /** @expose */
882 _p.mapWidth;
883 cc.defineGetterSetter(_p, "mapWidth", _p._getMapWidth, _p._setMapWidth);
884 /** @expose */
885 _p.mapHeight;
886 cc.defineGetterSetter(_p, "mapHeight", _p._getMapHeight, _p._setMapHeight);
887 /** @expose */
888 _p.tileWidth;
889 cc.defineGetterSetter(_p, "tileWidth", _p._getTileWidth, _p._setTileWidth);
890 /** @expose */
891 _p.tileHeight;
892 cc.defineGetterSetter(_p, "tileHeight", _p._getTileHeight, _p._setTileHeight);
893 
894 
895 /**
896  * Creates a TMX Format with a tmx file or content string
897  * @param {String} tmxFile fileName or content string
898  * @param {String} resourcePath  If tmxFile is a file name ,it is not required.If tmxFile is content string ,it is must required.
899  * @return {cc.TMXMapInfo}
900  * @example
901  * 1.
902  * //create a TMXMapInfo with file name
903  * var tmxMapInfo = cc.TMXMapInfo.create("res/orthogonal-test1.tmx");
904  * 2.
905  * //create a TMXMapInfo with content string and resource path
906  * var resources = "res/TileMaps";
907  * var filePath = "res/TileMaps/orthogonal-test1.tmx";
908  * var xmlStr = cc.loader.getRes(filePath);
909  * var tmxMapInfo = cc.TMXMapInfo.create(xmlStr, resources);
910  */
911 cc.TMXMapInfo.create = function (tmxFile, resourcePath) {
912     return new cc.TMXMapInfo(tmxFile, resourcePath);
913 };
914 
915 
916 cc.loader.register(["tmx", "tsx"], cc._txtLoader);
917 
918 
919 /**
920  * @constant
921  * @type Number
922  */
923 cc.TMXLayerInfo.ATTRIB_NONE = 1 << 0;
924 /**
925  * @constant
926  * @type Number
927  */
928 cc.TMXLayerInfo.ATTRIB_BASE64 = 1 << 1;
929 /**
930  * @constant
931  * @type Number
932  */
933 cc.TMXLayerInfo.ATTRIB_GZIP = 1 << 2;
934 /**
935  * @constant
936  * @type Number
937  */
938 cc.TMXLayerInfo.ATTRIB_ZLIB = 1 << 3;
939