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