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                         var value = tp[j].getAttribute('value');
584                         dict[name] = value;
585                     }
586                     this._tileProperties[this.getParentGID()] = dict;
587                 }
588             }
589         }
590 
591         // PARSE  <layer>
592         var layers = map.getElementsByTagName('layer');
593         if (layers) {
594             for (i = 0; i < layers.length; i++) {
595                 var selLayer = layers[i];
596                 var data = selLayer.getElementsByTagName('data')[0];
597 
598                 var layer = new cc.TMXLayerInfo();
599                 layer.name = selLayer.getAttribute('name');
600 
601                 var layerSize = cc.size(0, 0);
602                 layerSize.width = parseFloat(selLayer.getAttribute('width'));
603                 layerSize.height = parseFloat(selLayer.getAttribute('height'));
604                 layer._layerSize = layerSize;
605 
606                 var visible = selLayer.getAttribute('visible');
607                 layer.visible = !(visible == "0");
608 
609                 var opacity = selLayer.getAttribute('opacity') || 1;
610 
611                 if (opacity)
612                     layer._opacity = parseInt(255 * parseFloat(opacity));
613                 else
614                     layer._opacity = 255;
615                 layer.offset = cc.p(parseFloat(selLayer.getAttribute('x')) || 0, parseFloat(selLayer.getAttribute('y')) || 0);
616 
617                 var nodeValue = '';
618                 for (j = 0; j < data.childNodes.length; j++) {
619                     nodeValue += data.childNodes[j].nodeValue
620                 }
621                 nodeValue = nodeValue.trim();
622 
623                 // Unpack the tilemap data
624                 var compression = data.getAttribute('compression');
625                 var encoding = data.getAttribute('encoding');
626                 if(compression && compression !== "gzip" && compression !== "zlib"){
627                     cc.log("cc.TMXMapInfo.parseXMLFile(): unsupported compression method");
628                     return null;
629                 }
630                 switch (compression) {
631                     case 'gzip':
632                         layer._tiles = cc.unzipBase64AsArray(nodeValue, 4);
633                         break;
634                     case 'zlib':
635                         var inflator = new Zlib.Inflate(cc.Codec.Base64.decodeAsArray(nodeValue, 1));
636                         layer._tiles = cc.uint8ArrayToUint32Array(inflator.decompress());
637                         break;
638                     case null:
639                     case '':
640                         // Uncompressed
641                         if (encoding == "base64")
642                             layer._tiles = cc.Codec.Base64.decodeAsArray(nodeValue, 4);
643                         else if (encoding === "csv") {
644                             layer._tiles = [];
645                             var csvTiles = nodeValue.split(',');
646                             for (var csvIdx = 0; csvIdx < csvTiles.length; csvIdx++)
647                                 layer._tiles.push(parseInt(csvTiles[csvIdx]));
648                         } else {
649                             //XML format
650                             var selDataTiles = data.getElementsByTagName("tile");
651                             layer._tiles = [];
652                             for (var xmlIdx = 0; xmlIdx < selDataTiles.length; xmlIdx++)
653                                 layer._tiles.push(parseInt(selDataTiles[xmlIdx].getAttribute("gid")));
654                         }
655                         break;
656                     default:
657                         if(this.getLayerAttribs() == cc.TMX_LAYER_ATTRIB_NONE)
658                             cc.log("cc.TMXMapInfo.parseXMLFile(): Only base64 and/or gzip/zlib maps are supported");
659                         break;
660                 }
661 
662                 // The parent element is the last layer
663                 var layerProps = selLayer.querySelectorAll("properties > property");
664                 if (layerProps) {
665                     var layerProp = {};
666                     for (j = 0; j < layerProps.length; j++) {
667                         layerProp[layerProps[j].getAttribute('name')] = layerProps[j].getAttribute('value');
668                     }
669                     layer.setProperties(layerProp);
670                 }
671                 this.setLayers(layer);
672             }
673         }
674 
675         // PARSE <objectgroup>
676         var objectGroups = map.getElementsByTagName('objectgroup');
677         if (objectGroups) {
678             for (i = 0; i < objectGroups.length; i++) {
679                 var selGroup = objectGroups[i];
680                 var objectGroup = new cc.TMXObjectGroup();
681                 objectGroup.setGroupName(selGroup.getAttribute('name'));
682                 objectGroup.setPositionOffset(cc.p(parseFloat(selGroup.getAttribute('x')) * this.getTileSize().width || 0,
683                     parseFloat(selGroup.getAttribute('y')) * this.getTileSize().height || 0));
684 
685                 var groupProps = selGroup.querySelectorAll("objectgroup > properties > property");
686                 if (groupProps) {
687                     for (j = 0; j < groupProps.length; j++) {
688                         var groupProp = {};
689                         groupProp[groupProps[j].getAttribute('name')] = groupProps[j].getAttribute('value');
690                         // Add the property to the layer
691                         objectGroup.setProperties(groupProp);
692                     }
693                 }
694 
695                 var objects = selGroup.querySelectorAll('object');
696                 if (objects) {
697                     for (j = 0; j < objects.length; j++) {
698                         var selObj = objects[j];
699                         // The value for "type" was blank or not a valid class name
700                         // Create an instance of TMXObjectInfo to store the object and its properties
701                         var objectProp = {};
702 
703                         // Set the name of the object to the value for "name"
704                         objectProp["name"] = selObj.getAttribute('name') || "";
705 
706                         // Assign all the attributes as key/name pairs in the properties dictionary
707                         objectProp["type"] = selObj.getAttribute('type') || "";
708 
709                         objectProp["x"] = parseInt(selObj.getAttribute('x') || 0) + objectGroup.getPositionOffset().x;
710                         var y = parseInt(selObj.getAttribute('y') || 0) + objectGroup.getPositionOffset().y;
711 
712                         objectProp["width"] = parseInt(selObj.getAttribute('width')) || 0;
713                         objectProp["height"] = parseInt(selObj.getAttribute('height')) || 0;
714 
715                         // Correct y position. (Tiled uses Flipped, cocos2d uses Standard)
716                         objectProp["y"] = parseInt(this.getMapSize().height * this.getTileSize().height) - y - objectProp["height"];
717 
718                         var docObjProps = selObj.querySelectorAll("properties > property");
719                         if (docObjProps) {
720                             for (var k = 0; k < docObjProps.length; k++)
721                                 objectProp[docObjProps[k].getAttribute('name')] = docObjProps[k].getAttribute('value');
722                         }
723 
724                         //polygon
725                         var polygonProps = selObj.querySelectorAll("polygon");
726                         if(polygonProps && polygonProps.length > 0) {
727                             var selPgPointStr = polygonProps[0].getAttribute('points');
728                             if(selPgPointStr)
729                                 objectProp["polygonPoints"] = this._parsePointsString(selPgPointStr);
730                         }
731 
732                         //polyline
733                         var polylineProps = selObj.querySelectorAll("polyline");
734                         if(polylineProps && polylineProps.length > 0) {
735                             var selPlPointStr = polylineProps[0].getAttribute('points');
736                             if(selPlPointStr)
737                                 objectProp["polylinePoints"] = this._parsePointsString(selPlPointStr);
738                         }
739 
740                         // Add the object to the objectGroup
741                         objectGroup.setObjects(objectProp);
742                     }
743                 }
744 
745                 this.setObjectGroups(objectGroup);
746             }
747         }
748         return map;
749     },
750 
751     _parsePointsString:function(pointsString){
752          if(!pointsString)
753             return null;
754 
755         var points = [];
756         var pointsStr = pointsString.split(' ');
757         for(var i = 0; i < pointsStr.length; i++){
758             var selPointStr = pointsStr[i].split(',');
759             points.push({'x':selPointStr[0], 'y':selPointStr[1]});
760         }
761         return points;
762     },
763 
764     /**
765      * initializes parsing of an XML string, either a tmx (Map) string or tsx (Tileset) string
766      * @param {String} xmlString
767      * @return {Boolean}
768      */
769     parseXMLString:function (xmlString) {
770         return this.parseXMLFile(xmlString, true);
771     },
772 
773     /**
774      * @return {object}
775      */
776     getTileProperties:function () {
777         return this._tileProperties;
778     },
779 
780     /**
781      * @param {object} tileProperties
782      */
783     setTileProperties:function (tileProperties) {
784         this._tileProperties.push(tileProperties);
785     },
786 
787     /**
788      * @return {String}
789      */
790     getCurrentString:function () {
791         return this._currentString;
792     },
793 
794     /**
795      * @param {String} currentString
796      */
797     setCurrentString:function (currentString) {
798         this._currentString = currentString;
799     },
800 
801     /**
802      * @return {String}
803      */
804     getTMXFileName:function () {
805         return this._TMXFileName;
806     },
807 
808     /**
809      * @param {String} fileName
810      */
811     setTMXFileName:function (fileName) {
812         this._TMXFileName = fileName;
813     },
814 
815     _internalInit:function (tmxFileName, resourcePath) {
816         this._tileSets.length = 0;
817         this._layers.length = 0;
818 
819         //this._TMXFileName = cc.FileUtils.getInstance().fullPathForFilename(tmxFileName);
820         this._TMXFileName = tmxFileName;
821         if (resourcePath)
822             this._resources = resourcePath;
823 
824         this._objectGroups.length = 0;
825         this._properties.length = 0;
826         this._tileProperties.length = 0;
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