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._mapSize = cc.SizeZero();
274         this._tileSize = cc.SizeZero();
275         this._layers = [];
276         this._tileSets = [];
277         this._objectGroups = [];
278         this._properties = [];
279         this._tileProperties = {};
280 
281         this._currentFirstGID = 0;
282     },
283     /**
284      * @return {Number}
285      */
286     getOrientation:function () {
287         return this._orientation;
288     },
289 
290     /**
291      * @param {Number} Var
292      */
293     setOrientation:function (Var) {
294         this._orientation = Var;
295     },
296 
297     /**
298      * Map width & height
299      * @return {cc.Size}
300      */
301     getMapSize:function () {
302         return cc.size(this._mapSize.width,this._mapSize.height);
303     },
304 
305     /**
306      * @param {cc.Size} Var
307      */
308     setMapSize:function (Var) {
309         this._mapSize.width = Var.width;
310         this._mapSize.height = Var.height;
311     },
312 
313     /**
314      * Tiles width & height
315      * @return {cc.Size}
316      */
317     getTileSize:function () {
318         return cc.size(this._tileSize.width, this._tileSize.height);
319     },
320 
321     /**
322      * @param {cc.Size} Var
323      */
324     setTileSize:function (Var) {
325         this._tileSize.width = Var.width;
326         this._tileSize.height = Var.height;
327     },
328 
329     /**
330      * Layers
331      * @return {Array}
332      */
333     getLayers:function () {
334         return this._layers;
335     },
336 
337     /**
338      * @param {cc.TMXLayerInfo} Var
339      */
340     setLayers:function (Var) {
341         this._layers.push(Var);
342     },
343 
344     /**
345      * tilesets
346      * @return {Array}
347      */
348     getTilesets:function () {
349         return this._tileSets;
350     },
351 
352     /**
353      * @param {cc.TMXTilesetInfo} Var
354      */
355     setTilesets:function (Var) {
356         this._tileSets.push(Var);
357     },
358 
359     /**
360      * ObjectGroups
361      * @return {Array}
362      */
363     getObjectGroups:function () {
364         return this._objectGroups;
365     },
366 
367     /**
368      * @param {cc.TMXObjectGroup} Var
369      */
370     setObjectGroups:function (Var) {
371         this._objectGroups.push(Var);
372     },
373 
374     /**
375      * parent element
376      * @return {Number}
377      */
378     getParentElement:function () {
379         return this._parentElement;
380     },
381 
382     /**
383      * @param {Number} Var
384      */
385     setParentElement:function (Var) {
386         this._parentElement = Var;
387     },
388 
389     /**
390      * parent GID
391      * @return {Number}
392      */
393     getParentGID:function () {
394         return this._parentGID;
395     },
396 
397     /**
398      * @param {Number} Var
399      */
400     setParentGID:function (Var) {
401         this._parentGID = Var;
402     },
403 
404     /**
405      *  layer attribute
406      * @return {Number}
407      */
408     getLayerAttribs:function () {
409         return this._layerAttribs;
410     },
411 
412     /**
413      * @param {Number} Var
414      */
415     setLayerAttribs:function (Var) {
416         this._layerAttribs = Var;
417     },
418 
419     /**
420      * is string characters?
421      * @return {Boolean}
422      */
423     getStoringCharacters:function () {
424         return this._storingCharacters;
425     },
426 
427     /**
428      * @param {Boolean} Var
429      */
430     setStoringCharacters:function (Var) {
431         this._storingCharacters = Var;
432     },
433 
434     /**
435      * Properties
436      * @return {Array}
437      */
438     getProperties:function () {
439         return this._properties;
440     },
441 
442     /**
443      * @param {object} Var
444      */
445     setProperties:function (Var) {
446         this._properties = Var;
447     },
448 
449     /**
450      * Initializes a TMX format with a  tmx file
451      * @param {String} tmxFile
452      * @param {String} resourcePath
453      * @return {Element}
454      */
455     initWithTMXFile:function (tmxFile, resourcePath) {
456         this._internalInit(tmxFile, resourcePath);
457         return this.parseXMLFile(this._TMXFileName);
458         //return this.parseXMLFile(cc.FileUtils.getInstance().fullPathForFilename(this._TMXFileName));
459     },
460 
461     /**
462      * initializes a TMX format with an XML string and a TMX resource path
463      * @param {String} tmxString
464      * @param {String} resourcePath
465      * @return {Boolean}
466      */
467     initWithXML:function (tmxString, resourcePath) {
468         this._internalInit(null, resourcePath);
469         return this.parseXMLString(tmxString);
470     },
471 
472     /** Initalises parsing of an XML file, either a tmx (Map) file or tsx (Tileset) file
473      * @param {String} tmxFile
474      * @param {boolean} [isXmlString=false]
475      * @return {Element}
476      */
477     parseXMLFile:function (tmxFile, isXmlString) {
478         isXmlString = isXmlString || false;
479         tmxFile = cc.FileUtils.getInstance().fullPathForFilename(tmxFile);
480         var mapXML = cc.SAXParser.getInstance().tmxParse(tmxFile, isXmlString);
481         var i, j;
482 
483         // PARSE <map>
484         var map = mapXML.documentElement;
485 
486         var version = map.getAttribute('version');
487         var orientationStr = map.getAttribute('orientation');
488 
489         if (map.nodeName == "map") {
490             if (version != "1.0" && version !== null)
491                 cc.log("cocos2d: TMXFormat: Unsupported TMX version:" + version);
492 
493             if (orientationStr == "orthogonal")
494                 this.setOrientation(cc.TMX_ORIENTATION_ORTHO);
495             else if (orientationStr == "isometric")
496                 this.setOrientation(cc.TMX_ORIENTATION_ISO);
497             else if (orientationStr == "hexagonal")
498                 this.setOrientation(cc.TMX_ORIENTATION_HEX);
499             else if (orientationStr !== null)
500                 cc.log("cocos2d: TMXFomat: Unsupported orientation:" + this.getOrientation());
501 
502             var mapSize = cc.size(0, 0);
503             mapSize.width = parseFloat(map.getAttribute('width'));
504             mapSize.height = parseFloat(map.getAttribute('height'));
505             this.setMapSize(mapSize);
506 
507             mapSize = cc.size(0, 0);
508             mapSize.width = parseFloat(map.getAttribute('tilewidth'));
509             mapSize.height = parseFloat(map.getAttribute('tileheight'));
510             this.setTileSize(mapSize);
511 
512             // The parent element is the map
513             var propertyArr = map.querySelectorAll("map > properties >  property");
514             if (propertyArr) {
515                 var aPropertyDict = {};
516                 for (i = 0; i < propertyArr.length; i++) {
517                     aPropertyDict[propertyArr[i].getAttribute('name')] = propertyArr[i].getAttribute('value');
518                 }
519                 this.setProperties(aPropertyDict);
520             }
521         }
522 
523         // PARSE <tileset>
524         var tilesets = map.getElementsByTagName('tileset');
525         if (map.nodeName !== "map") {
526             tilesets = [];
527             tilesets.push(map);
528         }
529 
530         for (i = 0; i < tilesets.length; i++) {
531             var selTileset = tilesets[i];
532             // If this is an external tileset then start parsing that
533             var externalTilesetFilename = selTileset.getAttribute('source');
534             if (externalTilesetFilename) {
535                 //this._currentFirstGID = parseInt(selTileset.getAttribute('firstgid'));
536                 this.parseXMLFile(cc.FileUtils.getInstance().fullPathFromRelativeFile(externalTilesetFilename, isXmlString ? this._resources + "/" : tmxFile));
537             } else {
538                 var tileset = new cc.TMXTilesetInfo();
539                 tileset.name = selTileset.getAttribute('name') || "";
540                 //TODO need fix
541                 //if(this._currentFirstGID === 0){
542                 tileset.firstGid = parseInt(selTileset.getAttribute('firstgid')) || 0;
543                 //}else{
544                 //    tileset.firstGid = this._currentFirstGID;
545                 //    this._currentFirstGID = 0;
546                 //}
547 
548                 tileset.spacing = parseInt(selTileset.getAttribute('spacing')) || 0;
549                 tileset.margin = parseInt(selTileset.getAttribute('margin')) || 0;
550 
551                 var tilesetSize = cc.size(0, 0);
552                 tilesetSize.width = parseFloat(selTileset.getAttribute('tilewidth'));
553                 tilesetSize.height = parseFloat(selTileset.getAttribute('tileheight'));
554                 tileset._tileSize = tilesetSize;
555 
556                 var image = selTileset.getElementsByTagName('image')[0];
557                 var imagename = image.getAttribute('source');
558                 var num = -1;
559                 if(this._TMXFileName)
560                     num  = this._TMXFileName.lastIndexOf("/");
561                 if (num !== -1) {
562                     var dir = this._TMXFileName.substr(0, num + 1);
563                     tileset.sourceImage = dir + imagename;
564                 } else {
565                     tileset.sourceImage = this._resources + (this._resources ? "/" : "") + imagename;
566                 }
567                 this.setTilesets(tileset);
568             }
569         }
570 
571         // PARSE  <tile>
572         var tiles = map.querySelectorAll('tile');
573         if (tiles) {
574             for (i = 0; i < tiles.length; i++) {
575                 var info = this._tileSets[0];
576                 var t = tiles[i];
577                 this.setParentGID(parseInt(info.firstGid) + parseInt(t.getAttribute('id') || 0));
578                 var tp = t.querySelectorAll("properties > property");
579                 if (tp) {
580                     var dict = {};
581                     for (j = 0; j < tp.length; j++) {
582                         var name = tp[j].getAttribute('name');
583                         dict[name] = tp[j].getAttribute('value');
584                     }
585                     this._tileProperties[this.getParentGID()] = dict;
586                 }
587             }
588         }
589 
590         // PARSE  <layer>
591         var layers = map.getElementsByTagName('layer');
592         if (layers) {
593             for (i = 0; i < layers.length; i++) {
594                 var selLayer = layers[i];
595                 var data = selLayer.getElementsByTagName('data')[0];
596 
597                 var layer = new cc.TMXLayerInfo();
598                 layer.name = selLayer.getAttribute('name');
599 
600                 var layerSize = cc.size(0, 0);
601                 layerSize.width = parseFloat(selLayer.getAttribute('width'));
602                 layerSize.height = parseFloat(selLayer.getAttribute('height'));
603                 layer._layerSize = layerSize;
604 
605                 var visible = selLayer.getAttribute('visible');
606                 layer.visible = !(visible == "0");
607 
608                 var opacity = selLayer.getAttribute('opacity') || 1;
609 
610                 if (opacity)
611                     layer._opacity = parseInt(255 * parseFloat(opacity));
612                 else
613                     layer._opacity = 255;
614                 layer.offset = cc.p(parseFloat(selLayer.getAttribute('x')) || 0, parseFloat(selLayer.getAttribute('y')) || 0);
615 
616                 var nodeValue = '';
617                 for (j = 0; j < data.childNodes.length; j++) {
618                     nodeValue += data.childNodes[j].nodeValue
619                 }
620                 nodeValue = nodeValue.trim();
621 
622                 // Unpack the tilemap data
623                 var compression = data.getAttribute('compression');
624                 var encoding = data.getAttribute('encoding');
625                 if(compression && compression !== "gzip" && compression !== "zlib"){
626                     cc.log("cc.TMXMapInfo.parseXMLFile(): unsupported compression method");
627                     return null;
628                 }
629                 switch (compression) {
630                     case 'gzip':
631                         layer._tiles = cc.unzipBase64AsArray(nodeValue, 4);
632                         break;
633                     case 'zlib':
634                         var inflator = new Zlib.Inflate(cc.Codec.Base64.decodeAsArray(nodeValue, 1));
635                         layer._tiles = cc.uint8ArrayToUint32Array(inflator.decompress());
636                         break;
637                     case null:
638                     case '':
639                         // Uncompressed
640                         if (encoding == "base64")
641                             layer._tiles = cc.Codec.Base64.decodeAsArray(nodeValue, 4);
642                         else if (encoding === "csv") {
643                             layer._tiles = [];
644                             var csvTiles = nodeValue.split(',');
645                             for (var csvIdx = 0; csvIdx < csvTiles.length; csvIdx++)
646                                 layer._tiles.push(parseInt(csvTiles[csvIdx]));
647                         } else {
648                             //XML format
649                             var selDataTiles = data.getElementsByTagName("tile");
650                             layer._tiles = [];
651                             for (var xmlIdx = 0; xmlIdx < selDataTiles.length; xmlIdx++)
652                                 layer._tiles.push(parseInt(selDataTiles[xmlIdx].getAttribute("gid")));
653                         }
654                         break;
655                     default:
656                         if(this.getLayerAttribs() == cc.TMX_LAYER_ATTRIB_NONE)
657                             cc.log("cc.TMXMapInfo.parseXMLFile(): Only base64 and/or gzip/zlib maps are supported");
658                         break;
659                 }
660 
661                 // The parent element is the last layer
662                 var layerProps = selLayer.querySelectorAll("properties > property");
663                 if (layerProps) {
664                     var layerProp = {};
665                     for (j = 0; j < layerProps.length; j++) {
666                         layerProp[layerProps[j].getAttribute('name')] = layerProps[j].getAttribute('value');
667                     }
668                     layer.setProperties(layerProp);
669                 }
670                 this.setLayers(layer);
671             }
672         }
673 
674         // PARSE <objectgroup>
675         var objectGroups = map.getElementsByTagName('objectgroup');
676         if (objectGroups) {
677             for (i = 0; i < objectGroups.length; i++) {
678                 var selGroup = objectGroups[i];
679                 var objectGroup = new cc.TMXObjectGroup();
680                 objectGroup.setGroupName(selGroup.getAttribute('name'));
681                 objectGroup.setPositionOffset(cc.p(parseFloat(selGroup.getAttribute('x')) * this.getTileSize().width || 0,
682                     parseFloat(selGroup.getAttribute('y')) * this.getTileSize().height || 0));
683 
684                 var groupProps = selGroup.querySelectorAll("objectgroup > properties > property");
685                 if (groupProps) {
686                     for (j = 0; j < groupProps.length; j++) {
687                         var groupProp = {};
688                         groupProp[groupProps[j].getAttribute('name')] = groupProps[j].getAttribute('value');
689                         // Add the property to the layer
690                         objectGroup.setProperties(groupProp);
691                     }
692                 }
693 
694                 var objects = selGroup.querySelectorAll('object');
695                 if (objects) {
696                     for (j = 0; j < objects.length; j++) {
697                         var selObj = objects[j];
698                         // The value for "type" was blank or not a valid class name
699                         // Create an instance of TMXObjectInfo to store the object and its properties
700                         var objectProp = {};
701 
702                         // Set the name of the object to the value for "name"
703                         objectProp["name"] = selObj.getAttribute('name') || "";
704 
705                         // Assign all the attributes as key/name pairs in the properties dictionary
706                         objectProp["type"] = selObj.getAttribute('type') || "";
707 
708                         objectProp["x"] = parseInt(selObj.getAttribute('x') || 0) + objectGroup.getPositionOffset().x;
709                         var y = parseInt(selObj.getAttribute('y') || 0) + objectGroup.getPositionOffset().y;
710 
711                         objectProp["width"] = parseInt(selObj.getAttribute('width')) || 0;
712                         objectProp["height"] = parseInt(selObj.getAttribute('height')) || 0;
713 
714                         // Correct y position. (Tiled uses Flipped, cocos2d uses Standard)
715                         objectProp["y"] = parseInt(this.getMapSize().height * this.getTileSize().height) - y - objectProp["height"];
716 
717                         var docObjProps = selObj.querySelectorAll("properties > property");
718                         if (docObjProps) {
719                             for (var k = 0; k < docObjProps.length; k++)
720                                 objectProp[docObjProps[k].getAttribute('name')] = docObjProps[k].getAttribute('value');
721                         }
722 
723                         //polygon
724                         var polygonProps = selObj.querySelectorAll("polygon");
725                         if(polygonProps && polygonProps.length > 0) {
726                             var selPgPointStr = polygonProps[0].getAttribute('points');
727                             if(selPgPointStr)
728                                 objectProp["polygonPoints"] = this._parsePointsString(selPgPointStr);
729                         }
730 
731                         //polyline
732                         var polylineProps = selObj.querySelectorAll("polyline");
733                         if(polylineProps && polylineProps.length > 0) {
734                             var selPlPointStr = polylineProps[0].getAttribute('points');
735                             if(selPlPointStr)
736                                 objectProp["polylinePoints"] = this._parsePointsString(selPlPointStr);
737                         }
738 
739                         // Add the object to the objectGroup
740                         objectGroup.setObjects(objectProp);
741                     }
742                 }
743 
744                 this.setObjectGroups(objectGroup);
745             }
746         }
747         return map;
748     },
749 
750     _parsePointsString:function(pointsString){
751          if(!pointsString)
752             return null;
753 
754         var points = [];
755         var pointsStr = pointsString.split(' ');
756         for(var i = 0; i < pointsStr.length; i++){
757             var selPointStr = pointsStr[i].split(',');
758             points.push({'x':selPointStr[0], 'y':selPointStr[1]});
759         }
760         return points;
761     },
762 
763     /**
764      * initializes parsing of an XML string, either a tmx (Map) string or tsx (Tileset) string
765      * @param {String} xmlString
766      * @return {Boolean}
767      */
768     parseXMLString:function (xmlString) {
769         return this.parseXMLFile(xmlString, true);
770     },
771 
772     /**
773      * @return {object}
774      */
775     getTileProperties:function () {
776         return this._tileProperties;
777     },
778 
779     /**
780      * @param {object} tileProperties
781      */
782     setTileProperties:function (tileProperties) {
783         this._tileProperties.push(tileProperties);
784     },
785 
786     /**
787      * @return {String}
788      */
789     getCurrentString:function () {
790         return this._currentString;
791     },
792 
793     /**
794      * @param {String} currentString
795      */
796     setCurrentString:function (currentString) {
797         this._currentString = currentString;
798     },
799 
800     /**
801      * @return {String}
802      */
803     getTMXFileName:function () {
804         return this._TMXFileName;
805     },
806 
807     /**
808      * @param {String} fileName
809      */
810     setTMXFileName:function (fileName) {
811         this._TMXFileName = fileName;
812     },
813 
814     _internalInit:function (tmxFileName, resourcePath) {
815         this._tileSets.length = 0;
816         this._layers.length = 0;
817 
818         //this._TMXFileName = cc.FileUtils.getInstance().fullPathForFilename(tmxFileName);
819         this._TMXFileName = tmxFileName;
820         if (resourcePath)
821             this._resources = resourcePath;
822 
823         this._objectGroups.length = 0;
824         this._properties.length = 0;
825         this._tileProperties.length = 0;
826 
827         // tmp vars
828         this._currentString = "";
829         this._storingCharacters = false;
830         this._layerAttribs = cc.TMX_LAYER_ATTRIB_NONE;
831         this._parentElement = cc.TMX_PROPERTY_NONE;
832         this._currentFirstGID = 0;
833     }
834 });
835 
836 /**
837  * Creates a TMX Format with a tmx file
838  * @param {String} tmxFile
839  * @param {String} resourcePath
840  * @return {cc.TMXMapInfo}
841  */
842 cc.TMXMapInfo.create = function (tmxFile, resourcePath) {
843     var ret = new cc.TMXMapInfo();
844     if (ret.initWithTMXFile(tmxFile, resourcePath))
845         return ret;
846     return null;
847 };
848 
849 /**
850  * creates a TMX Format with an XML string and a TMX resource path
851  * @param {String} tmxString
852  * @param {String} resourcePath
853  * @return {cc.TMXMapInfo}
854  */
855 cc.TMXMapInfo.createWithXML = function (tmxString, resourcePath) {
856     var ret = new cc.TMXMapInfo();
857     if (ret.initWithXML(tmxString, resourcePath))
858         return ret;
859     return null;
860 };
861