1 // Copyright (c) 2013 Intel Corporation. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 var _next_reply_id = 0;
9 var _next_listener_id = 0;
11 var getNextReplyId = function() {
12 return _next_reply_id++;
15 function defineReadOnlyProperty(object, key, value) {
16 Object.defineProperty(object, key, {
23 var postMessage = function(msg, callback) {
24 var reply_id = getNextReplyId();
25 _callbacks[reply_id] = callback;
26 msg.reply_id = reply_id;
27 extension.postMessage(JSON.stringify(msg));
30 extension.setMessageListener(function(json) {
31 var msg = JSON.parse(json);
32 if (msg.cmd === 'storageChanged') {
33 handleStorageChanged(msg);
35 var reply_id = msg.reply_id;
36 var callback = _callbacks[reply_id];
37 if (typeof(callback) === 'function') {
40 delete _callbacks[reply_id];
42 console.log('Invalid reply_id from Tizen Filesystem: ' + reply_id);
47 var sendSyncMessage = function(msg, args) {
50 return JSON.parse(extension.internal.sendSyncMessage(JSON.stringify(args)));
53 var FileSystemStorage = function(label, type, state) {
54 Object.defineProperties(this, {
55 'label': { writable: false, value: label, enumerable: true },
56 'type': { writable: false, value: type, enumerable: true },
57 'state': { writable: false, value: state, enumerable: true }
61 var getFileParent = function(childPath) {
62 if (childPath.search('/') < 0)
65 var parentPath = childPath.substr(0, childPath.lastIndexOf('/'));
66 return new File(parentPath, getFileParent(parentPath));
69 function is_string(value) { return typeof(value) === 'string' || value instanceof String; }
70 function is_integer(value) { return isFinite(value) && !isNaN(parseInt(value)); }
71 function get_valid_mode(mode) {
74 else if (mode === 'a' || mode === 'w' || mode === 'r' || mode === 'rw')
77 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
80 function FileSystemManager() {
81 Object.defineProperty(this, 'maxPathLength', {
83 var message = sendSyncMessage('FileSystemManagerGetMaxPathLength');
92 FileSystemManager.prototype.resolve = function(location, onsuccess,
94 if (!(onsuccess instanceof Function))
95 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
96 if (onerror !== null && !(onerror instanceof Function) &&
98 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
100 mode = get_valid_mode(mode);
103 cmd: 'FileSystemManagerResolve',
106 }, function(result) {
108 onerror(new tizen.WebAPIException(result.errorCode));
110 onsuccess(new File(result.fullPath, getFileParent(result.fullPath)));
114 FileSystemManager.prototype.getStorage = function(label, onsuccess, onerror) {
115 if (!(onsuccess instanceof Function))
116 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
117 if (onerror !== null && !(onerror instanceof Function) &&
118 arguments.length > 2)
119 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
122 cmd: 'FileSystemManagerGetStorage',
124 }, function(result) {
126 onerror(new tizen.WebAPIError(result.errorCode));
128 onsuccess(new FileSystemStorage(result.label, result.type, result.state));
132 FileSystemManager.prototype.listStorages = function(onsuccess, onerror) {
133 if (!(onsuccess instanceof Function))
134 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
135 if (onerror !== null && !(onerror instanceof Function) &&
136 arguments.length > 1)
137 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
140 cmd: 'FileSystemManagerListStorages'
141 }, function(result) {
143 onerror(new tizen.WebAPIError(result.errorCode));
146 for (var i = 0; i < result.value.length; i++) {
147 var storage = result.value[i];
148 storages.push(new FileSystemStorage(storage.label, storage.type, storage.state));
155 function handleStorageChanged(msg) {
156 var storage = msg.storage;
157 _listeners.forEach(function(id) {
158 _listeners[id](new FileSystemStorage(storage.label, storage.type, storage.state));
162 FileSystemManager.prototype.addStorageStateChangeListener = function(onsuccess, onerror) {
163 if (!(onsuccess instanceof Function))
164 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
165 if (onerror !== null && !(onerror instanceof Function) &&
166 arguments.length > 1)
167 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
169 _listeners[_next_listener_id] = onsuccess;
170 return _next_listener_id++;
173 FileSystemManager.prototype.removeStorageStateChangeListener = function(watchId) {
174 if (!(typeof(watchId) !== 'number'))
175 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
177 var index = _listeners.indexOf(watchId);
179 _listeners.slice(index, 1);
181 throw new tizen.WebAPIException(tizen.WebAPIException.NOT_FOUND_ERR);
184 function FileFilter(name, startModified, endModified, startCreated, endCreated) {
186 toString: function() {
187 return JSON.stringify(this);
190 Object.defineProperties(self, {
191 'name': { writable: false, value: name, enumerable: true },
192 'startModified': { writable: false, value: startModified, enumerable: true },
193 'endModified': { writable: false, value: endModified, enumerable: true },
194 'startCreated': { writable: false, value: startCreated, enumerable: true },
195 'endCreated': { writable: false, value: endCreated, enumerable: true }
200 function FileStream(streamID, encoding) {
201 this.streamID = streamID;
202 this.encoding = encoding || 'UTF-8';
204 function fs_stat(streamID) {
205 var result = sendSyncMessage('FileStreamStat', { streamID: streamID });
211 var getStreamID = function() {
214 var getEncoding = function() {
217 var isEof = function() {
218 var status = fs_stat(streamID);
223 var getPosition = function() {
224 var status = fs_stat(streamID);
227 return status.position;
229 var setPosition = function(position) {
230 if (!(is_integer(position)))
233 var result = sendSyncMessage('FileStreamSetPosition',
234 { streamID: this.streamID,
235 position: position });
237 throw new tizen.WebAPIException(result.errorCode);
239 var getBytesAvailable = function() {
240 var status = fs_stat(streamID);
243 return status.bytesAvailable;
246 defineReadOnlyProperty(this, 'eof', false);
247 defineReadOnlyProperty(this, 'bytesAvailable', 0);
249 Object.defineProperties(this, {
250 'streamID': { get: getStreamID, enumerable: false },
251 'encoding': { get: getEncoding, enumerable: false },
252 'position': { get: getPosition, set: setPosition, enumerable: true }
256 FileStream.prototype.close = function() {
257 sendSyncMessage('FileStreamClose', {
258 streamID: this.streamID
262 FileStream.prototype.read = function(charCount) {
263 if (arguments.length == 1 && !(is_integer(charCount)))
264 throw new tizen.WebAPIException(tizen.WebAPIException.INVALID_VALUES_ERR);
266 var result = sendSyncMessage('FileStreamRead', {
267 streamID: this.streamID,
268 encoding: this.encoding,
273 throw new tizen.WebAPIException(result.errorCode);
278 FileStream.prototype.readBytes = function(byteCount) {
279 if (arguments.length == 1 && !(is_integer(byteCount)))
280 throw new tizen.WebAPIException(tizen.WebAPIException.INVALID_VALUES_ERR);
282 var result = sendSyncMessage('FileStreamRead', {
283 streamID: this.streamID,
284 encoding: this.encoding,
289 throw new tizen.WebAPIException(result.errorCode);
294 FileStream.prototype.readBase64 = function(byteCount) {
295 if (arguments.length == 1 && !(is_integer(byteCount)))
296 throw new tizen.WebAPIException(tizen.WebAPIException.INVALID_VALUES_ERR);
298 var result = sendSyncMessage('FileStreamRead', {
299 streamID: this.streamID,
300 encoding: this.encoding,
305 throw new tizen.WebAPIException(result.errorCode);
310 FileStream.prototype.write = function(stringData) {
311 if (!(is_string(stringData)))
312 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
314 var result = sendSyncMessage('FileStreamWrite', {
315 streamID: this.streamID,
316 encoding: this.encoding,
321 throw new tizen.WebAPIException(result.errorCode);
324 FileStream.prototype.writeBytes = function(byteData) {
325 if (!Array.isArray(byteData))
326 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
328 var result = sendSyncMessage('FileStreamWrite', {
329 streamID: this.streamID,
330 encoding: this.encoding,
335 throw new tizen.WebAPIException(result.errorCode);
338 FileStream.prototype.writeBase64 = function(base64Data) {
339 if (!(is_string(base64Data)))
340 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
342 var result = sendSyncMessage('FileStreamWrite', {
343 streamID: this.streamID,
344 encoding: this.encoding,
349 throw new tizen.WebAPIException(result.errorCode);
352 function File(fullPath, parent) {
353 this.fullPath = fullPath;
354 this.parent = parent;
356 var stat_cached = undefined;
357 var stat_last_time = undefined;
360 var now = Date.now();
361 if (stat_cached === undefined || (now - stat_last_time) > 5) {
362 var result = sendSyncMessage('FileStat', { fullPath: fullPath });
366 stat_cached = result;
367 stat_last_time = now;
368 result.value.isError = result.isError;
371 return stat_cached.value;
374 var getParent = function() {
377 var getReadOnly = function() {
381 return status.readOnly;
383 var getIsFile = function() {
387 return status.isFile;
389 var getIsDirectory = function() {
393 return status.isDirectory;
395 var getCreatedDate = function() {
399 return new Date(status.created * 1000);
401 var getModifiedDate = function() {
405 return new Date(status.modified * 1000);
407 var getPath = function() {
408 var lastSlashIndex = fullPath.lastIndexOf('/');
409 if (lastSlashIndex < 0)
411 return fullPath.slice(0, lastSlashIndex + 1);
413 var getName = function() {
414 var lastSlashIndex = fullPath.lastIndexOf('/');
415 if (lastSlashIndex < 0)
417 return fullPath.substr(lastSlashIndex + 1);
419 var getFullPath = function() {
422 var getFileSize = function() {
426 if (status.isDirectory)
430 var getLength = function() {
434 if (status.isDirectory)
435 return status.length;
439 Object.defineProperties(this, {
440 'parent': { get: getParent, enumerable: true },
441 'readOnly': { get: getReadOnly, enumerable: true },
442 'isFile': { get: getIsFile, enumerable: true },
443 'isDirectory': { get: getIsDirectory, enumerable: true },
444 'created': { get: getCreatedDate, enumerable: true },
445 'modified': { get: getModifiedDate, enumerable: true },
446 'path': { get: getPath, enumerable: true },
447 'name': { get: getName, enumerable: true },
448 'fullPath': { get: getFullPath, enumerable: true },
449 'fileSize': { get: getFileSize, enumerable: true },
450 'length': { get: getLength, enumerable: true }
454 File.prototype.toURI = function() {
455 var status = sendSyncMessage('FileGetURI', { fullPath: this.fullPath });
462 File.prototype.listFiles = function(onsuccess, onerror, filter) {
463 if (!(onsuccess instanceof Function))
464 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
465 if (onerror !== null && !(onerror instanceof Function) &&
466 arguments.length > 1)
467 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
468 if (filter !== null && !(filter instanceof FileFilter) &&
469 arguments.length > 2)
470 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
473 cmd: 'FileListFiles',
474 fullPath: this.fullPath,
475 filter: filter ? filter.toString() : ''
476 }, function(result) {
477 if (result.isError) {
479 onerror(new tizen.WebAPIError(result.errorCode));
480 } else if (onsuccess) {
483 for (var i = 0; i < result.value.length; i++)
484 file_list.push(new File(result.value[i], getFileParent(result.value[i])));
486 onsuccess(file_list);
491 File.prototype.openStream = function(mode, onsuccess, onerror, encoding) {
492 if (!(onsuccess instanceof Function))
493 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
494 if (onerror !== null && !(onerror instanceof Function) &&
495 arguments.length > 2)
496 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
498 mode = get_valid_mode(mode);
500 if ((arguments.length > 3 && is_string(encoding)) &&
501 (encoding != 'UTF-8' && encoding != 'ISO-8859-1'))
502 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
505 cmd: 'FileOpenStream',
506 fullPath: this.fullPath,
509 }, function(result) {
510 if (result.isError) {
512 onerror(new tizen.WebAPIError(result.errorCode));
513 } else if (onsuccess) {
514 onsuccess(new FileStream(result.streamID, result.encoding));
519 File.prototype.readAsText = function(onsuccess, onerror, encoding) {
520 if (!(onsuccess instanceof Function))
521 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
522 if (onerror !== null && !(onerror instanceof Function) &&
523 arguments.length > 1)
524 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
526 if ((arguments.length > 2 && is_string(encoding)) &&
527 (encoding != 'UTF-8' && encoding != 'ISO-8859-1'))
528 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
530 var streamOpened = function(stream) {
531 onsuccess(stream.read());
534 var streamError = function(error) {
539 if (this.isDirectory) {
540 streamError(new tizen.WebAPIException(tizen.WebAPIException.IO_ERR));
544 this.openStream('r', streamOpened, streamError, encoding);
547 File.prototype.copyTo = function(originFilePath, destinationFilePath,
548 overwrite, onsuccess, onerror) {
549 // originFilePath, destinationFilePath - full virtual file path
550 if (onsuccess !== null && !(onsuccess instanceof Function) &&
551 arguments.length > 3)
552 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
553 if (onerror !== null && !(onerror instanceof Function) &&
554 arguments.length > 4)
555 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
557 if (!is_string(originFilePath) || !is_string(destinationFilePath)) {
558 onerror(new tizen.WebAPIException(tizen.WebAPIException.NOT_FOUND_ERR));
562 if (originFilePath.indexOf('./') >= 0 || destinationFilePath.indexOf('./') >= 0) {
563 onerror(new tizen.WebAPIException(tizen.WebAPIException.NOT_FOUND_ERR));
567 if (originFilePath.indexOf(this.fullPath) < 0) {
568 onerror(new tizen.WebAPIException(tizen.WebAPIException.NOT_FOUND_ERR));
574 originFilePath: originFilePath,
575 destinationFilePath: destinationFilePath,
577 }, function(result) {
578 if (result.isError) {
580 onerror(new tizen.WebAPIException(result.errorCode));
582 } else if (onsuccess) {
588 File.prototype.moveTo = function(originFilePath, destinationFilePath,
589 overwrite, onsuccess, onerror) {
590 // originFilePath, destinationFilePath - full virtual file path
591 if (onsuccess !== null && !(onsuccess instanceof Function) &&
592 arguments.length > 3)
593 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
594 if (onerror !== null && !(onerror instanceof Function) &&
595 arguments.length > 4)
596 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
598 if (!is_string(originFilePath) || !is_string(destinationFilePath)) {
599 onerror(new tizen.WebAPIException(tizen.WebAPIException.NOT_FOUND_ERR));
603 if (originFilePath.indexOf('./') >= 0 || destinationFilePath.indexOf('./') >= 0) {
604 onerror(new tizen.WebAPIException(tizen.WebAPIException.NOT_FOUND_ERR));
608 if (originFilePath.indexOf(this.fullPath) < 0) {
609 onerror(new tizen.WebAPIException(tizen.WebAPIException.NOT_FOUND_ERR));
615 originFilePath: originFilePath,
616 destinationFilePath: destinationFilePath,
618 }, function(result) {
619 if (result.isError) {
621 onerror(new tizen.WebAPIException(result.errorCode));
623 } else if (onsuccess) {
629 File.prototype.createDirectory = function(relativeDirPath) {
630 if (relativeDirPath.indexOf('./') >= 0)
631 throw new tizen.WebAPIException(tizen.WebAPIException.INVALID_VALUES_ERR);
633 var status = sendSyncMessage('FileCreateDirectory', {
634 fullPath: this.fullPath,
635 relativeDirPath: relativeDirPath
639 throw new tizen.WebAPIException(status.errorCode);
641 return new File(status.value, getFileParent(status.value));
644 File.prototype.createFile = function(relativeFilePath) {
645 if (relativeFilePath.indexOf('./') >= 0)
646 throw new tizen.WebAPIException(tizen.WebAPIException.INVALID_VALUES_ERR);
648 var status = sendSyncMessage('FileCreateFile', {
649 fullPath: this.fullPath,
650 relativeFilePath: relativeFilePath
654 throw new tizen.WebAPIException(status.errorCode);
656 return new File(status.value, getFileParent(status.value));
659 File.prototype.resolve = function(relativeFilePath) {
660 var status = sendSyncMessage('FileResolve', {
661 fullPath: this.fullPath,
662 relativeFilePath: relativeFilePath
666 throw new tizen.WebAPIException(status.errorCode);
668 return new File(status.value, getFileParent(status.value));
671 File.prototype.deleteDirectory = function(directoryPath, recursive, onsuccess, onerror) {
672 // directoryPath - full virtual directory path
673 if (onsuccess !== null && !(onsuccess instanceof Function) &&
674 arguments.length > 2)
675 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
676 if (onerror !== null && !(onerror instanceof Function) &&
677 arguments.length > 3)
678 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
680 if (directoryPath.indexOf(this.fullPath) < 0 && onerror) {
681 onerror(new tizen.WebAPIError(tizen.WebAPIException.NOT_FOUND_ERR));
686 cmd: 'FileDeleteDirectory',
687 directoryPath: directoryPath,
688 recursive: !!recursive
689 }, function(result) {
690 if (result.isError) {
692 onerror(new tizen.WebAPIError(result.errorCode));
693 } else if (onsuccess) {
699 File.prototype.deleteFile = function(filePath, onsuccess, onerror) {
700 // filePath - full virtual file path
701 if (onsuccess !== null && !(onsuccess instanceof Function) &&
702 arguments.length > 1)
703 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
704 if (onerror !== null && !(onerror instanceof Function) &&
705 arguments.length > 2)
706 throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR);
708 if (filePath.indexOf(this.fullPath) < 0 && onerror) {
709 onerror(new tizen.WebAPIError(tizen.WebAPIException.NOT_FOUND_ERR));
714 cmd: 'FileDeleteFile',
716 }, function(result) {
717 if (result.isError) {
719 onerror(new tizen.WebAPIError(result.errorCode));
720 } else if (onsuccess) {
727 exports = new FileSystemManager();