[Common] Applied some modifications from vd_fork
[platform/core/api/webapi-plugins.git] / src / filesystem / js / file_stream.js
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 var can_change_size = false;
18
19 function FileStream(data, mode, encoding) {
20     var _totalBytes = data.fileSize || 0;
21     var _position = mode === 'a' ? _totalBytes : 0;
22
23     Object.defineProperties(this, {
24         eof: {
25             get: function() {
26                 return _totalBytes < _position;
27             },
28             set: function(v) {},
29             enumerable: true
30         },
31         position: {
32             get: function() {
33                 return _position;
34             },
35             set: function(v) {
36                 _position = Math.max(0, v);
37                 if (can_change_size) {
38                     _totalBytes = Math.max(_position, _totalBytes);
39                 }
40             },
41             enumerable: true
42         },
43         bytesAvailable: {
44             get: function() {
45                 return this.eof ? -1 : Math.max(0, _totalBytes - _position);
46             },
47             set: function(v) {},
48             enumerable: true
49         },
50         _mode: { value: mode, writable: false, enumerable: false },
51         _encoding: { value: encoding, writable: false, enumerable: false },
52         _file: { value: data, writable: false, enumerable: false },
53         _closed: { value: false, writable: true, enumerable: false },
54         _truncate: {
55             value: mode === 'w', // 'w' truncates file to zero length
56             writable: true,
57             enumerable: false
58         }
59     });
60 }
61
62 function _checkClosed(stream) {
63     if (stream._closed) {
64         throw new WebAPIException(WebAPIException.IO_ERR, 'Stream is closed.');
65     }
66 }
67
68 function closeFileStream() {
69     privUtils_.deprecationWarn(
70         'FileStream.close() is deprecated since Tizen 5.0. ' +
71             'Use FileHandle.close() instead.',
72         '5.0'
73     );
74
75     this._closed = true;
76 }
77
78 FileStream.prototype.close = function() {
79     closeFileStream.apply(this, arguments);
80 };
81
82 function _checkReadAccess(mode) {
83     if (mode !== 'r' && mode !== 'rw') {
84         throw new WebAPIException(WebAPIException.IO_ERR, 'Stream is not in read mode.');
85     }
86 }
87
88 function _checkWriteAccess(mode) {
89     if (mode !== 'a' && mode !== 'w' && mode !== 'rw') {
90         throw new WebAPIException(WebAPIException.IO_ERR, 'Stream is not in write mode.');
91     }
92 }
93
94 function read() {
95     privUtils_.deprecationWarn(
96         'FileStream.read() is deprecated since Tizen 5.0. ' +
97             'Use FileHandle.readString() or FileHandle.readStringNonBlocking() instead.',
98         '5.0'
99     );
100
101     var args = validator_.validateArgs(arguments, [
102         { name: 'charCount', type: types_.LONG }
103     ]);
104
105     _checkClosed(this);
106     _checkReadAccess(this._mode);
107
108     if (!arguments.length) {
109         throw new WebAPIException(
110             WebAPIException.INVALID_VALUES_ERR,
111             'Argument "charCount" missing'
112         );
113     }
114     if (!type_.isNumber(args.charCount)) {
115         throw new WebAPIException(
116             WebAPIException.TYPE_MISMATCH_ERR,
117             'Argument "charCount" must be a number'
118         );
119     }
120     if (args.charCount <= 0) {
121         throw new WebAPIException(
122             WebAPIException.INVALID_VALUES_ERR,
123             'Argument "charCount" must be greater than 0'
124         );
125     }
126     if (this.eof) {
127         throw new WebAPIException(WebAPIException.IO_ERR, 'Stream is marked as EOF.');
128     }
129
130     var _count = this.bytesAvailable;
131
132     var data = {
133         location: commonFS_.toRealPath(this._file.fullPath),
134         encoding: this._encoding,
135         offset: this.position || 0,
136         length: args.charCount > _count ? _count : args.charCount
137     };
138
139     var result = native_.callSync('FileReadString', data);
140     if (native_.isFailure(result)) {
141         throw new WebAPIException(WebAPIException.IO_ERR, 'Could not read');
142     }
143     var outData = native_.getResultObject(result);
144
145     if (outData.length) {
146         can_change_size = true;
147         this.position += outData.length;
148         can_change_size = false;
149     } else {
150         this.position += 1; // Set EOF
151     }
152
153     return outData;
154 }
155
156 FileStream.prototype.read = function() {
157     return read.apply(this, arguments);
158 };
159
160 function readBytes() {
161     var args = validator_.validateArgs(arguments, [
162         { name: 'byteCount', type: types_.LONG }
163     ]);
164
165     _checkClosed(this);
166     _checkReadAccess(this._mode);
167
168     if (args.byteCount <= 0) {
169         throw new WebAPIException(
170             WebAPIException.INVALID_VALUES_ERR,
171             'Argument "byteCount" must be greater than 0'
172         );
173     }
174
175     var _count = this.bytesAvailable;
176
177     var data = {
178         location: commonFS_.toRealPath(this._file.fullPath),
179         offset: this.position || 0,
180         length: args.byteCount > _count ? _count : args.byteCount
181     };
182
183     var result = native_.callSync('FileReadBytes', data);
184     if (native_.isFailure(result)) {
185         throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Could not read');
186     }
187
188     var decoded = StringToArray(native_.getResultObject(result), Array);
189
190     if (decoded.length) {
191         can_change_size = true;
192         this.position += decoded.length;
193         can_change_size = false;
194     } else {
195         this.position += 1; // Set EOF
196     }
197
198     return decoded;
199 }
200
201 FileStream.prototype.readBytes = function() {
202     privUtils_.deprecationWarn(
203         'FileStream.readBytes() is deprecated since Tizen 5.0. ' +
204             'Use FileHandle.readData() or FileHandle.readDataNonBlocking() instead.',
205         '5.0'
206     );
207
208     return readBytes.apply(this, arguments);
209 };
210
211 FileStream.prototype.readBase64 = function() {
212     privUtils_.deprecationWarn(
213         'FileStream.readBase64() is deprecated since Tizen 5.0. ' +
214             'Use FileHandle.readData() or FileHandle.readDataNonBlocking() in combination ' +
215             'with atob() and btoa() functions instead.',
216         '5.0'
217     );
218
219     return base64_encode(readBytes.apply(this, arguments));
220 };
221
222 function check_characters_outside_latin1(str) {
223     var len = str.length;
224     for (var i = 0; i < len; ++i) {
225         if (str.charCodeAt(i) > 255) {
226             throw new WebAPIException(
227                 WebAPIException.IO_ERR,
228                 'Invalid character at ' + i + ': ' + str.charAt(i) + ' (not ISO-8859-1)'
229             );
230         }
231     }
232 }
233
234 function write() {
235     privUtils_.deprecationWarn(
236         'FileStream.write() is deprecated since Tizen 5.0. ' +
237             'Use FileHandle.writeString() or FileHandle.writeStringNonBlocking() instead.',
238         '5.0'
239     );
240
241     var args = validator_.validateArgs(arguments, [
242         { name: 'stringData', type: types_.STRING }
243     ]);
244
245     _checkClosed(this);
246     _checkWriteAccess(this._mode);
247
248     if (!arguments.length) {
249         throw new WebAPIException(
250             WebAPIException.NOT_FOUND_ERR,
251             'Argument "stringData" missing'
252         );
253     }
254
255     var data = {
256         location: commonFS_.toRealPath(this._file.fullPath),
257         encoding: this._encoding,
258         offset: this.position,
259         data: args.stringData,
260         truncate: this._truncate
261     };
262
263     if (data.encoding == 'iso-8859-1') {
264         check_characters_outside_latin1(data.data);
265     }
266
267     var result = native_.callSync('FileWriteString', data);
268
269     if (native_.isFailure(result)) {
270         throw new WebAPIException(WebAPIException.IO_ERR, 'Could not write');
271     }
272     can_change_size = true;
273     this.position = this.position + args.stringData.length;
274     can_change_size = false;
275     this._truncate = false;
276 }
277
278 FileStream.prototype.write = function() {
279     write.apply(this, arguments);
280 };
281
282 function writeBytes() {
283     privUtils_.deprecationWarn(
284         'FileStream.writeBytes() is deprecated since Tizen 5.0. ' +
285             'Use FileHandle.writeData() or FileHandle.writeDataNonBlocking() instead.',
286         '5.0'
287     );
288
289     var args = validator_.validateArgs(arguments, [
290         {
291             name: 'byteData',
292             type: types_.ARRAY,
293             values: undefined /* was types_.OCTET, but checking moved to ArrayToString for
294                              performance */
295         }
296     ]);
297
298     _checkClosed(this);
299     _checkWriteAccess(this._mode);
300
301     if (!arguments.length) {
302         throw new WebAPIException(
303             WebAPIException.TYPE_MISMATCH_ERR,
304             'Argument "byteData" missing'
305         );
306     }
307
308     var data = {
309         location: commonFS_.toRealPath(this._file.fullPath),
310         offset: this.position,
311         data: ArrayToString(args.byteData),
312         truncate: this._truncate
313     };
314
315     var result = native_.callSync('FileWriteBytes', data);
316
317     if (native_.isFailure(result)) {
318         throw new WebAPIException(WebAPIException.IO_ERR, 'Could not write');
319     }
320     can_change_size = true;
321     this.position = this.position + args.byteData.length;
322     can_change_size = false;
323     this._truncate = false;
324 }
325
326 FileStream.prototype.writeBytes = function() {
327     writeBytes.apply(this, arguments);
328 };
329
330 function writeBase64() {
331     privUtils_.deprecationWarn(
332         'FileStream.writeBase64() is deprecated since Tizen 5.0. ' +
333             'Use FileHandle.writeData() or FileHandle.writeDataNonBlocking() in combination ' +
334             'with atob() and btoa() functions instead.',
335         '5.0'
336     );
337
338     var args = validator_.validateArgs(arguments, [
339         { name: 'base64Data', type: types_.STRING }
340     ]);
341
342     _checkClosed(this);
343     _checkWriteAccess(this._mode);
344
345     var data = {
346         location: commonFS_.toRealPath(this._file.fullPath),
347         offset: this.position,
348         data: args.base64Data,
349         truncate: this._truncate
350     };
351
352     var result = native_.callSync('FileWriteBase64', data);
353
354     if (native_.isFailure(result)) {
355         throw native_.getErrorObject(result);
356     }
357
358     var written_bytes = native_.getResultObject(result);
359
360     can_change_size = true;
361     this.position += written_bytes;
362     can_change_size = false;
363     this._truncate = false;
364 }
365
366 FileStream.prototype.writeBase64 = function() {
367     writeBase64.apply(this, arguments);
368 };