Update change log and spec for wrt-plugins-tizen_0.4.70
[framework/web/wrt-plugins-tizen.git] / src / Filesystem / JSFilestream.cpp
1 //
2 // Tizen Web Device API
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18  
19 #include "JSFilestream.h"
20
21 #include <dpl/scoped_array.h>
22
23 #include <Commons/Base64.h>
24 #include <CommonsJavaScript/JSUtils.h>
25 #include <JSWebAPIErrorFactory.h>
26 #include <SecurityExceptions.h>
27 #include <TimeTracer.h>
28 #include <Export.h>
29
30 #include "Converter.h"
31 #include "Encodings.h"
32 #include "plugin_config.h"
33 #include "FilesystemUtils.h"
34 #include <Logger.h>
35
36 namespace {
37 const char* PLUGIN_NAME = "FileStream";
38 const char* PROPERTY_EOF = "eof";
39 const char* PROPERTY_POSITION = "position";
40 const char* PROPERTY_BYTES_AVAILABLE = "bytesAvailable";
41 }
42
43 using namespace WrtDeviceApis::Commons;
44 using namespace WrtDeviceApis::CommonsJavaScript;
45 using namespace DeviceAPI::Common;
46
47 namespace DeviceAPI {
48 namespace Filesystem {
49 JSClassRef JSFilestream::m_classRef = 0;
50
51 JSClassDefinition JSFilestream::m_classInfo = {
52         0,
53         kJSClassAttributeNone,
54         PLUGIN_NAME,
55         0,
56         m_properties,
57         m_functions,
58         initialize,
59         finalize,
60         NULL,
61         NULL,
62         NULL,
63         NULL,
64         getPropertyNames,
65         NULL,
66         NULL,
67         hasInstance,
68         NULL
69 };
70
71 JSStaticValue JSFilestream::m_properties[] = {
72         { PROPERTY_EOF, getProperty, NULL, kJSPropertyAttributeReadOnly },
73         { PROPERTY_POSITION, getProperty, setProperty, kJSPropertyAttributeNone },
74         { PROPERTY_BYTES_AVAILABLE, getProperty, NULL, kJSPropertyAttributeReadOnly },
75         { 0, 0, 0, 0 }
76 };
77
78 JSStaticFunction JSFilestream::m_functions[] = {
79         { "close", close, kJSPropertyAttributeNone },
80         { "read", read, kJSPropertyAttributeNone },
81         { "readBytes", readBytes, kJSPropertyAttributeNone },
82         { "readBase64", readBase64, kJSPropertyAttributeNone },
83         { "write", write, kJSPropertyAttributeNone },
84         { "writeBytes", writeBytes, kJSPropertyAttributeNone },
85         { "writeBase64", writeBase64, kJSPropertyAttributeNone },
86         { 0, 0, 0 }
87 };
88
89 void JSFilestream::initialize(JSContextRef context,
90         JSObjectRef object)
91 {
92 }
93
94 void JSFilestream::finalize(JSObjectRef object)
95 {
96         PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(object));
97         delete privateObject;
98 }
99
100 const JSClassRef DLL_EXPORT JSFilestream::getClassRef()
101 {
102         if (!m_classRef) {
103                 m_classRef = JSClassCreate(&m_classInfo);
104         }
105         return m_classRef;
106 }
107
108 const JSClassDefinition* JSFilestream::getClassInfo()
109 {
110         return &m_classInfo;
111 }
112
113 JSValueRef JSFilestream::getProperty(JSContextRef context,
114                 JSObjectRef object,
115                 JSStringRef propertyName,
116                 JSValueRef* exception)
117 {
118         PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(object));
119         if (!privateObject) {
120                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, "Type mismatch error");
121                 
122         }
123
124         PrivateObject::ObjectType stream = privateObject->getObject();
125         Converter converter(context);
126         try {
127                 if (JSStringIsEqualToUTF8CString(propertyName, PROPERTY_EOF)) {
128                         return converter.toJSValueRef(stream->isEof());
129                 } else if (JSStringIsEqualToUTF8CString(propertyName, PROPERTY_POSITION)) {
130                         long pos = stream->getPosition();
131                         if (pos < 0) {
132                                 return JSValueMakeUndefined(context);
133                         }
134                         return converter.toJSValueRef(static_cast<unsigned long>(pos));
135                 } else if (JSStringIsEqualToUTF8CString(propertyName, PROPERTY_BYTES_AVAILABLE)) {
136                         long position = stream->getPosition();
137                         long bytes = stream->getSize() - position;
138                         
139                         return converter.toJSValueRefLong(static_cast<long>(bytes));
140                 }
141         } catch (const WrtDeviceApis::Commons::ConversionException& ex) {
142                 LoggerW("trying to get incorrect value");
143         }
144
145         return JSValueMakeUndefined(context);
146 }
147
148 bool JSFilestream::setProperty(JSContextRef context,
149                 JSObjectRef object,
150                 JSStringRef propertyName,
151                 JSValueRef value,
152                 JSValueRef* exception)
153 {
154         PrivateObject* privateObject =  static_cast<PrivateObject*>(JSObjectGetPrivate(object));
155         if (!privateObject) {
156                 return false;
157         }
158
159         Converter converter(context);
160         try {
161                 if (JSStringIsEqualToUTF8CString(propertyName, PROPERTY_POSITION)) {
162                         privateObject->getObject()->setPosition(converter.toLong(value));
163                         return true;
164                 }
165         } catch (const WrtDeviceApis::Commons::Exception& ex) {
166                 LoggerW("trying to set incorrect value");
167         }
168
169         return false;
170 }
171
172 void JSFilestream::getPropertyNames(JSContextRef context,
173                 JSObjectRef object,
174                 JSPropertyNameAccumulatorRef propertyNames)
175 {
176 }
177
178 bool JSFilestream::hasInstance(JSContextRef context,
179                 JSObjectRef constructor,
180                 JSValueRef instance,
181                 JSValueRef* exception)
182 {
183     return JSValueIsObjectOfClass(context, instance, JSFilestream::getClassRef());
184 }
185
186 JSValueRef JSFilestream::close(JSContextRef context,
187                 JSObjectRef object,
188                 JSObjectRef thisObject,
189                 size_t argc,
190                 const JSValueRef argv[],
191                 JSValueRef* exception)
192 {
193         TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
194         PrivateObject* privateObject =  static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
195         if (!privateObject) {
196                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, "Type mismatch error");
197                 
198         }
199         
200         TIZEN_CHECK_ACCESS(context, exception, privateObject, FILESYSTEM_FUNCTION_API_CLOSE);
201
202         Try {
203                 privateObject->getObject()->close();
204         } Catch (WrtDeviceApis::Commons::PlatformException) {
205                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::UNKNOWN_ERROR, "Unknown error");
206         }
207
208         TIME_TRACER_ITEM_END(__FUNCTION__, 0);
209         return JSValueMakeUndefined(context);
210 }
211
212 JSValueRef JSFilestream::read(JSContextRef context,
213                 JSObjectRef object,
214                 JSObjectRef thisObject,
215                 size_t argc,
216                 const JSValueRef argv[],
217                 JSValueRef* exception)
218 {
219         TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
220         TIME_TRACER_ITEM_BEGIN("read(UTF8)", 0);
221         PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
222         if (!privateObject) {
223                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, "Type mismatch error");
224         }
225
226         Converter converter(context);
227
228         
229         TIZEN_CHECK_ACCESS(context, exception, privateObject, FILESYSTEM_FUNCTION_API_READ);
230
231         try {
232                 JSValueRef undefinedValue = JSValueMakeUndefined(context);
233                 unsigned long count = 0;
234
235                 if (argc > 0) 
236                         count = converter.toULong(argv[0]);
237                 else 
238                         count = converter.toULong(undefinedValue);
239
240                 if (count <= 0) {
241                         ThrowMsg(InvalidArgumentException, "Invalid argument");
242                 }
243                 std::string outStr = "";
244                 std::string currentCharSet = privateObject->getObject()->getCharSet();
245
246                 DPL::ScopedArray<char> text(privateObject->getObject()->getChars(count));
247
248                 // utf8, iso8859-1, skip
249                 if (!strcmp(currentCharSet.c_str(), Encodings::UTF8) || !strcmp(currentCharSet.c_str(), Encodings::ISO88591))
250                 {
251                         TIME_TRACER_ITEM_END(__FUNCTION__, 0);
252                         return converter.toJSValueRef(std::string(text.Get()));         
253                 }
254                 else 
255                 {
256                         Utils::toUTF8String(currentCharSet, text.Get(), count, outStr);
257                         TIME_TRACER_ITEM_END("read(UTF8)", 0);
258                         return converter.toJSValueRef(outStr);
259                 }
260         } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
261                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, ex.GetMessage());
262         } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
263                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::NOT_SUPPORTED_ERROR, ex.GetMessage());
264         } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
265                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::INVALID_VALUES_ERROR, ex.GetMessage());
266         } catch(const WrtDeviceApis::Commons::PlatformException& ex) {
267                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::IO_ERROR, ex.GetMessage());
268         }
269         
270 }
271
272 JSValueRef JSFilestream::readBytes(JSContextRef context,
273                 JSObjectRef object,
274                 JSObjectRef thisObject,
275                 size_t argc,
276                 const JSValueRef argv[],
277                 JSValueRef* exception)
278 {
279         TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
280         PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
281         if (!privateObject) {
282                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, "Type mismatch error");
283         }
284
285         TIZEN_CHECK_ACCESS(context, exception, privateObject, FILESYSTEM_FUNCTION_API_READ_BYTES);
286
287         Converter converter(context);
288         Try {
289                 JSValueRef undefinedValue = JSValueMakeUndefined(context);
290                 unsigned long count = 0;
291
292                 if (argc > 0) 
293                         count = converter.toULong(argv[0]);
294                 else 
295                         count = converter.toULong(undefinedValue);
296
297                 if (count <= 0) {
298                         ThrowMsg(InvalidArgumentException, "Invalid argument");
299                 }               
300
301                 DPL::ScopedArray<unsigned char> data(privateObject->getObject()->getBytes(count));
302                 TIME_TRACER_ITEM_END(__FUNCTION__, 0);
303                 return converter.toJSValueRef(data.Get(), privateObject->getObject()->getCount());
304         } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
305                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, ex.GetMessage());
306         } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
307                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::NOT_SUPPORTED_ERROR, ex.GetMessage());
308         } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
309                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::INVALID_VALUES_ERROR, ex.GetMessage());
310         } catch(const WrtDeviceApis::Commons::PlatformException& ex) {
311                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::IO_ERROR, ex.GetMessage());
312         }
313
314 }
315
316 JSValueRef JSFilestream::readBase64(JSContextRef context,
317                 JSObjectRef object,
318                 JSObjectRef thisObject,
319                 size_t argc,
320                 const JSValueRef argv[],
321                 JSValueRef* exception)
322 {
323         TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
324         PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
325         if (!privateObject) {
326                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, "Type mismatch error");
327         }
328
329         TIZEN_CHECK_ACCESS(context, exception, privateObject, FILESYSTEM_FUNCTION_API_READ_BASE64);
330
331         Converter converter(context);
332         try {
333                 JSValueRef undefinedValue = JSValueMakeUndefined(context);
334                 unsigned long count = 0;
335
336                 if (argc > 0) 
337                         count = converter.toULong(argv[0]);
338                 else 
339                         count = converter.toULong(undefinedValue);
340
341                 if (count <= 0) {
342                         ThrowMsg(InvalidArgumentException, "Invalid argument");
343                 }
344
345                 DPL::ScopedArray<unsigned char> data(privateObject->getObject()->getBytes(count));
346                 std::string base64 = WrtDeviceApis::Commons::Base64::encode(data.Get(), privateObject->getObject()->getCount());
347                 TIME_TRACER_ITEM_END(__FUNCTION__, 0);
348                 return converter.toJSValueRef(base64);
349         } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
350                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, ex.GetMessage());
351         } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
352                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::NOT_SUPPORTED_ERROR, ex.GetMessage());
353         } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
354                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::INVALID_VALUES_ERROR, ex.GetMessage());
355         } catch(const WrtDeviceApis::Commons::PlatformException& ex) {
356                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::IO_ERROR, ex.GetMessage());
357         }
358
359 }
360
361 JSValueRef JSFilestream::write(JSContextRef context,
362         JSObjectRef object,
363         JSObjectRef thisObject,
364         size_t argc,
365         const JSValueRef argv[],
366         JSValueRef* exception)
367 {
368         TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
369         PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
370         if (!privateObject) {
371                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, "Type mismatch error");
372         }
373
374         TIZEN_CHECK_ACCESS(context, exception, privateObject, FILESYSTEM_FUNCTION_API_WRITE);
375
376         Converter converter(context);
377         try {
378                 JSValueRef undefinedValue = JSValueMakeUndefined(context);
379
380                 if (argc > 0) 
381                         privateObject->getObject()->write(converter.toString(argv[0]));
382                 else 
383                         privateObject->getObject()->write(converter.toString(undefinedValue));
384
385
386         } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
387                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, ex.GetMessage());
388         } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
389                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::NOT_SUPPORTED_ERROR, ex.GetMessage());
390         } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
391                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::INVALID_VALUES_ERROR, ex.GetMessage());
392         } catch(const WrtDeviceApis::Commons::PlatformException& ex) {
393                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::IO_ERROR, ex.GetMessage());
394         }
395
396         TIME_TRACER_ITEM_END(__FUNCTION__, 0);
397         return JSValueMakeUndefined(context);
398 }
399
400 JSValueRef JSFilestream::writeBytes(JSContextRef context,
401                 JSObjectRef object,
402                 JSObjectRef thisObject,
403                 size_t argc,
404                 const JSValueRef argv[],
405                 JSValueRef* exception)
406 {
407         TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
408         PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
409         if (!privateObject) {
410                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, "Type mismatch error");
411         }
412
413         TIZEN_CHECK_ACCESS(context, exception, privateObject, FILESYSTEM_FUNCTION_API_WRITE_BYTES);
414
415         Converter converter(context);
416         Try {
417                 if (argc < 1 || !JSIsArrayValue(context, argv[0]))
418                         ThrowMsg(ConversionException,  "Type mismatch error");
419
420                 PrivateObject::ObjectType stream = privateObject->getObject();
421                 std::vector<unsigned char> data = converter.toVectorOfUChars(argv[0]);
422                 std::vector<unsigned char>::const_iterator it = data.begin();
423                 for (; it != data.end(); ++it) {
424                         stream->write(*it);
425                 }
426         } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
427                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, ex.GetMessage());
428         } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
429                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::NOT_SUPPORTED_ERROR, ex.GetMessage());
430         } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
431                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::INVALID_VALUES_ERROR, ex.GetMessage());
432         } catch(const WrtDeviceApis::Commons::PlatformException& ex) {
433                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::IO_ERROR, ex.GetMessage());
434         }
435
436         TIME_TRACER_ITEM_END(__FUNCTION__, 0);
437         return JSValueMakeUndefined(context);
438 }
439
440 JSValueRef JSFilestream::writeBase64(JSContextRef context,
441                 JSObjectRef object,
442                 JSObjectRef thisObject,
443                 size_t argc,
444                 const JSValueRef argv[],
445                 JSValueRef* exception)
446 {
447         TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 0);
448         PrivateObject* privateObject = static_cast<PrivateObject*>(JSObjectGetPrivate(thisObject));
449         if (!privateObject) {
450                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, "Type mismatch error");
451         }
452
453         TIZEN_CHECK_ACCESS(context, exception, privateObject, FILESYSTEM_FUNCTION_API_WRITE_BASE64);
454
455         Converter converter(context);
456         try {
457                 LoggerD("OK");
458                 
459                 JSValueRef undefinedValue = JSValueMakeUndefined(context);
460                 std::string base64;
461                 if (argc > 0) 
462                         base64 = WrtDeviceApis::Commons::Base64::decode(converter.toString(argv[0]));
463                 else 
464                         base64 = WrtDeviceApis::Commons::Base64::decode(converter.toString(undefinedValue));
465
466                 privateObject->getObject()->write(base64);
467         } catch(const WrtDeviceApis::Commons::ConversionException& ex) {
468                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::TYPE_MISMATCH_ERROR, ex.GetMessage());
469         } catch (const WrtDeviceApis::Commons::UnsupportedException& ex) {
470                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::NOT_SUPPORTED_ERROR, ex.GetMessage());
471         } catch(const WrtDeviceApis::Commons::InvalidArgumentException& ex) {
472                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::INVALID_VALUES_ERROR, ex.GetMessage());
473         } catch(const WrtDeviceApis::Commons::PlatformException& ex) {
474                 return JSWebAPIErrorFactory::postException(context, exception, JSWebAPIErrorFactory::IO_ERROR, ex.GetMessage());
475         }
476
477         TIME_TRACER_ITEM_END(__FUNCTION__, 0);
478         return JSValueMakeUndefined(context);
479 }
480 } // Tizen1_0
481 } // TizenApis
482