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.length = 0;
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.onload = function (e) {
206                 var fileContents = xhr.responseText;
207                 if (fileContents) {
208                     selfPointer._fileDataCache[fileUrl] = selfPointer._stringConvertToArray(fileContents);
209                 } else {
210                     cc.Loader.getInstance().onResLoadingErr(fileUrl);
211                 }
212                 cc.Loader.getInstance().onResLoaded();
213             };
214         }
215         xhr.send(null);
216     },
217 
218     _loadBinaryFileData:function (fileUrl) {
219         var req = this._getXMLHttpRequest();
220         req.open('GET', fileUrl, false);
221         var arrayInfo = null;
222         if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
223             req.setRequestHeader("Accept-Charset", "x-user-defined");
224             req.send(null);
225             if (req.status != 200)
226                 return null;
227 
228             var fileContents = cc._convertResponseBodyToText(req["responseBody"]);
229             if (fileContents) {
230                 arrayInfo = this._stringConvertToArray(fileContents);
231                 this._fileDataCache[fileUrl] = arrayInfo;
232             }
233         } else {
234             if (req.overrideMimeType)
235                 req.overrideMimeType('text\/plain; charset=x-user-defined');
236             req.send(null);
237             if (req.status != 200)
238                 return null;
239 
240             arrayInfo = this._stringConvertToArray(req.responseText);
241             this._fileDataCache[fileUrl] = arrayInfo;
242         }
243         return arrayInfo;
244     },
245 
246     _stringConvertToArray:function (strData) {
247         if (!strData)
248             return null;
249 
250         var arrData = new Uint8Array(strData.length);
251         for (var i = 0; i < strData.length; i++) {
252             arrData[i] = strData.charCodeAt(i) & 0xff;
253         }
254         return arrData;
255     },
256 
257     unloadTextFileData:function (fileUrl) {
258         fileUrl = this.fullPathForFilename(fileUrl);
259         if (this._textFileCache.hasOwnProperty(fileUrl))
260             delete this._textFileCache[fileUrl];
261     },
262 
263     preloadTextFileData:function (fileUrl) {
264         fileUrl = this.fullPathForFilename(fileUrl);
265         var selfPointer = this;
266 
267         var xhr = this._getXMLHttpRequest();
268         xhr.open("GET", fileUrl, true);
269         if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
270             // IE-specific logic here
271             xhr.setRequestHeader("Accept-Charset", "utf-8");
272             xhr.onreadystatechange = function (event) {
273                 if (xhr.readyState == 4) {
274                     if (xhr.status == 200) {
275                         var fileContents = xhr.responseText;
276                         if (fileContents)
277                             selfPointer._textFileCache[fileUrl] = fileContents;
278                     } else {
279                         cc.Loader.getInstance().onResLoadingErr(fileUrl);
280                     }
281                     cc.Loader.getInstance().onResLoaded();
282                 }
283             };
284         } else {
285             if (xhr.overrideMimeType)
286                 xhr.overrideMimeType("text\/plain; charset=utf-8");
287             xhr.onload = function (e) {
288                 if (xhr.responseText) {
289                     selfPointer._textFileCache[fileUrl] = xhr.responseText;
290                 } else {
291                     cc.Loader.getInstance().onResLoadingErr(fileUrl);
292                 }
293                 cc.Loader.getInstance().onResLoaded();
294             };
295         }
296         xhr.send(null);
297     },
298 
299     _loadTextFileData:function (fileUrl) {
300         var req = this._getXMLHttpRequest();
301         req.open('GET', fileUrl, false);
302         var fileContents = null;
303         if (/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) {
304             req.setRequestHeader("Accept-Charset", "utf-8");
305         } else {
306             if (req.overrideMimeType)
307                 req.overrideMimeType('text\/plain; charset=utf-8');
308         }
309         req.send(null);
310         if (req.status != 200)
311             return null;
312 
313         fileContents = req.responseText;
314         if (fileContents) {
315             this._textFileCache[fileUrl] = fileContents;
316         }
317         return fileContents;
318     },
319 
320     /**
321      *  Gets resource file data
322      * @param {String} fileUrl The resource file name which contains the path.
323      * @returns {String}
324      */
325     getTextFileData:function (fileUrl) {
326         fileUrl = this.fullPathForFilename(fileUrl);
327         if (this._textFileCache.hasOwnProperty(fileUrl))
328             return this._textFileCache[fileUrl];
329         return this._loadTextFileData(fileUrl);
330     },
331 
332     /**
333      * Get resource file data from zip file
334      * @function
335      * @param {String} pszZipFilePath
336      * @param {String} fileName fileName The resource file name which contain the relative path of zip file
337      * @param {Number} size size If get the file data succeed the it will be the data size,or it will be 0
338      * @warning If you get the file data succeed,you must delete it after used.
339      * @deprecated
340      */
341     getFileDataFromZip:function (pszZipFilePath, fileName, size) {
342     },
343 
344     /**
345      * removes the HD suffix from a path
346      * @function
347      * @param {String} path
348      * @deprecated
349      */
350     removeSuffixFromFile:function (path) {
351     },
352 
353     //////////////////////////////////////////////////////////////////////////
354     // Notification support when getByteArrayFromFile from invalid file path.
355     //////////////////////////////////////////////////////////////////////////
356     /**
357      * Notification support when getByteArrayFromFile from invalid file path.
358      * @function
359      * @type {Boolean}
360      */
361     popupNotify:true,
362 
363     /**
364      * Generate the absolute path of the file.
365      * @function
366      * @param {String} pszRelativePath
367      * @return {String} The absolute path of the file.
368      * @warning We only add the ResourcePath before the relative path of the file. <br/>
369      * If you have not set the ResourcePath,the function add "/NEWPLUS/TDA_DATA/UserData/" as default.<br/>
370      * You can set ResourcePath by function void setResourcePath(const char *resourcePath);
371      */
372     fullPathFromRelativePath:function (pszRelativePath) {
373         return pszRelativePath;
374     },
375 
376     /**
377      * <p>
378      *      Returns the fullpath for a given filename.                                                                                                                             </br>
379      *      First it will try to get a new filename from the "filenameLookup" dictionary.                                                                                          </br>
380      *      If a new filename can't be found on the dictionary, it will use the original filename.                                                                                 </br>
381      *      Then it will try obtain the full path of the filename using the CCFileUtils search rules:  resources directory and search paths.                                       </br>
382      *      The file search is based on the array element order of search paths and resolution directories.                                                                        </br>
383      *                                                                                                                                                                             </br>
384      *      For instance:                                                                                                                                                          </br>
385      *                                                                                                                                                                             </br>
386      *          We set two elements("/mnt/sdcard/", "internal_dir/") to search paths vector by setSearchPaths,                                                                     </br>
387      *          and set three elements("resources-ipadhd/", "resources-ipad/", "resources-iphonehd")                                                                               </br>
388      *          to resolutions vector by setSearchResolutionsOrder. The "internal_dir" is relative to "Resources/".                                                                </br>
389      *                                                                                                                                                                             </br>
390      *          If we have a file named 'sprite.png', the mapping in fileLookup dictionary contains `key: sprite.png -> value: sprite.pvr.gz`.                                     </br>
391      *          Firstly, it will replace 'sprite.png' with 'sprite.pvr.gz', then searching the file sprite.pvr.gz as follows:                                                      </br>
392      *              /mnt/sdcard/resources-ipadhd/sprite.pvr.gz      (if not found, search next)                                                                                    </br>
393      *              /mnt/sdcard/resources-ipad/sprite.pvr.gz        (if not found, search next)                                                                                    </br>
394      *              /mnt/sdcard/resources-iphonehd/sprite.pvr.gz    (if not found, search next)                                                                                    </br>
395      *              /mnt/sdcard/sprite.pvr.gz                       (if not found, search next)                                                                                    </br>
396      *              internal_dir/resources-ipadhd/sprite.pvr.gz     (if not found, search next)                                                                                    </br>
397      *              internal_dir/resources-ipad/sprite.pvr.gz       (if not found, search next)                                                                                    </br>
398      *              internal_dir/resources-iphonehd/sprite.pvr.gz   (if not found, search next)                                                                                    </br>
399      *              internal_dir/sprite.pvr.gz                      (if not found, return "sprite.png")                                                                            </br>
400      *                                                                                                                                                                             </br>
401      *         If the filename contains relative path like "gamescene/uilayer/sprite.png",                                                                                         </br>
402      *         and the mapping in fileLookup dictionary contains `key: gamescene/uilayer/sprite.png -> value: gamescene/uilayer/sprite.pvr.gz`.                                    </br>
403      *         The file search order will be:                                                                                                                                      </br>
404      *              /mnt/sdcard/gamescene/uilayer/resources-ipadhd/sprite.pvr.gz      (if not found, search next)                                                                  </br>
405      *              /mnt/sdcard/gamescene/uilayer/resources-ipad/sprite.pvr.gz        (if not found, search next)                                                                  </br>
406      *              /mnt/sdcard/gamescene/uilayer/resources-iphonehd/sprite.pvr.gz    (if not found, search next)                                                                  </br>
407      *              /mnt/sdcard/gamescene/uilayer/sprite.pvr.gz                       (if not found, search next)                                                                  </br>
408      *              internal_dir/gamescene/uilayer/resources-ipadhd/sprite.pvr.gz     (if not found, search next)                                                                  </br>
409      *              internal_dir/gamescene/uilayer/resources-ipad/sprite.pvr.gz       (if not found, search next)                                                                  </br>
410      *              internal_dir/gamescene/uilayer/resources-iphonehd/sprite.pvr.gz   (if not found, search next)                                                                  </br>
411      *              internal_dir/gamescene/uilayer/sprite.pvr.gz                      (if not found, return "gamescene/uilayer/sprite.png")                                        </br>
412      *                                                                                                                                                                             </br>
413      *         If the new file can't be found on the file system, it will return the parameter pszFileName directly.                                                               </br>
414      *                                                                                                                                                                             </br>
415      *         This method was added to simplify multiplatform support. Whether you are using cocos2d-js or any cross-compilation toolchain like StellaSDK or Apportable,          </br>
416      *         you might need to load different resources for a given file in the different platforms.
417      * </p>
418      * @param {String} filename
419      * @return {String} full path for a given filename.
420      */
421     fullPathForFilename:function (filename) {
422         var found = false;
423 
424         var newFileName = this._getNewFilename(filename);
425         var fullPath;
426 
427         //if (newFileName && newFileName.length > 1)
428         //    return newFileName;
429 
430         for (var i = 0; i < this._searchPathArray.length; i++) {
431             var searchPath = this._searchPathArray[i];
432             for (var j = 0; j < this._searchResolutionsOrderArray.length; j++) {
433                 var resourceDirectory = this._searchResolutionsOrderArray[j];
434                 fullPath = this._getPathForFilename(newFileName, resourceDirectory, searchPath);
435                 if (fullPath) {
436                     found = true;
437                     break;
438                 }
439             }
440             if (found)
441                 break;
442         }
443 
444         return found ? fullPath : newFileName;
445     },
446 
447     /**
448      * <p>
449      *     Loads the filenameLookup dictionary from the contents of a filename.                                        <br/>
450      *                                                                                                                 <br/>
451      *     @note The plist file name should follow the format below:                                                   <br/>
452      *     <?xml version="1.0" encoding="UTF-8"?>                                                                      <br/>
453      *         <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">  <br/>
454      *             <plist version="1.0">                                                                               <br/>
455      *                 <dict>                                                                                          <br/>
456      *                     <key>filenames</key>                                                                        <br/>
457      *                     <dict>                                                                                      <br/>
458      *                         <key>sounds/click.wav</key>                                                             <br/>
459      *                         <string>sounds/click.caf</string>                                                       <br/>
460      *                         <key>sounds/endgame.wav</key>                                                           <br/>
461      *                         <string>sounds/endgame.caf</string>                                                     <br/>
462      *                         <key>sounds/gem-0.wav</key>                                                             <br/>
463      *                         <string>sounds/gem-0.caf</string>                                                       <br/>
464      *                     </dict>                                                                                     <br/>
465      *                     <key>metadata</key>                                                                         <br/>
466      *                     <dict>                                                                                      <br/>
467      *                         <key>version</key>                                                                      <br/>
468      *                         <integer>1</integer>                                                                    <br/>
469      *                     </dict>                                                                                     <br/>
470      *                 </dict>                                                                                         <br/>
471      *              </plist>                                                                                           <br/>
472      * </p>
473      * @param {String} filename  The plist file name.
474      */
475     loadFilenameLookup:function (filename) {
476         var fullPath = this.fullPathForFilename(filename);
477         if (fullPath.length > 0) {
478             var dict = cc.SAXParser.getInstance().parse(fullPath);
479             var metadataDict = dict["metadata"];
480             var version = parseInt(metadataDict["version"]);
481             if (version != 1) {
482                 cc.log("cocos2d: ERROR: Invalid filenameLookup dictionary version: " + version + ". Filename: " + filename);
483                 return;
484             }
485             this.setFilenameLookupDictionary(dict["filenames"]);
486         }
487     },
488 
489     /**
490      * Sets the filenameLookup dictionary.
491      * @param {Object} filenameLookupDict The dictionary for replacing filename.
492      */
493     setFilenameLookupDictionary:function (filenameLookupDict) {
494         this._filenameLookupDict = filenameLookupDict;
495     },
496 
497     /**
498      * Gets full path from a file name and the path of the reletive file.
499      * @param {String} filename The file name.
500      * @param {String} relativeFile The path of the relative file.
501      * @return {String} The full path.
502      */
503     fullPathFromRelativeFile:function (filename, relativeFile) {
504         var tmpPath;
505         if (filename) {
506             tmpPath = relativeFile.substring(0, relativeFile.lastIndexOf("/") + 1);
507             return tmpPath + filename;
508         }
509         else {
510             tmpPath = relativeFile.substring(0, relativeFile.lastIndexOf("."));
511             tmpPath = tmpPath + ".png";
512             return tmpPath;
513         }
514     },
515 
516     /**
517      * <p>
518      *     Sets the array that contains the search order of the resources.
519      * </p>
520      * @see getSearchResolutionsOrder(void), fullPathForFilename(const char*).
521      * @param {Array} searchResolutionsOrder
522      */
523     setSearchResolutionsOrder:function (searchResolutionsOrder) {
524         this._searchResolutionsOrderArray = searchResolutionsOrder;
525     },
526 
527     /**
528      * Gets the array that contains the search order of the resources.
529      * @see setSearchResolutionsOrder(), fullPathForFilename(const char*).
530      * @return {Array}
531      */
532     getSearchResolutionsOrder:function () {
533         return this._searchResolutionsOrderArray;
534     },
535 
536     /**
537      * <p>
538      *     Array of search paths.                                                                                                  <br/>
539      *     You can use this array to modify the search path of the resources.                                                      <br/>
540      *     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/>
541      *                                                                                                                                <br/>
542      *     By default it is an array with only the "" (empty string) element.                                                         <br/>
543      * </p>
544      * @param {Array} searchPaths
545      */
546     setSearchPath:function (searchPaths) {
547         this._searchPathArray = searchPaths;
548     },
549 
550     /**
551      * return Array of search paths.
552      * @return {Array}
553      */
554     getSearchPath:function () {
555         return this._searchPathArray;
556     },
557 
558     getResourceDirectory:function () {
559         return this._directory;
560     },
561 
562 
563     /**
564      * Set the ResourcePath,we will find resource in this path
565      * @function
566      * @param {String} resourcePath The absolute resource path
567      * @warning Don't call this function in android and iOS, it has not effect.<br/>
568      * In android, if you want to read file other than apk, you shoud use invoke getByteArrayFromFile(), and pass the<br/>
569      * absolute path.
570      * @deprecated
571      */
572     setResourcePath:function (resourcePath) {
573     },
574 
575     /**
576      * Generate an Dictionary of object by file
577      * @deprecated
578      * @param fileName The file name of *.plist file
579      * @return {object} The Dictionary of object generated from the file
580      */
581     dictionaryWithContentsOfFile:function (fileName) {
582         cc.log("dictionaryWithContentsOfFile is deprecated. Use createDictionaryWithContentsOfFile instead");
583         return this.createDictionaryWithContentsOfFile(fileName);
584     },
585 
586     /**
587      * Generate an Dictionary of object by file
588      * @param filename The file name of *.plist file
589      * @return {object} The Dictionary of object generated from the file
590      */
591     createDictionaryWithContentsOfFile: function(filename){
592         return  cc.SAXParser.getInstance().parse(filename);
593     },
594 
595     /**
596      * get string  from file
597      * @function
598      * @param {String} fileName
599      * @return {String}
600      */
601     getStringFromFile:function (fileName) {
602         return this.getTextFileData(fileName); //cc.SAXParser.getInstance().getList(fileName);
603     },
604 
605     /**
606      * The same meaning as dictionaryWithContentsOfFile(), but it doesn't call autorelease, so the invoker should call release().
607      * @function
608      * @param {String} fileName
609      * @return {object} The Dictionary of object generated from the file
610      */
611     dictionaryWithContentsOfFileThreadSafe:function (fileName) {
612         return cc.SAXParser.getInstance().parse(fileName);
613     },
614 
615     /**
616      * Get the writeable path
617      * @return {String}  The path that can write/read file
618      * @deprecated
619      */
620     getWritablePath:function () {
621         return "";
622     },
623 
624     /**
625      * Set whether pop-up a message box when the image load failed
626      * @param {Boolean} notify
627      */
628     setPopupNotify:function (notify) {
629         cc.popupNotify = notify;
630     },
631 
632     /**
633      * Get whether pop-up a message box when the image load failed
634      * @return {Boolean}
635      */
636     isPopupNotify:function () {
637         return cc.popupNotify;
638     },
639 
640     _resourceRootPath:"",
641     getResourceRootPath:function () {
642         return this._resourceRootPath;
643     },
644 
645     setResourceRootPath:function (resourceRootPath) {
646         this._resourceRootPath = resourceRootPath;
647     },
648 
649     /**
650      * Gets the new filename from the filename lookup dictionary.
651      * @param {String} filename
652      * @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.
653      * @private
654      */
655     _getNewFilename:function (filename) {
656         var newFileName = null;
657         var fileNameFound = this._filenameLookupDict ? this._filenameLookupDict[filename] : null;
658         if (!fileNameFound || fileNameFound.length === 0)
659             newFileName = filename;
660         else {
661             newFileName = fileNameFound;
662             cc.log("FOUND NEW FILE NAME: " + newFileName);
663         }
664         return newFileName;
665     },
666 
667     /**
668      * Gets full path for filename, resolution directory and search path.
669      * @param {String} filename
670      * @param {String} resourceDirectory
671      * @param {String} searchPath
672      * @return {String} The full path of the file. It will return an empty string if the full path of the file doesn't exist.
673      * @private
674      */
675     _getPathForFilename:function (filename, resourceDirectory, searchPath) {
676         var ret;
677         var resourceRootPath = this.getResourceRootPath(); //cc.Application.getInstance().getResourceRootPath();
678 
679         if (filename && (filename.length > 0) && (filename.indexOf('/') === 0 || filename.indexOf("\\") === 0)) {
680             ret = "";
681         } else if (resourceRootPath.length > 0) {
682             ret = resourceRootPath;
683             if (ret[ret.length - 1] != '\\' && ret[ret.length - 1] != '/')
684                 ret += "/";
685         } else {
686             ret = resourceRootPath;
687         }
688 
689         var file = filename;
690         var file_path = "";
691         var pos = filename.lastIndexOf('/');
692         if (pos != -1) {
693             file_path = filename.substr(0, pos + 1);
694             file = filename.substr(pos + 1);
695         }
696         var path = searchPath;
697         if (path.length > 0 && path.lastIndexOf('/') !== path.length - 1)
698             path += '/';
699         path += file_path;
700         path += resourceDirectory;
701         if (path.length > 0 && path.lastIndexOf("/") !== path.length - 1)
702             path += '/';
703         path += file;
704         ret += path;
705         return ret;
706     },
707 
708     /**
709      * Gets full path for the directory and the filename.
710      * @param {String} directory The directory contains the file we are looking for.
711      * @param {String} fileName The name of the file.
712      * @return {Boolean} The full path of the file, if the file can't be found, it will return an empty string.
713      * @private
714      */
715     _getFullPathForDirectoryAndFilename:function(directory, fileName){
716 
717     },
718 
719     /**
720      * <p>
721      *     Sets the array of search paths.                                                                                                                 <br/>
722      *                                                                                                                                                     <br/>
723      *     You can use this array to modify the search path of the resources.                                                                              <br/>
724      *     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/>
725      *                                                                                                                                                     <br/>
726      *     @note This method could access relative path and absolute path.                                                                                <br/>
727      *            If the relative path was passed to the vector, CCFileUtils will add the default resource directory before the relative path.             <br/>
728      *            For instance:                                                                                                                            <br/>
729      *              On Android, the default resource root path is "assets/".                                                                               <br/>
730      *              If "/mnt/sdcard/" and "resources-large" were set to the search paths vector,                                                           <br/>
731      *              "resources-large" will be converted to "assets/resources-large" since it was a relative path.
732      * </p>
733      * @see fullPathForFilename(const char*)
734      * @param {Array} searchPaths The array contains search paths.
735      */
736     setSearchPaths:function (searchPaths) {
737         var existDefaultRootPath = false;
738 
739         var locPathArray = this._searchPathArray;
740         locPathArray.length = 0;
741         for (var i = 0; i < searchPaths.length; i++) {
742             var iter = searchPaths[i];
743 
744             var strPrefix;
745             var path;
746             if (!this.isAbsolutePath(iter)) { // Not an absolute path
747                 strPrefix = this._defaultResRootPath;
748             }
749             path = strPrefix + iter;
750             if (path.length > 0 && path[path.length - 1] != '/') {
751                 path += "/";
752             }
753             if (!existDefaultRootPath && path == this._defaultResRootPath) {
754                 existDefaultRootPath = true;
755             }
756             locPathArray.push(path);
757         }
758 
759         if (!existDefaultRootPath) {
760             //cc.log("Default root path doesn't exist, adding it.");
761             locPathArray.push(this._defaultResRootPath);
762         }
763     },
764 
765     /**
766      * Add search path.
767      * @param {String} path
768      */
769     addSearchPath:function (path) {
770         var strPrefix;
771         if (!this.isAbsolutePath(path)) { // Not an absolute path
772             strPrefix = this._defaultResRootPath;
773         }
774         path = strPrefix + path;
775         if (path.length > 0 && path[path.length - 1] != '/') {
776             path += "/";
777         }
778         this._searchPathArray.push(path);
779     },
780 
781     /**
782      *  Gets the array of search paths.
783      *  @see fullPathForFilename(const char*).
784      *  @return {Array} The array of search paths.
785      */
786     getSearchPaths:function(){
787 
788     },
789 
790     /**
791      * Checks whether the path is an absolute path.
792      * @param {String} strPath The path that needs to be checked.
793      * @returns {boolean} true if it's an absolute path, otherwise it will return false.
794      */
795     isAbsolutePath:function (strPath) {
796         return (strPath[0] == '/');
797     }
798 });
799 
800 cc.s_SharedFileUtils = null;
801 /**
802  * Gets the instance of CCFileUtils.
803  * @returns {cc.FileUtils}
804  */
805 cc.FileUtils.getInstance = function () {
806     if (cc.s_SharedFileUtils == null) {
807         cc.s_SharedFileUtils = new cc.FileUtils();
808     }
809     return cc.s_SharedFileUtils;
810 };
811