From 3fa108400b5bf98d9191ea6f3d92406310408cea Mon Sep 17 00:00:00 2001 From: Arkadiusz Pietraszek Date: Mon, 8 Jan 2018 16:23:33 +0100 Subject: [PATCH 01/16] [Filesystem] Fix to commit ce958812096 to read 64 Kb and greater files Commit ce958812096 has introduced error in which only first 64 Kb of text file was read. [Verification] TCT pass rate is 100% Automated tests has been run: tct-archive-tizen-tests tct-systeminfo-tizen-tests tct-content-tizen-tests tct-filesystem-tizen-tests Change-Id: I266c839e78af9420bdad328e8fa4332bdc16b8a4 --- src/filesystem/js/file.js | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/filesystem/js/file.js b/src/filesystem/js/file.js index 8424826..a55531d 100644 --- a/src/filesystem/js/file.js +++ b/src/filesystem/js/file.js @@ -324,20 +324,24 @@ function readAsText() { function readFile() { var result, encoded, buffers = []; - result = native_.callSync('File_readSync', data); - if (native_.isFailure(result)) { - setTimeout(function() { - native_.callIfPossible(args.onerror, native_.getErrorObject(result)); - }, 0); - return; - } - result = native_.getResultObject(result); - if (result.length) { - data.offset += data.length; - } + var output = ""; + do { + result = native_.callSync('File_readSync', data); + if (native_.isFailure(result)) { + setTimeout(function() { + native_.callIfPossible(args.onerror, native_.getErrorObject(result)); + }, 0); + return; + } + result = native_.getResultObject(result); + if (result.length) { + data.offset += data.length; + } + output = output + result; + } while (result.length); setTimeout(function() { - native_.callIfPossible(args.onsuccess, result); + native_.callIfPossible(args.onsuccess, output); }, 0); } -- 2.7.4 From f745269c0e4e1efa1f78ac9579c4fe33a5b0c74c Mon Sep 17 00:00:00 2001 From: Piotr Kosko Date: Tue, 16 Jan 2018 10:38:34 +0100 Subject: [PATCH 02/16] [version] 2.13 Code format was also fixed Change-Id: Iae0d214d3caeeb67cdbfe1938718863d70a15789 Signed-off-by: Piotr Kosko --- packaging/webapi-plugins.spec | 2 +- src/bluetooth/bluetooth_le_device.cc | 4 ++-- src/filesystem/filesystem_instance.cc | 3 ++- src/iotcon/iotcon_instance.cc | 12 ++++++------ src/messaging/DBus/MessageProxy.cpp | 2 +- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/packaging/webapi-plugins.spec b/packaging/webapi-plugins.spec index 545ab7d..4cc0921 100644 --- a/packaging/webapi-plugins.spec +++ b/packaging/webapi-plugins.spec @@ -10,7 +10,7 @@ %define crosswalk_extensions_path %{_libdir}/%{crosswalk_extensions} Name: webapi-plugins -Version: 2.12 +Version: 2.13 Release: 0 License: Apache-2.0 and BSD-3-Clause and MIT Group: Development/Libraries diff --git a/src/bluetooth/bluetooth_le_device.cc b/src/bluetooth/bluetooth_le_device.cc index b0f6413..62caee5 100644 --- a/src/bluetooth/bluetooth_le_device.cc +++ b/src/bluetooth/bluetooth_le_device.cc @@ -435,9 +435,9 @@ void BluetoothLEDevice::GattConnectionState(int result, bool connected, const ch // check state change success PlatformResult operation_success = ValidateConnectionChange(result); if (operation_success) { - if (connected) { // connect success + if (connected) { // connect success le_device->is_connected_.insert(remote_address); - } else { // disconnect success + } else { // disconnect success le_device->CleanClientInfo(remote_address); } } diff --git a/src/filesystem/filesystem_instance.cc b/src/filesystem/filesystem_instance.cc index 08c0fe5..e32021a 100644 --- a/src/filesystem/filesystem_instance.cc +++ b/src/filesystem/filesystem_instance.cc @@ -158,7 +158,8 @@ void FilesystemInstance::FileReadSync(const picojson::value& args, picojson::obj PrepareError(e, out); }; - FilesystemManager::GetInstance().FileRead(location, offset, length, is_string, onSuccess, onError); + FilesystemManager::GetInstance().FileRead(location, offset, length, is_string, onSuccess, + onError); } void FilesystemInstance::FileWrite(const picojson::value& args, picojson::object& out) { diff --git a/src/iotcon/iotcon_instance.cc b/src/iotcon/iotcon_instance.cc index d650699..705fb1f 100644 --- a/src/iotcon/iotcon_instance.cc +++ b/src/iotcon/iotcon_instance.cc @@ -1379,12 +1379,12 @@ common::TizenResult IotconInstance::ClientFindResource(const picojson::object& a delete data; LogAndReturnTizenError(result); } else { - int timeout = 60; //default value set much bigger than default value for iotcon = 30s + int timeout = 60; // default value set much bigger than default value for iotcon = 30s auto result = IotconUtils::ConvertIotconError(iotcon_get_timeout(&timeout)); if (!result) { LoggerE("iotcon_get_timeout - function call failed, using default value %d", timeout); } else { - timeout = timeout + 10; //add 10 extra second to prevent too fast delete + timeout = timeout + 10; // add 10 extra second to prevent too fast delete } // adding listener to delete data, when find would be finished std::thread([data, timeout]() { @@ -1550,12 +1550,12 @@ common::TizenResult IotconInstance::ClientFindDeviceInfo(const picojson::object& delete data; LogAndReturnTizenError(result); } else { - int timeout = 60; //default value set much bigger than default value for iotcon = 30s + int timeout = 60; // default value set much bigger than default value for iotcon = 30s auto result = IotconUtils::ConvertIotconError(iotcon_get_timeout(&timeout)); if (!result) { LoggerE("iotcon_get_timeout - function call failed, using default value %d", timeout); } else { - timeout = timeout + 10; //add 10 extra second to prevent too fast delete + timeout = timeout + 10; // add 10 extra second to prevent too fast delete } // adding listener to delete data, when find would be finished std::thread([data, timeout]() { @@ -1656,12 +1656,12 @@ common::TizenResult IotconInstance::ClientFindPlatformInfo(const picojson::objec delete data; LogAndReturnTizenError(result); } else { - int timeout = 60; //default value set much bigger than default value for iotcon = 30s + int timeout = 60; // default value set much bigger than default value for iotcon = 30s auto result = IotconUtils::ConvertIotconError(iotcon_get_timeout(&timeout)); if (!result) { LoggerE("iotcon_get_timeout - function call failed, using default value %d", timeout); } else { - timeout = timeout + 10; //add 10 extra second to prevent too fast delete + timeout = timeout + 10; // add 10 extra second to prevent too fast delete } // adding listener to delete data, when find would be finished std::thread([data, timeout]() { diff --git a/src/messaging/DBus/MessageProxy.cpp b/src/messaging/DBus/MessageProxy.cpp index 30e17b5..19c6253 100644 --- a/src/messaging/DBus/MessageProxy.cpp +++ b/src/messaging/DBus/MessageProxy.cpp @@ -35,7 +35,7 @@ MessageProxy::MessageProxy(EmailManager& manager) : common::dbus::Proxy(kDBusPathEmailStorageChange, kDBusIfaceEmailStorageChange, kDBusNameSignalEmail, kDBusPathEmailStorageChange, kDBusIfaceEmailStorageChange), - email_manager_(manager) { + email_manager_(manager) { ScopeLogger(); } -- 2.7.4 From c03544c5c8a382440ca703374cfd88a732b75f36 Mon Sep 17 00:00:00 2001 From: Rafal Walczyna Date: Wed, 17 Jan 2018 14:43:45 +0100 Subject: [PATCH 03/16] [humanactivitymonitor] Fix timestamp in HumanActivityRecognitionData [Verification] auto and manual tests which use this data pass Change-Id: I8f174925147c561cfcf22590cc5d4b5abbbba506 Signed-off-by: Rafal Walczyna (cherry picked from commit f3123977c14bad5410ee36b520f07c4061d4fc3a) --- src/humanactivitymonitor/humanactivitymonitor_manager.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/humanactivitymonitor/humanactivitymonitor_manager.cc b/src/humanactivitymonitor/humanactivitymonitor_manager.cc index 4b08cd0..8897a28 100644 --- a/src/humanactivitymonitor/humanactivitymonitor_manager.cc +++ b/src/humanactivitymonitor/humanactivitymonitor_manager.cc @@ -1204,7 +1204,7 @@ class HumanActivityMonitorManager::ActivityRecognition { callback(&val); return; } - + timestamp = std::floor(timestamp); SLoggerD("Activity type: (%d)", type); SLoggerD("Activity accuracy: (%d)", accuracy); SLoggerD("Activity timestamp: (%f)", timestamp); -- 2.7.4 From f95fafc2ed357c0cc33e6e8658cee44ae15d5e14 Mon Sep 17 00:00:00 2001 From: Jakub Skowron Date: Wed, 10 Jan 2018 07:54:35 +0100 Subject: [PATCH 04/16] [Filesystem] Read file performace improvement (binary data through UTF-8) Improve performance of readBytes, readBase64 by pushing binary data through UTF-8 null-terminated string. Byte 0x00 is encoded as U+0100. Removed not used functions in FilesystemFile. Improved performance of readAsText. [Verification] TCT pass rate is 100% tct-filesystem-tizen-tests Change-Id: I41fe2f9c7855721b38ad4bbf268e8eb7851b10eb Signed-off-by: Jakub Skowron --- src/filesystem/filesystem_file.cc | 110 +------------------------ src/filesystem/filesystem_file.h | 2 - src/filesystem/filesystem_instance.cc | 146 +++++++++++++++++++++++++++------- src/filesystem/filesystem_instance.h | 4 +- src/filesystem/filesystem_manager.cc | 29 ------- src/filesystem/filesystem_manager.h | 4 - src/filesystem/js/file.js | 35 +++----- src/filesystem/js/file_stream.js | 79 ++++-------------- 8 files changed, 153 insertions(+), 256 deletions(-) diff --git a/src/filesystem/filesystem_file.cc b/src/filesystem/filesystem_file.cc index 7172f3d..1174747 100644 --- a/src/filesystem/filesystem_file.cc +++ b/src/filesystem/filesystem_file.cc @@ -162,112 +162,6 @@ FilesystemFile::FilesystemFile(const std::string& path_) : path(path_) { ScopeLogger(); } -bool FilesystemFile::Read(FilesystemBuffer* data, size_t offset, size_t length) { - ScopeLogger(); - if (!data) { - LoggerE("Missing output buffer"); - return false; - } - - data->resize(length); - FILE* file = fopen(path.c_str(), "r"); - if (!file) { - LoggerE("Cannot open file %s to read!", path.c_str()); - return false; - } - SCOPE_EXIT { - int status = fclose(file); - if (status) { - LoggerE("Cannot close file!"); - } - }; - int status; - status = fseek(file, offset, SEEK_SET); - if (status) { - LoggerE("Cannot perform seek!"); - return false; - } - - size_t readed = 0; - uint8_t* data_p = data->data(); - size_t data_size = length; - while (readed < data->size()) { - size_t part = fread(data_p, 1, data_size, file); - - readed += part; - data_p += part; - data_size -= part; - - LoggerD("Readed part %li bytes", readed); - - if (ferror(file)) { - LoggerE("Error during file write!"); - return false; - } - - if (feof(file)) { - LoggerD("File is at end before buffer is filled. Finish."); - break; - } - } - LoggerD("Readed %li bytes", readed); - data->resize(readed); - return true; -} - -bool FilesystemFile::ReadString(std::vector* data, size_t offset, size_t length) { - ScopeLogger(); - if (!data) { - LoggerE("Missing output buffer"); - return false; - } - - data->resize(length); - FILE* file = fopen(path.c_str(), "r"); - if (!file) { - LoggerE("Cannot open file %s to read!", path.c_str()); - return false; - } - SCOPE_EXIT { - int status = fclose(file); - if (status) { - LoggerE("Cannot close file!"); - } - }; - int status; - status = fseek(file, offset, SEEK_SET); - if (status) { - LoggerE("Cannot perform seek!"); - return false; - } - - size_t readed = 0; - char* data_p = data->data(); - size_t data_size = length; - while (readed < data->size()) { - size_t part = fread(data_p, 1, data_size, file); - - readed += part; - data_p += part; - data_size -= part; - - LoggerD("Readed part %u bytes", readed); - - if (ferror(file)) { - LoggerE("Error during file write!"); - return false; - } - - if (feof(file)) { - LoggerD("File is at end before buffer is filled. Finish."); - break; - } - } - LoggerD("Readed %u bytes", readed); - data->resize(readed); - return true; -} - bool FilesystemFile::Write(const FilesystemBuffer& data, size_t offset, bool rewrite) { ScopeLogger(); @@ -292,7 +186,7 @@ bool FilesystemFile::Write(const FilesystemBuffer& data, size_t offset, bool rew int status; status = fseek(file, offset, SEEK_SET); - LoggerD("Offset is %li, writing %i bytes", offset, data.size()); + LoggerD("Offset is %u, writing %i bytes", offset, data.size()); if (status) { LoggerE("Cannot perform seek!"); return false; @@ -325,7 +219,7 @@ bool FilesystemFile::Write(const FilesystemBuffer& data, size_t offset, bool rew LoggerE("Cannot sync file!"); return false; } - LoggerD("Written %li bytes", written); + LoggerD("Written %u bytes", written); return true; } diff --git a/src/filesystem/filesystem_file.h b/src/filesystem/filesystem_file.h index 1e2d5c8..e8dce33 100644 --- a/src/filesystem/filesystem_file.h +++ b/src/filesystem/filesystem_file.h @@ -44,8 +44,6 @@ class FilesystemFile { public: FilesystemFile(const std::string& path_); - bool Read(FilesystemBuffer* data, size_t offset, size_t length); - bool ReadString(std::vector* data, size_t offset, size_t length); bool Write(const FilesystemBuffer& data, size_t offset, bool rewrite); bool WriteString(const std::string& data, size_t offset, bool rewrite); }; diff --git a/src/filesystem/filesystem_instance.cc b/src/filesystem/filesystem_instance.cc index e32021a..848c6dc 100644 --- a/src/filesystem/filesystem_instance.cc +++ b/src/filesystem/filesystem_instance.cc @@ -16,11 +16,15 @@ #include "filesystem/filesystem_instance.h" +#include #include +#include +#include #include "common/logger.h" #include "common/picojson.h" #include "common/platform_exception.h" +#include "common/scope_exit.h" #include "common/task-queue.h" #include "common/tools.h" #include "filesystem_manager.h" @@ -43,29 +47,26 @@ FilesystemInstance::FilesystemInstance() { using std::placeholders::_2; #define REGISTER_SYNC(c, x) RegisterSyncHandler(c, std::bind(&FilesystemInstance::x, this, _1, _2)); -#define REGISTER_ASYNC(c, x) \ - RegisterSyncHandler(c, std::bind(&FilesystemInstance::x, this, _1, _2)); - - REGISTER_ASYNC("File_stat", FileStat); + REGISTER_SYNC("File_stat", FileStat); REGISTER_SYNC("File_statSync", FileStatSync); REGISTER_SYNC("File_createSync", FileCreateSync); - REGISTER_ASYNC("File_readDir", ReadDir); - REGISTER_ASYNC("File_rename", FileRename); - REGISTER_SYNC("File_readSync", FileReadSync); - REGISTER_ASYNC("File_write", FileWrite); + REGISTER_SYNC("File_readDir", ReadDir); + REGISTER_SYNC("File_rename", FileRename); + REGISTER_SYNC("File_readBytes", FileReadBytes); + REGISTER_SYNC("File_readString", FileReadString); + REGISTER_SYNC("File_write", FileWrite); REGISTER_SYNC("File_writeSync", FileWriteSync); REGISTER_SYNC("Filesystem_fetchVirtualRoots", FilesystemFetchVirtualRoots); REGISTER_SYNC("FileSystemManager_addStorageStateChangeListener", StartListening); REGISTER_SYNC("FileSystemManager_removeStorageStateChangeListener", StopListening); REGISTER_SYNC("FileSystemManager_fetchStorages", FileSystemManagerFetchStorages); - REGISTER_ASYNC("FileSystemManager_mkdir", FileSystemManagerMakeDirectory); + REGISTER_SYNC("FileSystemManager_mkdir", FileSystemManagerMakeDirectory); REGISTER_SYNC("FileSystemManager_mkdirSync", FileSystemManagerMakeDirectorySync); - REGISTER_ASYNC("File_unlinkFile", UnlinkFile); - REGISTER_ASYNC("File_removeDirectory", RemoveDirectory); - REGISTER_ASYNC("File_copyTo", CopyTo); + REGISTER_SYNC("File_unlinkFile", UnlinkFile); + REGISTER_SYNC("File_removeDirectory", RemoveDirectory); + REGISTER_SYNC("File_copyTo", CopyTo); REGISTER_SYNC("FileSystemManager_getCanonicalPath", FileSystemManagerGetCanonicalPath); #undef REGISTER_SYNC -#undef REGISTER_ASYNC FilesystemManager::GetInstance().AddListener(this); } @@ -135,31 +136,122 @@ void FilesystemInstance::FileRename(const picojson::value& args, picojson::objec std::bind(&FilesystemManager::Rename, &fsm, oldPath, newPath, onSuccess, onError)); } -void FilesystemInstance::FileReadSync(const picojson::value& args, picojson::object& out) { +static constexpr std::size_t NPOS = (std::size_t)(-1); +/** + * Returns a buffer. If length is NPOS, then it reads whole file, up to the end. + * On failure throws std::runtime_error + */ +static std::vector read_file(std::string path, std::size_t offset, + std::size_t length = NPOS) { + ScopeLogger(); + + FILE* file = std::fopen(path.c_str(), "r"); + if (!file) { + throw std::runtime_error("cannot open file to read"); + } + + SCOPE_EXIT { + int status = std::fclose(file); + if (status) { + LoggerE("Cannot close file!"); + } + }; + + if (std::fseek(file, offset, SEEK_SET) != 0) { + throw std::runtime_error("cannot perform seek"); + } + + // By default reads whole file. Get the file size. + if (length == NPOS) { + struct ::stat buf; + if (::fstat(::fileno(file), &buf) != 0) { + throw std::runtime_error("cannot fstat"); + } + length = buf.st_size - offset; + } + + std::vector out_buf(length); + std::uint8_t* data_p = out_buf.data(); + std::uint8_t* end_p = data_p + length; + while (data_p != end_p) { + data_p += std::fread(data_p, 1, end_p - data_p, file); + + if (std::ferror(file)) { + throw std::runtime_error("error during file read"); + } + + if (std::feof(file)) { + LoggerD("File is at end before buffer is filled. Finish."); + break; + } + } + return out_buf; +} + +/* str should be reference to (possibly empty) std::string */ +static void encode_binary_in_string(const std::vector& buf, std::string& str) { + ScopeLogger(); + str.reserve(str.size() + buf.size()); + + for (std::uint8_t byte : buf) { + if (byte >= 128) { + str += 0xC0 | (byte >> 6); + str += 0x80 | (byte & 0x3F); + } else if (byte > 0) { + str += byte; + } else { + // zero as codepoint U+0100 + str += 0xC4; + str += 0x80; + } + } +} + +void FilesystemInstance::FileReadString(const picojson::value& args, picojson::object& out) { + ScopeLogger(); + CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out); + CHECK_EXIST(args, "location", out) + CHECK_EXIST(args, "offset", out) + CHECK_EXIST(args, "encoding", out) + + const std::string& location = args.get("location").get(); + size_t offset = static_cast(args.get("offset").get()); + size_t length = args.contains("length") ? (size_t)args.get("length").get() : NPOS; + + try { + std::vector out_data = read_file(location, offset, length); + out_data.push_back('\0'); + const char* str = (const char*)out_data.data(); + + // TODO: support iso-8859-1 (latin-1) encoding + ReportSuccess(picojson::value{str}, out); + } catch (std::runtime_error& e) { + LoggerE("Cannot read file %s, cause: %s", location.c_str(), e.what()); + PrepareError(FilesystemError::Other, out); + } +} + +void FilesystemInstance::FileReadBytes(const picojson::value& args, picojson::object& out) { ScopeLogger(); CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemRead, &out); CHECK_EXIST(args, "location", out) CHECK_EXIST(args, "offset", out) CHECK_EXIST(args, "length", out) - CHECK_EXIST(args, "isString", out) const std::string& location = args.get("location").get(); size_t offset = static_cast(args.get("offset").get()); size_t length = static_cast(args.get("length").get()); - bool is_string = static_cast(args.get("isString").get()); - - auto onSuccess = [this, &out](const std::string& data) { - ScopeLogger("Entered into asynchronous function, onSuccess"); - ReportSuccess(picojson::value(data), out); - }; - auto onError = [this, &out](FilesystemError e) { - ScopeLogger("Entered into asynchronous function, onError"); - PrepareError(e, out); - }; + try { + std::vector out_data = read_file(location, offset, length); - FilesystemManager::GetInstance().FileRead(location, offset, length, is_string, onSuccess, - onError); + out["result"] = picojson::value(picojson::string_type, true); + encode_binary_in_string(out_data, out["result"].get()); + ReportSuccess(out); + } catch (std::runtime_error& e) { + LoggerE("Cannot read file %s, cause: %s", location.c_str(), e.what()); + PrepareError(FilesystemError::Other, out); + } } void FilesystemInstance::FileWrite(const picojson::value& args, picojson::object& out) { diff --git a/src/filesystem/filesystem_instance.h b/src/filesystem/filesystem_instance.h index 2212323..da21bc7 100644 --- a/src/filesystem/filesystem_instance.h +++ b/src/filesystem/filesystem_instance.h @@ -35,8 +35,8 @@ class FilesystemInstance : public common::ParsedInstance, FilesystemStateChangeL void FileRename(const picojson::value& args, picojson::object& out); void FileStat(const picojson::value& args, picojson::object& out); void FileStatSync(const picojson::value& args, picojson::object& out); - void FileRead(const picojson::value& args, picojson::object& out); - void FileReadSync(const picojson::value& args, picojson::object& out); + void FileReadString(const picojson::value& args, picojson::object& out); + void FileReadBytes(const picojson::value& args, picojson::object& out); void FileWrite(const picojson::value& args, picojson::object& out); void FileWriteSync(const picojson::value& args, picojson::object& out); void FilesystemFetchVirtualRoots(const picojson::value& args, picojson::object& out); diff --git a/src/filesystem/filesystem_manager.cc b/src/filesystem/filesystem_manager.cc index 54fcffd..0836c76 100644 --- a/src/filesystem/filesystem_manager.cc +++ b/src/filesystem/filesystem_manager.cc @@ -397,35 +397,6 @@ void FilesystemManager::RemoveDirectory(const std::string& path, return; } -void FilesystemManager::FileRead(const std::string& path, size_t offset, size_t length, - bool is_string, - const std::function& success_cb, - const std::function& error_cb) { - ScopeLogger(); - FilesystemFile file(path); - - // Encode data if its type is not string - if (!is_string) { - FilesystemBuffer buffer; - if (!file.Read(&buffer, offset, length)) { - LoggerE("Cannot read file %s", path.c_str()); - error_cb(FilesystemError::Other); - return; - } - std::string out_data = buffer.EncodeData(); - success_cb(out_data); - } else { - std::vector buffer(length); - if (!file.ReadString(&buffer, offset, length)) { - LoggerE("Cannot read file %s", path.c_str()); - error_cb(FilesystemError::Other); - return; - } - std::string out_data(buffer.begin(), buffer.end()); - success_cb(out_data); - } -} - void FilesystemManager::FileWrite(const std::string& path, const std::string& data, size_t offset, bool rewrite, bool is_string, const std::function& success_cb, diff --git a/src/filesystem/filesystem_manager.h b/src/filesystem/filesystem_manager.h index f4e8c72..1f2fdbb 100644 --- a/src/filesystem/filesystem_manager.h +++ b/src/filesystem/filesystem_manager.h @@ -83,10 +83,6 @@ class FilesystemManager { void RemoveDirectory(const std::string& path, const std::function& success_cb, const std::function& error_cb); - void FileRead(const std::string& path, size_t offset, size_t length, bool is_string, - const std::function& success_cb, - const std::function& error_cb); - void FileWrite(const std::string& path, const std::string& data, size_t offset, bool rewrite, bool is_string, const std::function& success_cb, const std::function& error_cb); diff --git a/src/filesystem/js/file.js b/src/filesystem/js/file.js index a55531d..524d7b6 100644 --- a/src/filesystem/js/file.js +++ b/src/filesystem/js/file.js @@ -227,7 +227,7 @@ var Encoding = { 'iso-8859-1': 'iso-8859-1', 'sjis': 'sjis', // backward compatibility 'null': 'utf-8', - 'undefined': 'utf-8' + 'undefined': 'utf-8' // default value }; function _checkEncoding(encoding) { @@ -316,32 +316,23 @@ function readAsText() { var data = { location: commonFS_.toRealPath(this.fullPath), offset: 0, - length: 65536, - encoding: args.encoding, - isString: true + encoding: args.encoding }; function readFile() { - var result, encoded, buffers = []; - - var output = ""; - do { - result = native_.callSync('File_readSync', data); - if (native_.isFailure(result)) { - setTimeout(function() { - native_.callIfPossible(args.onerror, native_.getErrorObject(result)); - }, 0); - return; - } - result = native_.getResultObject(result); - if (result.length) { - data.offset += data.length; - } - output = output + result; - } while (result.length); + var result; + + result = native_.callSync('File_readString', data); + if (native_.isFailure(result)) { + setTimeout(function() { + native_.callIfPossible(args.onerror, native_.getErrorObject(result)); + }, 0); + return; + } + result = native_.getResultObject(result); setTimeout(function() { - native_.callIfPossible(args.onsuccess, output); + native_.callIfPossible(args.onsuccess, result); }, 0); } diff --git a/src/filesystem/js/file_stream.js b/src/filesystem/js/file_stream.js index 2eb097e..49f6bba 100644 --- a/src/filesystem/js/file_stream.js +++ b/src/filesystem/js/file_stream.js @@ -134,12 +134,12 @@ function read() { var data = { location: commonFS_.toRealPath(this._file.fullPath), + encoding: this._encoding, offset: this.position || 0, length: args.charCount > _count ? _count : args.charCount, - isString: true }; - var result = native_.callSync('File_readSync', data); + var result = native_.callSync('File_readString', data); if (native_.isFailure(result)) { throw new WebAPIException(WebAPIException.IO_ERR, 'Could not read'); } @@ -160,6 +160,17 @@ FileStream.prototype.read = function() { return read.apply(this, arguments); }; +/* returns array of numbers */ +function string_to_binary( str ) { + var output = []; + var len = str.length; + for( var i = 0; i < len; i++ ) { + // decode unicode codepoint U+0100 as zero byte + output.push( str[i] == '\u0100' ? 0 : str.charCodeAt(i) ); + } + return output; +} + function readBytes() { var args = validator_.validateArgs(arguments, [ { @@ -181,16 +192,15 @@ function readBytes() { var data = { location: commonFS_.toRealPath(this._file.fullPath), offset: this.position || 0, - length: args.byteCount > _count ? _count : args.byteCount, - isString: false + length: (args.byteCount > _count ? _count : args.byteCount) }; - var result = native_.callSync('File_readSync', data); + var result = native_.callSync('File_readBytes', data); if (native_.isFailure(result)) { throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Could not read'); } - var decoded = Base64.decode(native_.getResultObject(result)); + var decoded = string_to_binary( native_.getResultObject(result) ); if (decoded.length) { can_change_size = true; @@ -207,63 +217,8 @@ FileStream.prototype.readBytes = function() { return readBytes.apply(this, arguments); }; -function readBase64() { - var args = validator_.validateArgs(arguments, [ - { - name: 'byteCount', - type: types_.LONG - } - ]); - - _checkClosed(this); - _checkReadAccess(this._mode); - - if (!arguments.length) { - throw new WebAPIException(WebAPIException.TYPE_MISMATCH_ERR, - 'Argument "byteCount" missing'); - } - if (type_.isString(arguments[0]) && !arguments[0].length) { - throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, - 'Argument "byteCount" must be a number'); - } - if (!type_.isNumber(arguments[0])) { - throw new WebAPIException(WebAPIException.TYPE_MISMATCH_ERR, - 'Argument "byteCount" must be a number'); - } - if (args.byteCount <= 0) { - throw new WebAPIException(WebAPIException.TYPE_MISMATCH_ERR, - 'Argument "byteCount" must be greater than 0'); - } - - var _count = this.bytesAvailable; - - var data = { - location: commonFS_.toRealPath(this._file.fullPath), - offset: this.position || 0, - length: args.byteCount > _count ? _count : args.byteCount, - isString: false - }; - - var result = native_.callSync('File_readSync', data); - if (native_.isFailure(result)) { - throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, 'Could not read'); - } - var encoded = native_.getResultObject(result); - var decoded = Base64.decode(encoded); - - if (decoded.length) { - can_change_size = true; - this.position += decoded.length; - can_change_size = false; - } else { - this.position += 1; // Set EOF - } - - return encoded; -}; - FileStream.prototype.readBase64 = function() { - return readBase64.apply(this, arguments); + return Base64.encode(readBytes.apply(this, arguments)); } function write() { -- 2.7.4 From 0e203294c1e1cfbbcc3f3ece729f2a58126937cb Mon Sep 17 00:00:00 2001 From: Jakub Skowron Date: Wed, 17 Jan 2018 13:46:16 +0100 Subject: [PATCH 05/16] [Filesystem] Write file performace improvement (binary data through UTF-8) Improve performance of write, writeBytes, writeBase64 by pushing binary data through UTF-8 null-terminated string. Byte 0x00 is encoded as U+0100. Removed class FilesystemFile. [Verification] TCT pass rate is 100% tct-filesystem-tizen-tests Change-Id: Iee5983a429ed484eb0fd6a6d35ea794d292de8de Signed-off-by: Jakub Skowron --- src/filesystem/filesystem.gyp | 2 - src/filesystem/filesystem_file.cc | 290 ---------------------------------- src/filesystem/filesystem_file.h | 54 ------- src/filesystem/filesystem_instance.cc | 247 ++++++++++++++++++++++------- src/filesystem/filesystem_instance.h | 5 +- src/filesystem/filesystem_manager.cc | 29 ---- src/filesystem/filesystem_manager.h | 4 - src/filesystem/js/file_stream.js | 72 ++++----- 8 files changed, 229 insertions(+), 474 deletions(-) delete mode 100644 src/filesystem/filesystem_file.cc delete mode 100644 src/filesystem/filesystem_file.h diff --git a/src/filesystem/filesystem.gyp b/src/filesystem/filesystem.gyp index 9a3c737..6f3f46a 100644 --- a/src/filesystem/filesystem.gyp +++ b/src/filesystem/filesystem.gyp @@ -19,8 +19,6 @@ 'filesystem_api.js', 'filesystem_extension.cc', 'filesystem_extension.h', - 'filesystem_file.cc', - 'filesystem_file.h', 'filesystem_instance.cc', 'filesystem_instance.h', 'filesystem_manager.cc', diff --git a/src/filesystem/filesystem_file.cc b/src/filesystem/filesystem_file.cc deleted file mode 100644 index 1174747..0000000 --- a/src/filesystem/filesystem_file.cc +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "filesystem_file.h" -#include -#include -#include -#include - -namespace extension { -namespace filesystem { - -namespace { -uint8_t characterToNumber(char c) { - if (c == '+') { - return 62; - } - if (c == '/') { - return 63; - } - if (c <= '9') { - return c + 0x04; - } - if (c <= 'Z') { - return c - 0x41; - } - if (c <= 'z') { - return c - 0x47; - } - return 0; -} - -char numberToCharacter(uint8_t i) { - if (i <= 25) { - return 'A' + i; - } - if (i <= 51) { - return 'a' + i - 26; - } - if (i <= 61) { - return '0' + i - 52; - } - if (i == 62) { - return '+'; - } - if (i == 63) { - return '/'; - } - return 0; -} - -bool validateCharacter(char c) { - if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '=') || - (c == '+') || (c == '/')) { - return true; - } - return false; -} -} // namespace - -/** - * Data is encoded using Base64 encoding. - */ - -bool FilesystemBuffer::DecodeData(const std::string& data) { - ScopeLogger(); - if (data.length() % 4) { - LoggerE("Buffer has invalid length"); - return false; - } - - for (auto c : data) { - if (!validateCharacter(c)) { - LoggerE("Buffer has invalid character"); - return false; - } - } - - // Validate padding - for (size_t i = 0; i + 2 < data.length(); ++i) { - if (data[i] == '=') { - LoggerE("Unexpected padding character in string"); - return false; - } - } - - if (data[data.length() - 2] == '=' && data[data.length() - 1] != '=') { - LoggerE("Unexpected padding character in string"); - return false; - } - - clear(); - - if (data.length() == 0) { - return true; - } - - int padding = 0; - if (data[data.length() - 1] == '=') { - padding++; - } - - if (data[data.length() - 2] == '=') { - padding++; - } - - for (size_t i = 0; i < data.length(); i += 4) { - uint8_t part[] = {characterToNumber(data[i + 0]), characterToNumber(data[i + 1]), - characterToNumber(data[i + 2]), characterToNumber(data[i + 3])}; - push_back(uint8_t((part[0] << 2) | (part[1] >> 4))); - if ((data.length() - i != 4) || (padding < 2)) { - push_back(uint8_t((part[1] << 4) | (part[2] >> 2))); - } - if ((data.length() - i != 4) || (padding < 1)) { - push_back(uint8_t((part[2] << 6) | (part[3]))); - } - } - return true; -} - -std::string FilesystemBuffer::EncodeData() const { - ScopeLogger(); - std::string out; - - for (size_t i = 0; i < size(); i += 3) { - uint8_t part[] = {safe_get(i), safe_get(i + 1), safe_get(i + 2)}; - out.push_back(numberToCharacter(0x3F & (part[0] >> 2))); - out.push_back(numberToCharacter(0x3F & ((part[0] << 4) | (part[1] >> 4)))); - out.push_back(numberToCharacter(0x3F & ((part[1] << 2) | (part[2] >> 6)))); - out.push_back(numberToCharacter(0x3F & (part[2]))); - } - - if (out.size() == 0) return out; - - // Add padding - int fillup = (size() % 3); - if (fillup == 1) { - out[out.size() - 2] = '='; - } - - if (fillup == 1 || fillup == 2) { - out[out.size() - 1] = '='; - } - - return out; -} - -FilesystemFile::FilesystemFile(const std::string& path_) : path(path_) { - ScopeLogger(); -} - -bool FilesystemFile::Write(const FilesystemBuffer& data, size_t offset, bool rewrite) { - ScopeLogger(); - - FILE* file = nullptr; - if (rewrite) { - file = fopen(path.c_str(), "w"); - } else { - file = fopen(path.c_str(), "r+"); - } - - if (!file) { - LoggerE("Cannot open file %s to write!", path.c_str()); - return false; - } - - SCOPE_EXIT { - int status = fclose(file); - if (status) { - LoggerE("Cannot close file!"); - } - }; - - int status; - status = fseek(file, offset, SEEK_SET); - LoggerD("Offset is %u, writing %i bytes", offset, data.size()); - if (status) { - LoggerE("Cannot perform seek!"); - return false; - } - - size_t written = 0; - uint8_t* data_p = const_cast(data.data()); - size_t data_size = data.size(); - while (written < data.size()) { - size_t part = fwrite(data_p, 1, data_size, file); - - if (ferror(file)) { - LoggerE("Error during file write!"); - return false; - } - - written += part; - data_p += part; - data_size -= part; - } - - status = fflush(file); - if (status) { - LoggerE("Cannot flush file!"); - return false; - } - - status = fsync(fileno(file)); - if (status) { - LoggerE("Cannot sync file!"); - return false; - } - LoggerD("Written %u bytes", written); - - return true; -} - -bool FilesystemFile::WriteString(const std::string& data, size_t offset, bool rewrite) { - ScopeLogger(); - - FILE* file = nullptr; - if (rewrite) { - file = fopen(path.c_str(), "w"); - } else { - file = fopen(path.c_str(), "r+"); - } - - if (!file) { - LoggerE("Cannot open file %s to write!", path.c_str()); - return false; - } - - SCOPE_EXIT { - int status = fclose(file); - if (status) { - LoggerE("Cannot close file!"); - } - }; - - int status; - status = fseek(file, offset, SEEK_SET); - LoggerD("Offset is %u, writing %i bytes", offset, data.size()); - if (status) { - LoggerE("Cannot perform seek!"); - return false; - } - - size_t written = 0; - uint8_t* data_p = (uint8_t*)(data.c_str()); - size_t data_size = data.size(); - - while (written < data.size()) { - size_t part = fwrite(data_p, 1, data_size, file); - - if (ferror(file)) { - LoggerE("Error during file write!"); - return false; - } - - written += part; - data_p += part; - data_size -= part; - } - - status = fflush(file); - if (status) { - LoggerE("Cannot flush file!"); - return false; - } - - status = fsync(fileno(file)); - if (status) { - LoggerE("Cannot sync file!"); - return false; - } - LoggerD("Written %u bytes", written); - - return true; -} -} // namespace filesystem -} // namespace extension diff --git a/src/filesystem/filesystem_file.h b/src/filesystem/filesystem_file.h deleted file mode 100644 index e8dce33..0000000 --- a/src/filesystem/filesystem_file.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FILESYSTEM_FILESYSTEM_FILE_H -#define FILESYSTEM_FILESYSTEM_FILE_H - -#include -#include -#include - -namespace extension { -namespace filesystem { - -class FilesystemBuffer : public std::vector { - public: - bool DecodeData(const std::string& data); - std::string EncodeData() const; - - private: - inline uint8_t safe_get(size_t i) const { - if (i >= size()) { - return 0; - } - return at(i); - } -}; - -class FilesystemFile { - const std::string path; - - public: - FilesystemFile(const std::string& path_); - - bool Write(const FilesystemBuffer& data, size_t offset, bool rewrite); - bool WriteString(const std::string& data, size_t offset, bool rewrite); -}; - -} // namespace filesystem -} // namespace extension - -#endif // FILESYSTEM_FILESYSTEM_FILE_H diff --git a/src/filesystem/filesystem_instance.cc b/src/filesystem/filesystem_instance.cc index 848c6dc..eaceadc 100644 --- a/src/filesystem/filesystem_instance.cc +++ b/src/filesystem/filesystem_instance.cc @@ -54,8 +54,9 @@ FilesystemInstance::FilesystemInstance() { REGISTER_SYNC("File_rename", FileRename); REGISTER_SYNC("File_readBytes", FileReadBytes); REGISTER_SYNC("File_readString", FileReadString); - REGISTER_SYNC("File_write", FileWrite); - REGISTER_SYNC("File_writeSync", FileWriteSync); + REGISTER_SYNC("File_writeBytes", FileWriteBytes); + REGISTER_SYNC("File_writeBase64", FileWriteBase64); + REGISTER_SYNC("File_writeString", FileWriteString); REGISTER_SYNC("Filesystem_fetchVirtualRoots", FilesystemFetchVirtualRoots); REGISTER_SYNC("FileSystemManager_addStorageStateChangeListener", StartListening); REGISTER_SYNC("FileSystemManager_removeStorageStateChangeListener", StopListening); @@ -136,6 +137,44 @@ void FilesystemInstance::FileRename(const picojson::value& args, picojson::objec std::bind(&FilesystemManager::Rename, &fsm, oldPath, newPath, onSuccess, onError)); } +/* str should be a reference to (possibly empty) std::string */ +static void encode_binary_in_string(const std::vector& buf, std::string& str) { + ScopeLogger(); + str.reserve(str.size() + buf.size()); + + for (std::uint8_t byte : buf) { + if (byte >= 128) { + str += 0xC0 | (byte >> 6); + str += 0x80 | (byte & 0x3F); + } else if (byte > 0) { + str += byte; + } else { + // zero as codepoint U+0100 + str += 0xC4; + str += 0x80; + } + } +} + +/* buf should be a reference to (possibly empty) vector */ +static void decode_binary_from_string(const std::string& str, std::vector& buf) { + ScopeLogger(); + buf.reserve(buf.size() + str.size()); + + const std::uint8_t* it = (std::uint8_t*)str.data(); + const std::uint8_t* end = it + str.size(); + while (it != end) { + if (*it < 128) { + buf.push_back(*it++); + continue; + } + auto b1 = *it++; + auto b2 = *it++; + unsigned int x = ((b1 & 0x1F) << 6) | (b2 & 0x3F); + buf.push_back(x != 0x100 ? x : 0); + } +} + static constexpr std::size_t NPOS = (std::size_t)(-1); /** * Returns a buffer. If length is NPOS, then it reads whole file, up to the end. @@ -188,24 +227,109 @@ static std::vector read_file(std::string path, std::size_t offset, return out_buf; } -/* str should be reference to (possibly empty) std::string */ -static void encode_binary_in_string(const std::vector& buf, std::string& str) { +/** + * On failure throws std::runtime_error + */ +void write_file(const std::uint8_t* data, std::size_t len, std::string path, std::size_t offset, + bool rewrite) { ScopeLogger(); - str.reserve(str.size() + buf.size()); - for (std::uint8_t byte : buf) { - if (byte >= 128) { - str += 0xC0 | (byte >> 6); - str += 0x80 | (byte & 0x3F); - } else if (byte > 0) { - str += byte; - } else { - // zero as codepoint U+0100 - str += 0xC4; - str += 0x80; + FILE* file = fopen(path.c_str(), rewrite ? "w" : "r+"); + + if (!file) { + throw std::runtime_error("cannot open file to write"); + } + + SCOPE_EXIT { + int status = std::fclose(file); + if (status) { + LoggerE("Cannot close file!"); } + }; + + if (std::fseek(file, offset, SEEK_SET) != 0) { + throw std::runtime_error("cannot perform seek"); + } + + const std::uint8_t* data_p = data; + const std::uint8_t* end_p = data + len; + while (data_p != end_p) { + data_p += fwrite(data_p, 1, end_p - data_p, file); + + if (std::ferror(file)) { + throw std::runtime_error("error during file write"); + } + } + + if (std::fflush(file)) { + throw std::runtime_error("error during file write"); + } +} + +namespace base64 { +static const char int_to_char[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const std::uint8_t INV = 255; +static const std::uint8_t PAD = 254; +static const std::uint8_t char_to_int[] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 255, 255, 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, + 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255}; + +/** + * On error throws std::runtime_error + */ +static std::vector decode(const char* str, std::size_t len) { + std::vector out; + if (len % 4 != 0) throw std::runtime_error("string length is not multiple of 4"); + if (len == 0) return out; + + const std::uint8_t* p = (std::uint8_t*)str; + const std::uint8_t* end = p + len - 4; // last four can have padding in it + std::uint8_t b1, b2, b3, b4; + out.reserve(len / 4 * 3); + while (p != end) { + b1 = char_to_int[*p++]; + b2 = char_to_int[*p++]; + b3 = char_to_int[*p++]; + b4 = char_to_int[*p++]; + + if (b1 > 63 || b2 > 63 || b3 > 63 || b4 > 63) throw std::runtime_error("invalid character"); + + out.push_back((b1 << 2) | (b2 >> 4)); + out.push_back((b2 << 4) | (b3 >> 2)); + out.push_back((b3 << 6) | b4); } + b1 = char_to_int[*p++]; + b2 = char_to_int[*p++]; + b3 = char_to_int[*p++]; + b4 = char_to_int[*p++]; + + if (b1 == PAD || b1 == INV || b2 == PAD || b2 == INV || b3 == INV || b4 == INV) + throw std::runtime_error("invalid character"); + + out.push_back((b1 << 2) | (b2 >> 4)); + if (b3 == PAD) { + if (b4 != PAD) throw std::runtime_error("invalid character"); + } else { + out.push_back((b2 << 4) | (b3 >> 2)); + if (b4 != PAD) out.push_back((b3 << 6) | b4); + } + + return out; } +} // namespace base64 void FilesystemInstance::FileReadString(const picojson::value& args, picojson::object& out) { ScopeLogger(); @@ -254,73 +378,82 @@ void FilesystemInstance::FileReadBytes(const picojson::value& args, picojson::ob } } -void FilesystemInstance::FileWrite(const picojson::value& args, picojson::object& out) { +void FilesystemInstance::FileWriteString(const picojson::value& args, picojson::object& out) { ScopeLogger(); - CHECK_EXIST(args, "callbackId", out) + CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out); CHECK_EXIST(args, "location", out) CHECK_EXIST(args, "data", out) CHECK_EXIST(args, "offset", out) CHECK_EXIST(args, "rewrite", out) - CHECK_EXIST(args, "isString", out) + CHECK_EXIST(args, "encoding", out) - double callback_id = args.get("callbackId").get(); const std::string& location = args.get("location").get(); - const std::string& data = args.get("data").get(); - size_t offset = static_cast(args.get("location").get()); + const std::string& str = args.get("data").get(); + size_t offset = static_cast(args.get("offset").get()); bool rewrite = static_cast(args.get("rewrite").get()); - bool is_string = static_cast(args.get("isString").get()); - auto onSuccess = [this, callback_id]() { - ScopeLogger("Entered into asynchronous function, onSuccess"); - picojson::value response = picojson::value(picojson::object()); - picojson::object& obj = response.get(); - obj["callbackId"] = picojson::value(callback_id); - ReportSuccess(obj); - PostMessage(response.serialize().c_str()); - }; + try { + write_file((const std::uint8_t*)str.c_str(), str.length(), location, offset, rewrite); + } catch (std::runtime_error& e) { + LoggerE("Cannot write to file %s, cause: %s", location.c_str(), e.what()); + PrepareError(FilesystemError::Other, out); + } + ReportSuccess(out); +} - auto onError = [this, callback_id](FilesystemError e) { - ScopeLogger("Entered into asynchronous function, onError"); - picojson::value response = picojson::value(picojson::object()); - picojson::object& obj = response.get(); - obj["callbackId"] = picojson::value(callback_id); - PrepareError(e, obj); - PostMessage(response.serialize().c_str()); - }; +void FilesystemInstance::FileWriteBytes(const picojson::value& args, picojson::object& out) { + ScopeLogger(); + CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out); + CHECK_EXIST(args, "location", out) + CHECK_EXIST(args, "data", out) + CHECK_EXIST(args, "offset", out) + CHECK_EXIST(args, "rewrite", out) - FilesystemManager& fsm = FilesystemManager::GetInstance(); - common::TaskQueue::GetInstance().Async(std::bind(&FilesystemManager::FileWrite, &fsm, location, - data, offset, rewrite, is_string, onSuccess, - onError)); + const std::string& location = args.get("location").get(); + const std::string& str = args.get("data").get(); + size_t offset = static_cast(args.get("offset").get()); + bool rewrite = static_cast(args.get("rewrite").get()); + + try { + std::vector data; + decode_binary_from_string(str, data); + write_file(data.data(), data.size(), location, offset, rewrite); + } catch (std::runtime_error& e) { + LoggerE("Cannot write to %s, cause: %s", location.c_str(), e.what()); + PrepareError(FilesystemError::Other, out); + } + ReportSuccess(out); } -void FilesystemInstance::FileWriteSync(const picojson::value& args, picojson::object& out) { +void FilesystemInstance::FileWriteBase64(const picojson::value& args, picojson::object& out) { ScopeLogger(); CHECK_PRIVILEGE_ACCESS(kPrivilegeFilesystemWrite, &out); CHECK_EXIST(args, "location", out) CHECK_EXIST(args, "data", out) CHECK_EXIST(args, "offset", out) CHECK_EXIST(args, "rewrite", out) - CHECK_EXIST(args, "isString", out) const std::string& location = args.get("location").get(); - const std::string& data = args.get("data").get(); + const std::string& str = args.get("data").get(); size_t offset = static_cast(args.get("offset").get()); bool rewrite = static_cast(args.get("rewrite").get()); - bool is_string = static_cast(args.get("isString").get()); - - auto onSuccess = [this, &out]() { - ScopeLogger("Entered into asynchronous function, onSuccess"); - ReportSuccess(out); - }; - auto onError = [this, &out](FilesystemError e) { - ScopeLogger("Entered into asynchronous function, onError"); - PrepareError(e, out); - }; + std::vector data; + try { + data = base64::decode(str.c_str(), str.length()); + } catch (std::runtime_error& e) { + LoggerE("Can't decode base64: %s", e.what()); + ReportError(InvalidValuesException(std::string("Can't decode base64: ") + e.what()), out); + return; + } - FilesystemManager::GetInstance().FileWrite(location, data, offset, rewrite, is_string, onSuccess, - onError); + try { + write_file(data.data(), data.size(), location, offset, rewrite); + ReportSuccess(picojson::value{(double)data.size()}, out); + } catch (std::runtime_error& e) { + LoggerE("Cannot write to %s, cause: %s", location.c_str(), e.what()); + PrepareError(FilesystemError::Other, out); + } } void FilesystemInstance::FileStat(const picojson::value& args, picojson::object& out) { diff --git a/src/filesystem/filesystem_instance.h b/src/filesystem/filesystem_instance.h index da21bc7..07fb8fa 100644 --- a/src/filesystem/filesystem_instance.h +++ b/src/filesystem/filesystem_instance.h @@ -37,8 +37,9 @@ class FilesystemInstance : public common::ParsedInstance, FilesystemStateChangeL void FileStatSync(const picojson::value& args, picojson::object& out); void FileReadString(const picojson::value& args, picojson::object& out); void FileReadBytes(const picojson::value& args, picojson::object& out); - void FileWrite(const picojson::value& args, picojson::object& out); - void FileWriteSync(const picojson::value& args, picojson::object& out); + void FileWriteBytes(const picojson::value& args, picojson::object& out); + void FileWriteBase64(const picojson::value& args, picojson::object& out); + void FileWriteString(const picojson::value& args, picojson::object& out); void FilesystemFetchVirtualRoots(const picojson::value& args, picojson::object& out); void FileSystemManagerFetchStorages(const picojson::value& args, picojson::object& out); void FileSystemManagerMakeDirectory(const picojson::value& args, picojson::object& out); diff --git a/src/filesystem/filesystem_manager.cc b/src/filesystem/filesystem_manager.cc index 0836c76..e6b373d 100644 --- a/src/filesystem/filesystem_manager.cc +++ b/src/filesystem/filesystem_manager.cc @@ -37,7 +37,6 @@ #include "common/logger.h" #include "common/scope_exit.h" #include "common/tools.h" -#include "filesystem/filesystem_file.h" namespace extension { namespace filesystem { @@ -397,34 +396,6 @@ void FilesystemManager::RemoveDirectory(const std::string& path, return; } -void FilesystemManager::FileWrite(const std::string& path, const std::string& data, size_t offset, - bool rewrite, bool is_string, - const std::function& success_cb, - const std::function& error_cb) { - ScopeLogger(); - FilesystemFile file(path); - FilesystemBuffer buffer; - // Decode buffer data if type is not string - if (!is_string) { - if (!buffer.DecodeData(data)) { - LoggerE("Cannot decode file data!"); - error_cb(FilesystemError::Other); - return; - } - if (file.Write(buffer, offset, rewrite)) { - success_cb(); - } else { - LoggerE("Cannot write to file %s!", path.c_str()); - error_cb(FilesystemError::Other); - } - } else if (file.WriteString(data, offset, rewrite)) { - success_cb(); - } else { - LoggerE("Cannot write to file %s!", path.c_str()); - error_cb(FilesystemError::Other); - } -} - void FilesystemManager::StartListening() { ScopeLogger(); auto set = std::bind(&FilesystemManager::OnStorageDeviceChanged, this, std::placeholders::_1, diff --git a/src/filesystem/filesystem_manager.h b/src/filesystem/filesystem_manager.h index 1f2fdbb..e0d2d12 100644 --- a/src/filesystem/filesystem_manager.h +++ b/src/filesystem/filesystem_manager.h @@ -83,10 +83,6 @@ class FilesystemManager { void RemoveDirectory(const std::string& path, const std::function& success_cb, const std::function& error_cb); - void FileWrite(const std::string& path, const std::string& data, size_t offset, bool rewrite, - bool is_string, const std::function& success_cb, - const std::function& error_cb); - void CopyTo(const std::string& originFilePath, const std::string& destinationFilePath, const bool overwrite, const std::function& success_cb, const std::function& error_cb); diff --git a/src/filesystem/js/file_stream.js b/src/filesystem/js/file_stream.js index 49f6bba..954ef49 100644 --- a/src/filesystem/js/file_stream.js +++ b/src/filesystem/js/file_stream.js @@ -103,6 +103,33 @@ function _checkWriteAccess(mode) { } } +/* returns array of numbers */ +function string_to_binary( str ) { + var output = []; + var len = str.length; + var c; + for( var i = 0; i < len; i++ ) { + // decode unicode codepoint U+0100 as zero byte + c = str.charCodeAt(i); + output.push( c == 0x100 ? 0 : c ); + } + return output; +} + +/* receives array of numbers, returns string */ +function binary_to_string( data ) { + var output = ""; + var len = data.length; + // endecode zero byte as unicode codepoint U+0100 + var zero = String.fromCharCode(0x100); + var b; + for( var i = 0; i < len; i++ ) { + b = data[i]; + output += b == 0 ? zero : String.fromCharCode(b); + } + return output; +} + function read() { var args = validator_.validateArgs(arguments, [ { @@ -160,17 +187,6 @@ FileStream.prototype.read = function() { return read.apply(this, arguments); }; -/* returns array of numbers */ -function string_to_binary( str ) { - var output = []; - var len = str.length; - for( var i = 0; i < len; i++ ) { - // decode unicode codepoint U+0100 as zero byte - output.push( str[i] == '\u0100' ? 0 : str.charCodeAt(i) ); - } - return output; -} - function readBytes() { var args = validator_.validateArgs(arguments, [ { @@ -239,13 +255,13 @@ function write() { var data = { location: commonFS_.toRealPath(this._file.fullPath), + encoding: this._encoding, offset: this.position, data: args.stringData, - rewrite: this._rewrite, - isString: true + rewrite: this._rewrite }; - var result = native_.callSync('File_writeSync', data); + var result = native_.callSync('File_writeString', data); if (native_.isFailure(result)) { throw new WebAPIException(WebAPIException.IO_ERR, 'Could not write'); @@ -280,12 +296,11 @@ function writeBytes() { var data = { location: commonFS_.toRealPath(this._file.fullPath), offset: this.position, - data: Base64.encode(args.byteData), + data: binary_to_string(args.byteData), rewrite: this._rewrite, - isString: false }; - var result = native_.callSync('File_writeSync', data); + var result = native_.callSync('File_writeBytes', data); if (native_.isFailure(result)) { throw new WebAPIException(WebAPIException.IO_ERR, 'Could not write'); @@ -300,11 +315,6 @@ FileStream.prototype.writeBytes = function() { writeBytes.apply(this, arguments); }; -function _isBase64(str) { - var base64 = new RegExp('^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$'); - return base64.test(str); -} - function writeBase64() { var args = validator_.validateArgs(arguments, [ { @@ -316,33 +326,23 @@ function writeBase64() { _checkClosed(this); _checkWriteAccess(this._mode); - if (!arguments.length) { - throw new WebAPIException(WebAPIException.TYPE_MISMATCH_ERR, - 'Argument "base64Data" missing'); - } - if (!args.base64Data.length || !_isBase64(args.base64Data)) { - throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR, - 'Data is not base64'); - } - var data = { location: commonFS_.toRealPath(this._file.fullPath), offset: this.position, data: args.base64Data, rewrite: this._rewrite, - isString: false }; - var result = native_.callSync('File_writeSync', data); + var result = native_.callSync('File_writeBase64', data); if (native_.isFailure(result)) { - throw new WebAPIException(WebAPIException.IO_ERR, 'Could not write'); + throw native_.getErrorObject(result); } - var decoded = Base64.decode(args.base64Data); + var written_bytes = native_.getResultObject(result); can_change_size = true; - this.position += decoded.length; + this.position += written_bytes; can_change_size = false; this._rewrite = false; }; -- 2.7.4 From b63d0e1c8ac71a09cf88b16aa6ddfe5c6e55db35 Mon Sep 17 00:00:00 2001 From: Jakub Skowron Date: Wed, 17 Jan 2018 15:43:31 +0100 Subject: [PATCH 06/16] [Filesystem] Speed up conversion to octet in writeBytes Do not use validateArgs to validate each value in array Change-Id: I9ac59f59187c7f57a0213778d0f2552cb9de4538 Signed-off-by: Jakub Skowron --- src/filesystem/js/file_stream.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/filesystem/js/file_stream.js b/src/filesystem/js/file_stream.js index 954ef49..07e7fca 100644 --- a/src/filesystem/js/file_stream.js +++ b/src/filesystem/js/file_stream.js @@ -124,7 +124,7 @@ function binary_to_string( data ) { var zero = String.fromCharCode(0x100); var b; for( var i = 0; i < len; i++ ) { - b = data[i]; + b = data[i] & 0xFF; // conversion to octet output += b == 0 ? zero : String.fromCharCode(b); } return output; @@ -281,7 +281,7 @@ function writeBytes() { { name: 'byteData', type: types_.ARRAY, - values: types_.OCTET + values: undefined /* was types_.OCTET, but checking moved to binary_to_string for performance */ } ]); -- 2.7.4 From 659af4d85af457cced0ca9145cd8802886c444bf Mon Sep 17 00:00:00 2001 From: Jakub Skowron Date: Wed, 17 Jan 2018 17:04:49 +0100 Subject: [PATCH 07/16] [Filesystem] Remove unused Base64 and UTF-8 functions removed: encodeString, decode, decodeString, getCodePoint, _utf8_encode, _utf8_decode Change-Id: I269cd71eb252e2f6ea9b266a50acde3f769db50e Signed-off-by: Jakub Skowron --- src/filesystem/js/base64.js | 223 +++++---------------------------------- src/filesystem/js/file_stream.js | 2 +- 2 files changed, 26 insertions(+), 199 deletions(-) diff --git a/src/filesystem/js/base64.js b/src/filesystem/js/base64.js index 4074d48..0952f23 100755 --- a/src/filesystem/js/base64.js +++ b/src/filesystem/js/base64.js @@ -14,204 +14,31 @@ * limitations under the License. */ -var Base64 = { - _b64: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', - encodeString: function(str) { - return this.encode(this._utf8_encode(str)); - }, - encode: function(data) { - var output = ''; - var chr1, chr2, chr3, enc1, enc2, enc3, enc4; - var i = 0; - - while (i < data.length) { - - chr1 = data[i++]; - chr2 = data[i++]; - chr3 = data[i++]; - - enc1 = chr1 >> 2; - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - enc4 = chr3 & 63; - - if (isNaN(chr2)) { - enc3 = enc4 = 64; - } else if (isNaN(chr3)) { - enc4 = 64; - } - - output += this._b64.charAt(enc1) + this._b64.charAt(enc2) + - this._b64.charAt(enc3) + this._b64.charAt(enc4); - - } - - return output; - }, - decodeString: function(data) { - return this._utf8_decode(this.decode(data)); - }, - decode: function(data) { - var output = []; - var chr1, chr2, chr3; - var enc1, enc2, enc3, enc4; - var i = 0; - - data = data.replace(/[^A-Za-z0-9\+\/\=]/g, ''); - - while (i < data.length) { - - enc1 = this._b64.indexOf(data.charAt(i++)); - enc2 = this._b64.indexOf(data.charAt(i++)); - enc3 = this._b64.indexOf(data.charAt(i++)); - enc4 = this._b64.indexOf(data.charAt(i++)); - - chr1 = (enc1 << 2) | (enc2 >> 4); - chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); - chr3 = ((enc3 & 3) << 6) | enc4; - - output.push(chr1); - - if (enc3 !== 64) { - output.push(chr2); - } - if (enc4 !== 64) { - output.push(chr3); - } - - } - - return output; - }, - getCodePoint: function(string, position) { - var highWord = string.charCodeAt(position); - - if ((highWord & 0xFC00) === 0xD800) { - if (position + 1 >= string.length) { - return undefined; //the string is corrupted - } - - var lowWord = string.charCodeAt(position + 1); - if ((lowWord & 0xFC00) === 0xDC00) { - return ((highWord & 0x03FF) << 10) | (lowWord & 0x03FF) + 0x10000; - } else { - return undefined; //the string is corrupted - } - } - return highWord; - }, - _utf8_encode: function(str) { - str = str.replace(/\r\n/g, '\n'); - var utfarray = []; - - //TODO: use for( var c of str ) in future versions - for (var offset = 0; offset < str.length; offset++) { - var code = this.getCodePoint(str, offset); - - if (code <= 0x7F) { - utfarray.push(code); - } - else if (code <= 0x7FF) { - utfarray.push( 0xC0 | (code >> 6), 0x80 | (code & 0x3F) ); - } - else if (code <= 0xFFFF) { - utfarray.push( 0xE0 | (code >> 12), 0x80 | ((code >> 6) & 0x3F), 0x80 | (code & 0x3F) ); - } - else { - utfarray.push( 0xF0 | (code >> 18), 0x80 | ((code >> 12) & 0x3F), - 0x80 | ((code >> 6) & 0x3F), 0x80 | (code & 0x3F) ); - offset++; //there is a UTF16 surrogate pair in str, so jump two elements - } +function base64_encode(data) { + var _b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + var output = ''; + var chr1, chr2, chr3, enc1, enc2, enc3, enc4; + var i = 0; + + while (i < data.length) { + chr1 = data[i++]; + chr2 = data[i++]; + chr3 = data[i++]; + + enc1 = chr1 >> 2; + enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); + enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); + enc4 = chr3 & 63; + + if (isNaN(chr2)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3)) { + enc4 = 64; } - return utfarray; - }, - - /* - * This function validates read characters. Non-standard UTF-8 characters are substituted with - * a replacement symbol. - * - * Used validation check cases are described in http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt, - * by Markus Kuhn, distributed under CC-BY 4.0 license (https://creativecommons.org/licenses/by/4.0/legalcode). - */ - - _utf8_decode: function(utfarray) { - var str = ''; - var i = 0, c = 0, c1 = 0, c2 = 0, c3 = 0, charCode = 0; - var INVALID_CHARACTER = String.fromCharCode(0xFFFD); - - while (i < utfarray.length) { - c = utfarray[i]; - - if (c < 128) { - str += String.fromCharCode(c); - i++; - } else if ((c >= 194) && (c < 224) && (utfarray[i + 1] & 0x80)) { - c1 = utfarray[i + 1]; - charCode = ((c & 31) << 6) | (c1 & 63); - /* - * Below condition is true, if the sequence could be encoded in less than 2 bytes. - * Such a byte series is invalid in terms of UTF-8. - * This and similar, longer, sequences will be refered to as "overlong sequence". - */ - if (!(charCode & 0xFF80)) { - str += INVALID_CHARACTER; - } else { - str += String.fromCharCode(charCode); - } - - i += 2; - } else if ((c >= 224) && (c < 240) && (utfarray[i + 1] & 0x80) && (utfarray[i + 2] & 0x80)) { - c1 = utfarray[i + 1]; - c2 = utfarray[i + 2]; - charCode = ((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63); - - if (!(charCode & 0xF800) //overlong sequence test - /* - * Below test checks, if the character is an UTF-16 surrogate halve, - * UTF-16 surrogate halves are invalid Unicode codepoints. - */ - || (0xD800 <= charCode && charCode <=0xDFFF)) { - str += INVALID_CHARACTER; - } else { - str += String.fromCharCode(charCode); - } - - i += 3; - } else if ((c >= 240) && (c < 245) & (utfarray[i + 1] & 0x80) && (utfarray[i + 2] & 0x80) && (utfarray[i + 3] & 0x80)) { - c1 = utfarray[i + 1]; - c2 = utfarray[i + 2]; - c3 = utfarray[i + 3]; - charCode = ((c & 7) << 18) | ((c1 & 63) << 12) | ((c2 & 63) << 6) | (c3 & 63); - - if (!(charCode & 0x1F0000)) { //overlong sequence test - str += INVALID_CHARACTER; - } else { - str += String.fromCharCode(charCode); - } - i += 4; - /* - * Below condition is true if a continuation byte appeared without a proper leading byte - */ - } else if ((c & 0x80) && (~c & 0x40)) { - str += INVALID_CHARACTER; - i++; - } else { - /* - * One or more continuation bytes are missing - * OR 'c' is a prohibited byte in terms of UTF-8 standard. - */ - str += INVALID_CHARACTER; - - /* - * All following continuation bytes are skipped. - */ - do { - i++; - } while((utfarray[i] & 0x80) && (~utfarray[i] & 0x40)); - } - } - - return str; + output += _b64.charAt(enc1) + _b64.charAt(enc2) + + _b64.charAt(enc3) + _b64.charAt(enc4); } -}; + + return output; +} diff --git a/src/filesystem/js/file_stream.js b/src/filesystem/js/file_stream.js index 07e7fca..bc3e9a6 100644 --- a/src/filesystem/js/file_stream.js +++ b/src/filesystem/js/file_stream.js @@ -234,7 +234,7 @@ FileStream.prototype.readBytes = function() { }; FileStream.prototype.readBase64 = function() { - return Base64.encode(readBytes.apply(this, arguments)); + return base64_encode(readBytes.apply(this, arguments)); } function write() { -- 2.7.4 From 9c2349dcc1e7014d4148dcd026ff83b859c402ca Mon Sep 17 00:00:00 2001 From: Piotr Kosko Date: Thu, 18 Jan 2018 13:32:21 +0100 Subject: [PATCH 08/16] [version] 2.14 Change-Id: I7b9924c14471bce00e2e5eaf607080c869ad92b1 Signed-off-by: Piotr Kosko --- packaging/webapi-plugins.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/webapi-plugins.spec b/packaging/webapi-plugins.spec index 4cc0921..977ccc8 100644 --- a/packaging/webapi-plugins.spec +++ b/packaging/webapi-plugins.spec @@ -10,7 +10,7 @@ %define crosswalk_extensions_path %{_libdir}/%{crosswalk_extensions} Name: webapi-plugins -Version: 2.13 +Version: 2.14 Release: 0 License: Apache-2.0 and BSD-3-Clause and MIT Group: Development/Libraries -- 2.7.4 From 23957cecf0404340245c43c5e8eb3a476e9c8cc8 Mon Sep 17 00:00:00 2001 From: Rafal Walczyna Date: Thu, 25 Jan 2018 10:01:43 +0100 Subject: [PATCH 09/16] [humanactivitymonitor] Fix crash when WRIST_UP event was called [Verification] Tested with custom app - event fires properly Auto test on TW2 - 100% passrate Change-Id: I762a2a0950c4b17333f78b11eb320680f8ec1128 Signed-off-by: Rafal Walczyna --- src/humanactivitymonitor/humanactivitymonitor_manager.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/humanactivitymonitor/humanactivitymonitor_manager.cc b/src/humanactivitymonitor/humanactivitymonitor_manager.cc index 8897a28..22d52b5 100644 --- a/src/humanactivitymonitor/humanactivitymonitor_manager.cc +++ b/src/humanactivitymonitor/humanactivitymonitor_manager.cc @@ -516,7 +516,7 @@ class HumanActivityMonitorManager::Monitor::GestureMonitor return; } - picojson::value v = picojson::value(); // null value + picojson::value v = picojson::value(picojson::object()); callback(&v); } -- 2.7.4 From cd1f144454957fd1c6b91ce70bbf32865df3d441 Mon Sep 17 00:00:00 2001 From: Lukasz Bardeli Date: Thu, 25 Jan 2018 11:53:43 +0100 Subject: [PATCH 10/16] [Download] Fix preventing crash. Prevent call callback twice Add condition to prevent call some callback twice and modify body of methods OnFinished, OnCanceled and OnFailed to prevent crash. [Verification] Code compiles without error. TCT passrate 100% Change-Id: I7d194b4d762a52f0281e22555bfd54caa3cb4579 Signed-off-by: Lukasz Bardeli --- src/download/download_instance.cc | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/download/download_instance.cc b/src/download/download_instance.cc index 5a1dd70..73bd411 100644 --- a/src/download/download_instance.cc +++ b/src/download/download_instance.cc @@ -187,6 +187,14 @@ void DownloadInstance::OnStateChanged(int download_id, download_state_e state, v ScopeLogger(); CallbackPtr downCbPtr = static_cast(user_data); + // Prevent to call finished, cancelled or failed function more than once + if (DOWNLOAD_STATE_COMPLETED == downCbPtr->state || + DOWNLOAD_STATE_CANCELED == downCbPtr->state || + DOWNLOAD_STATE_FAILED == downCbPtr->state) { + LoggerD("Already finished job, not calling callback for %d state", downCbPtr->state); + return; + } + downCbPtr->state = state; downCbPtr->downloadId = download_id; @@ -314,9 +322,8 @@ gboolean DownloadInstance::OnFinished(void* user_data) { out["fullPath"] = picojson::value(common::FilesystemProvider::Create().GetVirtualPath(fullPath)); Instance::PostMessage(downCbPtr->instance, picojson::value(out).serialize().c_str()); - downCbPtr->instance->download_callbacks.erase(callback_id); - delete (downCbPtr); - + // downCbPtr is freed in destructor, it prevent from crash if OnFinished state + // was called after OnCanceled or OnFailed free(fullPath); return FALSE; @@ -384,9 +391,8 @@ gboolean DownloadInstance::OnCanceled(void* user_data) { out["callbackId"] = picojson::value(static_cast(callback_id)); Instance::PostMessage(downCbPtr->instance, picojson::value(out).serialize().c_str()); - downCbPtr->instance->download_callbacks.erase(callback_id); - delete (downCbPtr); - + // downCbPtr is freed in destructor, it prevent from crash if OnFinished state + // was called after OnFinished or OnFailed return FALSE; } @@ -443,9 +449,8 @@ gboolean DownloadInstance::OnFailed(void* user_data) { out["callbackId"] = picojson::value(static_cast(downCbPtr->callbackId)); Instance::PostMessage(downCbPtr->instance, picojson::value(out).serialize().c_str()); - downCbPtr->instance->download_callbacks.erase(callback_id); - delete (downCbPtr); - + // downCbPtr is freed in destructor, it prevent from crash if OnFinished state + // was called after OnFinished or OnCanceled return FALSE; } -- 2.7.4 From 1129a8f18c453f8be2765f034314bb04bb6fa66a Mon Sep 17 00:00:00 2001 From: Jakub Skowron Date: Wed, 17 Jan 2018 14:27:09 +0100 Subject: [PATCH 11/16] [Utils] Fix Long conversion (allow hex string value) Until now string "0x15" would be converted 0. This change affects all numeric conversions which use _toLong. According to https://www.w3.org/TR/WebIDL-1/#es-long value should be initialized by ToNumber, which is defined in https://tc39.github.io/ecma262/#sec-tonumber-applied-to-the-string-type and allows value to be in form of HexIntegerLiteral. Change-Id: Ib719ce8fd5beccc5947b761dc905c49ac0469490 --- src/utils/utils_api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/utils_api.js b/src/utils/utils_api.js index 51e9104..4cc9868 100644 --- a/src/utils/utils_api.js +++ b/src/utils/utils_api.js @@ -386,7 +386,7 @@ Converter.prototype.toBoolean = function(val, nullable) { }; function _toLong(val) { - var ret = parseInt(val, 10); + var ret = parseInt(val); return isNaN(ret) ? (val === true ? 1 : 0) : ret; } -- 2.7.4 From f0d174fe3affd1d5dead0f3c4517a36ae86aa557 Mon Sep 17 00:00:00 2001 From: Piotr Kosko Date: Fri, 26 Jan 2018 11:04:18 +0100 Subject: [PATCH 12/16] [version] 2.15 - version increased - fixed minor style issue Change-Id: I70a371ce7e6834bf73c413e19de37111168c9147 Signed-off-by: Piotr Kosko --- packaging/webapi-plugins.spec | 2 +- src/download/download_instance.cc | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packaging/webapi-plugins.spec b/packaging/webapi-plugins.spec index 977ccc8..3b4e9b2 100644 --- a/packaging/webapi-plugins.spec +++ b/packaging/webapi-plugins.spec @@ -10,7 +10,7 @@ %define crosswalk_extensions_path %{_libdir}/%{crosswalk_extensions} Name: webapi-plugins -Version: 2.14 +Version: 2.15 Release: 0 License: Apache-2.0 and BSD-3-Clause and MIT Group: Development/Libraries diff --git a/src/download/download_instance.cc b/src/download/download_instance.cc index 73bd411..fda4c57 100644 --- a/src/download/download_instance.cc +++ b/src/download/download_instance.cc @@ -188,8 +188,7 @@ void DownloadInstance::OnStateChanged(int download_id, download_state_e state, v CallbackPtr downCbPtr = static_cast(user_data); // Prevent to call finished, cancelled or failed function more than once - if (DOWNLOAD_STATE_COMPLETED == downCbPtr->state || - DOWNLOAD_STATE_CANCELED == downCbPtr->state || + if (DOWNLOAD_STATE_COMPLETED == downCbPtr->state || DOWNLOAD_STATE_CANCELED == downCbPtr->state || DOWNLOAD_STATE_FAILED == downCbPtr->state) { LoggerD("Already finished job, not calling callback for %d state", downCbPtr->state); return; -- 2.7.4 From ba2505210e9d1b649802676a8791f87e6d474c90 Mon Sep 17 00:00:00 2001 From: Michal Bistyga Date: Fri, 2 Feb 2018 12:37:08 +0100 Subject: [PATCH 13/16] [Bluetooth] Fixing undefined behaviour during cast Char is unsigned by default on ARM architecture. static_cast from double to unsigned char is undefined behaviour and complier overwritten any negative value with 0. [Validation] tests 100% pass rate Change-Id: Iec39a3c17b18ec7aa4f020fe5de709d66fa426fd Signed-off-by: Michal Bistyga --- src/bluetooth/bluetooth_gatt_service.cc | 2 +- src/bluetooth/bluetooth_health_channel.cc | 2 +- src/bluetooth/bluetooth_socket.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bluetooth/bluetooth_gatt_service.cc b/src/bluetooth/bluetooth_gatt_service.cc index 14f4bc7..f6798a8 100644 --- a/src/bluetooth/bluetooth_gatt_service.cc +++ b/src/bluetooth/bluetooth_gatt_service.cc @@ -424,7 +424,7 @@ void BluetoothGATTService::WriteValue(const picojson::value& args, picojson::obj int value_size = value_array.size(); std::unique_ptr value_data(new char[value_size]); for (int i = 0; i < value_size; ++i) { - value_data[i] = static_cast(value_array[i].get()); + value_data[i] = (int) value_array[i].get(); } struct Data { diff --git a/src/bluetooth/bluetooth_health_channel.cc b/src/bluetooth/bluetooth_health_channel.cc index 8d19279..e119693 100644 --- a/src/bluetooth/bluetooth_health_channel.cc +++ b/src/bluetooth/bluetooth_health_channel.cc @@ -77,7 +77,7 @@ void BluetoothHealthChannel::SendData(const picojson::value& data, picojson::obj std::unique_ptr data_ptr{new char[data_size]}; for (std::size_t i = 0; i < data_size; ++i) { - data_ptr[i] = static_cast(binary_data[i].get()); + data_ptr[i] = (int) binary_data[i].get(); } int ntv_ret = bt_hdp_send_data(channel, data_ptr.get(), data_size); diff --git a/src/bluetooth/bluetooth_socket.cc b/src/bluetooth/bluetooth_socket.cc index 7625ae4..fea9ed1 100644 --- a/src/bluetooth/bluetooth_socket.cc +++ b/src/bluetooth/bluetooth_socket.cc @@ -63,7 +63,7 @@ void BluetoothSocket::WriteData(const picojson::value& data, picojson::object& o std::unique_ptr data_ptr{new char[data_size]}; for (std::size_t i = 0; i < data_size; ++i) { - data_ptr[i] = static_cast(binary_data[i].get()); + data_ptr[i] = (int) binary_data[i].get(); } if (kBluetoothError == bt_socket_send_data(socket, data_ptr.get(), data_size)) { -- 2.7.4 From ce879c7ab668c7f6f04077bb94903e0b7ac2035f Mon Sep 17 00:00:00 2001 From: Michal Bistyga Date: Fri, 2 Feb 2018 16:09:33 +0100 Subject: [PATCH 14/16] [NFC] Fixing undefined behaviour during static_cast to unsigned char Validation: Automatic tests 100% pass rate TODO manual tests Change-Id: I9c15efc77c82f0f7e4019913b2bd02d0f8047bb1 Signed-off-by: Michal Bistyga --- src/nfc/nfc_api.js | 5 +++-- src/nfc/nfc_util.cc | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/nfc/nfc_api.js b/src/nfc/nfc_api.js index 6c3f19b..c282348 100644 --- a/src/nfc/nfc_api.js +++ b/src/nfc/nfc_api.js @@ -692,7 +692,7 @@ NFCAdapter.prototype.removeHCEEventListener = function() { NFCAdapter.prototype.sendHostAPDUResponse = function(apdu, successCallback, errorCallback) { var args = validator_.validateArgs(arguments, [ - {name: 'apdu', type: types_.ARRAY, values: types_.OCTET}, + {name: 'apdu', type: types_.ARRAY, values: types_.BYTE}, {name: 'successCallback', type: types_.FUNCTION, optional: true, nullable: true}, {name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true} ]); @@ -1102,7 +1102,8 @@ function NFCTag(tagid) { var args = validator_.validateArgs(arguments, [ { name: 'data', - type: types_.ARRAY + type: types_.ARRAY, + values: types_.BYTE }, { name: 'dataCallback', diff --git a/src/nfc/nfc_util.cc b/src/nfc/nfc_util.cc index 46be48b..8a5928f 100644 --- a/src/nfc/nfc_util.cc +++ b/src/nfc/nfc_util.cc @@ -336,7 +336,7 @@ unsigned char* NFCUtil::DoubleArrayToUCharArray(const picojson::array& array_in) ScopeLogger(); unsigned char* result_array = new unsigned char[array_in.size()]; for (std::size_t i = 0; i < array_in.size(); ++i) { - result_array[i] = static_cast(array_in.at(i).get()); + result_array[i] = (int) array_in.at(i).get(); } return result_array; } -- 2.7.4 From 868d6551b4d2ca28a0cf597673d82e6c765ba92f Mon Sep 17 00:00:00 2001 From: Piotr Kosko Date: Mon, 5 Feb 2018 07:49:29 +0100 Subject: [PATCH 15/16] [version] 2.16 Change-Id: I7316b54e3c6ab3fe41b5e2e1ac6e4b1a9e7dfa35 Signed-off-by: Piotr Kosko --- packaging/webapi-plugins.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/webapi-plugins.spec b/packaging/webapi-plugins.spec index 3b4e9b2..f3b3345 100644 --- a/packaging/webapi-plugins.spec +++ b/packaging/webapi-plugins.spec @@ -10,7 +10,7 @@ %define crosswalk_extensions_path %{_libdir}/%{crosswalk_extensions} Name: webapi-plugins -Version: 2.15 +Version: 2.16 Release: 0 License: Apache-2.0 and BSD-3-Clause and MIT Group: Development/Libraries -- 2.7.4 From 31177b000157a07480049a6d726650eb7c827d36 Mon Sep 17 00:00:00 2001 From: Piotr Kosko Date: Mon, 5 Feb 2018 13:48:16 +0100 Subject: [PATCH 16/16] [SecureElement][NFC][Messageport] Fixing casting problems [Bug] Casting double -> char should not be done directly. [Verification] Passing values greater than 127 to API makes that values are correctly translated. TCT passrate 100%. Change-Id: I786392fd3be2e7d0eb5211e224a25c8078f383e9 Signed-off-by: Piotr Kosko --- src/messageport/messageport_instance.cc | 4 ++-- src/nfc/nfc_message_utils.cc | 12 ++++++------ src/secureelement/secureelement_instance.cc | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/messageport/messageport_instance.cc b/src/messageport/messageport_instance.cc index 2614fda..28df499 100644 --- a/src/messageport/messageport_instance.cc +++ b/src/messageport/messageport_instance.cc @@ -403,7 +403,7 @@ void MessageportInstance::RemoteMessagePortSendmessage(const picojson::value& ar size_t i = 0; for (auto iter = value_array.begin(); iter != value_array.end(); ++iter, ++i) { - arr[i] = static_cast((*iter).get()); + arr[i] = (int)(*iter).get(); } bundle_add_byte(bundle, (*it).get("key").to_str().c_str(), arr, size); delete[] arr; @@ -421,7 +421,7 @@ void MessageportInstance::RemoteMessagePortSendmessage(const picojson::value& ar size_t j = 0; for (auto byteIter = byteStream.begin(); byteIter != byteStream.end(); ++byteIter, ++j) { - arr[j] = static_cast((*byteIter).get()); + arr[j] = (int)(*byteIter).get(); } bundle_set_byte_array_element(bundle, (*it).get("key").to_str().c_str(), i, arr, diff --git a/src/nfc/nfc_message_utils.cc b/src/nfc/nfc_message_utils.cc index 4581c5e..1e36a2f 100644 --- a/src/nfc/nfc_message_utils.cc +++ b/src/nfc/nfc_message_utils.cc @@ -301,7 +301,7 @@ PlatformResult NFCMessageUtils::ReportNDEFMessage(const picojson::value& args, std::unique_ptr data(new unsigned char[size]); for (ssize_t i = 0; i < size; i++) { - data[i] = static_cast(raw_data[i].get()); + data[i] = (int)raw_data[i].get(); } return ReportNdefMessageFromData(data.get(), size, out); @@ -321,19 +321,19 @@ static PlatformResult NdefRecordGetHandle(picojson::value& record, auto type_size = type_data.size(); std::unique_ptr type(new unsigned char[type_size]); for (size_t i = 0; i < type_size; i++) { - type[i] = static_cast(type_data[i].get()); + type[i] = (int)type_data[i].get(); } const picojson::array& id_data = FromJson(record_obj, "id"); auto id_size = id_data.size(); std::unique_ptr id(new unsigned char[id_size]); for (size_t i = 0; i < id_size; i++) { - id[i] = static_cast(id_data[i].get()); + id[i] = (int)(id_data[i].get()); } const picojson::array& payload_data = FromJson(record_obj, "payload"); auto payload_size = payload_data.size(); std::unique_ptr payload(new unsigned char[payload_size]); for (size_t i = 0; i < payload_size; i++) { - payload[i] = static_cast(payload_data[i].get()); + payload[i] = (int)payload_data[i].get(); } if ((tnf_from_json < TNF_MIN) || (tnf_from_json > TNF_MAX)) { return LogAndCreateResult(ErrorCode::TYPE_MISMATCH_ERR, "Type mismatch", ("Not supported TNF")); @@ -531,7 +531,7 @@ PlatformResult NFCMessageUtils::ReportNDEFRecord(const picojson::value& args, std::unique_ptr data(new unsigned char[size]); for (ssize_t i = 0; i < size; i++) { - data[i] = static_cast(raw_data[i].get()); + data[i] = (int)raw_data[i].get(); } nfc_ndef_message_h message_handle = NULL; @@ -900,7 +900,7 @@ PlatformResult NFCMessageUtils::ReportNDEFRecordMedia(const picojson::value& arg std::unique_ptr data(new unsigned char[size]); for (ssize_t i = 0; i < size; i++) { - data[i] = static_cast(raw_data[i].get()); + data[i] = (int)raw_data[i].get(); } nfc_ndef_record_h handle = NULL; diff --git a/src/secureelement/secureelement_instance.cc b/src/secureelement/secureelement_instance.cc index ac4139a..7313d70 100644 --- a/src/secureelement/secureelement_instance.cc +++ b/src/secureelement/secureelement_instance.cc @@ -378,7 +378,7 @@ TizenResult SecureElementInstance::OpenBasicChannel(picojson::object const& args }; for (size_t i = 0; i < v_aid_size; i++) { - aid[i] = static_cast(v_aid[i].get()); + aid[i] = (int)v_aid[i].get(); } int ret = smartcard_session_open_basic_channel(session, aid, v_aid_size, P2, &channel); @@ -423,7 +423,7 @@ TizenResult SecureElementInstance::OpenLogicalChannel(picojson::object const& ar }; for (size_t i = 0; i < v_aid_size; i++) { - aid[i] = static_cast(v_aid[i].get()); + aid[i] = (int)v_aid[i].get(); } int ret = smartcard_session_open_logical_channel(session, aid, v_aid_size, P2, &channel); @@ -554,7 +554,7 @@ TizenResult SecureElementInstance::Transmit(picojson::object const& args, }; for (size_t i = 0; i < v_cmd_size; i++) { - cmd[i] = static_cast(v_cmd[i].get()); + cmd[i] = (int) v_cmd[i].get(); } int length = 0; -- 2.7.4