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