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.SAX_NONE = 0;
 32 
 33 /**
 34  * @constant
 35  * @type Number
 36  */
 37 cc.SAX_KEY = 1;
 38 
 39 /**
 40  * @constant
 41  * @type Number
 42  */
 43 cc.SAX_DICT = 2;
 44 
 45 /**
 46  * @constant
 47  * @type Number
 48  */
 49 cc.SAX_INT = 3;
 50 
 51 /**
 52  * @constant
 53  * @type Number
 54  */
 55 cc.SAX_REAL = 4;
 56 
 57 /**
 58  * @constant
 59  * @type Number
 60  */
 61 cc.SAX_STRING = 5;
 62 
 63 /**
 64  * @constant
 65  * @type Number
 66  */
 67 cc.SAX_ARRAY = 6;
 68 
 69 //Compatibility with IE9
 70 var Uint8Array = Uint8Array || Array;
 71 
 72 if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
 73     var IEBinaryToArray_ByteStr_Script =
 74         "<!-- IEBinaryToArray_ByteStr -->\r\n" +
 75             //"<script type='text/vbscript'>\r\n" +
 76             "Function IEBinaryToArray_ByteStr(Binary)\r\n" +
 77             "   IEBinaryToArray_ByteStr = CStr(Binary)\r\n" +
 78             "End Function\r\n" +
 79             "Function IEBinaryToArray_ByteStr_Last(Binary)\r\n" +
 80             "   Dim lastIndex\r\n" +
 81             "   lastIndex = LenB(Binary)\r\n" +
 82             "   if lastIndex mod 2 Then\r\n" +
 83             "       IEBinaryToArray_ByteStr_Last = Chr( AscB( MidB( Binary, lastIndex, 1 ) ) )\r\n" +
 84             "   Else\r\n" +
 85             "       IEBinaryToArray_ByteStr_Last = " + '""' + "\r\n" +
 86             "   End If\r\n" +
 87             "End Function\r\n";// +
 88     //"</script>\r\n";
 89 
 90     // inject VBScript
 91     //document.write(IEBinaryToArray_ByteStr_Script);
 92     var myVBScript = document.createElement('script');
 93     myVBScript.type = "text/vbscript";
 94     myVBScript.textContent = IEBinaryToArray_ByteStr_Script;
 95     document.body.appendChild(myVBScript);
 96 
 97     // helper to convert from responseBody to a "responseText" like thing
 98     cc._convertResponseBodyToText = function (binary) {
 99         var byteMapping = {};
100         for (var i = 0; i < 256; i++) {
101             for (var j = 0; j < 256; j++) {
102                 byteMapping[ String.fromCharCode(i + j * 256) ] =
103                     String.fromCharCode(i) + String.fromCharCode(j);
104             }
105         }
106         var rawBytes = IEBinaryToArray_ByteStr(binary);
107         var lastChr = IEBinaryToArray_ByteStr_Last(binary);
108         return rawBytes.replace(/[\s\S]/g,
109             function (match) {
110                 return byteMapping[match];
111             }) + lastChr;
112     };
113 }
114 
115 /**
116  * @namespace
117  */
118 cc.FileUtils = cc.Class.extend({
119     _fileDataCache:null,
120     _textFileCache:null,
121 
122     _directory:null,
123     _filenameLookupDict:null,
124     _searchResolutionsOrderArray:null,
125     _searchPathArray:null,
126     _defaultResRootPath:"",
127 
128     ctor:function () {
129         this._fileDataCache = {};
130         this._textFileCache = {};
131 
132         this._searchPathArray = [];
133         this._searchPathArray.push(this._defaultResRootPath);
134 
135         this._searchResolutionsOrderArray = [];
136         this._searchResolutionsOrderArray.push("");
137     },
138 
139     /**
140      * <p>
141      *      Purges the file searching cache.                                                                           <br/>
142      *                                                                                                                 <br/>
143      *      @note It should be invoked after the resources were updated.                                              <br/>
144      *           For instance, in the CocosPlayer sample, every time you run application from CocosBuilder,            <br/>
145      *           All the resources will be downloaded to the writable folder, before new js app launchs,               <br/>
146      *           this method should be invoked to clean the file search cache.
147      * </p>
148      */
149     purgeCachedEntries:function(){
150         this._searchPathArray = [];
151     },
152     /**
153      * Get Byte Array from file
154      * @function
155      * @param {String} fileName The resource file name which contain the path
156      * @param {String} mode mode The read mode of the file
157      * @param {Number} size If get the file data succeed the it will be the data size,or it will be 0
158      * @warning If you get the file data succeed,you must delete it after used.
159      */
160     getByteArrayFromFile:function (fileName, mode, size) {
161         fileName = this.fullPathForFilename(fileName);
162         if (this._fileDataCache.hasOwnProperty(fileName))
163             return this._fileDataCache[fileName];
164         return this._loadBinaryFileData(fileName);
165     },
166 
167     _getXMLHttpRequest:function () {
168         if (window.XMLHttpRequest) {
169             return new window.XMLHttpRequest();
170         } else {
171             return new ActiveXObject("MSXML2.XMLHTTP");
172         }
173     },
174 
175     unloadBinaryFileData:function (fileUrl) {
176         if (this._fileDataCache.hasOwnProperty(fileUrl))
177             delete this._fileDataCache[fileUrl];
178     },
179 
180     preloadBinaryFileData:function (fileUrl) {
181         fileUrl = this.fullPathForFilename(fileUrl);
182         var selfPointer = this;
183 
184         var xhr = this._getXMLHttpRequest();
185         xhr.open("GET", fileUrl, true);
186         if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
187             // IE-specific logic here
188             xhr.setRequestHeader("Accept-Charset", "x-user-defined");
189             xhr.onreadystatechange = function (event) {
190                 if (xhr.readyState == 4) {
191                     if (xhr.status == 200) {
192                         var fileContents = cc._convertResponseBodyToText(xhr["responseBody"]);
193                         if (fileContents)
194                             selfPointer._fileDataCache[fileUrl] = selfPointer._stringConvertToArray(fileContents);
195                     } else {
196                         cc.Loader.getInstance().onResLoadingErr(fileUrl);
197                     }
198                     cc.Loader.getInstance().onResLoaded();
199                 }
200             };
201         } else {
202             if (xhr.overrideMimeType)
203                 xhr.overrideMimeType("text\/plain; charset=x-user-defined");
204 
205             xhr.onreadystatechange = function (event) {
206                 if (xhr.readyState == 4) {
207                     if (xhr.status == 200) {
208                         var fileContents = xhr.responseText;
209                         if (fileContents)
210                             selfPointer._fileDataCache[fileUrl] = selfPointer._stringConvertToArray(fileContents);
211                     } else {
212                         cc.Loader.getInstance().onResLoadingErr(fileUrl);
213                     }
214                     cc.Loader.getInstance().onResLoaded();
215                 }
216             };
217         }
218         xhr.send(null);
219     },
220 
221     _loadBinaryFileData:function (fileUrl) {
222         var req = this._getXMLHttpRequest();
223         req.open('GET', fileUrl, false);
224         var arrayInfo = null;
225         if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
226             req.setRequestHeader("Accept-Charset", "x-user-defined");
227             req.send(null);
228             if (req.status != 200)
229                 return null;
230 
231             var fileContents = cc._convertResponseBodyToText(req["responseBody"]);
232             if (fileContents) {
233                 arrayInfo = this._stringConvertToArray(fileContents);
234                 this._fileDataCache[fileUrl] = arrayInfo;
235             }
236         } else {
237             if (req.overrideMimeType)
238                 req.overrideMimeType('text\/plain; charset=x-user-defined');
239             req.send(null);
240             if (req.status != 200)
241                 return null;
242 
243             arrayInfo = this._stringConvertToArray(req.responseText);
244             this._fileDataCache[fileUrl] = arrayInfo;
245         }
246         return arrayInfo;
247     },
248 
249     _stringConvertToArray:function (strData) {
250         if (!strData)
251             return null;
252 
253         var arrData = new Uint8Array(strData.length);
254         for (var i = 0; i < strData.length; i++) {
255             arrData[i] = strData.charCodeAt(i) & 0xff;
256         }
257         return arrData;
258     },
259 
260     unloadTextFileData:function (fileUrl) {
261         if (this._textFileCache.hasOwnProperty(fileUrl))
262             delete this._textFileCache[fileUrl];
263     },
264 
265     preloadTextFileData:function (fileUrl) {
266         fileUrl = this.fullPathForFilename(fileUrl);
267         var selfPointer = this;
268 
269         var xhr = this._getXMLHttpRequest();
270         xhr.open("GET", fileUrl, true);
271         if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
272             // IE-specific logic here
273             xhr.setRequestHeader("Accept-Charset", "utf-8");
274         } else {
275             if (xhr.overrideMimeType)
276                 xhr.overrideMimeType("text\/plain; charset=utf-8");
277         }
278         xhr.onreadystatechange = function (event) {
279             if (xhr.readyState == 4) {
280                 if (xhr.status == 200) {
281                     var fileContents = xhr.responseText;
282                     if (fileContents)
283                         selfPointer._textFileCache[fileUrl] = fileContents;
284                 } else {
285                     cc.Loader.getInstance().onResLoadingErr(fileUrl);
286                 }
287                 cc.Loader.getInstance().onResLoaded();
288             }
289         };
290         xhr.send(null);
291     },
292 
293     _loadTextFileData:function (fileUrl) {
294         var req = this._getXMLHttpRequest();
295         req.open('GET', fileUrl, false);
296         var fileContents = null;
297         if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
298             req.setRequestHeader("Accept-Charset", "utf-8");
299         } else {
300             if (req.overrideMimeType)
301                 req.overrideMimeType('text\/plain; charset=utf-8');
302         }
303         req.send(null);
304         if (req.status != 200)
305             return null;
306 
307         fileContents = req.responseText;
308         if (fileContents) {
309             this._textFileCache[fileUrl] = fileContents;
310         }
311         return fileContents;
312     },
313 
314     /**
315      *  Gets resource file data
316      * @param {String} fileUrl The resource file name which contains the path.
317      * @returns {String}
318      */
319     getTextFileData:function (fileUrl) {
320         if (this._textFileCache.hasOwnProperty(fileUrl))
321             return this._textFileCache[fileUrl];
322         return this._loadTextFileData(fileUrl);
323     },
324 
325     /**
326      * Get resource file data from zip file
327      * @function
328      * @param {String} pszZipFilePath
329      * @param {String} fileName fileName The resource file name which contain the relative path of zip file
330      * @param {Number} size size If get the file data succeed the it will be the data size,or it will be 0
331      * @warning If you get the file data succeed,you must delete it after used.
332      * @deprecated
333      */
334     getFileDataFromZip:function (pszZipFilePath, fileName, size) {
335     },
336 
337     /**
338      * removes the HD suffix from a path
339      * @function
340      * @param {String} path
341      * @deprecated
342      */
343     removeSuffixFromFile:function (path) {
344     },
345 
346     //////////////////////////////////////////////////////////////////////////
347     // Notification support when getByteArrayFromFile from invalid file path.
348     //////////////////////////////////////////////////////////////////////////
349     /**
350      * Notification support when getByteArrayFromFile from invalid file path.
351      * @function
352      * @type {Boolean}
353      */
354     popupNotify:true,
355 
356     /**
357      * Generate the absolute path of the file.
358      * @function
359      * @param {String} pszRelativePath
360      * @return {String} The absolute path of the file.
361      * @warning We only add the ResourcePath before the relative path of the file. <br/>
362      * If you have not set the ResourcePath,the function add "/NEWPLUS/TDA_DATA/UserData/" as default.<br/>
363      * You can set ResourcePath by function void setResourcePath(const char *resourcePath);
364      */
365     fullPathFromRelativePath:function (pszRelativePath) {
366         return pszRelativePath;
367     },
368 
369     /**
370      * <p>
371      *      Returns the fullpath for a given filename.                                                                                                                             </br>
372      *      First it will try to get a new filename from the "filenameLookup" dictionary.                                                                                          </br>
373      *      If a new filename can't be found on the dictionary, it will use the original filename.                                                                                 </br>
374      *      Then it will try obtain the full path of the filename using the CCFileUtils search rules:  resources directory and search paths.                                       </br>
375      *      The file search is based on the array element order of search paths and resolution directories.                                                                        </br>
376      *                                                                                                                                                                             </br>
377      *      For instance:                                                                                                                                                          </br>
378      *                                                                                                                                                                             </br>
379      *          We set two elements("/mnt/sdcard/", "internal_dir/") to search paths vector by setSearchPaths,                                                                     </br>
380      *          and set three elements("resources-ipadhd/", "resources-ipad/", "resources-iphonehd")                                                                               </br>
381      *          to resolutions vector by setSearchResolutionsOrder. The "internal_dir" is relative to "Resources/".                                                                </br>
382      *                                                                                                                                                                             </br>
383      *          If we have a file named 'sprite.png', the mapping in fileLookup dictionary contains `key: sprite.png -> value: sprite.pvr.gz`.                                     </br>
384      *          Firstly, it will replace 'sprite.png' with 'sprite.pvr.gz', then searching the file sprite.pvr.gz as follows:                                                      </br>
385      *              /mnt/sdcard/resources-ipadhd/sprite.pvr.gz      (if not found, search next)                                                                                    </br>
386      *              /mnt/sdcard/resources-ipad/sprite.pvr.gz        (if not found, search next)                                                                                    </br>
387      *              /mnt/sdcard/resources-iphonehd/sprite.pvr.gz    (if not found, search next)                                                                                    </br>
388      *              /mnt/sdcard/sprite.pvr.gz                       (if not found, search next)                                                                                    </br>
389      *              internal_dir/resources-ipadhd/sprite.pvr.gz     (if not found, search next)                                                                                    </br>
390      *              internal_dir/resources-ipad/sprite.pvr.gz       (if not found, search next)                                                                                    </br>
391      *              internal_dir/resources-iphonehd/sprite.pvr.gz   (if not found, search next)                                                                                    </br>
392      *              internal_dir/sprite.pvr.gz                      (if not found, return "sprite.png")                                                                            </br>
393      *                                                                                                                                                                             </br>
394      *         If the filename contains relative path like "gamescene/uilayer/sprite.png",                                                                                         </br>
395      *         and the mapping in fileLookup dictionary contains `key: gamescene/uilayer/sprite.png -> value: gamescene/uilayer/sprite.pvr.gz`.                                    </br>
396      *         The file search order will be:                                                                                                                                      </br>
397      *              /mnt/sdcard/gamescene/uilayer/resources-ipadhd/sprite.pvr.gz      (if not found, search next)                                                                  </br>
398      *              /mnt/sdcard/gamescene/uilayer/resources-ipad/sprite.pvr.gz        (if not found, search next)                                                                  </br>
399      *              /mnt/sdcard/gamescene/uilayer/resources-iphonehd/sprite.pvr.gz    (if not found, search next)                                                                  </br>
400      *              /mnt/sdcard/gamescene/uilayer/sprite.pvr.gz                       (if not found, search next)                                                                  </br>
401      *              internal_dir/gamescene/uilayer/resources-ipadhd/sprite.pvr.gz     (if not found, search next)                                                                  </br>
402      *              internal_dir/gamescene/uilayer/resources-ipad/sprite.pvr.gz       (if not found, search next)                                                                  </br>
403      *              internal_dir/gamescene/uilayer/resources-iphonehd/sprite.pvr.gz   (if not found, search next)                                                                  </br>
404      *              internal_dir/gamescene/uilayer/sprite.pvr.gz                      (if not found, return "gamescene/uilayer/sprite.png")                                        </br>
405      *                                                                                                                                                                             </br>
406      *         If the new file can't be found on the file system, it will return the parameter pszFileName directly.                                                               </br>
407      *                                                                                                                                                                             </br>
408      *         This method was added to simplify multiplatform support. Whether you are using cocos2d-js or any cross-compilation toolchain like StellaSDK or Apportable,          </br>
409      *         you might need to load different resources for a given file in the different platforms.
410      * </p>
411      * @param {String} filename
412      * @return {String} full path for a given filename.
413      */
414     fullPathForFilename:function (filename) {
415         var found = false;
416 
417         var newFileName = this._getNewFilename(filename);
418         var fullPath;
419 
420         if (newFileName && newFileName.length > 1 && (newFileName.indexOf(":") == 1))
421             return newFileName;
422 
423         for (var i = 0; i < this._searchPathArray.length; i++) {
424             var searchPath = this._searchPathArray[i];
425             for (var j = 0; j < this._searchResolutionsOrderArray.length; j++) {
426                 var resourceDirectory = this._searchResolutionsOrderArray[j];
427                 fullPath = this._getPathForFilename(newFileName, resourceDirectory, searchPath);
428                 if (fullPath) {
429                     found = true;
430                     break;
431                 }
432             }
433             if (found)
434                 break;
435         }
436 
437         return found ? fullPath : newFileName;
438     },
439 
440     /**
441      * <p>
442      *     Loads the filenameLookup dictionary from the contents of a filename.                                        <br/>
443      *                                                                                                                 <br/>
444      *     @note The plist file name should follow the format below:                                                   <br/>
445      *     <?xml version="1.0" encoding="UTF-8"?>                                                                      <br/>
446      *         <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">  <br/>
447      *             <plist version="1.0">                                                                               <br/>
448      *                 <dict>                                                                                          <br/>
449      *                     <key>filenames</key>                                                                        <br/>
450      *                     <dict>                                                                                      <br/>
451      *                         <key>sounds/click.wav</key>                                                             <br/>
452      *                         <string>sounds/click.caf</string>                                                       <br/>
453      *                         <key>sounds/endgame.wav</key>                                                           <br/>
454      *                         <string>sounds/endgame.caf</string>                                                     <br/>
455      *                         <key>sounds/gem-0.wav</key>                                                             <br/>
456      *                         <string>sounds/gem-0.caf</string>                                                       <br/>
457      *                     </dict>                                                                                     <br/>
458      *                     <key>metadata</key>                                                                         <br/>
459      *                     <dict>                                                                                      <br/>
460      *                         <key>version</key>                                                                      <br/>
461      *                         <integer>1</integer>                                                                    <br/>
462      *                     </dict>                                                                                     <br/>
463      *                 </dict>                                                                                         <br/>
464      *              </plist>                                                                                           <br/>
465      * </p>
466      * @param {String} filename  The plist file name.
467      */
468     loadFilenameLookup:function (filename) {
469         var fullPath = this.fullPathForFilename(filename);
470         if (fullPath.length > 0) {
471             var dict = cc.SAXParser.getInstance().parse(fullPath);
472             var metadataDict = dict["metadata"];
473             var version = parseInt(metadataDict["version"]);
474             if (version != 1) {
475                 cc.log("cocos2d: ERROR: Invalid filenameLookup dictionary version: " + version + ". Filename: " + filename);
476                 return;
477             }
478             this.setFilenameLookupDictionary(dict["filenames"]);
479         }
480     },
481 
482     /**
483      * Sets the filenameLookup dictionary.
484      * @param {Object} filenameLookupDict The dictionary for replacing filename.
485      */
486     setFilenameLookupDictionary:function (filenameLookupDict) {
487         this._filenameLookupDict = filenameLookupDict;
488     },
489 
490     /**
491      * Gets full path from a file name and the path of the reletive file.
492      * @param {String} filename The file name.
493      * @param {String} relativeFile The path of the relative file.
494      * @return {String} The full path.
495      */
496     fullPathFromRelativeFile:function (filename, relativeFile) {
497         var tmpPath;
498         if (filename) {
499             tmpPath = relativeFile.substring(0, relativeFile.lastIndexOf("/") + 1);
500             return tmpPath + filename;
501         }
502         else {
503             tmpPath = relativeFile.substring(0, relativeFile.lastIndexOf("."));
504             tmpPath = tmpPath + ".png";
505             return tmpPath;
506         }
507     },
508 
509     /**
510      * <p>
511      *     Sets the array that contains the search order of the resources.
512      * </p>
513      * @see getSearchResolutionsOrder(void), fullPathForFilename(const char*).
514      * @param {Array} searchResolutionsOrder
515      */
516     setSearchResolutionsOrder:function (searchResolutionsOrder) {
517         this._searchResolutionsOrderArray = searchResolutionsOrder;
518     },
519 
520     /**
521      * Gets the array that contains the search order of the resources.
522      * @see setSearchResolutionsOrder(), fullPathForFilename(const char*).
523      * @return {Array}
524      */
525     getSearchResolutionsOrder:function () {
526         return this._searchResolutionsOrderArray;
527     },
528 
529     /**
530      * <p>
531      *     Array of search paths.                                                                                                  <br/>
532      *     You can use this array to modify the search path of the resources.                                                      <br/>
533      *     If you want to use "themes" or search resources in the "cache", you can do it easily by adding new entries in this array.  <br/>
534      *                                                                                                                                <br/>
535      *     By default it is an array with only the "" (empty string) element.                                                         <br/>
536      * </p>
537      * @param {Array} searchPaths
538      */
539     setSearchPath:function (searchPaths) {
540         this._searchPathArray = searchPaths;
541     },
542 
543     /**
544      * return Array of search paths.
545      * @return {Array}
546      */
547     getSearchPath:function () {
548         return this._searchPathArray;
549     },
550 
551     getResourceDirectory:function () {
552         return this._directory;
553     },
554 
555 
556     /**
557      * Set the ResourcePath,we will find resource in this path
558      * @function
559      * @param {String} resourcePath The absolute resource path
560      * @warning Don't call this function in android and iOS, it has not effect.<br/>
561      * In android, if you want to read file other than apk, you shoud use invoke getByteArrayFromFile(), and pass the<br/>
562      * absolute path.
563      * @deprecated
564      */
565     setResourcePath:function (resourcePath) {
566     },
567 
568     /**
569      * Generate an Dictionary of object by file
570      * @deprecated
571      * @param fileName The file name of *.plist file
572      * @return {object} The Dictionary of object generated from the file
573      */
574     dictionaryWithContentsOfFile:function (fileName) {
575         cc.log("dictionaryWithContentsOfFile is deprecated. Use createDictionaryWithContentsOfFile instead");
576         return this.createDictionaryWithContentsOfFile(fileName);
577     },
578 
579     /**
580      * Generate an Dictionary of object by file
581      * @param filename The file name of *.plist file
582      * @return {object} The Dictionary of object generated from the file
583      */
584     createDictionaryWithContentsOfFile: function(filename){
585         return  cc.SAXParser.getInstance().parse(filename);
586     },
587 
588     /**
589      * get string  from file
590      * @function
591      * @param {String} fileName
592      * @return {String}
593      */
594     getStringFromFile:function (fileName) {
595         return this.getTextFileData(fileName); //cc.SAXParser.getInstance().getList(fileName);
596     },
597 
598     /**
599      * The same meaning as dictionaryWithContentsOfFile(), but it doesn't call autorelease, so the invoker should call release().
600      * @function
601      * @param {String} fileName
602      * @return {object} The Dictionary of object generated from the file
603      */
604     dictionaryWithContentsOfFileThreadSafe:function (fileName) {
605         return cc.SAXParser.getInstance().parse(fileName);
606     },
607 
608     /**
609      * Get the writeable path
610      * @return {String}  The path that can write/read file
611      * @deprecated
612      */
613     getWritablePath:function () {
614         return "";
615     },
616 
617     /**
618      * Set whether pop-up a message box when the image load failed
619      * @param {Boolean} notify
620      */
621     setPopupNotify:function (notify) {
622         cc.popupNotify = notify;
623     },
624 
625     /**
626      * Get whether pop-up a message box when the image load failed
627      * @return {Boolean}
628      */
629     isPopupNotify:function () {
630         return cc.popupNotify;
631     },
632 
633     _resourceRootPath:"",
634     getResourceRootPath:function () {
635         return this._resourceRootPath;
636     },
637 
638     setResourceRootPath:function (resourceRootPath) {
639         this._resourceRootPath = resourceRootPath;
640     },
641 
642     /**
643      * Gets the new filename from the filename lookup dictionary.
644      * @param {String} filename
645      * @return {String|null}  The new filename after searching in the filename lookup dictionary. If the original filename wasn't in the dictionary, it will return the original filename.
646      * @private
647      */
648     _getNewFilename:function (filename) {
649         var newFileName = null;
650         var fileNameFound = this._filenameLookupDict ? this._filenameLookupDict[filename] : null;
651         if (!fileNameFound || fileNameFound.length === 0)
652             newFileName = filename;
653         else {
654             newFileName = fileNameFound;
655             cc.log("FOUND NEW FILE NAME: " + newFileName);
656         }
657         return newFileName;
658     },
659 
660     /**
661      * Gets full path for filename, resolution directory and search path.
662      * @param {String} filename
663      * @param {String} resourceDirectory
664      * @param {String} searchPath
665      * @return {String} The full path of the file. It will return an empty string if the full path of the file doesn't exist.
666      * @private
667      */
668     _getPathForFilename:function (filename, resourceDirectory, searchPath) {
669         var ret;
670         var resourceRootPath = this.getResourceRootPath(); //cc.Application.getInstance().getResourceRootPath();
671 
672         if (filename && (filename.length > 0) && (filename.indexOf('/') === 0 || filename.indexOf("\\") === 0)) {
673             ret = "";
674         } else if (resourceRootPath.length > 0) {
675             ret = resourceRootPath;
676             if (ret[ret.length - 1] != '\\' && ret[ret.length - 1] != '/')
677                 ret += "/";
678         } else {
679             ret = resourceRootPath;
680         }
681 
682         var file = filename;
683         var file_path = "";
684         var pos = filename.lastIndexOf('/');
685         if (pos != -1) {
686             file_path = filename.substr(0, pos + 1);
687             file = filename.substr(pos + 1);
688         }
689         var path = searchPath;
690         if (path.length > 0 && path.lastIndexOf('/') !== path.length - 1)
691             path += '/';
692         path += file_path;
693         path += resourceDirectory;
694         if (path.length > 0 && path.lastIndexOf("/") !== path.length - 1)
695             path += '/';
696         path += file;
697         ret += path;
698         return ret;
699     },
700 
701     /**
702      * Gets full path for the directory and the filename.
703      * @param {String} directory The directory contains the file we are looking for.
704      * @param {String} fileName The name of the file.
705      * @return {Boolean} The full path of the file, if the file can't be found, it will return an empty string.
706      * @private
707      */
708     _getFullPathForDirectoryAndFilename:function(directory, fileName){
709 
710     },
711 
712     /**
713      * <p>
714      *     Sets the array of search paths.                                                                                                                 <br/>
715      *                                                                                                                                                     <br/>
716      *     You can use this array to modify the search path of the resources.                                                                              <br/>
717      *     If you want to use "themes" or search resources in the "cache", you can do it easily by adding new entries in this array.                       <br/>
718      *                                                                                                                                                     <br/>
719      *     @note This method could access relative path and absolute path.                                                                                <br/>
720      *            If the relative path was passed to the vector, CCFileUtils will add the default resource directory before the relative path.             <br/>
721      *            For instance:                                                                                                                            <br/>
722      *              On Android, the default resource root path is "assets/".                                                                               <br/>
723      *              If "/mnt/sdcard/" and "resources-large" were set to the search paths vector,                                                           <br/>
724      *              "resources-large" will be converted to "assets/resources-large" since it was a relative path.
725      * </p>
726      * @see fullPathForFilename(const char*)
727      * @param {Array} searchPaths The array contains search paths.
728      */
729     setSearchPaths:function (searchPaths) {
730         var existDefaultRootPath = false;
731 
732         this._searchPathArray = [];
733         for (var i = 0; i < searchPaths.length; i++) {
734             var iter = searchPaths[i];
735 
736             var strPrefix;
737             var path;
738             if (!this.isAbsolutePath(iter)) { // Not an absolute path
739                 strPrefix = this._defaultResRootPath;
740             }
741             path = strPrefix + iter;
742             if (path.length > 0 && path[path.length - 1] != '/') {
743                 path += "/";
744             }
745             if (!existDefaultRootPath && path == this._defaultResRootPath) {
746                 existDefaultRootPath = true;
747             }
748             this._searchPathArray.push(path);
749         }
750 
751         if (!existDefaultRootPath) {
752             //cc.log("Default root path doesn't exist, adding it.");
753             this._searchPathArray.push(this._defaultResRootPath);
754         }
755 
756     },
757 
758     /**
759      * Add search path.
760      * @param {String} path
761      */
762     addSearchPath:function (path) {
763         var strPrefix;
764         if (!this.isAbsolutePath(path)) { // Not an absolute path
765             strPrefix = this._defaultResRootPath;
766         }
767         path = strPrefix + path;
768         if (path.length > 0 && path[path.length - 1] != '/') {
769             path += "/";
770         }
771         this._searchPathArray.push(path);
772     },
773 
774     /**
775      *  Gets the array of search paths.
776      *  @see fullPathForFilename(const char*).
777      *  @return {Array} The array of search paths.
778      */
779     getSearchPaths:function(){
780 
781     },
782 
783     /**
784      * Checks whether the path is an absolute path.
785      * @param {String} strPath The path that needs to be checked.
786      * @returns {boolean} true if it's an absolute path, otherwise it will return false.
787      */
788     isAbsolutePath:function (strPath) {
789         return (strPath[0] == '/');
790     }
791 });
792 
793 cc.s_SharedFileUtils = null;
794 /**
795  * Gets the instance of CCFileUtils.
796  * @returns {cc.FileUtils}
797  */
798 cc.FileUtils.getInstance = function () {
799     if (cc.s_SharedFileUtils == null) {
800         cc.s_SharedFileUtils = new cc.FileUtils();
801     }
802     return cc.s_SharedFileUtils;
803 };
804