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  * a SAX Parser
 29  * @class
 30  * @extends cc.Class
 31  */
 32 cc.SAXParser = cc.Class.extend(/** @lends cc.SAXParser# */{
 33     xmlDoc:null,
 34     parser:null,
 35     xmlList:[],
 36     plist:[],
 37 
 38     /**
 39      * parse a xml from a string (xmlhttpObj.responseText)
 40      * @param {String} textxml plist xml contents
 41      * @return {Array} plist object array
 42      */
 43     parse:function (textxml) {
 44         var textxml = this.getList(textxml);
 45         // get a reference to the requested corresponding xml file
 46         if (window.DOMParser) {
 47             this.parser = new DOMParser();
 48             this.xmlDoc = this.parser.parseFromString(textxml, "text/xml");
 49         } else // Internet Explorer (untested!)
 50         {
 51             this.xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
 52             this.xmlDoc.async = "false";
 53             this.xmlDoc.loadXML(textxml);
 54         }
 55         if (this.xmlDoc == null) {
 56             cc.log("cocos2d:xml " + this.xmlDoc + " not found!");
 57         }
 58         var plist = this.xmlDoc.documentElement;
 59         if (plist.tagName != 'plist') {
 60             throw "cocos2d:Not a plist file"
 61         }
 62         // Get first real node
 63         var node = null;
 64         for (var i = 0, len = plist.childNodes.length; i < len; i++) {
 65             node = plist.childNodes[i];
 66             if (node.nodeType == 1) {
 67                 break
 68             }
 69         }
 70         this.plist = this._parseNode(node);
 71         return this.plist;
 72     },
 73 
 74     /**
 75      * parse a tilemap xml from a string (xmlhttpObj.responseText)
 76      * @param  {String} textxml  tilemap xml content
 77      * @return {Document} xml document
 78      */
 79     tmxParse:function (textxml) {
 80         var textxml = this.getList(textxml);
 81         // get a reference to the requested corresponding xml file
 82         if (window.DOMParser) {
 83             this.parser = new DOMParser();
 84             this.xmlDoc = this.parser.parseFromString(textxml, "text/xml");
 85         } else // Internet Explorer (untested!)
 86         {
 87             this.xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
 88             this.xmlDoc.async = "false";
 89             this.xmlDoc.loadXML(textxml);
 90         }
 91         if (this.xmlDoc == null) {
 92             cc.log("cocos2d:xml " + this.xmlDoc + " not found!");
 93         }
 94         return this.xmlDoc;
 95     },
 96 
 97     _parseNode:function (node) {
 98         var data = null;
 99         switch (node.tagName) {
100             case 'dict':
101                 data = this._parseDict(node);
102                 break;
103             case 'array':
104                 data = this._parseArray(node);
105                 break;
106             case 'string':
107                 if (node.childNodes.length == 1) {
108                     data = node.firstChild.nodeValue;
109                 } else {
110                     //handle Firefox's 4KB nodeValue limit
111                     data = "";
112                     for (var i = 0; i < node.childNodes.length; i++) {
113                         data += node.childNodes[i].nodeValue;
114                     }
115                 }
116                 break;
117             case 'false':
118                 data = false;
119                 break;
120             case 'true':
121                 data = true;
122                 break;
123             case 'real':
124                 data = parseFloat(node.firstChild.nodeValue);
125                 break;
126             case 'integer':
127                 data = parseInt(node.firstChild.nodeValue, 10);
128                 break;
129         }
130 
131         return data;
132     },
133 
134     _parseArray:function (node) {
135         var data = [];
136         for (var i = 0, len = node.childNodes.length; i < len; i++) {
137             var child = node.childNodes[i];
138             if (child.nodeType != 1) {
139                 continue;
140             }
141             data.push(this._parseNode(child));
142         }
143         return data;
144     },
145 
146     _parseDict:function (node) {
147         var data = {};
148 
149         var key = null;
150         for (var i = 0, len = node.childNodes.length; i < len; i++) {
151             var child = node.childNodes[i];
152             if (child.nodeType != 1) {
153                 continue;
154             }
155 
156             // Grab the key, next noe should be the value
157             if (child.tagName == 'key') {
158                 key = child.firstChild.nodeValue;
159             } else {
160                 // Parse the value node
161                 data[key] = this._parseNode(child);
162             }
163         }
164         return data;
165     },
166 
167     /**
168      * Preload plist file
169      * @param {String} filePath
170      */
171     preloadPlist:function (filePath) {
172         filePath = cc.FileUtils.getInstance().fullPathFromRelativePath(filePath);
173 
174         if (window.XMLHttpRequest) {
175             // for IE7+, Firefox, Chrome, Opera, Safari brower
176             var xmlhttp = new XMLHttpRequest();
177             // is xml file?
178             if (xmlhttp.overrideMimeType)
179                 xmlhttp.overrideMimeType('text/xml');
180         } else {
181             // for IE6, IE5 brower
182             xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
183         }
184         if (xmlhttp != null) {
185             var that = this;
186             xmlhttp.onreadystatechange = function () {
187                 if (xmlhttp.readyState == 4) {
188                     if (xmlhttp.responseText) {
189                         cc.Loader.getInstance().onResLoaded();
190                         that.xmlList[filePath] = xmlhttp.responseText;
191                         xmlhttp = null;
192                     } else {
193                         cc.Assert("cocos2d:There was a problem retrieving the xml data:" + xmlhttp.statusText);
194                     }
195                 }
196             };
197             // load xml
198             xmlhttp.open("GET", filePath, true);
199             xmlhttp.send(null);
200         } else {
201             cc.Assert("cocos2d:Your browser does not support XMLHTTP.");
202         }
203     },
204 
205     /**
206      * get filename from filepath
207      * @param {String} filePath
208      * @return {String}
209      */
210     getName:function (filePath) {
211         var startPos = filePath.lastIndexOf("/", filePath.length) + 1;
212         var endPos = filePath.lastIndexOf(".", filePath.length);
213         return filePath.substring(startPos, endPos);
214     },
215 
216     /**
217      * get file extension name from filepath
218      * @param {String} filePath
219      * @return {String}
220      */
221     getExt:function (filePath) {
222         var startPos = filePath.lastIndexOf(".", filePath.length) + 1;
223         return filePath.substring(startPos, filePath.length);
224     },
225 
226     /**
227      * get value by key from xmlList
228      * @param {String} key
229      * @return {String} xml content
230      */
231     getList:function (key) {
232         if (this.xmlList != null) {
233             return this.xmlList[key];
234         } else {
235             return null;
236         }
237     }
238 });
239 
240 /**
241  * get a singleton SAX parser
242  * @function
243  * @return {cc.SAXParser}
244  */
245 cc.SAXParser.getInstance = function () {
246     if (!this._instance) {
247         this._instance = new cc.SAXParser();
248     }
249     return this._instance;
250 };
251 
252 cc.SAXParser._instance = null;