1 /*
  2  * This is system cordova_plugin (TV specific API).
  3  * Apache License (2004). See http://www.apache.org/licenses/LICENSE-2.0
  4  *
  5  * Copyright (c) 2014, LG Electronics, Inc.
  6  */
  7 
  8 
  9 /**
 10  * This represents the FileManager API itself, and provides a global namespace for operating FileManager service.
 11  * FileManager will be used to manage files in internal memory.
 12  * 
 13  * To locate a resource for file system APIs, SCAP URI is used.
 14  * SCAP URI has following format.
 15  * 
 16  * @class
 17  */
 18 
 19 cordova.define('cordova/plugin/storage', function (require, exports, module) { // jshint ignore:line
 20     var service;
 21     function log(msg) {
 22         //    //console.log//will be removed // jshint ignore:line
 23     }
 24     if (window.PalmSystem) { // jshint ignore:line
 25         log("Window.PalmSystem Available");
 26         service = require('cordova/plugin/webos/service');
 27     }
 28     else {
 29         service = {
 30             Request: function (uri, params) {
 31                 log(uri + " invoked. But I am a dummy because PalmSystem is not available");
 32                 if (typeof params.onFailure === 'function') {
 33                     params.onFailure({
 34                         returnValue: false,
 35                         errorText: "PalmSystem Not Available. Cordova is not installed?"
 36                     });
 37                 }
 38             }
 39         };
 40     }
 41 
 42     function isValidFileURI(uri) {
 43         if (uri) {
 44             // Length of URI should be less than 256
 45             if (uri.length > 256) {
 46                 log("URI IS TOO LONG" + uri.length);
 47                 return false;
 48             }
 49             else {
 50                 // Only acceptable characters for filename is Alphanumeric and -_.
 51                 var pathandhost = uri.substring(uri.indexOf("://") + "://".length);
 52                 var path = pathandhost.substring(pathandhost.indexOf("/"));
 53                 var regex = new RegExp(/^[a-zA-Z0-9-_\/\.]*$/g);
 54                 var ret = regex.exec(path);
 55                 if (ret) {
 56                     log("GOOD URI");
 57                     return true;
 58                 }
 59                 else {
 60                     log("INVALID URI" + uri);
 61                     return false;
 62                 }
 63             }
 64         }
 65         else {
 66             log("NO URI" + uri);
 67             return false;
 68         }
 69 
 70     }
 71 	
 72 	
 73 	/**
 74 	 * storage interface
 75 	 */
 76     var Storage = function () {
 77     };
 78 
 79 	/**
 80 	 * @namespace Error
 81 	 */
 82     Error.ERROR_CODE = {
 83         /**
 84          * There was an error while doing a file IO.
 85          * @since 1.3
 86          * @constant
 87          */
 88         IO_ERROR: "IO_ERROR",
 89 
 90         /**
 91          * There was an error while accessing external storage devices.
 92          * @since 1.3
 93          * @constant
 94          */
 95         DEVICE_ERROR: "DEVICE_ERROR",
 96         
 97         /**
 98          * The input parameter has error.
 99          * @since 1.3
100          * @constant
101          */
102         BAD_PARAMETER: "BAD_PARAMETER",
103 
104         /**
105          * The remote server returned error.
106          * @since 1.3
107          * @constant
108          */
109         SERVER_ERROR: "SERVER_ERROR",
110 
111         /**
112          * The network has error connecting to the remote site.
113          * @since 1.3
114          * @constant
115          */
116         NETWORK_ERROR: "NETWORK_ERROR",
117 
118         /**
119          * The signage monitor system had error while executing the command.
120          * @since 1.3
121          * @constant
122          */
123         SYSTEM_ERROR: "SYSTEM_ERROR",
124     };
125 	
126 	/**
127 	 * <p>
128 	 * This section describes the SCAP URI to locate resources for the SCAP strorage APIs.
129 	 * SCAP URI follows the syntax of a standard URI. 	  
130 	 * </p>
131 	 * <p>
132 	 * Those restrictions are applied to the SCAP URI.
133 	 * <ul>
134 	 * <li> If the protocol for the URI is file://, then allowd charecter sets are [a-zA-Z0-9-._]</li>
135 	 * <li> URI cannot be longer than a 256 length string </li>
136 	 * </ul>
137 	 * </p>
138 	 * 
139 	 * Those are formats that are recognized by SCAP storage APIs.
140 	 * <p>
141 	 * <div align=left>
142 	 * <table class="hcap_spec" width=400>
143 	 *   <thead><tr><th>Name</th><th>Description</th></tr></thead>
144 	 *   <tbody>
145 	 *       <tr>
146 	 *       	<th>file://internal/</th>
147 	 *       	<th>
148 	 *       	Locate to a file in internal memory space. No directories or files should be included in the path beyond root path.<br>
149 	 * 		 	If the path to the file destination is not found, directories for the file path will be automatically created.<br>
150 	 * 		 	Maximum length for a pathname is 255.	
151 	 *       	<p>(note: ../ is not allowed in the file path. '*' and '?' are also not supported.)</p>
152 	 *       	</th>
153 	 *       </tr>
154 	 *       <tr class="odd">
155 	 *       	<th>file://usb:[index]/</th>
156 	 *       	<th>
157 	 *       	Locate to a file in USB storage device at USB port:[index]. A USB storage device should be connected to the port.<br>
158 	 *       	If the path to the file destination is not found, directories for the file path will be automatically created.<br>
159 	 * 		 	Maximum length for a pathname is 255.	
160 	 *       	<p>(note: ../ is not allowed in the file path. '*' and '?' are also not supported.)</p> 
161 	 *       	</th>
162 	 *       </tr>
163 	 *       <tr>
164 	 *       	<th>file://sdcard:[index]/</th>
165 	 *       	<th>
166 	 *       	Locate to a file in SD card device at SD card port:[index]. A SD card storage device should be connected to the port.<br>
167 	 *       	If the path to the file destination is not found, directories for the file path will be automatically created.<br>
168 	 * 		 	Maximum length for a pathname is 255.	
169 	 *       	<p>(note: ../ is not allowed in the file path. '*' and '?' are also not supported.)</p> 
170 	 *       	</th>
171 	 *       </tr>
172 	 *       <tr  class="odd">
173 	 *       	<th>http://, https://</th>
174 	 *       	<th>
175 	 *       	Locate to a file in remote location. The file is downloaded using HTTP GET protocol. 
176 	 *       	Secure connection using https protocol is also supported.
177 	 *       	</th>
178 	 *       </tr>
179 	 *       <tr>
180 	 *       	<th>
181 	 *       	ftp:// (FTP)<br>
182 	 *       	sftp:// (FTP with SSH file transfer protocol)<br>
183 	 *       	ftps:// (FTP over SSL/TLS)<br>
184 	 *       	</th>
185 	 *       	<th>
186 	 *       	Locate to a file from FTP server. sftp (FTP with SSH file transfer) and ftps (FTP with SSL/TLS) is also supported.</br>
187 	 *       	Additional security option may be defined for sftp and ftps.</br>
188 	 *       	User name, password should be part of the URI if needed. </br>
189 	 *       	ex) ftp://user:password@my.ftp.site:21/path/to/file.txt
190 	 *       	If port number is not defined in URI, port number will be 21 (ftp or ftps) or 22 (sftp). </br>
191 	 *       	If auth is not defined in URI, 'anonymous:anonymous@' will be used if protocol is ftp/ftps. </br>
192 	 *       	</th>
193 	 *       </tr>
194 	 *   </tbody>
195 	 * </table>
196 	 * </div>
197 	 * </p>
198 	 * 
199 	 * Note : Copied files can be accessed by local/USB application from the "./content" directory of the local/USB application</br>
200 	 * Note : Copied files can be accessed from local http file server.(http://127.0.0.1:9080/[copied_filename]) </br>
201 	 * Note : Files that are copied to USB storage can be accessed from the local http file server.(http://127.0.0.1:9080/external/usb/[usb_port]) </br>
202 	 * TIP : If DNS server is not set in the monitor, accessing local file server using 'localhost' can take a long time to load the resource.
203 	 * Use '127.0.0.1' instead.
204 	 * 
205 	 * @namespace Storage.SCAP_URI
206 	 * @typedef string
207 	 */
208     Storage.SCAP_URI = "";
209 	
210 	/**
211 	 * Maximum buffer length for readFile/writeFile (10K)
212 	 * @constant
213 	 */
214     Storage.MAX_BUFFER_LENGTH = 1024 * 10;
215 
216 	/**
217 	 * @namespace Storage.AppMode
218 	 */
219     Storage.AppMode = {
220         /**
221          * USB
222          * @since 1.1
223          * @constant
224          */
225         USB: "usb",
226         /**
227          * local
228          * @since 1.1
229          * @constant
230          */
231         LOCAL: "local"
232     };
233 	
234 
235 	/**
236 	 * @namespace Storage.AppType
237 	 */
238     Storage.AppType = {
239         /**
240          * IPK App
241          * @since 1.4.1
242          * @constant
243          */
244         IPK: "ipk",
245         /**
246          * ZIP App
247          * @since 1.4.1
248          * @constant
249          */
250         ZIP: "zip"
251     };
252 	/**
253 	 * <p>
254 	 * Downloads firmware from remote server using 'http' or 'https' protocol. 
255 	 * Before downloading, check the free storage size of the platform using Storage.getStorageInfo(). <br>
256 	 * Received firmware file will be deleted after upgrade is completed by calling Storage.upgradeFirmware(), which in turn results in monitor reboot. <br> 
257 	 * After reboot, stored firmware file will be deleted even if Storage.upgradeFirmware() was not called, so if wrong firmware file was downloaded, 
258 	 * just reboot the monitor without calling Storage.upgradeFirmware() to delete it.
259 	 * </p>
260 	 * 
261 	 * @example
262 	 * 
263 	 * function downloadFirmware() {
264 	 *    var successCb = function () { 
265 	 *      console.log("Download firmware is successful"); 
266 	 *    };
267 	 * 
268 	 *    var failureCb = function(cbObject) { 
269 	 *      var errorCode = cbObject.errorCode;
270 	 *      var errorText = cbObject.errorText; 
271 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
272 	 *    };
273 	 * 
274 	 *    var options = {
275 	 *       uri : "http://example.org/firmware.10-01.00.10_usb_V3_SECURED.epk"
276 	 *    };
277 	 *    
278 	 *    var storage = new Storage(); 
279 	 *    storage.downloadFirmware(successCb, failureCb, options);
280 	 *    
281 	 * }
282 	 * 
283 	 * 
284 	 * @class storage
285 	 * @param {Function}
286 	 *            successCallback success callback function.
287 	 * @param {Function}
288 	 *            errorCallback failure callback function.
289 	 * @param {Object} options
290 	 * <div align=left>
291 	 * <table class="hcap_spec" width=400>
292 	 *   <thead><tr><th>Property</th><th>Type</th><th>Description</th><th>Required</th></tr></thead>
293 	 *   <tbody>
294 	 *       <tr><th>uri</th><th>String</th><th>URI for the firmware(in http or https)</a></th><th>required</th></tr>
295 	 *   </tbody>
296 	 * </table>
297 	 * </div>
298 	 * @returns
299 	 *            <p>
300 	 *            After the method is successfully executed, successCallback is called without any parameter.</br>
301 	 *            If an error occurs, errorCallback is called with errorCode and errorText as parameters.
302 	 *            </p>
303 	 * @since 1.2
304 	 * @see
305 	 * <a href="Storage%23upgradeFirmware.html">Storage.upgradeFirmware()</a>, 
306 	 * <a href="Storage%23getFirmwareUpgradeStatus.html">Storage.getFirmwareUpgradeStatus()</a><br>
307 	 */
308     Storage.prototype.downloadFirmware = function (successCallback, errorCallback, options) {
309 
310         service.Request("luna://com.webos.service.commercial.signage.storageservice", {
311             method: "downloadFirmware",
312             parameters: {
313                 uri: options.uri
314             },
315             onSuccess: function (result) {
316                 if (result.returnValue === true) {
317                     successCallback();
318                 }
319                 else {
320                     errorCallback({
321                         errorCode: result.errorCode,
322                         errorText: result.errorText
323                     });
324                 }
325             },
326             onFailure: function (result) {
327                 errorCallback({
328                     errorCode: result.errorCode,
329                     errorText: result.errorText
330                 });
331             }
332         });
333     };
334 
335 	/**
336 	 * <p>
337 	 * Upgrades firmware using stored file which was downloaded by calling Storage.downloadFirmware(). 
338 	 * If upgrade is successful, the monitor will restart automatically. 
339 	 * 
340 	 * </p>
341 	 * 
342 	 * @example
343 	 * 
344 	 * function upgradeFirmware() {
345 	 *    var successCb = function () { 
346 	 *      console.log("firmware upgrade is successful"); 
347 	 *    };
348 	 * 
349 	 *    var failureCb = function(cbObject) { 
350 	 *      var errorCode = cbObject.errorCode;
351 	 *      var errorText = cbObject.errorText; 
352 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
353 	 *    };
354 	 * 
355 	 *    var storage = new Storage(); 
356 	 *    storage.upgradeFirmware(successCb, failureCb);
357 	 * }
358 	 * 
359 	 * @class storage
360 	 * @param {Function}
361 	 *            successCallback success callback function.
362 	 * @param {Function}
363 	 *            errorCallback failure callback function.
364 	 * @returns
365 	 *            <p>
366 	 *            After the method is successfully executed, successCallback is called without any parameter.</br>
367 	 *            If an error occurs, errorCallback is called with errorCode and errorText as parameters.
368 	 *            </p>
369 	 * @since 1.2
370 	 * @see
371 	 * <a href="Storage%23downloadFirmware.html">Storage.downloadFirmware()</a>, <a href="Storage%23getFirmwareUpgradeStatus.html">Storage.getFirmwareUpgradeStatus()</a><br>
372 	 */
373     Storage.prototype.upgradeFirmware = function (successCallback, errorCallback) {
374 
375         service.Request("luna://com.webos.service.commercial.signage.storageservice", {
376             method: "upgradeFirmware",
377             parameters: {},
378             onSuccess: function (result) {
379                 if (result.returnValue === true) {
380                     successCallback();
381                 }
382                 else {
383                     errorCallback({
384                         errorCode: result.errorCode,
385                         errorText: result.errorText
386                     });
387                 }
388             },
389             onFailure: function (result) {
390                 errorCallback({
391                     errorCode: result.errorCode,
392                     errorText: result.errorText
393                 });
394             }
395         });
396     };
397 
398 	/**
399 	 * <p>
400 	 * Gets the status of firmware upgrading. 
401 	 * 
402 	 * </p>
403 	 * 
404 	 * @example
405 	 * 
406 	 * function getFirmwareUpgradeStatus() {
407 	 *    var successCb = function (cbObject) { 
408 	 *      console.log("status " + cbObject.status);
409 	 *      console.log("upgradeProgress " + cbObject.upgradeProgress); 
410 	 *      console.log("downloadProgress " + cbObject.downloadProgress);
411 	 *    };
412 	 * 
413 	 *    var failureCb = function(cbObject) { 
414 	 *      var errorCode = cbObject.errorCode;
415 	 *      var errorText = cbObject.errorText; 
416 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
417 	 *    };
418 	 * 
419 	 *    var storage = new Storage(); 
420 	 *    storage.getFirmwareUpgradeStatus(successCb, failureCb);
421 	 * 
422 	 * }
423 	 * 
424 	 * @class storage
425 	 * @param {Function}
426 	 *            successCallback success callback function.
427 	 * @param {Function}
428 	 *            errorCallback failure callback function.
429 	 * @return {Object} 
430 	 * <div align=left>
431 	 * <table class="hcap_spec" width=400>
432 	 *   <thead><tr><th>Property</th><th>Type</th><th>Description</th></tr></thead>
433 	 *   <tbody>
434      *       <tr><th>status</th><th>String</th><th>idle | downloading | ready | in progress | completed | fail</a></th></tr>
435      *       <tr class="odd"><th>downloadProgress</th><th>Number</th><th> 0 ~ 100 </a></th></tr>
436      *       <th>upgradeProgress</th><th>Number</th><th> 0 ~ 100 </a></th></tr>
437 	 *   </tbody>
438 	 * </table>
439 	 * </div>
440 	 * @since 1.2
441 	 * @see
442 	 * <a href="Storage%23downloadFirmware.html">Storage.downloadFirmware()</a>, 
443 	 * <a href="Storage%23upgradeFirmware.html">Storage.upgradeFirmware()</a></br>
444 	 */
445     Storage.prototype.getFirmwareUpgradeStatus = function (successCallback, errorCallback) {
446 
447         service.Request("luna://com.webos.service.commercial.signage.storageservice", {
448             method: "getFirmwareUpgradeStatus",
449             parameters: {},
450             onSuccess: function (result) {
451                 if (result.returnValue === true) {
452                     successCallback({
453                         status: result.status,
454                         upgradeProgress: result.upgradeProgress,
455                         downloadProgress: result.downloadProgress
456                     });
457                 }
458                 else {
459                     errorCallback({
460                         errorCode: result.errorCode,
461                         errorText: result.errorText
462                     });
463                 }
464             },
465             onFailure: function (result) {
466                 errorCallback({
467                     errorCode: result.errorCode,
468                     errorText: result.errorText
469                 });
470             }
471         });
472     };
473 
474 	/**
475 	 * <p>
476 	 * Changes monitor logo image. Image can be loaded from internal|USB memory, or retrieved from remote server using 'http' or 'https'.
477 	 * Logo image has following restrictions :  <br>
478 	 *  - format : JPG or BMP <br>
479 	 *  - max resolution : 1920x1080 <br>
480 	 *  - max file size : 8 Mbytes for BMP <br>
481 	 * </p>
482 	 * 
483 	 * @example
484 	 * 
485 	 * function changeLogoImage() {
486 	 *    var successCb = function () { 
487 	 *      console.log("Upgrading logo image is successful"); 
488 	 *    };
489 	 * 
490 	 *    var failureCb = function(cbObject) { 
491 	 *      var errorCode = cbObject.errorCode;
492 	 *      var errorText = cbObject.errorText; 
493 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
494 	 *    };
495 	 * 
496 	 *    var options = {
497 	 *       uri : "http://example.org/myImage.jpg"
498 	 *    };
499 	 * 
500 	 *    var storage = new Storage(); 
501 	 *    storage.changeLogoImage(successCb, failureCb, options);
502 	 * 
503 	 * }
504 	 * 
505 	 * @class storage
506 	 * @param {Function}
507 	 *            successCallback success callback function.
508 	 * @param {Function}
509 	 *            errorCallback failure callback function.
510 	 * @param {Object} options
511 	 * <div align=left>
512 	 * <table class="hcap_spec" width=400>
513 	 *   <thead><tr><th>Property</th><th>Type</th><th>Description</th><th>Required</th></tr></thead>
514 	 *   <tbody>
515 	 *       <tr><th>uri</th><th>String</th><th>URI for the logo image(http, https, file://internal or file://usb:[index])</a></th><th>required</th></tr>
516 	 *   </tbody>
517 	 * </table>
518 	 * </div>
519 	 * @returns
520 	 *            <p>
521 	 *            After the method is successfully executed, successCallback is called without any parameter.</br>
522 	 *            If an error occurs, errorCallback is called with errorCode and errorText as parameters.
523 	 *            </p>
524 	 * @since 1.2
525 	 * @see
526 	 * <a href="Storage%23upgradeFirmware.html">Storage.upgradeFirmware()</a><br>
527 	 */
528     Storage.prototype.changeLogoImage = function (successCallback, errorCallback, options) {
529 
530         service.Request("luna://com.webos.service.commercial.signage.storageservice", {
531             method: "changeLogoImage",
532             parameters: {
533                 uri: options.uri
534             },
535             onSuccess: function (result) {
536                 if (result.returnValue === true) {
537                     successCallback();
538                 }
539                 else {
540                     errorCallback({
541                         errorCode: result.errorCode,
542                         errorText: result.errorText
543                     });
544                 }
545             },
546             onFailure: function (result) {
547                 errorCallback({
548                     errorCode: result.errorCode,
549                     errorText: result.errorText
550                 });
551             }
552         });
553     };
554 
555 	/**
556 	 * <p>
557 	 * Upgrades application stored in local or USB using the one from remote server. 
558 	 * Remote server information(serverIP and serverPort) is set in display menu.<br>
559 	 * New application will be launched at next boot time and old application will be deleted at the same time. 
560 	 * Application on the server should be at <br> 
561 	 * "http://serverIP:serverPort/procentric/scap/application/scap_app.zip".
562 	 * <br>
563 	 * Note : Size of scap_app.zip (zip file itself and extracted files) should not exceed free storage size of the platform.<br>
564 	 * When application is being upgraded, following files exist at the same time : <br>
565 	 *    - old application <br>
566 	 *    - downloaded scap_app.zip <br> 
567 	 *    - content data stored by storage.copyFile() API and <br> 
568 	 *    - new application extracted from the downloaded scap_app.zip <br>
569 	 * So before upgrading the application, call storage.getStorageInfo() and check the free storage size. <br>
570 	 * <br>
571 	 * Note : Application should not include 'content' directory under application's root folder. <br>
572 	 * (It is reserved for Storage.copyFile() API.)
573 	 * 
574 	 * </p>
575 	 * 
576 	 * @example
577 	 * 
578 	 * function upgradeApplication() {
579 	 *    var successCb = function (cbObject) { 
580 	 *      console.log("Application Update successful"); 
581 	 *    };
582 	 * 
583 	 *    var failureCb = function(cbObject) { 
584 	 *      var errorCode = cbObject.errorCode;
585 	 *      var errorText = cbObject.errorText; console.log( " Error Code [" + errorCode + "]: " + errorText); 
586 	 *    };
587 	 * 
588 	 *    var options = {
589 	 *       to : Storage.AppMode.USB,
590 	 *       recovery : false
591 	 *    };   
592 	 *    
593 	 *    var storage = new Storage(); 
594 	 *    storage.upgradeApplication(successCb, failureCb, options);
595 	 * }
596 	 * 
597 	 * @class storage
598 	 * @param {Function}
599 	 *            successCallback success callback function.
600 	 * @param {Function}
601 	 *            errorCallback failure callback function.
602 	 * @param {Object} options
603 	 * <div align=left>
604 	 * <table class="hcap_spec" width=400>
605 	 *   <thead><tr><th>Property</th><th>Type</th><th>Description</th><th>Required</th></tr></thead>
606 	 *   <tbody>
607 	 *       <tr><th>to</th><th>String</th><th><a href="Storage.AppMode.html#constructor">Storage.AppMode</a></th><th>required</th></tr>
608 	 *       <tr><th>type</th><th>String</th><th><a href="Storage.AppType.html#constructor">Storage.AppType</a><br>if there is no value, it will use application type value of 8080 server ui</th><th>optional</th></tr>
609 	 *       <tr class="odd"><tr><th>recovery</th><th>Boolean</th><th>true : Recover old application if there was an error during upgrade. Default value.<br>
610 	 *       false : Remove old application to obtain free storage space.</a></th><th>optional</th></tr>	 
611 	 *       
612 	 *   </tbody>
613 	 * </table>
614 	 * </div>
615 	 * @returns
616 	 *            <p>
617 	 *            After the method is successfully executed, successCallback is called without any parameter.</br>
618 	 *            If an error occurs, errorCallback is called with errorCode and errorText.
619 	 *            </p>
620 	 * @since 1.0
621 	 * @since 1.1 options.to options.recovery added
622 	 * @see
623 	 * <a href="Storage%23removeApplication.html">Storage.removeApplication()</a><br>
624 	 */
625     Storage.prototype.upgradeApplication = function (successCallback, errorCallback, options) {
626 
627 		var param = {
628 			from: 'remote',
629 			to: (options === undefined || options === null ? Storage.AppMode.LOCAL : options.to),
630 			recovery: (options === undefined || options === null ? false : options.recovery),			
631 		};
632 
633     	if(options.hasOwnProperty('type') === true && options.type !== undefined)
634     		param.type = options.type;
635 
636         service.Request("luna://com.webos.service.commercial.signage.storageservice", {
637             method: "upgradeApplication",
638             parameters: param,
639             onSuccess: function (result) {
640                 if (result.returnValue === true) {
641 					successCallback();
642                 }
643                 else {
644                     errorCallback({
645                         errorCode: result.errorCode,
646                         errorText: result.errorText
647                     });
648                 }
649             },
650             onFailure: function (result) {
651                 errorCallback({
652                     errorCode: result.errorCode,
653                     errorText: result.errorText
654                 });
655             }
656         });
657 
658     };
659 
660 	/**
661 	 * <p>
662 	 * Removes application stored in local or USB storage.<br>
663 	 * 
664 	 * Current running application can't remove itself using this API.<br>
665 	 * (e.g. Application running from USB cannot remove itself using this API)
666 	 * 
667 	 * </p>
668 	 * 
669 	 * @example
670 	 * 
671 	 * function removeApplication() {
672 	 *    var successCb = function (cbObject) { 
673 	 *      console.log("Application removes successfully"); 
674 	 *    };
675 	 * 
676 	 *    var failureCb = function(cbObject) { 
677 	 *      var errorCode = cbObject.errorCode;
678 	 *      var errorText = cbObject.errorText; 
679 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
680 	 *    };
681 	 * 
682 	 *    var options = { 
683 	 *       to : Storage.AppMode.LOCAL
684 	 *    };   
685 	 *     
686 	 *    var storage = new Storage(); 
687 	 *    storage.removeApplication(successCb, failureCb, options);
688 	 * }
689 	 * 
690 	 * @class storage
691 	 * @param {Function}
692 	 *            successCallback success callback function.
693 	 * @param {Function}
694 	 *            errorCallback failure callback function.
695 	 * @param {Object} options
696 	 * <div align=left>
697 	 * <table class="hcap_spec" width=400>
698 	 *   <thead><tr><th>Property</th><th>Type</th><th>Description</th><th>Required</th></tr></thead>
699 	 *   <tbody>
700 	 *       <tr><th>to</th><th>String</th><th><a href="Storage.AppMode.html#constructor">Storage.AppMode</a></th><th>required</th></tr>
701 	 *   </tbody>
702 	 * </table>
703 	 * </div>
704 	 * @returns
705 	 *            <p>
706 	 *            After the method is successfully executed, successCallback is called without any parameter.</br>
707 	 *            If an error occurs, errorCallback is called with errorCode and errorText.
708 	 *            </p>
709 	 * @since 1.1
710 	 * @see
711 	 * <a href="Storage%23upgradeApplication.html">Storage.upgradeApplication()</a><br>
712 	 */
713 
714     Storage.prototype.removeApplication = function (successCallback, errorCallback, options) {
715 
716         service.Request("luna://com.webos.service.commercial.signage.storageservice", {
717             method: "removeApplication",
718             parameters: {
719                 to: options.to
720             },
721             onSuccess: function (result) {
722                 if (result.returnValue === true) {
723                     successCallback();
724                 } else {
725                     errorCallback({
726                         errorCode: result.errorCode,
727                         errorText: result.errorText
728                     });
729                 }
730             },
731             onFailure: function (result) {
732                 errorCallback({
733                     errorCode: result.errorCode,
734                     errorText: result.errorText
735                 });
736             }
737         });
738     };
739 
740 
741 	/**
742 	 * <p>
743 	 * Copies file.
744 	 * File can be copied from internal, external memory, or remote site to internal, external memory, or a remote FTP site.</br>
745 	 * </p>
746 	 * 
747 	 * @example 
748 	 * 
749 	 * function copyFile() {
750 	 *    var successCb = function (){
751 	 *      console.log("Copying File done.");
752 	 *    };
753 	 * 
754 	 *    var failureCb = function(cbObject){ 
755 	 *      var errorCode = cbObject.errorCode;
756 	 *      var errorText = cbObject.errorText; 
757 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
758 	 *    };
759 	 * 
760 	 *    // Copy local file in internal memory to another location in internal memory.
761 	 *    var options_local_to_local = { 
762 	 *      source: 'file://internal/copy_me.txt',
763 	 *      destination : 'file://internal/copy/to/here.txt'
764 	 *    };
765 	 * 
766 	 *    var storage = new Storage();
767 	 *    storage.copyFile(successCb, failureCb, options_local_to_local);
768 	 * 
769 	 *    // Copy remote file to internal memory.
770 	 *    // Then set the file as he source for an image tag.
771 	 *    var options_remote_to_local = { 
772 	 *      source : 'http://remote.file.site/copy_me.txt',
773 	 *      destination : 'file://internal/copy/to/here.txt'
774 	 *    }; 
775 	 * 
776 	 *    storage.copyFile(successCb, failureCb, options_remote_to_local);
777 	 *          
778 	 *    // Copy file from USB memory at port 1 to internal memory.
779 	 *    var options_usb_to_local = { 
780 	 *      source : 'file://usb:1/from/copy_me.txt',
781 	 *      destination : 'file://internal/copy/to/here.txt'
782 	 *    };
783 	 * 
784 	 *    storage.copyFile(
785 	 *      function() {	// Success Call back. Set the copied file as image source.
786 	 *         var imgElement = document.getElementById('myImage');
787 	 *         imgElement.src = 'http://127.0.0.1:9080/copy/to/here.jpg';
788 	 *      },
789 	 *      failureCb, options_usb_to_local);
790 	 * 
791 	 *    // download remote file and copy to USB storage at port 1.
792 	 *    // Then set the file as he source for an image tag.
793 	 *    var options_remote_to_usb = { 
794 	 *      source : 'http://remote.file.site/copy_me.jpg',
795 	 *      destination : 'file://usb:1/copy/to/here.jpg'
796 	 *    };
797 	 * 
798 	 *    storage.copyFile(
799 	 *      function() {	// Success Call back. Set the copied file as image source.
800 	 *         var imgElement = document.getElementById('myImage');
801 	 *         imgElement.src = 'http://127.0.0.1:9080/external/usb/1/copy/to/here.jpg';
802 	 *      },
803 	 *      failureCb, options_remote_to_usb);
804 	 * 
805 	 * 
806 	 *    // Copy file from redirected server.
807 	 *    var options_redirect = { 
808 	 *      source : 'http://remote.site.that.will.redirect/copy_me.txt',
809 	 *      destination : 'file://usb:1/copy/to/here.txt',
810 	 *      maxRedirection: 5
811 	 *    };
812 	 * 
813 	 *    storage.copyFile(successCb, failureCb, options_redirect);
814 	 *    
815 	 *    // Copy file from ftp server.
816 	 *    var options_ftp = { 
817 	 *      source : 'ftp://user:password@remote.ftp.site/copy_me.txt',
818 	 *      destination : 'file://internal/copy/to/here.txt',
819 	 *    };
820 	 * 
821 	 *    storage.copyFile(successCb, failureCb, options_ftp);
822 	 *    
823 	 *    // Copy internal file to  ftp server.
824 	 *    var options_ftp2 = { 
825 	 *      source : 'file://internal/send/me/away.txt',
826 	 *      destination : 'ftp://user:password@remote.ftp.site/sent.txt',
827 	 *    };
828 	 * 
829 	 *    storage.copyFile(successCb, failureCb, options_ftp2);
830 	 * }
831 	 * 
832 	 * @class storage
833 	 * @param {Function}
834 	 *            successCallback success callback function.
835 	 * @param {Function}
836 	 *            errorCallback failure callback function.
837 	 * @param {Object} options
838      * <div align=left>
839      * <table class="hcap_spec" width=400>
840      *   <thead><tr><th>Property</th><th>Type</th><th>Description</th><th>Required</th></tr></thead>
841      *   <tbody>
842      *       <tr><th>source</th><th>{@link Storage.SCAP_URI}</th><th>URI to the source file</a></th><th>required</th></tr>
843      *       <tr class="odd"><tr><th>destination</th><th>{@link Storage.SCAP_URI}</th><th>URI to the destination file. </a></th><th>required</th></tr>
844      *       <th>ftpOption</th><th>Object</th><th>FTP/SFTP options. Additional options for FTP setting.</th><th>optional</th></tr>
845      *       <tr class="odd"><tr><th>ftpOption.secureOptions</th><th>Object</th><th>secure FTP options</a></th><th>optional</th></tr>
846      *       <th>ftpOption.secureOptions.privateKey</th><th>String</th><th>Private key for either key-based or hostbased user authentication (OpenSSH format)</a></th><th>optional</th></tr>
847      *       <tr class="odd"><tr><th>ftpOption.secureOptions.passphrase</th><th>String</th><th>For an encrypted private key, this is the passphrase used to decrypt it</a></th><th>optional</th></tr>
848      *       <th>ftpOption.connTimeout</th><th>Number</th><th>How long (in milliseconds) to wait for the control connection to be established (default : 10000 ms)</a></th><th>optional</th></tr>
849      *       <tr class="odd"><tr><th>ftpOption.pasvTimeout</th><th>Number</th><th>How long (in milliseconds) to wait for a PASV data connection to be established (default : 10000 ms)</a></th><th>optional</th></tr>
850      *       <th>ftpOption.keepalive</th><th>Number</th><th>How often (in milliseconds) to send a 'dummy'(NOOP) command to keep the connection alive (default : 10000 ms)</a></th><th>optional</th></tr>       
851      *       <tr class="odd"><th>httpOption</th><th>Object</th><th>HTTP/HTTPS file copy options</th><th>optional</th></tr>
852      *       <th>httpOption.maxRedirection</th><th>Number</th><th>Maximum number of allowed redirections.</br> 
853      *       Default value is 0, which means no redirection is allowed.</br>Request will be redirected if the response code was 301,
854      *       302,303, or 307 and a valid location was found in the response header. </br> 
855      *       This option is ignored if the source file is not a remote file. Maximum number of redirection is 5.</th><th>optional</th></tr>       
856      *       <tr class="odd"><tr><th>httpOption.headers</th><th>Object</th>
857      *       <th>The [name : value] pairs that will be included in the HTTP request header, for remote file request. </br>
858      *       This header data will be cascaded during redirection. </br> 
859      *       Maximum size of header data that can be contained is 1KB. </br> 
860      *       </a></th><th>optional</th></tr>
861      *       <tr><th>httpOption.timeout</th><th>Number</th>
862      *       <th> Milliseconds before the underlying TCP connection times out. 0 is for no time out. Default value is 0.</br>
863      *       Note that if there is a server side timeout, copy file can timeout before the timeout value set by this option.
864      *       </th><th>optional</th></tr>
865      *   </tbody>
866      * </table>
867      * </div>
868      * 
869 	 * @returns
870 	 *            <p>
871 	 *            After the method is successfully executed, successCallback is called without any parameter.</br>
872 	 *            If an error occurs, errorCallback is called with errorCode and errorText. </br>
873 	 *            To see how error codes are defined, check {@link Error.ERROR_CODE}
874 	 *            </p>
875 	 * 
876 	 * @since 1.0 
877 	 * @since 1.1 access to local file from remote application
878 	 * @since 1.2 options.maxRedirection
879 	 * @since 1.3 options.ftpOption
880 	 * @since 1.3 options.maxRedirection moves to options.httpOption.maxRedirection
881 	 * @since 1.3 options.httpOption.headers
882 	 * @since 1.3 options.httpOption.timeout
883 	 */
884     Storage.prototype.copyFile = function (successCallback, errorCallback, options) {
885 
886         log("Options: " + JSON.stringify(options, null, 3));
887 
888         if (options.maxRedirection && options.maxRedirection > 5) {
889             log("Bad options TOO MANY REDIRECTION");
890             errorCallback({ errorCode: "BAD_PARAMETER", errorText: "Redirect cannot be more that 5" });
891             return;
892         }
893         if (options.headers && JSON.stringify(options.headers).length > 1024) {
894             log("header too long header too long");
895             errorCallback({ errorCode: "BAD_PARAMETER", errorText: "Header data cannot be bigger than 1K" });
896             return;
897         }
898 
899         if (typeof options.httpOption === 'undefined') {
900             options.httpOption = {};
901         }
902 
903         if (options.httpOption.headers && JSON.stringify(options.httpOption.headers).length > 1024) {
904             log("header too long header too long");
905             errorCallback({
906                 errorCode: "BAD_PARAMETER",
907                 errorText: "Header data cannot be bigger than 1K"
908             });
909             return;
910         }
911 		
912         if (options.maxRedirection || options.headers) {
913             if (options.maxRedirection && typeof options.httpOption.maxRedirection === 'undefined') {
914                 options.httpOption.maxRedirection = options.maxRedirection;
915             }
916             if (options.headers && typeof options.httpOption.headers === 'undefined') {
917                 options.httpOption.headers = options.headers;
918             }
919         }
920                 
921         if (typeof options.httpOption.maxRedirection !== 'undefined') {
922             if (typeof options.maxRedirection !== 'undefined') {
923                 if (options.httpOption.maxRedirection !== options.maxRedirection) {
924                     // What do you want that use maxRedirection? Both values are different.
925                     errorCallback({
926                         errorCode: "BAD_PARAMETER",
927                         errorText: "Both options.httpOption.maxRedirection and options.maxRedirection are exists,"
928                         + "but different value. What value you want to use?"
929                     });
930                     return;
931                 }
932             }
933             else
934                 options.maxRedirection = options.httpOption.maxRedirection;
935         }
936         		
937         log(options);
938 			
939         service.Request("luna://com.webos.service.commercial.signage.storageservice", {
940             method: "fs/copyFile",
941             parameters: {
942                 dest: options.destination,
943                 src: options.source,
944                 ftpOption: options.ftpOption,
945                 httpOption: options.httpOption
946             },
947             onSuccess: function (result) {
948                 if (result.returnValue === true) {
949                     log("SUCCESS");
950                     successCallback();
951                 }
952                 else {
953                     log("Err: " + result.errorText);
954                     errorCallback({
955                         errorCode: result.errorCode,
956                         errorText: result.errorText
957                     });
958                 }
959             },
960             onFailure: function (result) {
961                 log("Err: " + result.errorText);
962                 errorCallback({
963                     errorCode: result.errorCode,
964                     errorText: result.errorText
965                 });
966             }
967         });
968     };
969 
970 	/**
971 	 * <p>
972 	 * Removes file in internal or external storage.
973 	 * Target path is described in URI form. 
974 	 * </p>
975 	 * If the target path is a file, it will be removed.</br>
976 	 * If the target path is a directory, the directory will be removed.</br>
977 	 * If 'recursive' parameter is 'true', any file or directory in the target directory will be removed.</br>
978 	 * If 'recursive' parameter is 'false', operation will fail if there is any file in that directory.</br>
979 	 * <p>
980 	 * file://internal/external, file://usb:[index]/content are predefined directory for special use, and cannot be removed. 
981 	 * </p>
982 	 * 
983 	 * @example 
984 	 * 
985 	 * function removeFile() {
986 	 *    var successCb = function (){
987 	 *      console.log("Removing File done.");
988 	 *    }; 
989 	 * 
990 	 *    var failureCb = function(cbObject){ 
991 	 *      var errorCode = cbObject.errorCode;
992 	 *      var errorText = cbObject.errorText; 
993 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
994 	 *    };
995 	 * 
996 	 * 
997 	 *    //delete a file
998 	 *    var options = { 
999 	 *      file: 'file://internal/delete_me.txt',
1000 	 *    }; 
1001 	 * 
1002 	 *    var storage = new Storage();
1003 	 *    storage.removeFile(successCb, failureCb, options);
1004 	 * 
1005 	 *    //delete a directory and contents in it
1006 	 *    var options = { 
1007 	 *      file: 'file://internal/delete/this/directory/',
1008 	 *      recursive : true
1009 	 *    }; 
1010 	 * 
1011 	 *    storage.removeFile(successCb, failureCb, options);
1012 	 * 
1013 	 *    //delete a directory, only if it's empty
1014 	 *    var options = { 
1015 	 *      file: 'file://internal/empty/directory/',
1016 	 *      recursive : false
1017 	 *    }; 
1018 	 * 
1019 	 *    storage.removeFile(successCb, failureCb, options);
1020 	 * }
1021 	 * 
1022 	 * @class storage
1023 	 * @param {Function}
1024 	 *            successCallback success callback function.
1025 	 * @param {Function}
1026 	 *            errorCallback failure callback function.
1027      * @param {Object} options
1028      * <div align=left>
1029      * <table class="hcap_spec" width=400>
1030      *   <thead><tr><th>Property</th><th>Type</th><th>Description</th><th>Required</th></tr></thead>
1031      *   <tbody>
1032      *       <tr><th>file</th><th>{@link Storage.SCAP_URI}</th><th>URI to the file to delete</a></th><th>required</th></tr>
1033      *       <tr class="odd"><tr><th>recursive</th><th>Boolean</th><th>only meaningful when removing a directory. Default value is 'false'.</br>
1034      *           If true, the directory and all contents in it will be removed.</br>
1035      *           If false, removing the directory will fail if it is not empty. 
1036      *            </a></th><th>optional</th></tr>
1037      *   </tbody>
1038      * </table>
1039      * </div>
1040 	 * 
1041 	 * @returns
1042 	 *            <p>
1043 	 *            After the method is successfully executed, successCallback is called without any parameter.</br>
1044 	 *            If an error occurs, errorCallback is called with errorCode and errorText.
1045 	 *            To see how error codes are defined, check {@link Error.ERROR_CODE}
1046 	 *            </p>
1047 	 * 
1048 	 * @since 1.0 1.1 options.recursive
1049 	 */
1050     Storage.prototype.removeFile = function (successCallback, errorCallback, options) {
1051 
1052         if (!(options && isValidFileURI(options.file))) {
1053             errorCallback({
1054                 errorCode: "BAD_PARAMETER",
1055                 errorText: "options.file is a mandatory parameter"
1056             });
1057             return;
1058         }
1059         var param = {
1060             file: options.file
1061         };
1062         if (options.recursive === true) {
1063             param.recursive = true;
1064         }
1065 
1066         service.Request("luna://com.webos.service.commercial.signage.storageservice", {
1067             method: "fs/removeFile",
1068             parameters: param,
1069             onSuccess: function (result) {
1070 
1071                 log("onSuccess");
1072 
1073                 if (result.returnValue === true) {
1074                     successCallback();
1075                 }
1076                 else {
1077                     errorCallback({
1078                         errorCode: result.errorCode,
1079                         errorText: result.errorText
1080                     });
1081                 }
1082             },
1083             onFailure: function (result) {
1084                 log("onFailure");
1085                 errorCallback({
1086                     errorCode: result.errorCode,
1087                     errorText: result.errorText
1088                 });
1089             }
1090         });
1091     };
1092 
1093 	/**
1094 	 * <p>
1095 	 * Lists files in a directory stored in external or internal memory. 
1096 	 * Directory location is in URI format. 
1097 	 * Listing a directory beyond the application root path is not allowed.
1098 	 * </p>
1099 	 * 
1100 	 * @example 
1101 	 * 
1102 	 * function listFiles() {
1103 	 * 
1104 	 *    var successCb = function (cbObject){
1105 	 *      var files = cbObject.files;
1106 	 *      for(var i = 0 ; i < files.length; ++i){
1107 	 *         var fileInfo = files[i];	
1108 	 *         console.log("File Name: " + fileInfo.name);
1109 	 *         console.log("File Type: " + fileInfo.type);
1110 	 *         console.log("File Size: " + fileInfo.size);
1111 	 *      }
1112 	 *    }; 
1113 	 * 
1114 	 *    var failureCb = function(cbObject){ 
1115 	 *      var errorCode = cbObject.errorCode;
1116 	 *      var errorText = cbObject.errorText; 
1117 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
1118 	 *    };
1119 	 * 
1120 	 *    // List files in the internal memory
1121 	 *    var listOption = { 
1122 	 *      path: "file://internal/list/this/dir"
1123 	 *    }; 
1124 	 * 
1125 	 *    var storage = new Storage();
1126 	 *    storage.listFiles(successCb, failureCb, listOption);
1127 	 *          
1128 	 *    // List files in the mass storage device in USB port 1.
1129 	 *    var listOption = { 
1130 	 *      path: "file://usb:1/list/this/dir"
1131 	 *    }; 
1132 	 * 
1133 	 *    storage.listFiles(successCb, failureCb, listOption);
1134 	 * 
1135 	 * }
1136 	 * 
1137 	 * @class storage
1138 	 * @param {Function}
1139 	 *            successCallback success callback function.
1140 	 * @param {Function}
1141 	 *            errorCallback failure callback function.
1142 	 *            
1143      * @param {Object} options
1144      * <div align=left>
1145      * <table class="hcap_spec" width=400>
1146      *   <thead><tr><th>Property</th><th>Type</th><th>Description</th><th>Required</th></tr></thead>
1147      *   <tbody>
1148      *       <tr><th>path</th><th>{@link Storage.SCAP_URI}</th><th>URI to the directory to look for.</a></th><th>required</th></tr>
1149      *   </tbody>
1150      * </table>
1151      * </div>
1152      * 
1153 	 * @returns
1154 	 *            <p>
1155 	 *            After the method is successfully executed, successCallback is called with total count and an array of file info, which contains a list of File Info Object.
1156 	 *            '.' and '..' will not be included in the list.
1157 	 * <div align=left>
1158 	 * <table class="hcap_spec" width=400>
1159 	 *   <thead><tr><th>Property</th><th>Type</th><th>Description</th></tr></thead>
1160 	 *   <tbody>
1161      *       <tr><th>totalCount</th><th>Number</th>
1162      *       <th>Number of items</th>
1163      *       </tr>
1164 	 *       <tr><th>files</th><th>Array</th>
1165 	 *       <th>List of files in the directory. File Info has following properties.</th>
1166 	 *       </tr>
1167      *      
1168 	 *       <tr><th>files.name</th><th>String</th>
1169 	 *       <th>Name of the file</th>
1170 	 *       </tr>
1171 	 *       
1172 	 *       <tr><th>files.type</th><th>String</th>
1173 	 *       <th>Type of the file</th>
1174 	 *       </tr>
1175 	 *       
1176 	 *       <tr><th>files.size</th><th>Number</th>
1177 	 *       <th>Size of the File</th>
1178 	 *       </tr>
1179 	 *       
1180 	 *	</tbody>
1181 	 * </table>
1182 	 * </div>
1183 	 *            </p>
1184 	 *            <p>
1185 	 *            If an error occurs, errorCallback is called with errorCode and errorText.
1186 	 *            To see how error codes are defined, check {@link Error.ERROR_CODE}
1187 	 *            </p>
1188 	 *            
1189 	 * @since 1.0
1190 	 * @since 1.1 list a directory
1191 	 */
1192     Storage.prototype.listFiles = function (successCallback, errorCallback, options) {
1193         var param = {};
1194 
1195         if (options && options.path) {
1196             if (isValidFileURI(options.path)) {
1197                 param.pathURI = options.path;
1198             }
1199             else {
1200                 errorCallback({
1201                     errorCode: "BAD_PARAMETER",
1202                     errorText: "File URI is not valid."
1203                 });
1204                 return;
1205             }
1206         }
1207         else {
1208             param.pathURI = "file://internal/";
1209         }
1210 
1211         service.Request("luna://com.webos.service.commercial.signage.storageservice/", {
1212             method: "fs/listFiles",
1213             parameters: param,
1214             onSuccess: function (result) {
1215                 if (result.returnValue === true) {
1216                     var files = [];
1217                     for (var i = 0; i < result.files.length; ++i) {
1218                         log(result.files[i]);
1219                         var fileinfo = {
1220                             name: result.files[i].name,
1221                             type: (result.files[i].type === 'folder') ? 'folder' : 'file',
1222                             size: result.files[i].size
1223                         };
1224                         files.push(fileinfo);
1225                     }
1226 
1227                     var cbObj = {
1228                         files: files,
1229                         totalCount: result.totalCount
1230                     };
1231                     successCallback(cbObj);
1232                 }
1233                 else {
1234                     errorCallback({
1235                         errorCode: result.errorCode,
1236                         errorText: result.errorText
1237                     });
1238                 }
1239             },
1240             onFailure: function (result) {
1241                 errorCallback({
1242                     errorCode: result.errorCode,
1243                     errorText: result.errorText
1244                 });
1245             }
1246         });
1247     };
1248 
1249 	/**
1250 	 * <p>
1251 	 * Gets internal memory status.
1252 	 * Returns free space and total space, in kilobytes.
1253 	 * If any external storage device is connected, the storage info for that device will be returned as well.
1254 	 * </p>
1255 	 * 
1256 	 * @example 
1257 	 * 
1258 	 * function getStorageInfo() {
1259 	 *    var successCb = function (cbObject){
1260 	 *      var free = cbObject.free;
1261 	 *      var total = cbObject.total;
1262 	 *      var used = cbObject.used;
1263 	 *      var externals = cbObject.externalMemory;
1264 	 *  	   
1265 	 *      console.log( "Total: " + total + "kilobytes"); 
1266 	 *      console.log( "Free: " + free + "kilobytes");
1267 	 *      console.log( "Used: " + used + "kilobytes"); 
1268 	 *
1269 	 *      for(var uri in externals){
1270 	 *         var external = externals[uri];
1271 	 *         console.log("base uri: " + uri);		// ex) usb:1
1272 	 *         console.log("Free: " + external.free);
1273 	 *         console.log("Used: " + external.used);
1274 	 *         console.log("Total: " + external.total);
1275 	 *      }
1276 	 *    }; 
1277 	 * 
1278 	 *    var failureCb = function(cbObject){ 
1279 	 *      var errorCode = cbObject.errorCode;
1280 	 *      var errorText = cbObject.errorText; 
1281 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
1282 	 *    };
1283 	 * 
1284 	 *    var storage = new Storage();
1285 	 *    storage.getStorageInfo(successCb, failureCb);
1286 	 *          
1287 	 * }
1288 	 * 
1289 	 * @class storage
1290 	 * @param {Function}
1291 	 *            successCallback success callback function.
1292 	 * @param {Function}
1293 	 *            errorCallback failure callback function.
1294 	 * @returns
1295 	 *            <p>
1296 	 *            After the method is successfully executed, successCallback is called with free and total space.
1297 	 * <div align=left>
1298 	 * <table class="hcap_spec" width=400>
1299 	 *   <thead><tr><th>Property</th><th>Type</th><th>Description</th></tr></thead>
1300 	 *   <tbody>
1301 	 *       <tr><th>free</th><th>Number</th>
1302 	 *       <th>
1303 	 *       Free space in internal memory, in KB.
1304 	 *       </th>
1305 	 *       </tr>
1306 	 *       <tr><th>total</th><th>Number</th>
1307 	 *       <th>
1308 	 *       Total space in internal memory, in KB.
1309 	 *       </th>
1310 	 *       </tr>
1311 	 *       <tr><th>used</th><th>Number</th>
1312 	 *       <th>
1313 	 *       Used space in internal memory, in KB.
1314 	 *       </th>
1315 	 *       </tr>
1316 	 *       <tr><th>externalMemory</th><th>Array</th>
1317 	 *       <th>
1318 	 *       <p>
1319 	 *       List of external memory connected to the device (ex.usb:1). Optional.
1320 	 *       </p>
1321 	 *       <p>Each external memory item is a JSON object containing following fields. </p>
1322 	 *      <table align="center" class="hcap_spec" width=400>
1323 	 *   		<thead><tr><th>Property</th><th>Type</th><th>Description</th></tr></thead>
1324 	 *   	    <tbody>
1325 	 *   	 	<tr><th>free</th><th>Number</th><th>Free space in the external memory, in KB.</th></tr>
1326 	 *   	 	<tr><th>used</th><th>Number</th><th>Used space in the external memory, in KB.</th></tr>
1327 	 *   	 	<tr><th>total</th><th>Number</th><th>Total space in the external memory, in KB.</th></tr>
1328 	 *          </tbody>
1329 	 *      </table>
1330 	 *       </th>
1331 	 *       </tr>	 
1332 	 *    </tbody>
1333 	 * </table>
1334 	 * </div>
1335 	 *            </p>
1336 	 *            <p>
1337 	 *            If an error occurs, errorCallback is called with errorCode and errorText.
1338 	 *            To see how error codes are defined, check {@link Error.ERROR_CODE}
1339 	 *            </p>
1340 	 * 
1341 	 * @since 1.0
1342 	 * @since 1.1 USB storage information
1343 	 * @since 1.3 SDCard storage information
1344 	 */
1345     Storage.prototype.getStorageInfo = function (successCallback, errorCallback) {
1346 
1347         service.Request("luna://com.webos.service.commercial.signage.storageservice", {
1348             method: "fs/storageInfo",
1349             parameters: {},
1350             onSuccess: function (result) {
1351                 log("returned : " + JSON.stringify(result, null, 3));
1352                 if (result.returnValue === true) {
1353                     log("returned : " + JSON.stringify(result, null, 3));
1354                     var cbObj = {
1355                         free: result.spaceInfo.freeSize,
1356                         total: result.spaceInfo.totalSize,
1357                         used: result.spaceInfo.usedSize,
1358                         externalMemory: result.externalStorage
1359                     };
1360                     successCallback(cbObj);
1361                 }
1362                 else {
1363                     errorCallback({
1364                         errorCode: result.errorCode,
1365                         errorText: result.errorText
1366                     });
1367                 }
1368             },
1369             onFailure: function (result) {
1370                 errorCallback({
1371                     errorCode: result.errorCode,
1372                     errorText: result.errorText
1373                 });
1374             }
1375         });
1376     };
1377 
1378 	/**
1379 	 * <p>
1380 	 * Creates a directory.
1381 	 * The path should be described in URI format.
1382 	 * If the URI is for external memory, external storage device should be connected to the external memory port with proper permission.
1383 	 * The directory will be created recursively.
1384 	 * </p>
1385 	 * 
1386 	 * @example 
1387 	 * 
1388 	 * function mkdir() {
1389 	 *    var successCb = function (){
1390 	 *      console.log( "directory created successfully"); 
1391 	 *    }; 
1392 	 * 
1393 	 *    var failureCb = function(cbObject){ 
1394 	 *      var errorCode = cbObject.errorCode;
1395 	 *      var errorText = cbObject.errorText; 
1396 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
1397 	 *    };
1398 	 * 
1399 	 *    // The directory will be created recursively.
1400 	 *    var mkdirOption = { 
1401 	 *      path: "file://internal/create/this/directory"
1402 	 *    }; 
1403 	 * 
1404 	 *    var storage = new Storage();
1405 	 *    storage.mkdir(successCb, failureCb, mkdirOption);
1406 	 * 
1407 	 * }
1408 	 * 
1409 	 * @class storage
1410 	 * @param {Function}
1411 	 *            successCallback success callback function.
1412 	 * @param {Function}
1413 	 *            errorCallback failure callback function.
1414 	 *            
1415      * @param {Object} options
1416      * <div align=left>
1417      * <table class="hcap_spec" width=400>
1418      *   <thead><tr><th>Property</th><th>Type</th><th>Description</th><th>Required</th></tr></thead>
1419      *   <tbody>
1420      *       <tr><th>path</th><th>{@link Storage.SCAP_URI}</th><th>URI to the directory to create. </a></th><th>required</th></tr>
1421      *   </tbody>
1422      * </table>
1423      * </div>
1424      * 
1425 	 * @returns
1426 	 *            <p>
1427 	 *            After the method is successfully executed, successCallback is called without any parameter.</br>
1428 	 *            If an error occurs, errorCallback is called with errorCode and errorText.
1429 	 *            To see how error codes are defined, check {@link Error.ERROR_CODE}
1430 	 *            </p>
1431 	 * 
1432 	 * @since 1.1
1433 	 */
1434     Storage.prototype.mkdir = function (successCallback, errorCallback, options) {
1435         if (!(options && isValidFileURI(options.path))) {
1436             errorCallback({
1437                 errorCode: "BAD_PARAMETER",
1438                 errorText: "options.path is a mandatory parameter"
1439             });
1440             return;
1441         }
1442         var param = {
1443             pathURI: options.path
1444         };
1445 
1446         service.Request("luna://com.webos.service.commercial.signage.storageservice", {
1447             method: "fs/mkdir",
1448             parameters: param,
1449             onSuccess: function (result) {
1450 
1451                 log("onSuccess");
1452 
1453                 if (result.returnValue === true) {
1454                     successCallback();
1455                 }
1456                 else {
1457                     errorCallback({
1458                         errorCode: result.errorCode,
1459                         errorText: result.errorText
1460                     });
1461                 }
1462             },
1463             onFailure: function (result) {
1464                 log("onFailure");
1465                 errorCallback({
1466                     errorCode: result.errorCode,
1467                     errorText: result.errorText
1468                 });
1469             }
1470         });
1471     };
1472 
1473 	/**
1474 	 * <p>
1475 	 * Checks if the given file exists or not.
1476 	 * The path should be in URI format.
1477 	 * If the URI is for external memory, external storage device must be connected to the external memory port with proper permission.
1478 	 * </p>
1479 	 * 
1480 	 * @example 
1481 	 * 
1482 	 * function exists() {
1483 	 *    var successCb = function (cbObject){
1484 	 *      var exists = cbObject.exists;
1485 	 *      console.log( "The file exists: " + exists); 
1486 	 *    }; 
1487 	 * 
1488 	 *    var failureCb = function(cbObject){ 
1489 	 *      var errorCode = cbObject.errorCode;
1490 	 *      var errorText = cbObject.errorText; 
1491 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
1492 	 *    };
1493 	 * 
1494 	 *    var existsOption = { 
1495 	 *      path: "file://internal/to/be/or/not/to/be"
1496 	 *    }; 
1497 	 * 
1498 	 *    var storage = new Storage();
1499 	 *    storage.exists(successCb, failureCb, existsOption);
1500 	 * 
1501 	 * }
1502 	 * 
1503 	 * @class storage
1504 	 * @param {Function}
1505 	 *            successCallback success callback function.
1506 	 * @param {Function}
1507 	 *            errorCallback failure callback function.
1508 	 *            
1509      * @param {Object} options
1510      * <div align=left>
1511      * <table class="hcap_spec" width=400>
1512      *   <thead><tr><th>Property</th><th>Type</th><th>Description</th><th>Required</th></tr></thead>
1513      *   <tbody>
1514      *       <tr><th>path</th><th>{@link Storage.SCAP_URI}</th><th>URI to the resource (internal/usb/sdcard).</a></th><th>required</th></tr>
1515      *   </tbody>
1516      * </table>
1517      * </div>
1518      * 
1519 	 * @returns
1520 	 *            <p>
1521 	 *            After the method is successfully executed, successCallback is called with a boolean attribute 'exists', which is true if the file exists and false otherwise.</br>
1522 	 *            If an error occurs, errorCallback is called with errorCode and errorText.
1523 	 *            To see how error codes are defined, check {@link Error.ERROR_CODE}
1524 	 *            </p>
1525 	 * 
1526 	 * @since 1.1
1527 	 */
1528     Storage.prototype.exists = function (successCallback, errorCallback, options) {
1529 
1530         if (!(options && isValidFileURI(options.path))) {
1531             log("BAD_PARAMETER");
1532 
1533             errorCallback({
1534                 errorCode: "BAD_PARAMETER",
1535                 errorText: "options.path is a mandatory parameter"
1536             });
1537             return;
1538         }
1539         var param = {
1540             pathURI: options.path
1541         };
1542 
1543         service.Request("luna://com.webos.service.commercial.signage.storageservice", {
1544             method: "fs/exists",
1545             parameters: param,
1546             onSuccess: function (result) {
1547 
1548                 log("onSuccess");
1549 
1550                 if (result.returnValue === true) {
1551                     log("returned : " + JSON.stringify(result, null, 3));
1552                     var cbObj = {
1553                         exists: result.exists
1554                     };
1555                     successCallback(cbObj);
1556                 }
1557                 else {
1558                     errorCallback({
1559                         errorCode: result.errorCode,
1560                         errorText: result.errorText
1561                     });
1562                 }
1563             },
1564             onFailure: function (result) {
1565                 log("onFailure");
1566                 errorCallback({
1567                     errorCode: result.errorCode,
1568                     errorText: result.errorText
1569                 });
1570             }
1571         });
1572     };
1573 
1574 	/**
1575 	 * <p>
1576 	 * Reads from a file.<br>
1577 	 * It is designed to read a small data file from filesystem (not suited for a big data file).
1578 	 * </p>
1579 	 * <p>
1580 	 * Note : For reading a big chunk of data, it is recommended to use AJAX with local file.
1581 	 * </p>
1582 	 * @example
1583 	 * 
1584 	 * function readFile() {
1585 	 *    // This example will read a file as binary.
1586 	 *    
1587 	 *    var successCb = function (cbObject){
1588 	 *      // If file is read as binary, array of uint8 will be returned. 
1589 	 *      // Create an image element, and set the source as the binary data.
1590 	 *      
1591 	 *      var binary_data = cbObject.data;
1592 	 *      var data_base64 = bin_array_to_base64(binary_data);
1593 	 *      var ele = document.createElement('img');
1594 	 *      ele.src = "data:image/jpeg;base64, " + data_base64;
1595 	 *      document.body.appendChild(ele); 
1596 	 *    }; 
1597 	 * 
1598 	 *    var failureCb = function(cbObject){ 
1599 	 *      var errorCode = cbObject.errorCode;
1600 	 *      var errorText = cbObject.errorText; 
1601 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
1602 	 *    };
1603 	 * 
1604 	 *     // Read file from the start, read the whole file, and read as binary
1605 	 *    var options = { 
1606 	 *      path: "file://internal/image.jpg",
1607 	 *      position : 0,
1608 	 *      encoding: 'binary'
1609 	 *    }; 
1610 	 * 
1611 	 *    var storage = new Storage();
1612 	 *    storage.readFile(successCb, failureCb, options);
1613 	 * 
1614 	 * 
1615 	 *    // This example will read file as text.
1616 	 *    var successCb = function (cbObject){
1617 	 *      // If file is read as text, utf encoded string will be returned.
1618 	 *      // Create an image element, and set the source as the binary data.
1619 	 *   
1620 	 *      var data_text = cbObject.data;
1621 	 *      var ele = document.createElement('div');
1622 	 *      ele.innerHTML = "Text is read: " + data_text;
1623 	 *      document.body.appendChild(ele); 
1624 	 *    }; 
1625 	 * 
1626 	 *    var failureCb = function(cbObject){ 
1627 	 *      var errorCode = cbObject.errorCode;
1628 	 *      var errorText = cbObject.errorText; 
1629 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
1630 	 *    };
1631 	 * 
1632 	 *    // Read file from the start, read the whole file, and read as text.
1633 	 *    var options = { 
1634 	 *      path : "file://internal/text.txt",
1635 	 *      position : 0,
1636 	 *      encoding: 'utf8'
1637 	 *    }; 
1638 	 * 
1639 	 *    var storage = new Storage();
1640 	 *    storage.readFile(successCb, failureCb, options);
1641 	 * 
1642 	 * }
1643 	 *
1644 	 * @example 
1645 	 *  // This is a recommended way of reading a big chunk of data from file with JQuery Ajax.
1646 	 *  // Reading a data chunk bigger than 50MB is not recommended because it can lead to memory overflow (depends on system).
1647 	 *  function readFileAjax(){
1648 	 *  	$.ajax({
1649 	 *  		url: "http://127.0.0.1:9080/chunk.data"
1650 	 *  	})
1651 	 *  	.fail(function(err){
1652 	 *  		// Handle error.
1653 	 *  	})
1654 	 *  	.done(function(data){
1655 	 *  		// Handle the data.
1656 	 *  	});
1657 	 *  } 
1658 	 * 
1659 	 * @class storage
1660 	 * @param {Function}
1661 	 *            successCallback success callback function.
1662 	 * @param {Function}
1663 	 *            errorCallback failure callback function.
1664 	 *            
1665      * @param {Object} options
1666      * <div align=left>
1667      * <table class="hcap_spec" width=400>
1668      *   <thead><tr><th>Property</th><th>Type</th><th>Description</th><th>Required</th></tr></thead>
1669      *   <tbody>
1670      *       <tr><th>path</th><th>{@link Storage.SCAP_URI}</th><th>URI to the resource (internal/usb/sdcard). </a></th><th>required</th></tr>
1671      *       <tr class="odd"><tr><th>position</th><th>Number</th><th>Position where this file will be read from. Default value is 0.</br> 
1672      *       If the value of the position parameter is out of the range of the input file, error will be returned.</a></th><th>optional</th></tr>
1673      *       <tr><th>length</th><th>Number</th><th>The length of the Read buffer. Maximum length of the buffer that can be read is currently 10KB. </br> 
1674      *            Default value is 10KB. </br>If the size of the file intended to be read is smaller than the length parameter, 
1675      *            return data will include the contents of the file.</a></th><th>optional</th></tr>
1676      *       <tr class="odd"><tr><th>encoding</th><th>String</th><th>Encoding method to be used for return value. </br>
1677      *            Default value is 'utf8'. Value of encoding can be:</br>
1678      *            'utf8' : Encoded as UTF-8. Return value will be a string.</br>
1679      *            'base64' : Encoded as base64. Return value will be a string.</br>
1680      *            'binary' : Raw binary data. Return value will be an ArrayBuffer.</br></a></th><th>optional</th></tr>
1681      *   </tbody>
1682      * </table>
1683      * </div>
1684 	 * @returns
1685 	 *            <p> 
1686 	 *            A string containing the file data with given encoding will be returned ('utf8', 'base64').</br>
1687 	 *            If the encoding is 'binary', an ArrayBuffer will be returned.</br>
1688 	 *            </p>
1689 	 *            <p>
1690 	 *            After the method is successfully executed, successCallback is called with file data.</br>
1691 	 *            If an error occurs, errorCallback is called with errorCode and errorText.
1692 	 *            To see how error codes are defined, check {@link Error.ERROR_CODE}
1693 	 *            </p>
1694 	 * 
1695 	 * @since 1.2
1696 	 */
1697     Storage.prototype.readFile = function (successCallback, errorCallback, options) {
1698         if (!options) {
1699             errorCallback({
1700                 errorCode: "BAD_PARAMETER",
1701                 errorText: "options.path is a mandatory parameter"
1702             });
1703         }
1704         else if (!isValidFileURI(options.path)) {
1705             errorCallback({
1706                 errorCode: "BAD_PARAMETER",
1707                 errorText: "options.path is a mandatory parameter"
1708             });
1709         }
1710         else if (options.length && (options.length > Storage.MAX_BUFFER_LENGTH || options.length < 1)) {
1711             errorCallback({
1712                 errorCode: "BAD_PARAMETER",
1713                 errorText: "length should be > 0 and < " + Storage.MAX_BUFFER_LENGTH
1714             });
1715         }
1716         else if (options.position && (options.position < 0)) {
1717             errorCallback({
1718                 errorCode: "BAD_PARAMETER",
1719                 errorText: "position should be > 0"
1720             });
1721         }
1722         else {
1723             var params = {};
1724 
1725             params.path = options.path;
1726             params.length = options.length ? options.length : Storage.MAX_BUFFER_LENGTH;
1727             params.position = options.position ? options.position : 0;
1728             params.encoding = options.encoding ? options.encoding : 'utf-8';
1729 
1730             service.Request("luna://com.webos.service.commercial.signage.storageservice", {
1731                 method: "fs/readFile",
1732                 parameters: params,
1733                 onSuccess: function (result) {
1734                     if (result.returnValue) {
1735                         if (params.encoding === 'binary') {
1736                             // Read as binary so return as ArrayBuffer.
1737                             // Returned data is a array of byte.
1738                             var byteArray = result.data;
1739                             var arrayView = new Uint8Array(byteArray.length);
1740                             for (var i = 0; i < byteArray.length; ++i) {
1741                                 arrayView[i] = byteArray[i];
1742                             }
1743                             successCallback({
1744                                 data: arrayView.buffer
1745                             });
1746                         }
1747                         else {
1748                             // return as a string
1749                             successCallback({
1750                                 data: result.data
1751                             });
1752                         }
1753                     }
1754                     else {
1755                         errorCallback({
1756                             errorCode: result.errorCode,
1757                             errorText: result.errorText
1758                         });
1759                     }
1760                 },
1761                 onFailure: function (result) {
1762                     errorCallback({
1763                         errorCode: result.errorCode,
1764                         errorText: result.errorText
1765                     });
1766                 }
1767             });
1768         }
1769     };
1770 
1771 	/**
1772 	 * 
1773 	 * Writes file
1774 	 * 
1775 	 * @example 
1776 	 *   
1777 	 * function writeFile() {
1778 	 *    // This example will write binary data to file.
1779 	 *   
1780 	 *    var successCb = function (cbObject){
1781 	 *      console.log( "Successfully writen " + cbObject.written + " bytes" ); 
1782 	 *    }; 
1783 	 * 
1784 	 *    var failureCb = function(cbObject){ 
1785 	 *      var errorCode = cbObject.errorCode;
1786 	 *      var errorText = cbObject.errorText; 
1787 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
1788 	 *    };
1789 	 * 
1790 	 * 
1791 	 *    //Read a file as binary with an ajax call.
1792 	 *    var oReq = new XMLHttpRequest();
1793 	 *    oReq.open("GET", '/my_file.data', true);
1794 	 *    oReq.responseType = "arraybuffer";
1795 	 *    oReq.onload = function (oEvent) {
1796 	 *       var arrayBuffer = oReq.response; // Note: not oReq.responseText
1797 	 * 
1798 	 *      if (arrayBuffer) {
1799 	 *         var uint8View =  new Int8Array(arrayBuffer);
1800 	 *         var array = [];
1801 	 *         for(var i=0;i < uint8View.length;++i) {
1802 	 *            array[i] = uint8View[i];
1803 	 *         }
1804 	 * 	
1805 	 *         // write data from the start, read the whole data, and write as binary
1806 	 *         var options = {
1807 	 *            data: array,
1808 	 *            path: 'file://internal/data.dat',
1809 	 *            position : 0,
1810 	 *            mode :'truncate',
1811 	 *            offset:0,
1812 	 *            length : array.length,
1813 	 *            encoding: 'binary'
1814 	 *         }; 
1815 	 * 
1816 	 *         var storage = new Storage();
1817 	 *         storage.writeFile(successCb, failureCb, options);
1818 	 *      }
1819 	 *    };
1820 	 * 
1821 	 *    oReq.send(null);
1822 	 *    // This example will write text data to a file.
1823 	 *   
1824 	 *    var successCb = function (cbObject){
1825 	 *      console.log( "Successfully writen " + cbObject.written + " bytes" ); 
1826 	 *    }; 
1827 	 * 
1828 	 *    var failureCb = function(cbObject) { 
1829 	 *      var errorCode = cbObject.errorCode;
1830 	 *      var errorText = cbObject.errorText; 
1831 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
1832 	 *    };
1833 	 * 
1834 	 *     // write Text data, use utf-8 encoding, write all text.
1835 	 *    var textData = "Hello SCAP!!!!!"; 
1836 	 *    var options = { 
1837 	 *      data: textData,
1838 	 *      path: 'file://internal/text.txt',
1839 	 *      position : 0,
1840 	 *      mode :'truncate',
1841 	 *      offset:0,
1842 	 *      length : textData.length,
1843 	 *      encoding: 'utf8'
1844 	 *    }; 
1845 	 *
1846 	 *    var storage = new Storage();
1847 	 *    storage.writeFile(successCb, failureCb, options);
1848 	 * 
1849 	 * }
1850 	 *          
1851 	 * @class storage
1852 	 * @param {Function}
1853 	 *            successCallback success callback function.
1854 	 * @param {Function}
1855 	 *            errorCallback failure callback function.
1856 	 *            
1857      * @param {Object} options
1858      * <div align=left>
1859      * <table class="hcap_spec" width=400>
1860      *   <thead><tr><th>Property</th><th>Type</th><th>Description</th><th>Required</th></tr></thead>
1861      *   <tbody>
1862      *       <tr><th>path</th><th>{@link Storage.SCAP_URI}</th><th>URI to the resource (internal/usb/sdcard).</a></th><th>required</th></tr>
1863      *       <tr class="odd"><tr><th>data</th><th>ArrayBuffer|String</th><th>Data to write to the file. Data type should be ArrayBuffer if encoding is 'binary' or string otherwise.</a></th><th>required</th></tr>
1864      *       <tr><th>mode</th><th>String</th><th>Write mode. Default is 'truncate'.</br>
1865      *            'truncate' : Truncate the file and start writing on it. File will be created if it doesn't exist. </br>
1866      *            'append'   : Append to the file. File will be created if it doesn't exist. </br>
1867      *            'position' : Write from the position given by option.position. File must exist for this mode. </br> </a></th><th>optional</th></tr>
1868      *       <tr class="odd"><tr><th>position</th><th>Number</th><th>Position where this file will be written. Default value is 0. This option is valid only if mode is 'position'.</br> 
1869      *       If position is bigger than the existing file for positional write, the gap between the file contents and write position will be filled with '\00' character.</a></th><th>optional</th></tr>
1870      *       <tr><th>length</th><th>Number</th><th>Write buffer length in bytes. Maximum buffer size is 10KB. </br>Default value is data.length, 
1871      *       or 10KB if data.length-offset > 10KB.</a></th><th>optional</th></tr>
1872      *       <tr class="odd"><tr><th>encoding</th><th>String</th><th>Encoding to be applied to input data. Default value is 'utf8'.</br>
1873      *            'utf8' : input data is encoded as UTF-8. options.data should be a string.</br>
1874      *            'base64' : input data is encoded as base64. options.data should be a string.</br>
1875      *            'binary' : input data is encoded as raw binary. options.data should be an ArrayBuffer.</br></a></th><th>optional</th></tr>
1876      *       <tr><th>offset</th><th>Number</th><th>Offset from buffer. Default value is 0. If offset+length > data.length, error will be returned.</a></th><th>optional</th></tr>
1877      *   </tbody>
1878      * </table>
1879      * </div>
1880      * 
1881 	 * @returns
1882 	 *            <p>
1883 	 *            After the method is successfully executed, successCallback is called with the number of bytes written.</br>
1884 	 *            The number of bytes written may be more than the length of the actual data. </br>
1885 	 *            If an error occurs, errorCallback is called with errorCode and errorText.
1886 	 *            To see how error codes are defined, check {@link Error.ERROR_CODE}
1887 	 *            </p>
1888 	 * 
1889 	 * @since 1.2
1890 	 */
1891     Storage.prototype.writeFile = function (successCallback, errorCallback, options) {
1892         if (!options) {
1893             errorCallback({
1894                 errorCode: "BAD_PARAMETER",
1895                 errorText: "options.path is a mandatory parameter"
1896             });
1897         }
1898         else if (!isValidFileURI(options.path)) {
1899             errorCallback({
1900                 errorCode: "BAD_PARAMETER",
1901                 errorText: "options.path is a is not valid"
1902             });
1903         }
1904         else if (!options.data) {
1905             errorCallback({
1906                 errorCode: "BAD_PARAMETER",
1907                 errorText: "options.data is a mandatory parameter"
1908             });
1909         }
1910         else if (options.mode && (options.mode !== 'truncate' && options.mode !== 'append' && options.mode !== 'position')) {
1911             errorCallback({
1912                 errorCode: "BAD_PARAMETER",
1913                 errorText: "mode should be 'truncate'|'append'|'position'"
1914             });
1915         }
1916         else if (options.position && (options.position < 0)) {
1917             errorCallback({
1918                 errorCode: "BAD_PARAMETER",
1919                 errorText: "position should be > 0"
1920             });
1921         }
1922         else if (options.offset && (options.offset < 0)) {
1923             errorCallback({
1924                 errorCode: "BAD_PARAMETER",
1925                 errorText: "offset should be > 0"
1926             });
1927         }
1928         else if (options.length && (options.length > Storage.MAX_BUFFER_LENGTH || options.length < 1)) {
1929             errorCallback({
1930                 errorCode: "BAD_PARAMETER",
1931                 errorText: "length should be > 0 and < " + Storage.MAX_BUFFER_LENGTH
1932             });
1933         }
1934         else if (options.encoding && (options.encoding !== 'utf8' && options.encoding !== 'binary' && options.encoding !== 'base64')) {
1935             errorCallback({
1936                 errorCode: "BAD_PARAMETER",
1937                 errorText: "Invalid encoding: " + options.encoding
1938             });
1939         }
1940 
1941         else {
1942             log("REQUEST");
1943             var params = {};
1944             params.path = options.path;
1945             params.mode = options.mode ? options.mode : 'truncate';
1946             params.position = options.position ? options.position : 0;
1947             params.encoding = options.encoding ? options.encoding : 'utf8';
1948             var offset = options.offset ? options.offset : 0; 
1949             // Input data is array Buffer when encoding is binary
1950             if (params.encoding === 'binary') {
1951                 log("binary, size is: " + options.data.byteLength);
1952                 var uint8View = new Uint8Array(options.data);
1953                 log("uint8View: " + uint8View);
1954                 var maxLength = options.length ? options.length : Storage.MAX_BUFFER_LENGTH;
1955                 var array = [];
1956                 var count = 0;
1957                 for (var i = offset; i < uint8View.length && count < maxLength; ++i, count++) {
1958                     array[count] = uint8View[i];
1959                 }
1960                 log("array length: " + count);
1961 
1962                 params.data = array;
1963                 params.length = count;
1964                 params.offset = 0;
1965             }
1966             // input data is base64 encoded string if encoding is base64
1967             else if (params.encoding === 'base64') {
1968                 var maxLength2 = options.length ? options.length : Storage.MAX_BUFFER_LENGTH;
1969                 log("base64, size is: " + options.data.length);
1970                 var base64Str = options.data;
1971                 var decodedRaw = window.atob(base64Str);
1972                 var decoded = decodedRaw.substring(offset, offset + maxLength2);
1973                 var arrayView = new Uint8Array(decoded.length);
1974 
1975                 var j;
1976                 for (j = 0; j < decoded.length; j++) {
1977                     arrayView[j] = decoded.charCodeAt(j);
1978                 }
1979 
1980                 var array2 = [];
1981                 for (j = 0; j < arrayView.length; ++j) {
1982                     array2[j] = arrayView[j];
1983                 }
1984 
1985                 params.data = array2;
1986                 params.length = array2.length;
1987                 params.offset = 0;
1988             }			
1989             // input data is utf-8 text. 
1990             else {
1991                 var maxLength3 = options.length ? options.length : Storage.MAX_BUFFER_LENGTH;
1992                 //var endPosition = (options.offset + maxLength3) > options.data.length ? options.data.length : (options.offset + maxLength3);
1993                 params.data = options.data.substring(offset, offset + maxLength3);
1994                 params.length = params.data.length;
1995                 params.offset = 0;
1996             }
1997             try {
1998                 service.Request("luna://com.webos.service.commercial.signage.storageservice", {
1999                     method: "fs/writeFile",
2000                     parameters: params,
2001                     onSuccess: function (result) {
2002                         log("onSuccess");
2003                         if (result.returnValue) {
2004                             successCallback({
2005                                 written: result.written
2006                             });
2007                         }
2008                         else {
2009                             log("FAILED: " + result.errorText);
2010                             errorCallback({
2011                                 errorCode: result.errorCode,
2012                                 errorText: result.errorText
2013                             });
2014                         }
2015                     },
2016                     onFailure: function (result) {
2017                         log("onFailure");
2018                         log("FAILED: " + result.errorText);
2019                         errorCallback({
2020                             errorCode: result.errorCode,
2021                             errorText: result.errorText
2022                         });
2023                     }
2024                 });
2025             } catch (err) {
2026                 log("EXCEPTION" + err);                
2027                 errorCallback({
2028                     errorCode: 'STWF',
2029                     errorText: 'Storage.writeFile() error is occured during operation.'
2030                 });
2031             }
2032         }
2033     };
2034 
2035 	/**
2036 	 * 
2037 	 * Gets file stat. Stat for linked file is not shown.
2038 	 * 
2039 	 * @example 
2040 	 * 
2041 	 * function statFile() {
2042 	 *    var successCb = function (cbObject){
2043 	 *      console.log( "Show File Stat: " ); 
2044 	 *      console.log( JSON.stringify(cbObject));
2045 	 *    }; 
2046 	 * 
2047 	 *    var failureCb = function(cbObject){ 
2048 	 *      var errorCode = cbObject.errorCode;
2049 	 *      var errorText = cbObject.errorText; 
2050 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
2051 	 *    };
2052 	 * 
2053 	 *    var options = { 
2054 	 *      path: 'file://internal/myFile.txt',
2055 	 *    }; 
2056 	 * 
2057 	 *    var storage = new Storage();
2058 	 *    storage.statFile(successCb, failureCb, options);
2059 	 * }
2060 	 * 
2061 	 * @class storage
2062 	 * @param {Function}
2063 	 *            successCallback success callback function.
2064 	 * @param {Function}
2065 	 *            errorCallback failure callback function.
2066 	 *            
2067      * @param {Object} options
2068      * <div align=left>
2069      * <table class="hcap_spec" width=400>
2070      *   <thead><tr><th>Property</th><th>Type</th><th>Description</th><th>Required</th></tr></thead>
2071      *   <tbody>
2072      *       <tr><th>path</th><th>{@link Storage.SCAP_URI}</th><th>URI to the resource (internal/usb/sdcard).</a></th><th>required</th></tr>
2073      *   </tbody>
2074      * </table>
2075      * </div>
2076 	 * @returns
2077 	 *            <p>
2078 	 *            After the method is successfully executed, successCallback is called with the file stat.</br>
2079 	 *            Example: 
2080 	 *            {   
2081 	 *            	  type: file|directory|unknown,
2082 	 *                size: 527,
2083 	 *                atime: Mon, 10 Oct 2011 23:24:11 GMT,
2084 	 *                mtime: Mon, 10 Oct 2011 23:24:11 GMT,
2085 	 *                ctime: Mon, 10 Oct 2011 23:24:11 GMT
2086 	 *            }
2087 	 *            </br>
2088 	 *            If an error occurs, errorCallback is called with errorCode and errorText.
2089 	 *            To see how error codes are defined, check {@link Error.ERROR_CODE}
2090 	 *            </p>
2091 	 * 
2092 	 * @since 1.2
2093 	 */
2094     Storage.prototype.statFile = function (successCallback, errorCallback, options) {
2095         if (!(options && isValidFileURI(options.path))) {
2096             errorCallback({
2097                 errorCode: "BAD_PARAMETER",
2098                 errorText: "options.path is a mandatory parameter"
2099             });
2100         }
2101         else if (!options.path) {
2102             errorCallback({
2103                 errorCode: "BAD_PARAMETER",
2104                 errorText: "options.path is a mandatory parameter"
2105             });
2106         } else {
2107             try {
2108                 service.Request("luna://com.webos.service.commercial.signage.storageservice", {
2109                     method: "fs/statFile",
2110                     parameters: {
2111                         path: options.path
2112                     },
2113                     onSuccess: function (result) {
2114                         log("onSuccess");
2115 
2116                         if (result.returnValue) {
2117                             successCallback(result.stat);
2118                         }
2119                         else {
2120                             log("FAILED: " + result.errorText);
2121                             errorCallback({
2122                                 errorCode: result.errorCode,
2123                                 errorText: result.errorText
2124                             });
2125                         }
2126                     },
2127                     onFailure: function (result) {
2128                         log("onFailure");
2129                         log("FAILED: " + result.errorText);
2130                         errorCallback({
2131                             errorCode: result.errorCode,
2132                             errorText: result.errorText
2133                         });
2134                     }
2135                 });
2136             } catch (err) {
2137                 log("EXCEPTION" + err);                
2138                 errorCallback({
2139                     errorCode: 'STSF',
2140                     errorText: 'Storage.statFile() error is occured during operation.'
2141                 });
2142             }
2143         }
2144     };
2145 
2146 	/**
2147 	 * 
2148 	 * Removes all files in given file system.
2149 	 * 
2150 	 * @example 
2151 	 * 
2152 	 * function removeAll() {
2153 	 *    var successCb = function (cbObject){
2154 	 *      console.log( "Removed all files " ); 
2155 	 *    }; 
2156 	 * 
2157 	 *    var failureCb = function(cbObject){ 
2158 	 *      var errorCode = cbObject.errorCode;
2159 	 *      var errorText = cbObject.errorText; 
2160 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
2161 	 *    };
2162 	 *
2163 	 *    var options = { 
2164 	 *      device: 'internal' // This will remove all files in the internal memory space.
2165 	 *    }; 
2166 	 * 
2167 	 *    var storage = new Storage();
2168 	 *    storage.removeAll(successCb, failureCb, options);
2169 	 * }
2170 	 *          
2171 	 * @class storage
2172 	 * @param {Function}
2173 	 *            successCallback success callback function.
2174 	 * @param {Function}
2175 	 *            errorCallback failure callback function.
2176 	 *            
2177      * @param {Object} options
2178      * <div align=left>
2179      * <table class="hcap_spec" width=400>
2180      *   <thead><tr><th>Property</th><th>Type</th><th>Description</th><th>Required</th></tr></thead>
2181      *   <tbody>
2182      *       <tr><th>device</th><th>String</th><th>device to remove all files from. (internal, usb:[index], sdcard:[index])</a></th><th>required</th></tr>
2183      *   </tbody>
2184      * </table>
2185      * </div>
2186 	 * @returns
2187 	 *            <p>
2188 	 *            After the method is successfully executed, successCallback is called without any parameter.</br>
2189 	 *            If an error occurs, errorCallback is called with errorCode and errorText.
2190 	 *            To see how error codes are defined, check {@link Error.ERROR_CODE}
2191 	 *            </p>
2192 	 * 
2193 	 * @since 1.2
2194 	 */
2195     Storage.prototype.removeAll = function (successCallback, errorCallback, options) {
2196         if (!options) {
2197             errorCallback({
2198                 errorCode: "BAD_PARAMETER",
2199                 errorText: "options.device is a mandatory parameter"
2200             });
2201         }
2202         else if (!options.device) {
2203             errorCallback({
2204                 errorCode: "BAD_PARAMETER",
2205                 errorText: "options.device is a mandatory parameter"
2206             });
2207         } else {
2208             try {
2209                 service.Request("luna://com.webos.service.commercial.signage.storageservice", {
2210                     method: "fs/removeAll",
2211                     parameters: {
2212                         device: options.device
2213                     },
2214                     onSuccess: function (result) {
2215                         log("onSuccess");
2216 
2217                         if (result.returnValue) {
2218                             successCallback();
2219                         }
2220                         else {
2221                             log("FAILED: " + result.errorText);
2222                             errorCallback({
2223                                 errorCode: result.errorCode,
2224                                 errorText: result.errorText
2225                             });
2226                         }
2227                     },
2228                     onFailure: function (result) {
2229                         log("onFailure");
2230                         log("FAILED: " + result.errorText);
2231                         errorCallback({
2232                             errorCode: result.errorCode,
2233                             errorText: result.errorText
2234                         });
2235                     }
2236                 });
2237             } catch (err) {
2238                 log("EXCEPTION" + err);                
2239                 errorCallback({
2240                     errorCode: 'STRA',
2241                     errorText: 'Storage.removeAll() error is occured during operation.'
2242                 });
2243             }
2244         }
2245     };
2246 
2247 	/**
2248 	 * 
2249 	 * Flushes modified files to filesystem.
2250 	 * 
2251 	 * @example 
2252 	 * 
2253 	 * function fsync() {
2254 	 *    // This example will copy a file to USB and sync it.
2255 	 * 
2256 	 *    var failureCb = function(cbObject){ 
2257 	 *      var errorCode = cbObject.errorCode;
2258 	 *      var errorText = cbObject.errorText; 
2259 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
2260 	 *    };
2261 	 * 
2262 	 *    var storage = new Storage();
2263 	 *    storage.copyFile(
2264 	 *      function(){  // Copy was success. fsync the file.
2265 	 *         storage.fsync(
2266 	 *            function(){
2267 	 *               console.log("File synched!!!!!!!!!!");
2268 	 *            },
2269 	 *            failureCb,
2270 	 *            {path : "file://usb:1/file.jpg"}
2271 	 *         );
2272 	 *      }, 
2273 	 *      failureCb, 
2274 	 *      {source:"file://internal/this.jpg", destination:"file://usb:1/file.jpg"}
2275 	 *    );
2276 	 * 
2277 	 *    // This example will sync whole file system.
2278 	 *    var failureCb = function(cbObject){ 
2279 	 *      var errorCode = cbObject.errorCode;
2280 	 *      var errorText = cbObject.errorText; 
2281 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
2282 	 *   };
2283 	 * 
2284 	 *    storage.copyFile(
2285 	 *      function(){  // Copy was success. fsync the device.
2286 	 *         storage.fsync(
2287 	 *            function(){
2288 	 *               console.log("File synched!!!!!!!!!!");
2289 	 *            },
2290 	 *            failureCb, // Failure Callback
2291 	 *            {} // Options
2292 	 *         );
2293 	 *      }, 
2294 	 *      failureCb, 	// Failure Callback
2295 	 *      {source:"file://internal/this.jpg", destination:"file://usb:1/file.jpg"} // Options
2296 	 *    );
2297 	 * 
2298 	 * }
2299 	 *          
2300 	 * @class storage
2301 	 * @param {Function}
2302 	 *            successCallback success callback function.
2303 	 * @param {Function}
2304 	 *            errorCallback failure callback function.
2305 	 *            
2306      * @param {Object} options
2307      * <div align=left>
2308      * <table class="hcap_spec" width=400>
2309      *   <thead><tr><th>Property</th><th>Type</th><th>Description</th><th>Required</th></tr></thead>
2310      *   <tbody>
2311      *       <tr><th>path</th><th>{@link Storage.SCAP_URI}</th><th>URI to the resource (internal/usb/sdcard).</br>If this parameter is not provided, whole file system is synced using 'sync' linux command.</a></th><th>optional</th></tr>
2312      *   </tbody>
2313      * </table>
2314      * </div>
2315      * 
2316 	 * @returns
2317 	 *            <p>
2318 	 *            After the method is successfully executed, successCallback is called without any parameter.</br>
2319 	 *            If an error, errorCallback is called with errorCode and errorText.
2320 	 *            To see how error codes are defined, check {@link Error.ERROR_CODE}
2321 	 *            </p>
2322 	 * 
2323 	 * @since 1.2
2324 	 */
2325     Storage.prototype.fsync = function (successCallback, errorCallback, options) {
2326         try {
2327             var params = {};
2328             if (options && options.path) {
2329                 if (isValidFileURI(options.path)) {
2330                     params.path = options.path;
2331                 }
2332                 else {
2333                     errorCallback({
2334                         errorCode: "BAD_PARAMETER",
2335                         errorText: "Invalid File URI"
2336                     });
2337                     return;
2338                 }
2339             }
2340 
2341             service.Request("luna://com.webos.service.commercial.signage.storageservice", {
2342                 method: "fs/fsyncFile",
2343                 parameters: params,
2344                 onSuccess: function (result) {
2345                     log("onSuccess");
2346                     if (result.returnValue) {
2347                         successCallback();
2348                     }
2349                     else {
2350                         log("FAILED: " + result.errorText);
2351                         errorCallback({
2352                             errorCode: result.errorCode,
2353                             errorText: result.errorText
2354                         });
2355                     }
2356                 },
2357                 onFailure: function (result) {
2358                     log("onFailure");
2359                     log("FAILED: " + result.errorText);
2360                     errorCallback({
2361                         errorCode: result.errorCode,
2362                         errorText: result.errorText
2363                     });
2364                 }
2365             });
2366         } catch (err) {
2367             log("EXCEPTION" + err);            
2368             errorCallback({
2369                 errorCode: 'STFS',
2370                 errorText: 'Storage.fsync() error is occured during operation.'
2371             });
2372         }
2373     };
2374 
2375 	/**
2376 	 * 
2377 	 * Moves a file or directory.
2378 	 * If newPath already exists, it will be replaced. </br>
2379 	 * If newPath and oldPath refer to a same file, it will return success but do nothing. </br>
2380 	 * If oldPath is a directory, newPath must be either non-existing or emptry directory. </br>
2381 	 * 
2382 	 * <p>
2383 	 *  file://internal/external, file://usb:[usb_port]/content are predefined directory for special use, and cannot be moved. 
2384 	 * </p>
2385 	 * @example 
2386 	 * 
2387 	 * function moveFile() {
2388 	 *    var successCb = function (){
2389 	 *      console.log("Move File done.");
2390 	 *    }; 
2391 	 * 
2392 	 *    var failureCb = function(cbObject){ 
2393 	 *      var errorCode = cbObject.errorCode;
2394 	 *      var errorText = cbObject.errorText; 
2395 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
2396 	 *    };
2397 	 * 
2398 	 *    var options = { 
2399 	 *      oldPath: 'file://internal/org.txt',
2400 	 *      newPath : 'file://internal/new.txt'
2401 	 *    };
2402 	 * 
2403 	 *    var storage = new Storage();
2404 	 *    storage.moveFile(successCb, failureCb, options);
2405 	 * }
2406 	 * 
2407 	 * @class storage
2408 	 * @param {Function}
2409 	 *            successCallback success callback function.
2410 	 * @param {Function}
2411 	 *            errorCallback failure callback function.
2412 	 *            
2413      * @param {Object} options
2414      * <div align=left>
2415      * <table class="hcap_spec" width=400>
2416      *   <thead><tr><th>Property</th><th>Type</th><th>Description</th><th>Required</th></tr></thead>
2417      *   <tbody>
2418      *       <tr><th>oldPath</th><th>{@link Storage.SCAP_URI}</th><th>URI to the original file (internal/usb/sdcard).</a></th><th>required</th></tr>
2419      *       <tr class="odd"><tr><th>newPath</th><th>{@link Storage.SCAP_URI}</th><th>URI to the new file (internal/usb/sdcard).</a></th><th>required</th></tr>
2420      *   </tbody>
2421      * </table>
2422      * </div>
2423 	 *            
2424 	 * @returns
2425 	 *            <p>
2426 	 *            After the method is successfully executed, successCallback is called without any parameter.</br>
2427 	 *            If an error occurs, errorCallback is called with errorCode and errorText.
2428 	 *            To see how error codes are defined, check {@link Error.ERROR_CODE}
2429 	 *            </p>
2430 	 * 
2431 	 * @since 1.2
2432 	 */
2433     Storage.prototype.moveFile = function (successCallback, errorCallback, options) {
2434         if (!options) {
2435             errorCallback({
2436                 errorCode: "BAD_PARAMETER",
2437                 errorText: "options.path is a mandatory parameter"
2438             });
2439         }
2440         else if (!isValidFileURI(options.oldPath)) {
2441             errorCallback({
2442                 errorCode: "BAD_PARAMETER",
2443                 errorText: "options.oldpath is a mandatory parameter"
2444             });
2445         }
2446         else if (!isValidFileURI(options.newPath)) {
2447             errorCallback({
2448                 errorCode: "BAD_PARAMETER",
2449                 errorText: "options.newPath is a mandatory parameter"
2450             });
2451         }
2452         else {
2453             try {
2454                 service.Request("luna://com.webos.service.commercial.signage.storageservice", {
2455                     method: "fs/moveFile",
2456                     parameters: {
2457                         oldPath: options.oldPath,
2458                         newPath: options.newPath
2459                     },
2460                     onSuccess: function (result) {
2461                         log("onSuccess");
2462 
2463                         if (result.returnValue) {
2464                             successCallback();
2465                         }
2466                         else {
2467                             log("FAILED: " + result.errorText);
2468                             errorCallback({
2469                                 errorCode: result.errorCode,
2470                                 errorText: result.errorText
2471                             });
2472                         }
2473                     },
2474                     onFailure: function (result) {
2475                         log("onFailur");
2476                         log("FAILED: " + result.errorText);
2477                         errorCallback({
2478                             errorCode: result.errorCode,
2479                             errorText: result.errorText
2480                         });
2481                     }
2482                 });
2483             } catch (err) {
2484                 log("EXCEPTION" + err);                
2485                 errorCallback({
2486                     errorCode: 'STMF',
2487                     errorText: 'Storage.moveFile() error is occured during operation.'
2488                 });
2489             }
2490         }
2491     };
2492 
2493 	/**
2494 	 * 
2495 	 * Unzip file. It should be compressed in PKI-ZIP format.
2496 	 * 
2497 	 * @example 
2498 	 * function unzipFile() {
2499 	 *    var successCb = function (){
2500 	 *      console.log("Unzip File successful");
2501 	 *    }; 
2502 	 * 
2503 	 *    var failureCb = function(cbObject){ 
2504 	 *      var errorCode = cbObject.errorCode;
2505 	 *      var errorText = cbObject.errorText; 
2506 	 *      console.log( " Error Code [" + errorCode + "]: " + errorText); 
2507 	 *    };
2508 	 * 
2509 	 *    var options = { 
2510 	 *      zipPath: 'file://internal/myFile.zip',
2511 	 *      targetPath: 'file://internal/unzip/to/here',
2512 	 *    };
2513 	 * 
2514 	 *    var storage = new Storage();
2515 	 *    storage.unzipFile(successCb, failureCb, options);
2516 	 * }
2517 	 * 
2518 	 * @class storage
2519 	 * @param {Function}
2520 	 *            successCallback success callback function.
2521 	 * @param {Function}
2522 	 *            errorCallback failure callback function.
2523 	 *            
2524      * @param {Object} options
2525      * <div align=left>
2526      * <table class="hcap_spec" width=400>
2527      *   <thead><tr><th>Property</th><th>Type</th><th>Description</th><th>Required</th></tr></thead>
2528      *   <tbody>
2529      *       <tr><th>zipPath</th><th>{@link Storage.SCAP_URI}</th><th>URI to the zip file (internal/usb/sdcard).</a></th><th>required</th></tr>
2530      *       <tr class="odd"><tr><th>targetPath</th><th>{@link Storage.SCAP_URI}</th><th>URI to the target directory where the contents of the zip file will be stored. (internal/usb/sdcard)</a></th><th>required</th></tr>
2531      *   </tbody>
2532      * </table>
2533      * </div>
2534      * 
2535 	 * @returns
2536 	 *            <p>
2537 	 *            After the method is successfully executed, successCallback is called without any parameter. </br>
2538 	 *            If an error occurs, errorCallback is called with errorCode and errorText.
2539 	 *            To see how error codes are defined, check {@link Error.ERROR_CODE}
2540 	 *            </p>
2541 	 * 
2542 	 * @since 1.2
2543 	 */
2544     Storage.prototype.unzipFile = function (successCallback, errorCallback, options) {
2545         if (!options) {
2546             errorCallback({
2547                 errorCode: "BAD_PARAMETER",
2548                 errorText: "options.path is a mandatory parameter"
2549             });
2550         }
2551         else if (!isValidFileURI(options.zipPath)) {
2552             errorCallback({
2553                 errorCode: "BAD_PARAMETER",
2554                 errorText: "options.zipPath is a mandatory parameter"
2555             });
2556         }
2557         else if (!isValidFileURI(options.targetPath)) {
2558             errorCallback({
2559                 errorCode: "BAD_PARAMETER",
2560                 errorText: "options.targetPath is a mandatory parameter"
2561             });
2562         }
2563         else {
2564             try {
2565                 service.Request("luna://com.webos.service.commercial.signage.storageservice", {
2566                     method: "fs/unzip",
2567                     parameters: {
2568                         zipPath: options.zipPath,
2569                         targetPath: options.targetPath
2570                     },
2571                     onSuccess: function (result) {
2572                         log("onSuccess");
2573 
2574                         if (result.returnValue) {
2575                             successCallback();
2576                         }
2577                         else {
2578                             log("FAILED: " + result.errorText);
2579                             errorCallback({
2580                                 errorCode: result.errorCode,
2581                                 errorText: result.errorText
2582                             });
2583                         }
2584                     },
2585                     onFailure: function (result) {
2586                         log("onFailure");
2587                         log("FAILED: " + result.errorText);
2588                         errorCallback({
2589                             errorCode: result.errorCode,
2590                             errorText: result.errorText
2591                         });
2592                     }
2593                 });
2594             } catch (err) {
2595                 log("EXCEPTION" + err);                
2596                 errorCallback({
2597                     errorCode: 'STUF',
2598                     errorText: 'Storage.unzipFile() error is occured during operation.'
2599                 });
2600             }
2601         }
2602     };
2603 
2604     module.exports = Storage;
2605 });
2606 
2607 Storage = cordova.require('cordova/plugin/storage');
2608