BuildRequires: pkgconfig(libudev)
BuildRequires: pkgconfig(message-port)
BuildRequires: pkgconfig(minizip)
+BuildRequires: pkgconfig(zlib)
BuildRequires: pkgconfig(msg-service)
BuildRequires: pkgconfig(pkgmgr)
BuildRequires: pkgconfig(pkgmgr-info)
'type': 'loadable_module',
'sources': [
'archive_api.js',
+ #'archive_callback_data.cc',
+ 'archive_callback_data.h',
'archive_extension.cc',
'archive_extension.h',
+ 'archive_file.cc',
+ 'archive_file.h',
+ 'archive_file_entry.cc',
+ 'archive_file_entry.h',
'archive_instance.cc',
- 'archive_instance.h'
+ 'archive_instance.h',
+ 'archive_manager.cc',
+ 'archive_manager.h',
+ 'archive_utils.cc',
+ 'archive_utils.h',
+ 'filesystem_file.cc'
+ 'filesystem_file.h',
+ 'defs.h',
+ 'un_zip.cc',
+ 'un_zip.h',
+ 'un_zip_extract_request.cc',
+ 'un_zip_extract_request.h',
+ 'zip_add_request.cc',
+ 'zip_add_request.h',
+ 'zip.cc',
+ 'zip.h'
],
'includes': [
- '../common/pkg-config.gypi',
+ '../common/pkg-config.gypi'
],
'conditions': [
['tizen == 1', {
'variables': {
'packages': [
- 'minizip'
+ 'minizip',
+ 'zlib'
]
},
}],
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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.
+//
+
+/**
+ * @file ArchiveCallbackData.cpp
+ */
+
+#include "archive_callback_data.h"
+
+#include "common/logger.h"
+
+//#include <FilesystemExternalUtils.h>
+#include "archive_file.h"
+#include "archive_utils.h"
+#include "un_zip.h"
+#include "zip.h"
+
+using namespace common;
+
+namespace DeviceAPI {
+namespace Archive {
+
+//namespace {
+//const char* CALLBACK_SUCCESS = "success";
+//const char* CALLBACK_ERROR = "error";
+//const char* CALLBACK_PROGRESS = "progress";
+//} //anonymous namespace
+//
+////----------------------------------------------------------------------------------------
+////OperationCallbackData
+////----------------------------------------------------------------------------------------
+//
+//OperationCallbackData::OperationCallbackData(ArchiveCallbackType callback_type) :
+// m_callback_type(callback_type),
+// m_op_id(0),
+// m_is_error(false),
+// m_is_canceled(false)
+//{
+// LOGD("Entered");
+//}
+//
+//OperationCallbackData::~OperationCallbackData()
+//{
+// LOGD("Entered");
+// if(m_op_id > 0){
+// ArchiveManager::getInstance().eraseElementFromArchiveFileMap(m_op_id);
+// }
+//}
+//
+//void OperationCallbackData::setError(const std::string &err_name,
+// const std::string &err_message)
+//{
+// LOGD("Entered");
+// //store only first error
+// if (!m_is_error) {
+// m_err_name = err_name;
+// m_err_message = err_message;
+// m_is_error = true;
+// }
+//}
+//
+//bool OperationCallbackData::isError() const
+//{
+// LOGD("Entered");
+// return m_is_error;
+//}
+//
+//bool OperationCallbackData::isCanceled() const
+//{
+// return m_is_canceled;
+//}
+//
+//void OperationCallbackData::setOperationId(long op_id)
+//{
+// LOGD("Entered");
+// m_op_id = op_id;
+//}
+//
+//long OperationCallbackData::getOperationId() const
+//{
+// LOGD("Entered");
+// return m_op_id;
+//}
+//
+//void OperationCallbackData::setIsCanceled(bool canceled)
+//{
+// m_is_canceled = canceled;
+//}
+//
+//const std::string& OperationCallbackData::getErrorName() const
+//{
+// LOGD("Entered");
+// return m_err_name;
+//}
+//
+//const std::string& OperationCallbackData::getErrorMessage() const
+//{
+// LOGD("Entered");
+// return m_err_message;
+//}
+//
+//ArchiveCallbackType OperationCallbackData::getCallbackType() const
+//{
+// LOGD("Entered");
+// return m_callback_type;
+//}
+//
+//ArchiveFilePtr OperationCallbackData::getArchiveFile() const
+//{
+// return m_caller_instance;
+//}
+//
+//void OperationCallbackData::setArchiveFile(ArchiveFilePtr caller)
+//{
+// m_caller_instance = caller;
+//}
+//
+//
+////void OperationCallbackData::setSuccessCallback(JSValueRef on_success)
+////{
+//// LOGD("Entered");
+//// auto ctx = getContext();
+//// if(on_success && JSValueIsObject(ctx, on_success)) {
+//// JSObjectRef success = JSValueToObject(ctx, on_success, NULL);
+//// this->setCallback(CALLBACK_SUCCESS, success);
+//// }
+////}
+//
+////void OperationCallbackData::setErrorCallback(JSValueRef on_error)
+////{
+//// LOGD("Entered");
+//// auto ctx = getContext();
+//// if(on_error && JSValueIsObject(ctx, on_error)) {
+//// JSObjectRef error = JSValueToObject(ctx, on_error, NULL);
+//// this->setCallback(CALLBACK_ERROR, error);
+//// }
+////}
+//
+//void OperationCallbackData::callSuccessCallback()
+//{
+// LOGD("Entered");
+// LOGW("STUB Not calling success callback");
+// //this->invokeCallback(CALLBACK_SUCCESS, 0, NULL);
+//}
+//
+////void OperationCallbackData::callSuccessCallback(JSValueRef success)
+////{
+//// LOGD("Entered");
+//// this->invokeCallback(CALLBACK_SUCCESS, success);
+////}
+//
+////void OperationCallbackData::callErrorCallback(JSValueRef err)
+////{
+//// LOGD("Entered");
+//// this->invokeCallback(CALLBACK_ERROR, err);
+////}
+//
+////----------------------------------------------------------------------------------------
+////OpenCallbackData
+////----------------------------------------------------------------------------------------
+//
+//OpenCallbackData::OpenCallbackData(ArchiveCallbackType callback_type):
+// OperationCallbackData(callback_type)
+//{
+// LOGD("Entered");
+//}
+//
+//OpenCallbackData::~OpenCallbackData()
+//{
+// LOGD("Entered");
+//}
+//
+//void OpenCallbackData::executeOperation(ArchiveFilePtr archive_file_ptr)
+//{
+// LOGE("Entered");
+//
+// Filesystem::FilePtr file = archive_file_ptr->getFile();
+// if (!file) {
+// LOGE("File is null");
+// throw UnknownException("File is null");
+// }
+// Filesystem::NodePtr node = file->getNode();
+// if(!node) {
+// LOGE("Node is null");
+// throw UnknownException("Node is null");
+// }
+// const FileMode fm = archive_file_ptr->m_file_mode;
+// if (0 == node->getSize()) {
+// if(FileMode::READ_WRITE == fm ||
+// FileMode::WRITE == fm ||
+// FileMode::ADD == fm) {
+// LOGD("Empty file obtained for writing/appending");
+//
+// // Do not create empty archive with minizip library - it will not be loaded
+// // by unzip.
+// //
+// // For explanation please see:
+// // ArchiveFile.h m_created_as_new_empty_archive description
+// //
+// archive_file_ptr->setCreatedAsNewEmptyArchive(true);
+// archive_file_ptr->setEntryMap(ArchiveFileEntryPtrMapPtr(
+// new ArchiveFileEntryPtrMap()));
+// archive_file_ptr->setIsOpen(true);
+// }
+// else {
+// LOGE("The file is empty throwing: InvalidValuesException - Invalid ZIP archive");
+// throw InvalidValuesException("Invalid ZIP archive");
+// }
+// }
+// else {
+// archive_file_ptr->setIsOpen(true);
+// archive_file_ptr->updateListOfEntries();
+// }
+//
+// guint id = g_idle_add(ArchiveFile::openTaskCompleteCB, this);
+// if (!id) {
+// LOGE("g_idle_add fails");
+// throw UnknownException("g_idle_add fails");
+// }
+//}
+//
+////----------------------------------------------------------------------------------------
+////GetEntriesCallbackData
+////----------------------------------------------------------------------------------------
+//
+//GetEntriesCallbackData::GetEntriesCallbackData(ArchiveCallbackType callback_type):
+// OperationCallbackData(callback_type)
+//{
+// LOGD("Entered");
+//}
+//GetEntriesCallbackData::~GetEntriesCallbackData()
+//{
+// LOGD("Entered");
+//}
+//
+//ArchiveFileEntryPtrMapPtr GetEntriesCallbackData::getEntries() const
+//{
+// return m_entries;
+//}
+//
+//void GetEntriesCallbackData::setEntries(ArchiveFileEntryPtrMapPtr entries)
+//{
+// m_entries = entries;
+//}
+//
+//void GetEntriesCallbackData::executeOperation(ArchiveFilePtr archive_file_ptr)
+//{
+// LOGD("Entered");
+//
+// setEntries(archive_file_ptr->getEntryMap());
+//
+// guint id = g_idle_add(ArchiveFile::getEntriesTaskCompleteCB, this);
+// if (!id) {
+// LOGE("g_idle_add fails");
+// throw UnknownException("g_idle_add fails");
+// }
+//}
+//
+////----------------------------------------------------------------------------------------
+////GetEntryByNameCallbackData
+////----------------------------------------------------------------------------------------
+//
+//GetEntryByNameCallbackData::GetEntryByNameCallbackData(ArchiveCallbackType callback_type):
+// OperationCallbackData(callback_type)
+//{
+// LOGD("Entered");
+//}
+//
+//GetEntryByNameCallbackData::~GetEntryByNameCallbackData()
+//{
+// LOGD("Entered");
+//}
+//
+//const std::string& GetEntryByNameCallbackData::getName() const
+//{
+// LOGD("Entered");
+// return m_name;
+//}
+//
+//void GetEntryByNameCallbackData::setName(const std::string& name)
+//{
+// LOGD("Entered");
+// m_name = name;
+//}
+//
+//ArchiveFileEntryPtr GetEntryByNameCallbackData::getFileEntry() const
+//{
+// return m_file_entry;
+//}
+//
+//void GetEntryByNameCallbackData::setFileEntry(ArchiveFileEntryPtr entry)
+//{
+// m_file_entry = entry;
+//}
+//
+//void GetEntryByNameCallbackData::executeOperation(ArchiveFilePtr archive_file_ptr)
+//{
+// LOGD("Entered");
+//
+// ArchiveFileEntryPtrMapPtr entries = archive_file_ptr->getEntryMap();
+// auto it = entries->find(getName());
+//
+// //Not found but if our name does not contain '/'
+// //try looking for directory with such name
+// //
+// if (it == entries->end() && !isDirectoryPath(getName())) {
+// const std::string try_directory = getName() + "/";
+// LOGD("GetEntryByName Trying directory: [%s]", try_directory.c_str());
+// it = entries->find(try_directory);
+// }
+//
+// if (it == entries->end()) {
+// LOGE("GetEntryByName Entry with name: [%s] not found", getName().c_str());
+// LOGE("Throwing NotFoundException - Entry not found");
+// throw NotFoundException("Entry not found");
+// }
+//
+// setFileEntry(it->second);
+//
+// guint id = g_idle_add(ArchiveFile::getEntryByNameTaskCompleteCB, this);
+// if (!id) {
+// LOGE("g_idle_add fails");
+// throw UnknownException("g_idle_add fails");
+// }
+//}
+//
+////----------------------------------------------------------------------------------------
+////BaseProgressCallback
+////----------------------------------------------------------------------------------------
+//
+//BaseProgressCallback::BaseProgressCallback(ArchiveCallbackType callback_type):
+// OperationCallbackData(callback_type),
+// m_overwrite(false)
+//{
+// LOGD("Entered");
+//}
+//
+//BaseProgressCallback::~BaseProgressCallback()
+//{
+// LOGD("Entered");
+//}
+//
+//bool BaseProgressCallback::getOverwrite() const
+//{
+// LOGD("Entered");
+// return m_overwrite;
+//}
+//
+//void BaseProgressCallback::setOverwrite(bool overwrite)
+//{
+// LOGD("Entered");
+// m_overwrite = overwrite;
+//}
+//
+//struct ProgressHolder
+//{
+// ProgressHolder() :
+// callback(NULL)
+// {
+// };
+//
+// double overall_progress;
+// ArchiveFileEntryPtr currently_processed_entry;
+// BaseProgressCallback* callback;
+//};
+//
+//void BaseProgressCallback::callSuccessCallbackOnMainThread()
+//{
+// guint id = g_idle_add(BaseProgressCallback::callSuccessCallbackCB,
+// static_cast<void*>(this));
+// if (!id) {
+// LOGE("g_idle_add fails - success callback will not be called");
+// }
+//}
+//
+//gboolean BaseProgressCallback::callSuccessCallbackCB(void* data)
+//{
+// BaseProgressCallback* callback = static_cast<BaseProgressCallback*>(data);
+// if (!callback) {
+// LOGE("callback pointer is NULL");
+// return false;
+// }
+//
+// std::unique_ptr<BaseProgressCallback> cb_ptr(callback);
+//
+// LOGW("STUB Not checking if context is still alive");
+// //JSContextRef context = callback->getContext();
+// //if (!GlobalContextManager::getInstance()->isAliveGlobalContext(context)) {
+// // LOGE("context closed - unable to call success callback");
+// // return false;
+// //}
+//
+// try {
+// callback->callSuccessCallback();
+// }
+// catch (const PlatformException &err) {
+// LOGE("%s (%s)", err.name().c_str(), err.message().c_str());
+// }
+// catch (...) {
+// LOGE("Unknown error occurs");
+// }
+//
+// callback->setArchiveFile(ArchiveFilePtr());
+// ArchiveManager::getInstance().eraseElementFromArchiveFileMap(callback->m_op_id);
+//
+// return false;
+//}
+//
+////void BaseProgressCallback::setProgressCallback(JSValueRef on_progress)
+////{
+//// LOGD("Entered");
+//// auto ctx = getContext();
+//// if(on_progress && JSValueIsObject(ctx, on_progress)) {
+//// JSObjectRef progress = JSValueToObject(ctx, on_progress, NULL);
+//// this->setCallback(CALLBACK_PROGRESS, progress);
+//// }
+////}
+//
+//void BaseProgressCallback::callProgressCallback(long operationId,
+// double value,
+// const std::string& filename)
+//{
+// LOGD("Entered");
+// LOGW("STUB calling progress callback");
+//
+// //auto ctx = getContext();
+// //const int SIZE = 3;
+// //JSValueRef parameters[SIZE] = {
+// // JSUtil::toJSValueRef(ctx, operationId),
+// // JSUtil::toJSValueRef(ctx, value),
+// // JSUtil::toJSValueRef(ctx, filename)
+// // };
+// //
+// //this->invokeCallback(CALLBACK_PROGRESS, SIZE, parameters);
+//}
+//
+//void BaseProgressCallback::callProgressCallbackOnMainThread(const double progress,
+// ArchiveFileEntryPtr current_entry)
+//{
+// ProgressHolder* ph = new(std::nothrow) ProgressHolder();
+//
+// if(ph) {
+// ph->overall_progress = progress;
+// ph->currently_processed_entry = current_entry;
+// ph->callback = this;
+//
+// guint id = g_idle_add(BaseProgressCallback::callProgressCallbackCB,
+// static_cast<void*>(ph));
+// if (!id) {
+// LOGE("g_idle_add fails");
+// delete ph;
+// ph = NULL;
+// }
+// } else {
+// LOGE("Couldn't allocate ProgressHolder");
+// }
+//}
+//
+//gboolean BaseProgressCallback::callProgressCallbackCB(void* data)
+//{
+// ProgressHolder* ph = static_cast<ProgressHolder*>(data);
+// if (!ph) {
+// LOGE("ph is null");
+// return false;
+// }
+//
+// std::unique_ptr<ProgressHolder> ph_ptr(ph);
+// if (!ph->callback) {
+// LOGE("ph->callback is null");
+// return false;
+// }
+//
+// LOGW("STUB Not checking if context is still alive");
+// //JSContextRef context = ph->callback->getContext();
+// //if (!GlobalContextManager::getInstance()->isAliveGlobalContext(context)) {
+// // LOGE("context was closed");
+// // return false;
+// //}
+//
+// try {
+// //Error callback is being handled by ArchiveFile queue - see
+// //ArchiveFile::taskManagerThread function
+// //
+// ph->callback->callProgressCallback(
+// ph->callback->m_op_id,
+// ph->overall_progress,
+// ph->currently_processed_entry->getName());
+// }
+// catch (const PlatformException &err) {
+// LOGE("%s (%s)", err.name().c_str(), err.message().c_str());
+// }
+// catch (...) {
+// LOGE("Unknown error occurs");
+// }
+//
+// return false;
+//}
+//
+////----------------------------------------------------------------------------------------
+////AddProgressCallback
+////----------------------------------------------------------------------------------------
+//
+//AddProgressCallback::AddProgressCallback(ArchiveCallbackType callback_type):
+// BaseProgressCallback(callback_type)
+//{
+// LOGD("Entered");
+//}
+//
+//AddProgressCallback::~AddProgressCallback()
+//{
+// LOGD("Entered");
+//}
+//
+//ArchiveFileEntryPtr AddProgressCallback::getFileEntry() const
+//{
+// LOGD("Entered");
+// return m_file_entry;
+//}
+//
+//void AddProgressCallback::setFileEntry(ArchiveFileEntryPtr file_entry)
+//{
+// LOGD("Entered");
+// m_file_entry = file_entry;
+//}
+//
+//void AddProgressCallback::setBasePath(const std::string& path)
+//{
+// LOGD("Entered");
+// m_base_path = path;
+// m_base_virt_path = Filesystem::External::toVirtualPath(m_base_path);
+// std::string::size_type pos = m_base_virt_path.find(Filesystem::Path::getSeparator());
+// if (pos != std::string::npos)
+// {
+// m_base_virt_path = m_base_virt_path.substr(pos + 1);
+// }
+// else
+// {
+// m_base_virt_path = "";
+// }
+//}
+//
+//const std::string& AddProgressCallback::getBasePath()
+//{
+// LOGD("Entered");
+// return m_base_path;
+//}
+//
+//const std::string& AddProgressCallback::getBaseVirtualPath()
+//{
+// LOGD("Entered");
+// return m_base_virt_path;
+//}
+//
+//void AddProgressCallback::executeOperation(ArchiveFilePtr archive_file_ptr)
+//{
+// LOGD("Entered");
+//
+// if(!m_file_entry) {
+// LOGE("ArchiveFileEntry is not set in callback");
+// throw UnknownException("Could not add file to archive");
+// }
+//
+// if(!archive_file_ptr) {
+// LOGE("archive_file_ptr is NULL");
+// throw UnknownException("Could not extract archive file entry");
+// }
+//
+// AddProgressCallback* callback = this;
+//
+// ZipPtr zip = archive_file_ptr->createZipObject();
+// zip->addFile(callback);
+// // Zip is no more needed but it locks file opening while
+// // it is needed to read entries from file
+// zip->close();
+//
+// //We have just finished adding file to archive so now
+// //this archive file should be valid .zip archive and
+// //we can remove CreatedAsNewEmptyArchive flag
+// archive_file_ptr->setCreatedAsNewEmptyArchive(false);
+//
+// LOGD("Update decompressed size and entry list");
+// // update informations about decompressed size and entry list
+// // TODO FIXME need to resolve problem with access to file by
+// // more than one thread
+// try{
+// archive_file_ptr->updateListOfEntries();
+// } catch(...){
+// LOGD("Unknown error during updating entries list inside archive");
+// }
+//}
+//
+////----------------------------------------------------------------------------------------
+////ExtractAllProgressCallback
+////----------------------------------------------------------------------------------------
+//
+//ExtractAllProgressCallback::ExtractAllProgressCallback(ArchiveCallbackType callback_type):
+// BaseProgressCallback(callback_type),
+// m_files_to_extract(0),
+// m_files_extracted(0),
+// m_current_file_size(0),
+// m_current_file_extracted_bytes(0),
+// m_progress_overall(0),
+// m_overall_decompressed(0)
+//{
+// LOGD("Entered");
+//}
+//
+//ExtractAllProgressCallback::~ExtractAllProgressCallback()
+//{
+// LOGD("Entered");
+//}
+//
+//Filesystem::FilePtr ExtractAllProgressCallback::getDirectory() const
+//{
+// return m_directory;
+//}
+//
+//void ExtractAllProgressCallback::setDirectory(Filesystem::FilePtr directory)
+//{
+// m_directory = directory;
+//}
+//
+//void ExtractAllProgressCallback::startedExtractingFile(unsigned long current_file_size)
+//{
+// m_current_file_size = current_file_size;
+// m_current_file_extracted_bytes = 0;
+//}
+//
+//void ExtractAllProgressCallback::extractedPartOfFile(unsigned long bytes_decompressed)
+//{
+// m_current_file_extracted_bytes += bytes_decompressed;
+// updateOverallProgress(bytes_decompressed);
+//}
+//
+//void ExtractAllProgressCallback::finishedExtractingFile()
+//{
+// m_current_file_size = 0;
+// m_current_file_extracted_bytes = 0;
+// ++m_files_extracted;
+// updateOverallProgress(0);
+//}
+//
+//void ExtractAllProgressCallback::updateOverallProgress(unsigned long bytes_decompressed)
+//{
+// m_overall_decompressed += bytes_decompressed;
+// m_progress_overall =
+// static_cast<double>(m_overall_decompressed + m_files_extracted) /
+// static_cast<double>(m_expected_decompressed_size + m_files_to_extract);
+//
+// LOGD("%s of %s - %f%% (%d/%d files)",
+// bytesToReadableString(m_overall_decompressed).c_str(),
+// bytesToReadableString(m_expected_decompressed_size).c_str(),
+// m_progress_overall * 100.0,
+// m_files_extracted, m_files_to_extract);
+//}
+//
+//double ExtractAllProgressCallback::getCurrentFileProgress() const
+//{
+// if(m_current_file_size > 0) {
+// return static_cast<double>(m_current_file_extracted_bytes) /
+// static_cast<double>(m_current_file_size);
+// }
+// else {
+// return 1.0;
+// }
+//}
+//
+//double ExtractAllProgressCallback::getOverallProgress() const
+//{
+// return m_progress_overall;
+//}
+//
+//void ExtractAllProgressCallback::executeOperation(ArchiveFilePtr archive_file_ptr)
+//{
+// LOGD("Entered");
+// archive_file_ptr->extractAllTask(this);
+//}
+//
+//void ExtractAllProgressCallback::setExpectedDecompressedSize(unsigned long exp_dec_size)
+//{
+// m_expected_decompressed_size = exp_dec_size;
+//}
+//
+//unsigned long ExtractAllProgressCallback::getExpectedDecompressedSize() const
+//{
+// return m_expected_decompressed_size;
+//}
+//
+//void ExtractAllProgressCallback::setNumberOfFilesToExtract(unsigned long files_count)
+//{
+// m_files_to_extract = files_count;
+//}
+//
+//unsigned long ExtractAllProgressCallback::getNumberOfFilesToExtract() const
+//{
+// return m_files_to_extract;
+//}
+//
+////----------------------------------------------------------------------------------------
+////OperationCanceledException
+////----------------------------------------------------------------------------------------
+//
+//const char* OPERATION_CANCELED_EXCEPTION = "OperationCanceledException";
+//
+//OperationCanceledException::OperationCanceledException(const char* message)
+//{
+// LOGD("Entered");
+//}
+//
+////----------------------------------------------------------------------------------------
+////ExtractEntryProgressCallback
+////----------------------------------------------------------------------------------------
+//
+//ExtractEntryProgressCallback::ExtractEntryProgressCallback():
+// ExtractAllProgressCallback(),
+// m_strip_name(false)
+//{
+// LOGD("Entered");
+// m_callback_type = EXTRACT_ENTRY_PROGRESS_CALLBACK;
+//}
+//
+//ExtractEntryProgressCallback::~ExtractEntryProgressCallback()
+//{
+// LOGD("Entered");
+//}
+//
+//ArchiveFileEntryPtr ExtractEntryProgressCallback::getArchiveFileEntry()
+//{
+// return m_archive_file_entry;
+//}
+//
+//void ExtractEntryProgressCallback::setArchiveFileEntry(ArchiveFileEntryPtr afentry)
+//{
+// m_archive_file_entry = afentry;
+//}
+//
+//void ExtractEntryProgressCallback::setStripName(bool strip_name)
+//{
+// m_strip_name = strip_name;
+//}
+//
+//bool ExtractEntryProgressCallback::getStripName() const
+//{
+// return m_strip_name;
+//}
+//
+//void ExtractEntryProgressCallback::setStripBasePath(
+// const std::string& strip_base_path)
+//{
+// m_strip_base_path = strip_base_path;
+//}
+//
+//const std::string& ExtractEntryProgressCallback::getStripBasePath() const
+//{
+// return m_strip_base_path;
+//}
+//
+//void ExtractEntryProgressCallback::executeOperation(ArchiveFilePtr archive_file_ptr)
+//{
+// LOGD("Entered");
+//
+// if(!m_archive_file_entry) {
+// LOGE("ArchiveFileEntry is not set in callback");
+// throw UnknownException("Could not extract archive file entry");
+// }
+//
+// if(!archive_file_ptr) {
+// LOGE("archive_file_ptr is NULL");
+// throw UnknownException("Could not extract archive file entry");
+// }
+//
+// UnZipPtr unzip = archive_file_ptr->createUnZipObject();
+// unzip->extractTo(this);
+//}
+
+} //namespace Archive
+} //namespace DeviceAPI
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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.
+//
+
+/**
+ * @file ArchiveCallbackData.h
+ */
+
+#ifndef __ARCHIVE_CALLBACK_DATA_H__
+#define __ARCHIVE_CALLBACK_DATA_H__
+
+#include <string>
+#include <memory>
+#include <glib.h>
+
+#include "filesystem_file.h"
+
+#include "archive_file_entry.h"
+
+namespace DeviceAPI {
+namespace Archive {
+
+class ArchiveFileEntry;
+typedef std::shared_ptr<ArchiveFileEntry> ArchiveFileEntryPtr;
+
+enum ArchiveCallbackType {
+ OPERATION_CALLBACK_DATA = 0,
+ OPEN_CALLBACK_DATA = 1,
+ GET_ENTRIES_CALLBACK_DATA = 2,
+ GET_ENTRY_BY_NAME_CALLBACK_DATA = 3,
+ BASE_PROGRESS_CALLBACK = 4,
+ EXTRACT_ALL_PROGRESS_CALLBACK = 5,
+ EXTRACT_ENTRY_PROGRESS_CALLBACK = 6,
+ ADD_PROGRESS_CALLBACK = 7
+};
+
+class ArchiveFile;
+typedef std::shared_ptr<ArchiveFile> ArchiveFilePtr;
+
+class OperationCallbackData
+{
+public:
+ OperationCallbackData(ArchiveCallbackType callback_type = OPERATION_CALLBACK_DATA);
+ virtual ~OperationCallbackData();
+
+ //void setSuccessCallback(JSValueRef on_success);
+ //void setErrorCallback(JSValueRef on_error);
+
+ void callSuccessCallback();
+ //void callSuccessCallback(JSValueRef err);
+ //void callErrorCallback(JSValueRef err);
+
+ void setError(const std::string &err_name,
+ const std::string &err_message);
+ bool isError() const;
+ const std::string& getErrorName() const;
+ const std::string& getErrorMessage() const;
+
+ void setOperationId(long op_id);
+ long getOperationId() const;
+
+ ArchiveCallbackType getCallbackType() const;
+
+ virtual void executeOperation(ArchiveFilePtr archive_file_ptr);
+
+ bool isCanceled() const;
+ void setIsCanceled(bool is_cancel);
+
+ ArchiveFilePtr getArchiveFile() const;
+ void setArchiveFile(ArchiveFilePtr caller);
+
+protected:
+ ArchiveCallbackType m_callback_type;
+ long m_op_id;
+
+private:
+ bool m_is_error;
+ bool m_is_canceled;
+ std::string m_err_name;
+ std::string m_err_message;
+
+ ArchiveFilePtr m_caller_instance;
+};
+
+class OpenCallbackData : public OperationCallbackData
+{
+public:
+ OpenCallbackData(ArchiveCallbackType callback_type = OPEN_CALLBACK_DATA);
+ virtual ~OpenCallbackData();
+
+ virtual void executeOperation(ArchiveFilePtr archive_file_ptr);
+};
+
+class GetEntriesCallbackData : public OperationCallbackData
+{
+public:
+ GetEntriesCallbackData(ArchiveCallbackType callback_type = GET_ENTRIES_CALLBACK_DATA);
+ virtual ~GetEntriesCallbackData();
+
+ ArchiveFileEntryPtrMapPtr getEntries() const;
+ void setEntries(ArchiveFileEntryPtrMapPtr entries);
+
+ virtual void executeOperation(ArchiveFilePtr archive_file_ptr);
+
+private:
+ ArchiveFileEntryPtrMapPtr m_entries;
+};
+
+class GetEntryByNameCallbackData : public OperationCallbackData
+{
+public:
+ GetEntryByNameCallbackData(ArchiveCallbackType callback_type = GET_ENTRY_BY_NAME_CALLBACK_DATA);
+ virtual ~GetEntryByNameCallbackData();
+
+ const std::string& getName() const;
+ void setName(const std::string& name);
+
+ ArchiveFileEntryPtr getFileEntry() const;
+ void setFileEntry(ArchiveFileEntryPtr entry);
+
+ virtual void executeOperation(ArchiveFilePtr archive_file_ptr);
+private:
+ std::string m_name;
+ ArchiveFileEntryPtr m_file_entry;
+
+};
+
+class BaseProgressCallback : public OperationCallbackData
+{
+public:
+ BaseProgressCallback(ArchiveCallbackType callback_type = BASE_PROGRESS_CALLBACK);
+ virtual ~BaseProgressCallback();
+
+ //void setProgressCallback(JSValueRef on_progress);
+
+ bool getOverwrite() const;
+ void setOverwrite(bool overwrite);
+
+ void callProgressCallbackOnMainThread(const double progress,
+ ArchiveFileEntryPtr current_entry);
+ void callSuccessCallbackOnMainThread();
+
+ virtual void executeOperation(ArchiveFilePtr archive_file_ptr);
+
+protected:
+ void callProgressCallback(long operationId,
+ double value,
+ const std::string& filename);
+
+private:
+ static gboolean callProgressCallbackCB(void* data);
+ static gboolean callSuccessCallbackCB(void* data);
+
+ bool m_overwrite;
+};
+
+class AddProgressCallback : public BaseProgressCallback
+{
+public:
+ AddProgressCallback(ArchiveCallbackType callback_type = ADD_PROGRESS_CALLBACK);
+ virtual ~AddProgressCallback();
+
+ virtual void executeOperation(ArchiveFilePtr archive_file_ptr);
+
+ void setBasePath(const std::string& path);
+ const std::string& getBasePath();
+ const std::string& getBaseVirtualPath();
+
+ ArchiveFileEntryPtr getFileEntry() const;
+ void setFileEntry(ArchiveFileEntryPtr file_entry);
+
+private:
+ ArchiveFileEntryPtr m_file_entry;
+ ArchiveFileEntryPtrMapPtr m_entry_map;
+ std::string m_base_path;
+ std::string m_base_virt_path;
+};
+
+class ExtractAllProgressCallback : public BaseProgressCallback
+{
+public:
+ ExtractAllProgressCallback(ArchiveCallbackType callback_type = EXTRACT_ALL_PROGRESS_CALLBACK);
+ virtual ~ExtractAllProgressCallback();
+
+ Filesystem::FilePtr getDirectory() const;
+ void setDirectory(Filesystem::FilePtr directory);
+
+ void startedExtractingFile(unsigned long current_file_size);
+ void extractedPartOfFile(unsigned long bytes_decompressed);
+ void finishedExtractingFile();
+
+ double getCurrentFileProgress() const;
+ double getOverallProgress() const;
+
+ virtual void executeOperation(ArchiveFilePtr archive_file_ptr);
+
+ void setExpectedDecompressedSize(unsigned long exp_dec_size);
+ unsigned long getExpectedDecompressedSize() const;
+
+ void setNumberOfFilesToExtract(unsigned long files_count);
+ unsigned long getNumberOfFilesToExtract() const;
+
+private:
+ void updateOverallProgress(unsigned long bytes_decompressed);
+
+ Filesystem::FilePtr m_directory;
+
+ //
+ // Constant values set before extracting entries:
+ //
+ unsigned long m_files_to_extract;
+ unsigned long m_expected_decompressed_size;
+
+ //
+ // Values updated during extraction
+ //
+
+ unsigned long m_current_file_size;
+ unsigned long m_current_file_extracted_bytes;
+ unsigned long m_files_extracted;
+
+ double m_progress_overall;
+ unsigned long m_overall_decompressed;
+};
+
+class ExtractEntryProgressCallback : public ExtractAllProgressCallback
+{
+public:
+ ExtractEntryProgressCallback();
+ virtual ~ExtractEntryProgressCallback();
+
+ ArchiveFileEntryPtr getArchiveFileEntry();
+ void setArchiveFileEntry(ArchiveFileEntryPtr afentry);
+
+ void setStripName(bool strip_name);
+ bool getStripName() const;
+
+ void setStripBasePath(const std::string& strip_base_path);
+ const std::string& getStripBasePath() const;
+
+ virtual void executeOperation(ArchiveFilePtr archive_file_ptr);
+
+private:
+ ArchiveFileEntryPtr m_archive_file_entry;
+ bool m_strip_name;
+ std::string m_strip_base_path;
+};
+
+class OperationCanceledException {
+public:
+ OperationCanceledException(const char* message = "Operation Canceled");
+};
+
+}
+}
+
+#endif //__ARCHIVE_CALLBACK_DATA_H__
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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 "archive_file.h"
+
+#include "common/logger.h"
+#include "common/platform_exception.h"
+
+#include "archive_manager.h"
+#include "archive_utils.h"
+#include "defs.h"
+#include "un_zip.h"
+#include "zip.h"
+
+
+using namespace common;
+
+namespace DeviceAPI {
+namespace Archive {
+
+Permission::Permission(bool r, bool w, bool rw, bool a){
+ permission[0] = r;
+ permission[1] = w;
+ permission[2] = rw;
+ permission[3] = a;
+}
+
+PermissionMap ArchiveFile::s_permission_map = {
+ {ARCHIVE_FUNCTION_API_ARCHIVE_FILE_ADD,
+ Permission(NOT_ALLOWED, ALLOWED, ALLOWED, ALLOWED)},
+ {ARCHIVE_FUNCTION_API_ARCHIVE_FILE_EXTRACT_ALL,
+ Permission(ALLOWED, NOT_ALLOWED, ALLOWED, NOT_ALLOWED)},
+ {ARCHIVE_FUNCTION_API_ARCHIVE_FILE_GET_ENTRIES,
+ Permission(ALLOWED, NOT_ALLOWED, ALLOWED, NOT_ALLOWED)},
+ {ARCHIVE_FUNCTION_API_ARCHIVE_FILE_GET_ENTRY_BY_NAME,
+ Permission(ALLOWED, NOT_ALLOWED, ALLOWED, NOT_ALLOWED)}
+};
+
+ArchiveFile::ArchiveFile() :
+ enable_shared_from_this<ArchiveFile>(),
+ m_decompressed_size(0),
+ m_is_open(false),
+ m_overwrite(false),
+ m_created_as_new_empty_archive(false)
+{
+ LOGD("Entered");
+}
+
+ArchiveFile::ArchiveFile(FileMode file_mode) :
+ enable_shared_from_this<ArchiveFile>(),
+ m_decompressed_size(0),
+ m_is_open(false),
+ m_overwrite(false)
+{
+ m_file_mode = file_mode;
+}
+
+ArchiveFile::~ArchiveFile()
+{
+ LOGD("Entered");
+
+ if(m_entry_map) {
+ LOGD("Unlinking old m_entry_map: %d ArchiveFileEntries", m_entry_map->size());
+ for(auto it = m_entry_map->begin(); it != m_entry_map->end(); ++it) {
+ if(it->second) {
+ it->second->setArchiveFileNonProtectPtr(NULL);
+ }
+ }
+ }
+}
+
+gboolean ArchiveFile::openTaskCompleteCB(void *data)
+{
+ LOGD("Entered");
+ LOGW("STUB Not calling success/error callback");
+
+ auto callback = static_cast<OperationCallbackData*>(data);
+ if (!callback) {
+ LOGE("callback is null");
+ return false;
+ }
+
+// JSContextRef context = callback->getContext();
+// if (!GlobalContextManager::getInstance()->isAliveGlobalContext(context)) {
+// LOGE("context was closed");
+// delete callback;
+// callback = NULL;
+// return false;
+// }
+// try {
+// if (callback->isError()) {
+// JSObjectRef errobj = JSWebAPIErrorFactory::makeErrorObject(context,
+// callback->getErrorName(),
+// callback->getErrorMessage());
+// callback->callErrorCallback(errobj);
+// }
+// else {
+// JSObjectRef result = JSArchiveFile::makeJSObject(context,
+// callback->getArchiveFile());
+// callback->callSuccessCallback(result);
+// }
+// }
+// catch (const PlatformException &err) {
+// LOGE("%s (%s)", err.name().c_str(), err.message().c_str());
+// }
+// catch (...) {
+// LOGE("Unknown error occurs");
+// }
+
+ delete callback;
+ callback = NULL;
+
+ return false;
+}
+
+gboolean ArchiveFile::callErrorCallback(void* data)
+{
+ LOGD("Entered");
+ LOGW("STUB Not calling success/error callback");
+
+ auto callback = static_cast<OperationCallbackData*>(data);
+ if (!callback) {
+ LOGE("callback is null");
+ return false;
+ }
+
+// JSContextRef context = callback->getContext();
+// if (!GlobalContextManager::getInstance()->isAliveGlobalContext(context)) {
+// LOGE("context was closed");
+// delete callback;
+// callback = NULL;
+// return false;
+// }
+//
+// try {
+// if (callback->isError()) {
+// JSObjectRef errobj = JSWebAPIErrorFactory::makeErrorObject(context,
+// callback->getErrorName(),
+// callback->getErrorMessage());
+// callback->callErrorCallback(errobj);
+// }
+// else {
+// LOGW("The success callback should be not be called in this case");
+// }
+// }
+// catch (const PlatformException &err) {
+// LOGE("%s (%s)", err.name().c_str(), err.message().c_str());
+// }
+// catch (...) {
+// LOGE("Unknown error occurs");
+// }
+
+ delete callback;
+ callback = NULL;
+
+ return false;
+}
+
+void* ArchiveFile::taskManagerThread(void *data)
+{
+ LOGD("Entered");
+ ArchiveFileHolder* archive_file_holder = static_cast<ArchiveFileHolder*>(data);
+ if (!archive_file_holder) {
+ LOGE("archive_file_holder is null");
+ return NULL;
+ }
+
+ if (!archive_file_holder->ptr){
+ LOGE("archive_file is null");
+ delete archive_file_holder;
+ archive_file_holder = NULL;
+ return NULL;
+ }
+
+ while(true){
+ OperationCallbackData* callback = NULL;
+ bool call_error_callback = false;
+ try{
+ {
+ std::lock_guard<std::mutex> lock(archive_file_holder->ptr->m_mutex);
+ if(archive_file_holder->ptr->m_task_queue.empty()){
+ break;
+ }
+ callback = archive_file_holder->ptr->m_task_queue.back().second;
+ }
+ if(callback && !callback->isCanceled()){
+ callback->executeOperation(archive_file_holder->ptr);
+ }
+ {
+ std::lock_guard<std::mutex> lock(archive_file_holder->ptr->m_mutex);
+ archive_file_holder->ptr->m_task_queue.pop_back();
+ }
+ } catch (const OperationCanceledException &err) {
+ {
+ std::lock_guard<std::mutex> lock(archive_file_holder->ptr->m_mutex);
+ archive_file_holder->ptr->m_task_queue.pop_back();
+ }
+ delete callback;
+ callback = NULL;
+ } catch (const PlatformException &err) {
+ LOGE("taskManagerThread fails, %s: %s", err.name().c_str(),
+ err.message().c_str());
+ callback->setError(err.name().c_str(), err.message().c_str());
+ call_error_callback = true;
+ } catch (...) {
+ LOGE("taskManagerThread fails");
+ callback->setError("UnknownError", "UnknownError");
+ call_error_callback = true;
+ }
+ if(call_error_callback) {
+ {
+ std::lock_guard<std::mutex> lock(archive_file_holder->ptr->m_mutex);
+ archive_file_holder->ptr->m_task_queue.pop_back();
+ }
+ if (!g_idle_add(callErrorCallback, static_cast<void*>(callback))) {
+ LOGE("g_idle_add fails");
+ delete callback;
+ callback = NULL;
+ }
+ }
+ }
+
+ delete archive_file_holder;
+ archive_file_holder = NULL;
+
+ return NULL;
+}
+
+long ArchiveFile::addOperation(OperationCallbackData* callback)
+{
+ LOGD("Entered callback type:%d", callback->getCallbackType());
+
+ const long operation_id =
+ ArchiveManager::getInstance().getNextOperationId(shared_from_this());
+ callback->setOperationId(operation_id);
+ callback->setArchiveFile(shared_from_this());
+ std::size_t size = 0;
+ {
+ std::lock_guard<std::mutex> lock(m_mutex);
+ m_task_queue.push_front(CallbackPair(operation_id, callback));
+ size = m_task_queue.size();
+ }
+ if(1 == size) {
+ pthread_t thread;
+ ArchiveFileHolder* holder = new(std::nothrow) ArchiveFileHolder();
+ if(!holder) {
+ LOGE("Memory allocation error");
+ throw UnknownException("Memory allocation error");
+ }
+ holder->ptr = shared_from_this();
+ if (pthread_create(&thread, NULL, taskManagerThread,
+ static_cast<void*>(holder))) {
+ LOGE("Thread creation failed");
+ delete holder;
+ holder = NULL;
+ throw UnknownException("Thread creation failed");
+ }
+
+ if (pthread_detach(thread)) {
+ LOGE("Thread detachment failed");
+ }
+ }
+ return operation_id;
+}
+
+void ArchiveFile::extractAllTask(ExtractAllProgressCallback* callback)
+{
+ Filesystem::FilePtr directory = callback->getDirectory();
+
+ if(!directory) {
+ LOGE("Directory is null");
+ throw UnknownException("Directory is null");
+ } else {
+ if(!directory->getNode()){
+ LOGE("Node in directory is null");
+ throw UnknownException("Node is null");
+ }
+ }
+
+ if(!m_file) {
+ LOGE("File is null");
+ throw UnknownException("File is null");
+ } else {
+ if(!m_file->getNode()){
+ LOGE("Node in file is null");
+ throw UnknownException("Node in file is null");
+ }
+ }
+
+ // For explanation please see:
+ // ArchiveFile.h m_created_as_new_empty_archive description
+ //
+ if(m_file->getSize() == 0) {
+ LOGD("Zip file: %s is empty",
+ m_file->getFullPath().c_str());
+
+ if(m_created_as_new_empty_archive) {
+ //We do not call progress callback since we do not have any ArchiveFileEntry
+ callback->callSuccessCallbackOnMainThread();
+ callback = NULL;
+ return;
+ }
+ else {
+ LOGW("m_created_as_new_empty_archive is false");
+ LOGE("Throwing InvalidStateException: File is not valid ZIP archive");
+ throw InvalidStateException("File is not valid ZIP archive");
+ }
+ }
+
+ UnZipPtr unzip = createUnZipObject();
+ unzip->extractAllFilesTo(directory->getFullPath(), callback);
+}
+
+long ArchiveFile::getEntries(GetEntriesCallbackData* callback)
+{
+ LOGD("Entered");
+ if(!callback) {
+ LOGE("callback is NULL");
+ throw UnknownException("Could not get list of files in archive");
+ }
+
+ throwInvalidStateErrorIfArchiveFileIsClosed();
+
+ return addOperation(callback);
+}
+
+gboolean ArchiveFile::getEntriesTaskCompleteCB(void *data)
+{
+ LOGD("Entered");
+ LOGW("STUB Not calling success/error callback");
+
+ auto callback = static_cast<GetEntriesCallbackData*>(data);
+ if (!callback) {
+ LOGE("callback is null");
+ return false;
+ }
+
+// JSContextRef context = callback->getContext();
+// if (!GlobalContextManager::getInstance()->isAliveGlobalContext(context)) {
+// LOGE("context was closed");
+// delete callback;
+// callback = NULL;
+// return false;
+// }
+//
+// try {
+// ArchiveFileEntryPtrMapPtr entries = callback->getEntries();
+// unsigned int size = entries->size();
+//
+// JSObjectRef objArray[size];
+// int i = 0;
+// for(auto it = entries->begin(); it != entries->end(); it++) {
+// objArray[i] = JSArchiveFileEntry::makeJSObject(context, it->second);
+// i++;
+// }
+//
+// JSValueRef exception = NULL;
+// JSObjectRef jsResult = JSObjectMakeArray(context, size,
+// size > 0 ? objArray : NULL, &exception);
+// if (exception != NULL) {
+// throw Common::UnknownException(context, exception);
+// }
+//
+// callback->callSuccessCallback(jsResult);
+// }
+// catch (const PlatformException &err) {
+// LOGE("%s (%s)", err.name().c_str(), err.message().c_str());
+// }
+// catch (...) {
+// LOGE("Unknown error occurs");
+// }
+
+ delete callback;
+ callback = NULL;
+
+ return false;
+}
+
+long ArchiveFile::extractAll(ExtractAllProgressCallback *callback)
+{
+ LOGD("Entered");
+ if(!callback) {
+ LOGE("callback is NULL");
+ throw UnknownException("Could not extract all files from archive");
+ }
+
+ throwInvalidStateErrorIfArchiveFileIsClosed();
+
+ return addOperation(callback);
+}
+
+long ArchiveFile::extractEntryTo(ExtractEntryProgressCallback* callback)
+{
+ LOGD("Entered");
+ if(!callback) {
+ LOGE("callback is NULL");
+ throw UnknownException("Could not extract archive file entry");
+ }
+
+ // FIXME according to documentation:
+ // if archive was closed, any further operation attempt will make InvalidStateError
+ // but method extract() from ArchiveFileEntryObject is not permitted to throw above exception
+
+ // uncomment in case when this method have permission to throwing InvalidStateError
+ // throwInvalidStateErrorIfArchiveFileisClosed();
+ if(!m_is_open) {
+ LOGE("Archive is not opened");
+ throw UnknownException("Archive is not opened");
+ }
+
+ return addOperation(callback);
+}
+
+
+long ArchiveFile::add(AddProgressCallback *callback)
+{
+ LOGD("Entered");
+ if(!callback) {
+ LOGE("callback is NULL");
+ throw UnknownException("Could not add file to archive");
+ }
+ if(FileMode::READ == m_file_mode) {
+ LOGE("Trying to add file when READ access mode selected");
+ throw InvalidAccessException("Add not allowed for \"r\" access mode");
+ }
+
+ throwInvalidStateErrorIfArchiveFileIsClosed();
+
+ return addOperation(callback);
+}
+
+void ArchiveFile::close()
+{
+ LOGD("Entered");
+
+ if(!m_is_open){
+ LOGD("Archive already closed");
+ }
+ m_is_open = false;
+
+ return;
+}
+
+long ArchiveFile::getEntryByName(GetEntryByNameCallbackData* callback)
+{
+ LOGD("Entered");
+ if(!callback) {
+ LOGE("callback is NULL");
+ throw UnknownException("Could not get archive file entries by name");
+ }
+
+ throwInvalidStateErrorIfArchiveFileIsClosed();
+
+ return addOperation(callback);
+}
+
+gboolean ArchiveFile::getEntryByNameTaskCompleteCB(void *data)
+{
+ LOGD("Entered");
+ LOGW("STUB Not calling success/error callback");
+
+ auto callback = static_cast<GetEntryByNameCallbackData*>(data);
+ if (!callback) {
+ LOGE("callback is null");
+ return false;
+ }
+
+// JSContextRef context = callback->getContext();
+// if (!GlobalContextManager::getInstance()->isAliveGlobalContext(context)) {
+// LOGE("context was closed");
+// delete callback;
+// callback = NULL;
+// return false;
+// }
+// try {
+// if (callback->isError()) {
+// JSObjectRef errobj = JSWebAPIErrorFactory::makeErrorObject(context,
+// callback->getErrorName(),
+// callback->getErrorMessage());
+// callback->callErrorCallback(errobj);
+// }
+// else {
+// JSObjectRef entry = JSArchiveFileEntry::makeJSObject(context,
+// callback->getFileEntry());
+// callback->callSuccessCallback(entry);
+// }
+// }
+// catch (const PlatformException &err) {
+// LOGE("%s (%s)", err.name().c_str(), err.message().c_str());
+// }
+// catch (...) {
+// LOGE("Unknown error occurs");
+// }
+
+ delete callback;
+ callback = NULL;
+
+ return false;
+}
+
+Filesystem::FilePtr ArchiveFile::getFile() const
+{
+ LOGD("Entered");
+ return m_file;
+}
+
+void ArchiveFile::setFile(Filesystem::FilePtr file)
+{
+ LOGD("Entered");
+ m_file = file;
+}
+
+bool ArchiveFile::isOverwrite() const
+{
+ return m_overwrite;
+}
+
+void ArchiveFile::setOverwrite(bool overwrite)
+{
+ LOGD("Entered");
+ m_overwrite = overwrite;
+}
+
+unsigned long ArchiveFile::getDecompressedSize() const
+{
+ LOGD("Entered");
+ return m_decompressed_size;
+}
+
+void ArchiveFile::setDecompressedSize(unsigned long decompressed_size)
+{
+ LOGD("Entered");
+ m_decompressed_size = decompressed_size;
+}
+
+bool ArchiveFile::isOpen() const
+{
+ LOGD("Entered");
+ return m_is_open;
+}
+
+void ArchiveFile::setIsOpen(bool is_open)
+{
+ LOGD("Entered");
+ m_is_open = is_open;
+}
+
+ArchiveFileEntryPtrMapPtr ArchiveFile::getEntryMap() const
+{
+ return m_entry_map;
+}
+
+void ArchiveFile::setEntryMap(ArchiveFileEntryPtrMapPtr entries)
+{
+ LOGD("Entered");
+
+ if(m_entry_map) {
+ LOGD("Unlinking old m_entry_map: %d ArchiveFileEntries", m_entry_map->size());
+ for(auto it = m_entry_map->begin(); it != m_entry_map->end(); ++it) {
+ if(it->second) {
+ it->second->setArchiveFileNonProtectPtr(NULL);
+ }
+ }
+ }
+
+ m_entry_map = entries;
+
+ LOGD("Linking new m_entry_map ArchiveFileEntries (%d) with ArchiveFile object",
+ m_entry_map->size());
+ for(auto it = m_entry_map->begin(); it != m_entry_map->end(); ++it) {
+ if(it->second) {
+ it->second->setArchiveFileNonProtectPtr(this);
+ }
+ }
+}
+
+UnZipPtr ArchiveFile::createUnZipObject()
+{
+ LOGD("Entered");
+ if(!m_is_open) {
+ LOGE("File is not opened");
+ throw UnknownException("File is not opened");
+ }
+
+ if (!m_file) {
+ LOGE("m_file is null");
+ throw UnknownException("File is null");
+ }
+
+// Filesystem::NodePtr node = m_file->getNode();
+// if(!node) {
+// LOGE("Node is null");
+// throw UnknownException("Node is null");
+// }
+
+ UnZipPtr unzip = UnZip::open(m_file->getFullPath());
+ return unzip;
+}
+
+ZipPtr ArchiveFile::createZipObject()
+{
+ LOGD("Entered");
+ if(!m_is_open) {
+ LOGE("File is not opened");
+ throw UnknownException("File is not opened");
+ }
+
+ if (!m_file) {
+ LOGE("m_file is null");
+ throw UnknownException("File is null");
+ }
+
+// Filesystem::NodePtr node = m_file->getNode();
+// if(!node) {
+// LOGE("Node is null");
+// throw UnknownException("Node is null");
+// }
+
+ ZipPtr zip = Zip::open(m_file->getFullPath());
+ return zip;
+
+}
+
+bool ArchiveFile::isAllowedOperation(const std::string& method_name)
+{
+ LOGD("Entered");
+ PermissionMap::iterator it = s_permission_map.find(method_name);
+ if (it != s_permission_map.end()) {
+ return it->second.permission[m_file_mode];
+ }
+ return false;
+}
+
+FileMode ArchiveFile::getFileMode() const
+{
+ LOGD("Entered");
+ return m_file_mode;
+}
+
+void ArchiveFile::setFileMode(FileMode file_mode)
+{
+ LOGD("Entered");
+ m_file_mode = file_mode;
+}
+
+void ArchiveFile::throwInvalidStateErrorIfArchiveFileIsClosed() const
+{
+ if(!m_is_open){
+ LOGE("ArchiveFile closed - operation not permitted");
+ throw InvalidStateException(
+ "ArchiveFile closed - operation not permitted");
+ }
+}
+
+void ArchiveFile::setCreatedAsNewEmptyArchive(bool new_and_empty)
+{
+ m_created_as_new_empty_archive = new_and_empty;
+}
+
+bool ArchiveFile::isCreatedAsNewEmptyArchive() const
+{
+ return m_created_as_new_empty_archive;
+}
+
+void ArchiveFile::updateListOfEntries()
+{
+ // For explanation please see:
+ // ArchiveFile.h m_created_as_new_empty_archive description
+ //
+ if(m_file->getSize() == 0) {
+ LOGD("Zip file: %s is empty",
+ m_file->getFullPath().c_str());
+
+ if(m_created_as_new_empty_archive) {
+ LOGD("OK this is empty archive = nothing to do yet");
+ return;
+ }
+ else {
+ LOGW("m_created_as_new_empty_archive is false");
+ LOGE("Throwing InvalidStateException: File is not valid ZIP archive");
+ throw InvalidStateException("File is not valid ZIP archive");
+ }
+ }
+
+ UnZipPtr unzip = createUnZipObject();
+ unsigned long decompressedSize = 0;
+ ArchiveFileEntryPtrMapPtr emap = unzip->listEntries(&decompressedSize);
+ setEntryMap(emap);
+ setDecompressedSize(decompressedSize);
+}
+
+bool ArchiveFile::isEntryWithNameInArchive(const std::string& name_in_zip,
+ bool* out_is_directory,
+ std::string* out_matching_name)
+{
+ if(!m_entry_map) {
+ LOGW("m_entry_map is NULL");
+ return false;
+ }
+
+ const bool name_in_zip_is_dir = isDirectoryPath(name_in_zip);
+ bool set_is_directory = false;
+ bool set_name_exists = false;
+
+ //Try exact name:
+ auto it = m_entry_map->find(name_in_zip);
+ if(it != m_entry_map->end()) {
+ set_is_directory = name_in_zip_is_dir;
+ set_name_exists = true;
+ }
+ else {
+ if(name_in_zip_is_dir) {
+ //If name_in_zip is pointing at directory try file
+ it = m_entry_map->find(removeTrailingDirectorySlashFromPath(name_in_zip));
+ set_is_directory = false;
+ } else {
+ //If name_in_zip is pointing at file try directory
+ it = m_entry_map->find(name_in_zip + "/");
+ set_is_directory = true;
+ }
+
+ if(it != m_entry_map->end()) {
+ set_name_exists = true;
+ }
+ }
+
+ if(!set_name_exists) {
+ return false;
+ }
+
+ if(out_is_directory) {
+ *out_is_directory = set_is_directory;
+ }
+ if(out_matching_name) {
+ *out_matching_name = it->first;
+ }
+
+ return true;
+}
+
+} // Archive
+} // DeviceAPI
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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 _TIZEN_ARCHIVE_ARCHIVE_FILE_H_
+#define _TIZEN_ARCHIVE_ARCHIVE_FILE_H_
+
+#include <deque>
+#include <memory>
+#include <mutex>
+#include <string>
+
+#include "archive_callback_data.h"
+#include "archive_manager.h"
+#include "filesystem_file.h"
+#include "un_zip.h"
+#include "zip.h"
+
+
+namespace DeviceAPI {
+namespace Archive {
+
+class ArchiveFile;
+class ArchiveManager;
+class OperationCallbackData;
+class OpenCallbackData;
+class GetEntriesCallbackData;
+class GetEntryByNameCallbackData;
+class BaseProgressCallback;
+class AddProgressCallback;
+class ExtractAllProgressCallback;
+class UnZipExtractRequest;
+class ExtractEntryProgressCallback;
+class Zip;
+class ZipAddRequest;
+
+enum FileMode {
+ READ = 0,
+ WRITE,
+ READ_WRITE,
+ ADD
+};
+
+enum IsAllowed {
+ NOT_ALLOWED = false,
+ ALLOWED = true
+};
+
+struct Permission {
+ Permission(bool r, bool w, bool rw, bool a);
+ bool permission[4];
+};
+
+typedef std::shared_ptr<ArchiveFile> ArchiveFilePtr;
+typedef std::pair<long, OperationCallbackData*> CallbackPair;
+typedef std::vector<ArchiveFileEntryPtr> ArchiveFileEntryPtrVector;
+typedef std::map<std::string, Permission> PermissionMap;
+typedef std::pair<std::string, Permission> PermissionPair;
+
+struct ArchiveFileHolder{
+ ArchiveFilePtr ptr;
+};
+
+class ArchiveFile : public std::enable_shared_from_this<ArchiveFile> {
+public:
+ ArchiveFile();
+ ArchiveFile(FileMode file_mode);
+ virtual ~ArchiveFile();
+
+ long getEntries(GetEntriesCallbackData* callback);
+ long getEntryByName(GetEntryByNameCallbackData* callback);
+ long extractAll(ExtractAllProgressCallback *callback);
+ long add(AddProgressCallback *callback);
+ void close();
+
+ Filesystem::FilePtr getFile() const;
+ void setFile(Filesystem::FilePtr file);
+ bool isOverwrite() const;
+ void setOverwrite(bool overwrite);
+ unsigned long getDecompressedSize() const;
+ void setDecompressedSize(unsigned long decompressed_size);
+ bool isOpen() const;
+ void setIsOpen(bool is_open);
+
+ ArchiveFileEntryPtrMapPtr getEntryMap() const;
+ void setEntryMap(ArchiveFileEntryPtrMapPtr entries);
+ bool isEntryWithNameInArchive(const std::string& name_in_zip,
+ bool* out_is_directory = NULL,
+ std::string* out_matching_name = NULL);
+
+
+ //Used by ArchiveFileEntry
+ long extractEntryTo(ExtractEntryProgressCallback* callback);
+
+ bool isAllowedOperation(const std::string& method_name);
+ FileMode getFileMode() const;
+ void setFileMode(FileMode file_mode);
+
+ /**
+ * \brief Throw InvalidStateError in case when ArchiveFile is closed
+ */
+ void throwInvalidStateErrorIfArchiveFileIsClosed() const;
+
+ void setCreatedAsNewEmptyArchive(bool new_and_empty);
+ bool isCreatedAsNewEmptyArchive() const;
+
+
+ void updateListOfEntries();
+private:
+ UnZipPtr createUnZipObject();
+ ZipPtr createZipObject();
+
+ std::deque<CallbackPair> m_task_queue;
+ std::mutex m_mutex;
+
+ Filesystem::FilePtr m_file;
+
+ FileMode m_file_mode;
+ static PermissionMap s_permission_map;
+
+ unsigned long m_decompressed_size;
+ bool m_is_open;
+ /**
+ * If set to true, during decompression archive will had permission to overwriting files.
+ * Warning: If decompressing file have got the same name as existing directory
+ * in place where file should be decompressed, directory will be deleted.
+ */
+ bool m_overwrite;
+ ArchiveFileEntryPtrMapPtr m_entry_map;
+
+
+ /**
+ * If we execute tizen.open(destFile , "w"/"rw"/ "a", ..., {overwrite: true}),
+ * destFile will be empty file with size = 0, which cannot be
+ * opened with minizip library.
+ *
+ * Zip file format restricts that at least one file / folder is compressed,
+ * threfore after creating new empty archive we cannot save it.
+ * Until we execute archive.add destFile is empty file with size 0 bytes.
+ *
+ * Unfortunately if we try to execute archive.getEntries or archive.extractAll
+ * minizip library will fail to open empty archive. To fix this issue we will
+ * use flag "created_as_new_empty_archive" which informs that this is new and
+ * empty archive threfore we should not try to open it.
+ *
+ * In extractAll we will just call success callback - there was nothing to extract
+ * but no error occured. In get entries we just should return empty list of entries.
+ */
+ bool m_created_as_new_empty_archive;
+
+ static gboolean openTaskCompleteCB(void *data);
+ static gboolean getEntriesTaskCompleteCB(void *data);
+ static gboolean getEntryByNameTaskCompleteCB(void *data);
+
+ static void* taskManagerThread(void *data);
+ long addOperation(OperationCallbackData* callback);
+ static gboolean callErrorCallback(void* data);
+
+ void extractAllTask(ExtractAllProgressCallback* callback);
+
+ friend class ExtractAllProgressCallback;
+ friend class UnZipExtractRequest;
+ friend class OpenCallbackData;
+ friend class GetEntriesCallbackData;
+ friend class GetEntryByNameCallbackData;
+ friend class ExtractEntryProgressCallback;
+ friend class ArchiveManager;
+ friend class AddProgressCallback;
+ friend class Zip;
+ friend class ZipAddRequest;
+ friend class BaseProgressCallback;
+};
+
+} // Archive
+} // DeviceAPI
+
+#endif /* _TIZEN_ARCHIVE_FILE_ENTRY_H_ */
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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 "archive_file_entry.h"
+
+#include "common/logger.h"
+#include "common/platform_exception.h"
+
+#include "archive_callback_data.h"
+#include "archive_file.h"
+#include "archive_utils.h"
+
+using namespace common;
+
+namespace DeviceAPI {
+namespace Archive {
+
+static const unsigned int s_default_compression_level = 5;
+
+ArchiveFileEntry::ArchiveFileEntry(Filesystem::FilePtr file) :
+ std::enable_shared_from_this<ArchiveFileEntry>(),
+ m_file(file),
+ m_archive(NULL),
+ m_striped(false),
+ m_size(0),
+ m_compressed_size(0),
+ m_modified(0),
+ m_compression_level(s_default_compression_level)
+{
+ LOGD("Entered");
+}
+
+ArchiveFileEntry::~ArchiveFileEntry()
+{
+ LOGD("Entered");
+}
+
+unsigned long ArchiveFileEntry::getCompressedSize() const
+{
+ return m_compressed_size;
+}
+
+void ArchiveFileEntry::setCompressedSize(unsigned long compressed_size)
+{
+ m_compressed_size = compressed_size;
+}
+
+Filesystem::FilePtr ArchiveFileEntry::getFile() const
+{
+ return m_file;
+}
+
+void ArchiveFileEntry::setFile(Filesystem::FilePtr file)
+{
+ m_file = file;
+}
+
+unsigned long ArchiveFileEntry::getSize() const
+{
+ return m_size;
+}
+
+void ArchiveFileEntry::setSize(unsigned long size)
+{
+ m_size = size;
+}
+
+const std::string& ArchiveFileEntry::getName() const
+{
+ return m_name;
+}
+
+void ArchiveFileEntry::setName(const std::string& name)
+{
+ m_name = name;
+}
+
+void ArchiveFileEntry::setModified(time_t time)
+{
+ m_modified = time;
+}
+
+time_t ArchiveFileEntry::getModified() const
+{
+ return m_modified;
+}
+
+const std::string& ArchiveFileEntry::getDestination() const
+{
+ return m_destination;
+}
+
+void ArchiveFileEntry::setDestination(const std::string& destination)
+{
+ m_destination = destination;
+}
+
+bool ArchiveFileEntry::getStriped() const
+{
+ return m_striped;
+}
+
+void ArchiveFileEntry::setStriped(bool striped)
+{
+ m_striped = striped;
+}
+
+void ArchiveFileEntry::setCompressionLevel(unsigned int level)
+{
+ m_compression_level = level;
+}
+unsigned int ArchiveFileEntry::getCompressionLevel() const
+{
+ return m_compression_level;
+}
+
+void ArchiveFileEntry::setArchiveFileNonProtectPtr(ArchiveFile* ptr)
+{
+ m_archive = ptr;
+}
+
+ArchiveFile* ArchiveFileEntry::getArchiveFileNonProtectPtr()
+{
+ return m_archive;
+}
+
+long ArchiveFileEntry::extractTo(ExtractEntryProgressCallback* callback)
+{
+ if(!m_archive) {
+ LOGE("m_archive is NULL");
+ throw UnknownException("Could not extract archive file entry");
+ }
+
+ //Callback should be associated with this instance of ArchiveFileEntry
+ callback->setArchiveFileEntry(shared_from_this());
+
+ //
+ // If strip name was set in JS layer we need to generate srip base path
+ //
+ if(callback->getStripName()) {
+
+ //Get base path - left side of last slash
+ std::string base_path_name = getBasePathFromPath(m_name);
+ if(!isDirectoryPath(base_path_name) && !base_path_name.empty()) {
+ base_path_name += "/";
+ }
+
+ LOGD("strip name is: true; archive file entry name is: [%s]; "
+ "stripBasePath will be: [%s]",
+ m_name.c_str(), base_path_name.c_str());
+
+ callback->setStripBasePath(base_path_name);
+ }
+
+ return m_archive->extractEntryTo(callback);
+}
+
+} // Archive
+} // DeviceAPI
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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 _TIZEN_ARCHIVE_ARCHIVE_FILE_ENTRY_H_
+#define _TIZEN_ARCHIVE_ARCHIVE_FILE_ENTRY_H_
+
+#include <map>
+#include <memory>
+
+#include "filesystem_file.h"
+
+namespace DeviceAPI {
+namespace Archive {
+
+class ArchiveFile;
+
+class ArchiveFileEntry;
+typedef std::shared_ptr<ArchiveFileEntry> ArchiveFileEntryPtr;
+
+class ExtractEntryProgressCallback;
+
+typedef std::map<std::string, ArchiveFileEntryPtr> ArchiveFileEntryPtrMap;
+typedef std::shared_ptr<ArchiveFileEntryPtrMap> ArchiveFileEntryPtrMapPtr;
+
+class ArchiveFileEntry : public std::enable_shared_from_this<ArchiveFileEntry> {
+public:
+ ArchiveFileEntry(Filesystem::FilePtr file = Filesystem::FilePtr());
+ ~ArchiveFileEntry();
+
+ unsigned long getCompressedSize() const;
+ void setCompressedSize(unsigned long compressedSize);
+ Filesystem::FilePtr getFile() const;
+ void setFile(Filesystem::FilePtr file);
+ unsigned long getSize() const;
+ void setSize(unsigned long size);
+ const std::string& getName() const;
+ void setName(const std::string& name);
+ void setModified(time_t time);
+ time_t getModified() const;
+ const std::string& getDestination() const;
+ void setDestination(const std::string& destination);
+ bool getStriped() const;
+ void setStriped(bool striped);
+ void setCompressionLevel(unsigned int level);
+ unsigned int getCompressionLevel() const;
+
+ void setArchiveFileNonProtectPtr(ArchiveFile* ptr);
+ ArchiveFile* getArchiveFileNonProtectPtr();
+
+ long extractTo(ExtractEntryProgressCallback* callback);
+
+private:
+ Filesystem::FilePtr m_file;
+ ArchiveFile* m_archive;
+ std::string m_name;
+ std::string m_destination;
+ bool m_striped;
+ unsigned long m_size;
+ unsigned long m_compressed_size;
+ time_t m_modified;
+ unsigned int m_compression_level;
+};
+
+} // Archive
+} // DeviceAPI
+
+#endif /* _TIZEN_ARCHIVE_FILE_ENTRY_H_ */
#include "archive/archive_instance.h"
+
+//#include "archive_manager.h"
+
#include <functional>
#include "common/picojson.h"
#include "common/logger.h"
#include "common/platform_exception.h"
+
+//using namespace DeviceAPI;
+//using namespace DeviceAPI::Archive;
+
namespace extension {
namespace archive {
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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 "archive_manager.h"
+
+#include <mutex>
+
+#include "common/logger.h"
+
+namespace DeviceAPI {
+namespace Archive {
+
+ArchiveManager::ArchiveManager():
+ m_next_unique_id(0)
+{
+ LOGD("Initialize ArchiveManager");
+}
+
+ArchiveManager::~ArchiveManager()
+{
+ LOGD("Deinitialize ArchiveManager");
+}
+
+ArchiveManager& ArchiveManager::getInstance()
+{
+ LOGD("Entered");
+ static ArchiveManager instance;
+ return instance;
+}
+
+void ArchiveManager::abort(long operation_id)
+{
+ LOGD("Entered");
+
+ ArchiveFileMap::iterator it = m_archive_file_map.find(operation_id);
+ if (it != m_archive_file_map.end()) {
+ ArchiveFilePtr archive_file_ptr = it->second;
+ std::lock_guard<std::mutex> lock(archive_file_ptr->m_mutex);
+
+ std::size_t size = archive_file_ptr->m_task_queue.size();
+ for(int i = 0; i < size; ++i){
+ if(operation_id == archive_file_ptr->m_task_queue[i].first){
+ archive_file_ptr->m_task_queue[i].second->setIsCanceled(true);
+ return;
+ }
+ }
+ }
+ LOGD("The Operation Identifier not found");
+}
+
+long ArchiveManager::open(OpenCallbackData* callback)
+{
+ LOGD("Entered");
+
+ ArchiveFilePtr a_ptr = callback->getArchiveFile();
+ return a_ptr->addOperation(callback);
+}
+
+long ArchiveManager::getNextOperationId(ArchiveFilePtr archive_file_ptr)
+{
+ LOGD("Entered");
+ long op_id = ++m_next_unique_id;
+ m_archive_file_map.insert(ArchiveFilePair(op_id, archive_file_ptr));
+ return op_id;
+}
+
+void ArchiveManager::eraseElementFromArchiveFileMap(long operation_id)
+{
+ LOGD("Entered");
+ ArchiveFileMap::iterator it = m_archive_file_map.find(operation_id);
+ if (it != m_archive_file_map.end()) {
+ m_archive_file_map.erase(it);
+ }
+}
+
+} // Archive
+} // DeviceAPI
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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 _TIZEN_ARCHIVE_ARCHIVE_MANAGER_H_
+#define _TIZEN_ARCHIVE_ARCHIVE_MANAGER_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "archive_file.h"
+#include "archive_callback_data.h"
+
+namespace DeviceAPI {
+namespace Archive {
+
+typedef std::map<long, ArchiveFilePtr> ArchiveFileMap;
+typedef std::pair<long, ArchiveFilePtr> ArchiveFilePair;
+
+class ArchiveManager {
+public:
+ static ArchiveManager& getInstance();
+ ~ArchiveManager();
+
+ void abort(long operation_id);
+ long getNextOperationId(ArchiveFilePtr archive_file_ptr);
+ void eraseElementFromArchiveFileMap(long operation_id);
+ long open(OpenCallbackData* callback);
+
+private:
+ ArchiveManager();
+ ArchiveManager(ArchiveManager const&);
+ void operator=(ArchiveManager const&);
+
+ ArchiveFileMap m_archive_file_map;
+
+ long m_next_unique_id;
+
+};
+
+} // Archive
+} // DeviceAPI
+
+#endif /* _TIZEN_ARCHIVE_ARCHIVE_MANAGER_H_ */
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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 "archive_utils.h"
+
+#include <sstream>
+#include <iomanip>
+
+#include "common/logger.h"
+
+//TODO:
+//#include <FilesystemExternalUtils.h>
+
+using namespace common;
+
+namespace DeviceAPI {
+namespace Archive {
+
+using namespace DeviceAPI::Filesystem;
+
+std::string bytesToReadableString(const size_t num_bytes)
+{
+ std::stringstream ss;
+ static const size_t one_mb = 1024 * 1024;
+ static const size_t one_kb = 1024;
+ ss << std::setprecision(2) << std::fixed;
+
+ if(num_bytes >= one_mb) {
+ ss << (float)num_bytes / one_mb << " MB";
+ } else if(num_bytes >= one_kb) {
+ ss << (float)num_bytes / one_kb << " KB";
+ } else {
+ ss << num_bytes << " B";
+ }
+
+ return ss.str();
+}
+
+std::string fileModeToString(FileMode fm)
+{
+ switch(fm) {
+ case FileMode::READ:
+ return "r";
+ case FileMode::WRITE:
+ return "w";
+ case FileMode::READ_WRITE:
+ return "rw";
+ case FileMode::ADD:
+ return "a";
+ default:
+ throw UnknownException("Unknown file mode");
+ }
+}
+
+FileMode stringToFileMode(std::string fmString)
+{
+ if (!fmString.compare("r")) {
+ return FileMode::READ;
+ }
+ else if (!fmString.compare("w")) {
+ return FileMode::WRITE;
+ }
+ else if(!fmString.compare("rw")) {
+ return FileMode::READ_WRITE;
+ }
+ else if(!fmString.compare("a")) {
+ return FileMode::ADD;
+ }
+ // In widl it's "TypeMismatchError" so this exception used
+ // instead of InvalidValues
+ throw TypeMismatchException("Invalid FileMode");
+}
+
+// FilePtr fileReferenceToFile(JSContextRef context, JSValueRef fileReference)
+// {
+// auto g_ctx = GlobalContextManager::getInstance()->getGlobalContext(context);
+//
+// FilePtr file_ptr;
+// try {
+// file_ptr = JSFile::getPrivateObject(context, fileReference);
+// } catch (const TypeMismatchException &tme) {
+// LOGD("Use virtual path.");
+// std::string virtual_path =
+// JSUtil::JSValueToString(context, fileReference);
+// if (!External::isVirtualPath(virtual_path)) {
+// LOGE("FileReference can be File object or a virtual path");
+// throw TypeMismatchException(
+// "FileReference can be File object or a virtual path");
+// }
+// std::string string_path =
+// External::fromVirtualPath(virtual_path, g_ctx);
+// LOGD("Path: %s", string_path.c_str());
+//
+// PathPtr path = Path::create(string_path);
+// NodePtr node_ptr = Node::resolve(path);
+// file_ptr = FilePtr(new File(node_ptr, File::PermissionList()));
+// }
+//
+// return file_ptr;
+// }
+
+void getBasePathAndName(const std::string& filepath,
+ std::string& out_basepath,
+ std::string& out_name)
+{
+ const size_t filepath_len = filepath.length();
+
+ size_t name_end_index = filepath_len;
+ size_t name_start_index = 0;
+
+ for(int i = filepath_len - 1; i >= 0; --i) {
+ const char& cur = filepath[i];
+ if(cur == '/' || cur == '\\') {
+ if( (filepath_len-1) == i ) {
+ name_end_index = i;
+ } else {
+ name_start_index = i+1;
+ out_name = filepath.substr(name_start_index,
+ name_end_index - name_start_index);
+
+ out_basepath = filepath.substr(0, name_start_index);
+ return;
+ }
+ }
+ }
+
+ // \ / is not found
+ out_basepath = "";
+ out_name = filepath.substr(0, name_end_index);
+}
+
+std::string removeDuplicatedSlashesFromPath(const std::string& path)
+{
+ const size_t path_len = path.length();
+
+ std::string out;
+ out.reserve(path_len);
+
+ bool prev_is_dir = false;
+ for(size_t i = 0; i < path_len; ++i) {
+ const char& cur = path[i];
+ if(cur == '/' || cur == '\\') {
+ if(!prev_is_dir) {
+ out += cur;
+ }
+ prev_is_dir = true;
+ } else {
+ prev_is_dir = false;
+ out += cur;
+ }
+ }
+
+ return out;
+}
+
+bool isDirectoryPath(const std::string& path)
+{
+ if(path.empty()) {
+ return false;
+ }
+
+ const char last_char = path[path.length() - 1];
+ return last_char == '\\' || last_char == '/';
+}
+
+std::string removeTrailingDirectorySlashFromPath(const std::string& path)
+{
+ if(!isDirectoryPath(path)) {
+ return path;
+ }
+
+ return path.substr(0, path.length() - 1);
+}
+
+std::string stripBasePathFromPath(const std::string& fullpath)
+{
+ const size_t location = fullpath.find_last_of("/\\");
+ if(std::string::npos == location) {
+ return fullpath;
+ }
+
+ return fullpath.substr(location + 1);
+}
+
+namespace{
+static std::string errErrno = "ERRNO";
+static std::string errEndOfListOfFile = "End list of file";
+static std::string errParamater = "Invalid parameter";
+static std::string errBadFile = "Incorrect file";
+static std::string errInternal = "Internal error";
+static std::string errCRC = "CRC error";
+static std::string errUnknown = "Unknown error";
+
+const std::string& getArchiveErrorMessage(int errorCode)
+{
+ /**
+ * All errors are defined in minizip library in files:
+ * zip.h and unzip.h
+ */
+ switch (errorCode) {
+ // ZIP_ERRNO & UNZ_ERRNO both value Z_ERRNO
+ case ZIP_ERRNO:
+ return errErrno;
+ // UNZ_END_OF_LIST_OF_FILE both value -100
+ case UNZ_END_OF_LIST_OF_FILE:
+ return errEndOfListOfFile;
+ // ZIP_PARAMERROR & UNZ_PARAMERROR both value -102
+ case ZIP_PARAMERROR:
+ return errParamater;
+ // ZIP_BADZIPFILE & UNZ_BADZIPFILE both value -103
+ case ZIP_BADZIPFILE:
+ return errBadFile;
+ // ZIP_INTERNALERROR & UNZ_INTERNALERROR bot value -104
+ case ZIP_INTERNALERROR:
+ return errInternal;
+ // UNZ_CRCERROR -105
+ case UNZ_CRCERROR:
+ return errCRC;
+ default:
+ return errUnknown;
+ }
+}
+}
+
+std::string getBasePathFromPath(const std::string& fullpath)
+{
+ const std::string tmp_path = removeTrailingDirectorySlashFromPath(fullpath);
+ const size_t location = tmp_path.find_last_of("/\\");
+ if(std::string::npos == location) {
+ return std::string();
+ }
+
+ return tmp_path.substr(0, location + 1);
+}
+
+std::string getArchiveLogMessage(const int errorCode, const std::string &hint)
+{
+ std::stringstream ss;
+ ss << "Failed " << hint << " : " << getArchiveErrorMessage(errorCode) << ", " << errorCode;
+ return std::string(ss.str());
+}
+
+} //namespace Archive
+} //namespace DeviceAPI
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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 __TIZEN_ARCHIVE_ARCHIVE_UTILS_H__
+#define __TIZEN_ARCHIVE_ARCHIVE_UTILS_H__
+
+#include <string>
+
+#include "common/platform_exception.h"
+
+#include "filesystem_file.h"
+#include "archive_file.h"
+
+namespace DeviceAPI {
+namespace Archive {
+
+std::string bytesToReadableString(const size_t num_bytes);
+std::string fileModeToString(FileMode fm);
+FileMode stringToFileMode(std::string fmString);
+
+//extern Filesystem::FilePtr fileReferenceToFile(
+// JSContextRef context, JSValueRef fileReference);
+
+/**
+ * Gets base path and name from full path string, example cases:
+ * full path | base path | name
+ * ----------------------+-------------------+------------------
+ * "" | "" | ""
+ * "/opt/usr/media/TEST" | "/opt/usr/media/" | "TEST"
+ * "/opt/usr/media/TEST/"| "/opt/usr/media/" | "TEST"
+ * "opt/usr/media/TEST" | "opt/usr/media/" | "TEST"
+ * "opt/usr/media/TEST/" | "opt/usr/media/" | "TEST"
+ * "TEST" | "" | "TEST"
+ * "TEST/" | "" | "TEST"
+ * "/TEST/" | "/" | "TEST"
+ */
+void getBasePathAndName(const std::string& filepath,
+ std::string& out_basepath,
+ std::string& out_name);
+
+/**
+ * If path contains duplicated slashes they will be removed
+ *
+ * Note this function does not fix slash style '/', '\'
+ * (Linux/Windows)
+ *
+ * Example path: | Result:
+ * ---------------------------+------------------------------
+ * "my/a//b/c/d/e" | "my/a/b/c/d/e"
+ * "add\ff\\\g" | "add\f\g"
+ * "first//second\\a\/" | "first/second\a" (mixed / with \)
+ */
+std::string removeDuplicatedSlashesFromPath(const std::string& path);
+
+/**
+ * Return true if last character of string is '/' or '\'
+ */
+bool isDirectoryPath(const std::string& path);
+
+/**
+ * If path contains trailing '/' or '\' it will be removed.
+ *
+ * Example path: | Result:
+ * ---------------------------+------------------------------
+ * "documents/someName/" | "documents/someName"
+ * "documents/yetAnotherName" | "documents/yetAnotherName"
+ */
+std::string removeTrailingDirectorySlashFromPath(const std::string& path);
+
+/**
+ * Returns FILE name without leading base path:
+ *
+ * Example path: | Result:
+ * ---------------------------+------------------------------
+ * "documents/ABC/a.txt" | "a.txt"
+ * "documents/A/X/Y/Z/my.log" | "my.log"
+ *
+ * "documents/A/B/C/" | "" (fullpath is directory)
+ * "a.txt" | "a.txt"
+ * "A/" | "" (fullpath is directory)
+ */
+std::string stripBasePathFromPath(const std::string& fullpath);
+
+/**
+ * Returns path without last directory or file part
+ *
+ * Example path: | Result: | Extracted ending:
+ * ---------------------------+-----------------------+--------------
+ * "documents/ABC/a.txt" | "documents/ABC/" | "a.txt"
+ * "documents/A/X/Y/Z/my.log" | "documents/A/X/Y/Z/" | "my.log"
+ *
+ * "documents/A/B/C/" | "documents/A/B/" | "C/"
+ * "a.txt" | "" | "a.txt"
+ * "A/" | "" | "A/"
+ */
+std::string getBasePathFromPath(const std::string& fullpath);
+
+std::string getArchiveLogMessage(const int errorCode, const std::string &hint);
+
+template <class T = common::UnknownException>
+void throwArchiveException(const int errorCode, const std::string &hint)
+{
+ std::string log = getArchiveLogMessage(errorCode, hint);
+ LOGE("%s", log.c_str());
+ throw T(log.c_str());
+}
+
+} //namespace Archive
+} //namespace DeviceAPI
+
+#endif // __TIZEN_ARCHIVE_ARCHIVE_UTILS_H__
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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 _ARCHIVE_PLUGIN_DEFS_H_
+#define _ARCHIVE_PLUGIN_DEFS_H_
+
+#define TIZEN_ARCHIVE_ARCHIVE_CLASS "archive"
+
+#define ARCHIVE_FUNCTION_API_ARCHIVE_MANAGER_ABORT "abort"
+#define ARCHIVE_FUNCTION_API_ARCHIVE_MANAGER_OPEN "open"
+
+#define ARCHIVE_FUNCTION_API_ARCHIVE_FILE_ADD "add"
+#define ARCHIVE_FUNCTION_API_ARCHIVE_FILE_EXTRACT_ALL "extractAll"
+#define ARCHIVE_FUNCTION_API_ARCHIVE_FILE_GET_ENTRIES "getEntries"
+#define ARCHIVE_FUNCTION_API_ARCHIVE_FILE_GET_ENTRY_BY_NAME "getEntryByName"
+#define ARCHIVE_FUNCTION_API_ARCHIVE_FILE_CLOSE "close"
+
+#define ARCHIVE_FUNCTION_API_ARCHIVE_FILE_ENTRY_EXTRACT "extract"
+
+
+
+#endif // _ARCHIVE_PLUGIN_DEFS_H_
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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 "common/logger.h"
+#include "common/platform_exception.h"
+
+using namespace common;
+
+namespace DeviceAPI {
+namespace Filesystem {
+
+} // Filesystem
+} // DeviceAPI
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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 _TIZEN_FILESYSTEM_FILE_H_
+#define _TIZEN_FILESYSTEM_FILE_H_
+
+#include <string>
+#include <memory>
+#include <vector>
+
+#include "common/logger.h"
+
+namespace DeviceAPI {
+namespace Filesystem {
+
+enum NodeType
+{
+ NT_DIRECTORY,
+ NT_FILE
+};
+
+class File;
+typedef std::shared_ptr<File> FilePtr;
+typedef std::shared_ptr<File> NodePtr; //STUB bad trick
+typedef std::vector<NodePtr> NodeList; //STUB bad trick
+
+class File : public std::enable_shared_from_this<File>
+{
+public:
+ File()
+ {
+ }
+
+ File(const std::string& fname) :
+ m_full_path(fname)
+ {
+ }
+
+ FilePtr getNode()
+ {
+ LOGW("STUB");
+ return shared_from_this();
+ }
+
+ size_t getSize()
+ {
+ LOGW("STUB");
+ return 0;
+ }
+
+ FilePtr getPath()
+ {
+ LOGW("STUB");
+ return shared_from_this();
+ }
+
+ //! \brief Gets type of current node.
+ //! @return Node's type.
+ NodeType getType() const
+ {
+ LOGW("STUB");
+ return NT_FILE;
+ }
+
+ const std::string& getFullPath() const
+ {
+ return m_full_path;
+ }
+
+ std::string m_full_path;
+};
+
+class Path;
+typedef std::shared_ptr<Path> PathPtr;
+
+class Path : public std::enable_shared_from_this<Path>
+{
+public:
+ typedef char SeparatorType;
+ static Path::SeparatorType getSeparator()
+ {
+ LOGW("STUB");
+ return '/';
+ }
+};
+
+class External {
+public:
+ static std::string toVirtualPath(const std::string& path)
+ {
+ LOGW("STUB Not implemented path -> virtual path. Return not changed path");
+ return path;
+ }
+
+ static void removeDirectoryRecursive(const std::string& fullpath)
+ {
+ LOGW("STUB Not implemented. Directory: [%s] will not be removed!", fullpath.c_str());
+ }
+};
+
+
+} // Filesystem
+} // DeviceAPI
+
+#endif /* _TIZEN_FILESYSTEM_FILE_H_ */
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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 "un_zip.h"
+
+#include <cstdio>
+#include <errno.h>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "common/logger.h"
+#include "common/platform_exception.h"
+#include "filesystem_file.h"
+
+#include "archive_file.h"
+#include "archive_utils.h"
+#include "un_zip_extract_request.h"
+
+using namespace common;
+
+namespace DeviceAPI {
+namespace Archive {
+
+UnZip::UnZip(const std::string& filename) :
+ m_zipfile_name(filename),
+ m_unzip(NULL),
+ m_default_buffer_size(1024 * 1024)
+{
+ LOGD("Entered");
+
+ m_unzip = unzOpen(filename.c_str());
+ if(!m_unzip) {
+ LOGE("unzOpen returned NULL : It means the file is invalid.");
+ throw InvalidValuesException("Failed to open zip file");
+ }
+ m_is_open = true;
+}
+
+UnZip::~UnZip()
+{
+ close();
+}
+
+void UnZip::close()
+{
+ LOGD("Entered");
+ if(!m_is_open) {
+ LOGD("Unzip already closed - exiting");
+ return;
+ }
+
+ int errclose = unzClose(m_unzip);
+ m_unzip = NULL;
+
+ if (errclose != UNZ_OK) {
+ LOGE("ret: %d",errclose);
+ throwArchiveException(errclose, "unzClose()");
+ }
+ m_is_open = false;
+}
+
+UnZipPtr UnZip::open(const std::string& filename)
+{
+ LOGD("Entered");
+ return UnZipPtr(new UnZip(filename));
+}
+
+ArchiveFileEntryPtrMapPtr UnZip::listEntries(unsigned long *decompressedSize)
+{
+ if(!m_is_open) {
+ LOGE("Failed to get list of entries - UnZip closed");
+ throw UnknownException("Failed to get list of files in zip archive");
+ }
+ unz_global_info gi;
+ int err = unzGetGlobalInfo (m_unzip, &gi);
+ if (UNZ_OK != err) {
+ LOGE("ret: %d",err);
+ throwArchiveException(err, "unzGetGlobalInfo()");
+ }
+
+ char filename_inzip[512];
+ unz_file_info file_info;
+
+ ArchiveFileEntryPtrMapPtr map = ArchiveFileEntryPtrMapPtr(
+ new ArchiveFileEntryPtrMap());
+
+ unsigned long totalDecompressed = 0;
+
+ err = unzGoToFirstFile(m_unzip);
+ if (err != UNZ_OK) {
+ LOGW("%s",getArchiveLogMessage(err, "unzGoToFirstFile()").c_str());
+ }
+
+ for (uLong i = 0; i < gi.number_entry; i++) {
+
+ err = unzGetCurrentFileInfo(m_unzip, &file_info,
+ filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0);
+ if (err != UNZ_OK) {
+ LOGE("ret: %d",err);
+ throwArchiveException(err, "unzGetCurrentFileInfo()");
+ }
+
+ LOGD("file: %s | unc size: %d | comp size: %d", filename_inzip,
+ file_info.uncompressed_size, file_info.compressed_size);
+
+ ArchiveFileEntryPtr entry = ArchiveFileEntryPtr(new ArchiveFileEntry());
+ entry->setName(filename_inzip);
+ entry->setSize(file_info.uncompressed_size);
+ entry->setCompressedSize(file_info.compressed_size);
+
+ totalDecompressed += file_info.uncompressed_size;
+
+ tm date;// = file_info.tmu_date;
+ date.tm_sec = file_info.tmu_date.tm_sec;
+ date.tm_min = file_info.tmu_date.tm_min;
+ date.tm_hour = file_info.tmu_date.tm_hour;
+ date.tm_mday = file_info.tmu_date.tm_mday;
+ date.tm_mon = file_info.tmu_date.tm_mon;
+ date.tm_year = file_info.tmu_date.tm_year - 1900;
+ date.tm_wday = 0;
+ date.tm_yday = 0;
+ date.tm_isdst = 0;
+ LOGD("%d, %d, %d, %d, %d, %d", date.tm_hour, date.tm_min, date.tm_sec, date.tm_mday, date.tm_mon, date.tm_year);
+ entry->setModified(mktime(&date));
+
+ map->insert(std::make_pair(filename_inzip, entry));
+
+ if ( (i+1) < gi.number_entry) {
+
+ err = unzGoToNextFile(m_unzip);
+ if (UNZ_OK != err) {
+ LOGE("ret: %d",err);
+ throwArchiveException(err, "unzGoToNextFile()");
+ }
+ }
+ }
+
+ (*decompressedSize) = totalDecompressed;
+
+ return map;
+}
+
+void UnZip::extractAllFilesTo(const std::string& extract_path,
+ ExtractAllProgressCallback* callback)
+{
+ if(!m_is_open) {
+ LOGE("Failed to extract files - UnZip closed");
+ throw UnknownException("Failed to extract zip archive");
+ }
+
+ //
+ // Calculate number of entries to extract and total number of bytes
+ //
+ unz_global_info gi;
+ updateCallbackWithArchiveStatistics(callback, gi);
+
+ //
+ // Begin extracting entries
+ //
+ int err = unzGoToFirstFile(m_unzip);
+ if (err != UNZ_OK) {
+ LOGW("%s",getArchiveLogMessage(err, "unzGoToFirstFile()").c_str());
+ }
+
+ for (uLong i = 0; i < gi.number_entry; i++) {
+
+ if (callback->isCanceled()) {
+ LOGD("Operation cancelled");
+ throw OperationCanceledException();
+ }
+
+ extractCurrentFile(extract_path, std::string(), callback);
+
+ if ((i + 1) < gi.number_entry) {
+ err = unzGoToNextFile(m_unzip);
+ if (UNZ_OK != err) {
+ LOGE("ret: %d",err);
+ throwArchiveException(err, "unzGoToNextFile()");
+ }
+ }
+ }
+
+ callback->callSuccessCallbackOnMainThread();
+ callback = NULL;
+}
+
+struct ExtractDataHolder
+{
+ UnZip* unzip;
+ ExtractEntryProgressCallback* callback;
+ std::string root_output_path;
+};
+
+void UnZip::extractTo(ExtractEntryProgressCallback* callback)
+{
+ if(!m_is_open) {
+ LOGE("Extract archive file entry failed - UnZip closed");
+ throw UnknownException("Extract archive file entry failed");
+ }
+
+ if(!callback) {
+ LOGE("callback is NULL");
+ throw UnknownException("Extract archive file entry failed");
+ }
+
+ if(!callback->getArchiveFileEntry()) {
+ LOGE("callback->getArchiveFileEntry() is NULL");
+ throw UnknownException("Extract archive file entry failed");
+ }
+
+ Filesystem::FilePtr out_dir = callback->getDirectory();
+ if(!out_dir) {
+ LOGE("Output directory is not valid");
+ throw InvalidValuesException("Output directory is not correct");
+ }
+
+// Filesystem::NodePtr out_node = out_dir->getNode();
+// if(!out_node) {
+// LOGE("Output directory is not valid");
+// throw InvalidValuesException("Output directory is not correct");
+// }
+//
+// Filesystem::PathPtr out_path = out_node->getPath();
+// if(!out_path) {
+// LOGE("Output directory is not valid");
+// throw InvalidValuesException("Output directory is not correct");
+// }
+
+ auto entry_name_in_zip = callback->getArchiveFileEntry()->getName();
+ auto root_output_path = out_dir->getFullPath();
+ LOGD("Extract: [%s] to root output directory: [%s] (stripBasePath: [%s])",
+ entry_name_in_zip.c_str(),
+ root_output_path.c_str(),
+ callback->getStripBasePath().c_str());
+
+
+ //
+ // Calculate number of entries to extract and total number of bytes
+ //
+ unz_global_info gi;
+ updateCallbackWithArchiveStatistics(callback, gi, entry_name_in_zip);
+
+ //
+ // Begin extracting entries
+ //
+
+ ExtractDataHolder h;
+ h.unzip = this;
+ h.callback = callback;
+ h.root_output_path = root_output_path;
+
+ // this loop call internally progress callbacks
+ IterateFilesInZip(gi, entry_name_in_zip, callback, extractItFunction, &h);
+
+ // after finish extracting success callback will be called
+ callback->callSuccessCallbackOnMainThread();
+ callback = NULL;
+}
+
+void UnZip::extractItFunction(const std::string& file_name, unz_file_info& file_info,
+ void* user_data)
+{
+ ExtractDataHolder* h = static_cast<ExtractDataHolder*>(user_data);
+ if(!h) {
+ LOGE("ExtractDataHolder is NULL!");
+ throw UnknownException("Could not list content of zip archive");
+ }
+
+ h->unzip->extractCurrentFile(h->root_output_path,
+ h->callback->getStripBasePath(),
+ h->callback);
+}
+
+unsigned int UnZip::IterateFilesInZip(unz_global_info& gi,
+ const std::string& entry_name_in_zip,
+ OperationCallbackData* callback,
+ UnZip::IterateFunction itfunc,
+ void* user_data)
+{
+ int err = unzGoToFirstFile(m_unzip);
+ if (UNZ_OK != err) {
+ LOGW("%s",getArchiveLogMessage(err, "unzGoToFirstFile()").c_str());
+ }
+
+ unsigned int num_file_or_folder_matched = 0;
+ const bool is_directory = isDirectoryPath(entry_name_in_zip);
+
+ unz_file_info cur_file_info;
+ char tmp_fname[512];
+
+ for (uLong i = 0; i < gi.number_entry; i++) {
+
+ if (callback->isCanceled()) {
+ LOGD("Operation cancelled");
+ throw OperationCanceledException();
+ }
+
+ err = unzGetCurrentFileInfo(m_unzip, &cur_file_info,
+ tmp_fname, sizeof(tmp_fname), NULL, 0, NULL, 0);
+ if (UNZ_OK != err) {
+ LOGE("ret: %d",err);
+ throwArchiveException(err, "unzGetCurrentFileInfo()");
+ }
+
+ const std::string cur_filename_in_zip(tmp_fname);
+ bool match = true;
+
+ if(!entry_name_in_zip.empty()) {
+ if(is_directory) {
+ //If entry_name_in_zip is pointing at directory we need to check each entry in
+ //zip if its path starts with entry_name_in_zip
+ match = (0 == cur_filename_in_zip.find(entry_name_in_zip));
+ } else {
+ //If entry name points to file we only extract entry with matching name
+ match = (cur_filename_in_zip == entry_name_in_zip);
+ }
+ }
+
+ if(match) {
+ itfunc(cur_filename_in_zip, cur_file_info, user_data);
+ ++num_file_or_folder_matched;
+ }
+
+ if ((i + 1) < gi.number_entry) {
+ err = unzGoToNextFile(m_unzip);
+ if (UNZ_OK != err) {
+ LOGE("ret: %d",err);
+ throwArchiveException(err, "unzGoToNextFile()");
+ }
+ }
+ }
+
+ return num_file_or_folder_matched;
+}
+
+void UnZip::extractCurrentFile(const std::string& extract_path,
+ const std::string& base_strip_path,
+ BaseProgressCallback* callback)
+{
+ LOGD("Entered");
+
+ if (callback->isCanceled()) {
+ LOGD("Operation cancelled");
+ throw OperationCanceledException();
+ }
+
+ LOGD("extract_path: [%s] base_strip_path: [%s] ", extract_path.c_str(),
+ base_strip_path.c_str());
+ UnZipExtractRequest::execute(*this, extract_path, base_strip_path, callback);
+}
+
+struct ArchiveStatistics
+{
+ ArchiveStatistics() : uncompressed_size(0),
+ number_of_files(0),
+ number_of_folders(0) {}
+
+ unsigned long uncompressed_size;
+ unsigned long number_of_files;
+ unsigned long number_of_folders;
+};
+
+void generateArchiveStatistics(const std::string& file_name, unz_file_info& file_info,
+ void* user_data)
+{
+ if(user_data) {
+ ArchiveStatistics* astats = static_cast<ArchiveStatistics*>(user_data);
+ astats->uncompressed_size += file_info.uncompressed_size;
+
+ if(isDirectoryPath(file_name)) {
+ astats->number_of_folders += 1;
+ }
+ else {
+ astats->number_of_files += 1;
+ }
+ }
+}
+
+void UnZip::updateCallbackWithArchiveStatistics(ExtractAllProgressCallback* callback,
+ unz_global_info& out_global_info,
+ const std::string optional_filter)
+{
+ int err = unzGetGlobalInfo(m_unzip, &out_global_info);
+ if (UNZ_OK != err) {
+ LOGE("ret: %d",err);
+ throwArchiveException(err, "unzGetGlobalInfo()");
+ }
+
+ ArchiveStatistics astats;
+ const auto num_matched = IterateFilesInZip(out_global_info, optional_filter,
+ callback, generateArchiveStatistics, &astats);
+ if(0 == num_matched) {
+ LOGE("No matching file/directory: [%s] has been found in zip archive",
+ optional_filter.c_str());
+ LOGE("Throwing NotFoundException - Could not extract file from archive");
+ throw NotFoundException("Could not extract file from archive");
+ }
+
+ callback->setExpectedDecompressedSize(astats.uncompressed_size);
+ LOGD("Expected uncompressed size: %s",
+ bytesToReadableString(astats.uncompressed_size).c_str());
+
+ callback->setNumberOfFilesToExtract(astats.number_of_files);
+ LOGD("Number entries to extract: files: %d folders: %d", astats.number_of_files,
+ astats.number_of_folders);
+}
+
+} //namespace Archive
+} //namespace DeviceAPI
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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 __TIZEN_ARCHIVE_UNZIP_H__
+#define __TIZEN_ARCHIVE_UNZIP_H__
+
+#include <memory>
+#include <string>
+#include <queue>
+
+#include <unzip.h>
+
+#include "archive_callback_data.h"
+#include "archive_file_entry.h"
+
+namespace DeviceAPI {
+namespace Archive {
+
+class UnZipExtractRequest;
+
+typedef std::shared_ptr<std::vector<char>> CharVectorPtr;
+
+class UnZip;
+typedef std::shared_ptr<UnZip> UnZipPtr;
+
+class UnZip
+{
+public:
+ static UnZipPtr open(const std::string& filename);
+ ~UnZip();
+
+ ArchiveFileEntryPtrMapPtr listEntries(unsigned long *decompressedSize);
+
+ /**
+ * \brief Extract all files to output directory
+ * \param callback which keep pointer to ArchiveFile.
+ */
+ void extractAllFilesTo(const std::string& extract_path,
+ ExtractAllProgressCallback* callback);
+
+ void extractTo(ExtractEntryProgressCallback* callback);
+
+ void close();
+
+private:
+ UnZip(const std::string& filename);
+
+ /**
+ * \brief Extract current file (iterated with minizip library)
+ * \param callback which keep pointer to ArchiveFile.
+ */
+ void extractCurrentFile(const std::string& extract_path,
+ const std::string& base_strip_path,
+ BaseProgressCallback* callback);
+
+ static void extractItFunction(const std::string& file_name,
+ unz_file_info& file_info,
+ void* user_data);
+
+ typedef void (*IterateFunction) (const std::string& file_name,
+ unz_file_info& file_info,
+ void* user_data);
+
+ unsigned int IterateFilesInZip(unz_global_info& gi,
+ const std::string& entry_name_in_zip,
+ OperationCallbackData* callback,
+ IterateFunction itfunc,
+ void* user_data);
+
+ void updateCallbackWithArchiveStatistics(ExtractAllProgressCallback* callback,
+ unz_global_info& out_global_info,
+ const std::string optional_filter = std::string());
+
+ std::string m_zipfile_name;
+ unzFile m_unzip;
+ size_t m_default_buffer_size;
+ bool m_is_open;
+
+ friend class UnZipExtractRequest;
+};
+
+} //namespace Archive
+} //namespace DeviceAPI
+
+#endif // __TIZEN_ARCHIVE_ZIP_H__
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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 "un_zip_extract_request.h"
+
+#include <cstdio>
+#include <errno.h>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <string.h>
+#include <sys/stat.h>
+#include <utime.h>
+
+#include "common/logger.h"
+#include "common/platform_exception.h"
+#include "filesystem_file.h"
+
+#include "archive_file.h"
+#include "archive_utils.h"
+#include "un_zip.h"
+
+using namespace common;
+
+namespace DeviceAPI {
+namespace Archive {
+
+FilePathStatus getPathStatus(const std::string& path)
+{
+ if(path.empty()) {
+ return FPS_NOT_EXIST;
+ }
+
+ std::string npath = removeTrailingDirectorySlashFromPath(path);
+
+ struct stat sb;
+ if (stat(npath.c_str(), &sb) == -1) {
+ return FPS_NOT_EXIST;
+ }
+ if(sb.st_mode & S_IFDIR) {
+ return FPS_DIRECTORY;
+ } else {
+ return FPS_FILE;
+ }
+}
+
+void divideToPathAndName(const std::string& filepath, std::string& out_path,
+ std::string& out_name)
+{
+ size_t pos_last_dir = filepath.find_last_of("/\\");
+ if(pos_last_dir == std::string::npos) {
+ out_path = "";
+ out_name = filepath;
+ } else {
+ out_path = filepath.substr(0, pos_last_dir+1);
+ out_name = filepath.substr(pos_last_dir+1);
+ }
+}
+
+void createMissingDirectories(const std::string& path, bool check_first = true)
+{
+ if(check_first) {
+ const FilePathStatus path_status = getPathStatus(path);
+ //LOGD("[%s] status: %d", path.c_str(), path_status);
+ if(FPS_DIRECTORY == path_status) {
+ return;
+ }
+ }
+
+ const size_t extract_path_len = path.length();
+ for(size_t i = 0; i < extract_path_len; ++i) {
+ const char& cur = path[i];
+ if( (('\\' == cur || '/' == cur) && i > 0) || //handle left side from current /
+ (extract_path_len-1 == i) ) { //handle last subdirectory path
+
+ const std::string left_part = path.substr(0,i+1);
+ const FilePathStatus status = getPathStatus(left_part);
+ //LOGD("left_part: [%s] status:%d", left_part.c_str(), status);
+
+ if(FPS_DIRECTORY != status) {
+ //TODO investigate 0775 (mode) - Filesystem assumed that file should have parent mode
+ if(mkdir(left_part.c_str(), 0775) == -1) {
+ LOGE("Couldn't create new directory: %s errno:%s",
+ left_part.c_str(), strerror(errno));
+ //TODO check why mkdir return -1 but directory is successfully created
+ // throw UnknownException(
+ // "Could not create new directory");
+ }
+ }
+ }
+ }
+}
+
+void changeFileAccessAndModifyDate(const std::string& filepath, tm_unz tmu_date)
+{
+ struct utimbuf ut;
+ struct tm newdate;
+ newdate.tm_sec = tmu_date.tm_sec;
+ newdate.tm_min = tmu_date.tm_min;
+ newdate.tm_hour = tmu_date.tm_hour;
+ newdate.tm_mday = tmu_date.tm_mday;
+ newdate.tm_mon = tmu_date.tm_mon;
+
+ if (tmu_date.tm_year > 1900) {
+ newdate.tm_year = tmu_date.tm_year - 1900;
+ } else {
+ newdate.tm_year = tmu_date.tm_year ;
+ }
+ newdate.tm_isdst = -1;
+
+ ut.actime = ut.modtime = mktime(&newdate);
+ if(utime(filepath.c_str(), &ut) == -1) {
+ LOGE("Couldn't set time for: [%s] errno:%s", filepath.c_str(), strerror(errno));
+ }
+}
+
+void UnZipExtractRequest::execute(UnZip& owner, const std::string& extract_path,
+ const std::string& base_strip_path,
+ BaseProgressCallback* callback)
+{
+ UnZipExtractRequest req(owner, extract_path, base_strip_path, callback);
+ req.run();
+}
+
+UnZipExtractRequest::UnZipExtractRequest(UnZip& owner,
+ const std::string& extract_path,
+ const std::string& base_strip_path,
+ BaseProgressCallback* callback) :
+
+ m_owner(owner),
+ m_extract_path(extract_path),
+ m_base_strip_path(base_strip_path),
+ m_callback(callback),
+
+ m_output_file(NULL),
+ m_buffer(NULL),
+ m_delete_output_file(false),
+ m_close_unz_current_file(false),
+ m_new_dir_status(FPS_NOT_EXIST),
+
+ m_is_directory_entry(false)
+{
+ if(!m_callback){
+ LOGE("Callback is null");
+ throw UnknownException("Problem with callback functionality");
+ }
+}
+
+void UnZipExtractRequest::run()
+{
+ LOGD("Entered");
+
+ getCurrentFileInfo();
+
+ if(m_is_directory_entry) {
+ handleDirectoryEntry();
+ } else {
+ handleFileEntry();
+ }
+}
+
+UnZipExtractRequest::~UnZipExtractRequest()
+{
+ if(m_output_file) {
+ fclose(m_output_file);
+ m_output_file = NULL;
+ }
+
+ if(m_delete_output_file && !m_is_directory_entry) {
+ if(std::remove(m_output_filepath.c_str()) != 0) {
+ LOGE("Couldn't remove partial file! "
+ "std::remove(\"%s\") failed with errno:%s",
+ m_output_filepath.c_str(), strerror(errno));
+ }
+ }
+
+ delete [] m_buffer;
+ m_buffer = NULL;
+
+ if(m_close_unz_current_file) {
+ int err = unzCloseCurrentFile (m_owner.m_unzip);
+ if(UNZ_OK != err) {
+ LOGW("%s",getArchiveLogMessage(err, "unzCloseCurrentFile()").c_str());
+ }
+ }
+}
+
+void UnZipExtractRequest::getCurrentFileInfo()
+{
+ LOGD("Entered");
+ int err = unzGetCurrentFileInfo(m_owner.m_unzip, &m_file_info,
+ m_filename_inzip, sizeof(m_filename_inzip), NULL, 0, NULL, 0);
+ if (err != UNZ_OK) {
+ LOGE("ret: %d", err);
+ throwArchiveException(err, "unzGetCurrentFileInfo()");
+ }
+
+ LOGD("Input from ZIP: m_filename_inzip: [%s]", m_filename_inzip);
+ LOGD("m_base_strip_path: [%s]", m_base_strip_path.c_str());
+
+ std::string file_path = m_filename_inzip;
+ if(!m_base_strip_path.empty()) {
+ if(file_path.find(m_base_strip_path) != 0) {
+ LOGW("m_base_strip_path: [%s] is not begin of m_filename_inzip: [%s]!",
+ m_base_strip_path.c_str(),
+ m_filename_inzip);
+ }
+ else {
+ file_path = file_path.substr(m_base_strip_path.length());
+ LOGD("Stripped file name: [%s]", file_path.c_str());
+ }
+ }
+ else {
+ LOGD("Not stripped file name: [%s]", file_path.c_str());
+ }
+
+ m_output_filepath = removeDuplicatedSlashesFromPath(m_extract_path + "/" + file_path);
+
+ LOGD("Packed: [%s], uncompressed_size: %d, will extract to: [%s]",
+ m_filename_inzip, m_file_info.uncompressed_size,
+ m_output_filepath.c_str());
+
+ std::string path, name;
+ divideToPathAndName(file_path, path, name);
+ m_new_dir_path = removeDuplicatedSlashesFromPath(m_extract_path + "/" + path);
+ m_new_dir_status = getPathStatus(m_new_dir_path);
+ m_is_directory_entry = name.empty();
+
+ LOGD("New output dir: [%s] status: %d m_is_directory_entry: %d",
+ m_new_dir_path.c_str(), m_new_dir_status, m_is_directory_entry);
+
+ if(FPS_DIRECTORY != m_new_dir_status) {
+
+ if(m_is_directory_entry) {
+
+ std::string base_directories;
+ const size_t len = m_new_dir_path.length();
+
+ for(int i = static_cast<int>(len) - 2; i >= 0; i--) { //skip last \, /
+ const char& cur = m_new_dir_path[i];
+ if('\\' == cur || '/' == cur) {
+ base_directories = m_new_dir_path.substr(0, static_cast<size_t>(i));
+ break;
+ }
+ }
+
+ LOGD("Type: DIRECTORY checking base output directories: [%s]",
+ base_directories.c_str());
+ createMissingDirectories(base_directories, false);
+ } else {
+ LOGD("Type: FILE checking output dir: [%s]", m_new_dir_path.c_str());
+ createMissingDirectories(m_new_dir_path, false);
+ }
+ }
+}
+
+void UnZipExtractRequest::handleDirectoryEntry()
+{
+ LOGD("Entered");
+ if(FPS_DIRECTORY != m_new_dir_status) {
+
+ if(FPS_FILE == m_new_dir_status) {
+ if(m_callback->getOverwrite()) { //Is a file & overwrite is set:
+ std::string fn = removeTrailingDirectorySlashFromPath(m_new_dir_path);
+ if(std::remove(fn.c_str()) != 0) {
+ LOGE("std::remove(\"%s\") failed with errno:%s",
+ m_new_dir_path.c_str(), strerror(errno));
+ throw UnknownException(
+ "Could not overwrite file in output directory");
+ }
+ } else { //Is a file & overwrite is not set:
+ LOGE("Failed to extract directory, "
+ "file with the same name exists in output directory");
+ throw UnknownException("Failed to extract directory, "
+ "file with the same name exists in output directory");
+ }
+ }
+
+ //Try to create new directory in output directory
+ if(mkdir(m_new_dir_path.c_str(), 0775) == -1) {
+ LOGE("Couldn't create new directory: %s errno:%s",
+ m_new_dir_path.c_str(), strerror(errno));
+ throw UnknownException(
+ "Could not create new directory in extract output directory");
+ }
+ }
+
+ LOGD("Set dir: [%s] access and modify to: %4d-%2d-%2d %2d:%2d:%2d", m_new_dir_path.c_str(),
+ m_file_info.tmu_date.tm_year,
+ m_file_info.tmu_date.tm_mon,
+ m_file_info.tmu_date.tm_mday,
+ m_file_info.tmu_date.tm_hour,
+ m_file_info.tmu_date.tm_min,
+ m_file_info.tmu_date.tm_sec);
+
+ // Directory already exists we only need to update time
+ changeFileAccessAndModifyDate(m_new_dir_path, m_file_info.tmu_date);
+
+ LOGD("Extracted directory entry: [%s]", m_new_dir_path.c_str());
+}
+
+bool UnZipExtractRequest::prepareOutputSubdirectory()
+{
+ LOGD("Entered");
+ //This zip entry points to file - verify that parent directory in output dir exists
+ if(FPS_DIRECTORY != m_new_dir_status) {
+ if(FPS_FILE == m_new_dir_status) {
+ LOGE("Path: %s is pointing to file not directory!",
+ m_new_dir_path.c_str());
+ throw UnknownException("Failed to extract file from zip archive, "
+ "output path is invalid");
+ }
+
+ //Try to create new directory in output directory
+ //TODO investigate 0775 (mode) - Filesystem assumed that file should have parent mode
+ if(mkdir(m_new_dir_path.c_str(), 0775) == -1) {
+ LOGW("couldn't create new directory: %s errno:%s",
+ m_new_dir_path.c_str(), strerror(errno));
+ //TODO check why mkdir return -1 but directory is successfully created
+ // throw UnknownException(
+ // "Could not create new directory in extract output directory");
+ }
+ }
+
+ if(m_callback->isCanceled()) {
+ LOGD("Operation cancelled");
+ throw OperationCanceledException();
+ }
+
+ const FilePathStatus output_fstatus = getPathStatus(m_output_filepath);
+ if(FPS_NOT_EXIST != output_fstatus) {
+ if(!m_callback->getOverwrite()) {
+ LOGW("%s exists at output path: [%s], overwrite is set to FALSE",
+ (FPS_DIRECTORY == output_fstatus ? "Directory" : "File"),
+ m_output_filepath.c_str());
+
+ //Just skip this file - TODO: this should be documented in WIDL
+ return false;
+ } else {
+ if(FPS_DIRECTORY == output_fstatus) {
+ try {
+ LOGW("STUB Not removing directory");
+ //Filesystem::PathPtr path = Filesystem::Path::create(m_output_filepath);
+ //Filesystem::NodePtr node = Filesystem::Node::resolve(path);
+ //node->remove(Filesystem::OPT_RECURSIVE);
+ Filesystem::External::removeDirectoryRecursive(m_output_filepath);
+
+ LOGD("Removed directory: [%s]", m_output_filepath.c_str());
+ } catch(PlatformException& ex) {
+ LOGE("Remove dir: [%s] failed with exception: %s:%s",
+ m_output_filepath.c_str(),
+ ex.name().c_str(), ex.message().c_str());
+ throw UnknownException("Could not overwrite existing directory");
+ } catch (...) {
+ LOGE("Remove dir: [%s] failed", m_output_filepath.c_str());
+ throw UnknownException("Could not overwrite existing directory");
+ }
+ } //else {
+ //We will overwrite it with fopen
+ //}
+ }
+ }
+
+ return true;
+}
+
+void UnZipExtractRequest::handleFileEntry()
+{
+ LOGD("Entered");
+ if(!prepareOutputSubdirectory()) {
+ LOGE("File exists but overwrite is false");
+ throw InvalidModificationException("file already exists.");
+ }
+
+ int err = unzOpenCurrentFilePassword(m_owner.m_unzip,
+ NULL); //password is not supported yet therefore passing NULL
+ if (UNZ_OK != err) {
+ LOGE("ret: %d", err);
+ throwArchiveException(err, "unzOpenCurrentFilePassword()");
+ }
+
+ //We have successfully opened curent file, therefore we should close it later
+ m_close_unz_current_file = true;
+
+ const size_t buffer_size = m_owner.m_default_buffer_size;
+ m_buffer = new(std::nothrow) char[buffer_size];
+ if(!m_buffer) {
+ LOGE("Couldn't allocate buffer with size: %s",
+ bytesToReadableString(buffer_size).c_str());
+ throw UnknownException("Memory allocation failed");
+ }
+
+ m_output_file = fopen(m_output_filepath.c_str(), "wb");
+ if(!m_output_file) {
+ LOGE("Couldn't open output file: %s", m_output_filepath.c_str());
+ throw UnknownException("Could not create extracted file");
+ }
+ m_delete_output_file = true;
+
+ int read_size = 0;
+ bool marked_as_finished = false;
+
+ LOGD("Started extracting: [%s] uncompressed size: %d - %s", m_filename_inzip,
+ m_file_info.uncompressed_size,
+ bytesToReadableString(m_file_info.uncompressed_size).c_str());
+
+ ExtractAllProgressCallback* extract_callback = NULL;
+ if(m_callback->getCallbackType() == EXTRACT_ALL_PROGRESS_CALLBACK ||
+ m_callback->getCallbackType() == EXTRACT_ENTRY_PROGRESS_CALLBACK) {
+ extract_callback = static_cast<ExtractAllProgressCallback*>(m_callback);
+ extract_callback->startedExtractingFile(m_file_info.uncompressed_size);
+ }
+
+ ArchiveFileEntryPtrMapPtr entries = m_callback->getArchiveFile()->getEntryMap();
+ auto it = entries->find(m_filename_inzip);
+ if (it == entries->end()) {
+ LOGE("Entry not found");
+ throw NotFoundException("Entry not found");
+ }
+
+ while(true) {
+ if(m_callback->isCanceled()) {
+ LOGD("Operation cancelled");
+ throw OperationCanceledException();
+ }
+
+ read_size = unzReadCurrentFile(m_owner.m_unzip, m_buffer, buffer_size);
+ if (read_size < 0) {
+ LOGE("unzReadCurrentFile failed with error code:%d for file:%s", read_size,
+ m_filename_inzip);
+ throw UnknownException("Failed to extract file from zip archive");
+ }
+ else if(0 == read_size) {
+
+ if(extract_callback) {
+ if(!marked_as_finished) {
+ LOGD("NOT marked_as_finished -> increment extracted files counter");
+ extract_callback->finishedExtractingFile();
+
+ //Call progress callback only if we expected empty file
+ if(m_file_info.uncompressed_size == 0) {
+ LOGD("Calling progress callback(%f, %s)",
+ extract_callback->getOverallProgress(), m_filename_inzip);
+ extract_callback->callProgressCallbackOnMainThread(
+ extract_callback->getOverallProgress(), it->second);
+ }
+ }
+ }
+ //Finished writing file, we should not delete extracted file
+ m_delete_output_file = false;
+ break;
+ }
+
+ if (fwrite(m_buffer, read_size, 1, m_output_file) != 1) {
+ LOGE("Couldn't write extracted data to output file:%s",
+ m_output_filepath.c_str());
+ throw UnknownException("Could not write extract file into output file");
+ }
+
+ if(extract_callback) {
+ extract_callback->extractedPartOfFile(read_size);
+ LOGD("File: [%s] extracted: %s - %f%%; total progress %f%%", m_filename_inzip,
+ bytesToReadableString(read_size).c_str(),
+ 100.0f * extract_callback->getCurrentFileProgress(),
+ 100.0f * extract_callback->getOverallProgress());
+
+ // It is better to update number of extracted entries so we will have
+ // overal progres: 1.0 if all files are extracted
+ //
+ if(extract_callback->getCurrentFileProgress() >= 1.0) {
+ LOGD("Current file: [%s] progress: %f >= 1.0 -> "
+ "marked_as_finished = true and increment extracted files counter",
+ m_filename_inzip, extract_callback->getCurrentFileProgress());
+ marked_as_finished = true;
+ extract_callback->finishedExtractingFile();
+ }
+
+ LOGD("Calling progress callback(%f, %s)",
+ extract_callback->getOverallProgress(), m_filename_inzip);
+ extract_callback->callProgressCallbackOnMainThread(
+ extract_callback->getOverallProgress(), it->second);
+ }
+ }
+
+ if(m_output_file) {
+ fclose(m_output_file);
+ m_output_file = NULL;
+ }
+
+ changeFileAccessAndModifyDate(m_output_filepath, m_file_info.tmu_date);
+}
+
+} //namespace Archive
+} //namespace DeviceAPI
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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 __TIZEN_ARCHIVE_UNZIP_EXTRACT_REQUEST_H__
+#define __TIZEN_ARCHIVE_UNZIP_EXTRACT_REQUEST_H__
+
+#include <stdio.h>
+#include <string>
+#include "un_zip.h"
+
+namespace DeviceAPI {
+namespace Archive {
+
+enum FilePathStatus {
+ FPS_NOT_EXIST = 0,
+ FPS_FILE = 1,
+ FPS_DIRECTORY = 2
+};
+
+class UnZipExtractRequest
+{
+public:
+ static void execute(UnZip& owner,
+ const std::string& extract_path,
+ const std::string& base_strip_path,
+ BaseProgressCallback* callback);
+
+ ~UnZipExtractRequest();
+
+private:
+ UnZipExtractRequest(UnZip& owner,
+ const std::string& extract_path,
+ const std::string& base_strip_path,
+ BaseProgressCallback* callback);
+ void run();
+
+ void getCurrentFileInfo();
+
+ void handleDirectoryEntry();
+
+ void handleFileEntry();
+ bool prepareOutputSubdirectory();
+
+ //-----------------------------------------------------------------------------
+ //Input request variables
+ UnZip& m_owner;
+ const std::string m_extract_path;
+ const std::string m_base_strip_path;
+ BaseProgressCallback* m_callback;
+
+ //-----------------------------------------------------------------------------
+ //Working variables
+ FILE* m_output_file; //Used to write extracted file into output directory
+ char* m_buffer; //Memory buffer passed between Minizip lib and fwrite function
+
+ bool m_delete_output_file;
+ bool m_close_unz_current_file;
+
+ unz_file_info m_file_info; //Informations about current archive entry (from minizip)
+ char m_filename_inzip[512]; //Name of archive file entry (from minizip)
+ std::string m_output_filepath; //Extracted output file name with full path
+
+ FilePathStatus m_new_dir_status;
+ bool m_is_directory_entry; //Is this request for directory
+ std::string m_new_dir_path;
+};
+
+} //namespace Archive
+} //namespace DeviceAPI
+
+#endif // __TIZEN_ARCHIVE_UNZIP_EXTRACT_REQUEST_H__
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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 "zip.h"
+
+#include <iostream>
+#include <memory>
+#include <string>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "common/logger.h"
+#include "common/platform_exception.h"
+#include "filesystem_file.h"
+
+#include "archive_file.h"
+#include "archive_utils.h"
+#include "crypt.h"
+#include "zip_add_request.h"
+
+using namespace common;
+
+namespace DeviceAPI {
+namespace Archive {
+
+void Zip::generateZipFileInfo(const std::string& filename, zip_fileinfo& out_zi)
+{
+ memset(&out_zi, 0, sizeof(zip_fileinfo));
+
+ time_t tm_t = 0;
+ if (filename != "-") {
+ std::string name = filename;
+ if (name[name.length() - 1] == '/') {
+ name[name.length() - 1] = '\0';
+ }
+
+ struct stat s;
+ // not all systems allow stat'ing a file with / appended
+ if (stat(name.c_str(), &s) == 0) {
+ tm_t = s.st_mtime;
+ }
+ }
+
+ struct tm* filedate = localtime(&tm_t);
+ if(filedate) {
+ out_zi.tmz_date.tm_sec = filedate->tm_sec;
+ out_zi.tmz_date.tm_min = filedate->tm_min;
+ out_zi.tmz_date.tm_hour = filedate->tm_hour;
+ out_zi.tmz_date.tm_mday = filedate->tm_mday;
+ out_zi.tmz_date.tm_mon = filedate->tm_mon ;
+ out_zi.tmz_date.tm_year = filedate->tm_year;
+ }
+}
+
+Zip::Zip(const std::string& filename, ZipOpenMode open_mode) :
+ m_zipfile_name(filename),
+ m_zip(NULL),
+ m_default_buffer_size(1024 * 1024)
+{
+ LOGD("Entered");
+
+ int append_mode = APPEND_STATUS_CREATE;
+ if(ZOM_CREATEAFTER == open_mode) {
+ append_mode = APPEND_STATUS_CREATEAFTER;
+ } else if(ZOM_ADDINZIP == open_mode) {
+ append_mode = APPEND_STATUS_ADDINZIP;
+ }
+ LOGD("append_mode: %d", append_mode);
+
+ m_zip = zipOpen(filename.c_str(), append_mode);
+ if(!m_zip) {
+ LOGE("zipOpen returned NULL!");
+ throw UnknownException("Opening/creating zip file failed");
+ }
+ m_is_open = true;
+}
+
+Zip::~Zip()
+{
+ close();
+}
+
+void Zip::close()
+{
+ LOGD("Entered");
+ if(!m_is_open) {
+ LOGD("Already closed - exiting.");
+ return;
+ }
+
+ int errclose = zipClose(m_zip, NULL);
+ m_zip = NULL;
+
+ if (errclose != ZIP_OK) {
+ LOGE("ret: %d", errclose);
+ throwArchiveException(errclose, "zipClose()");
+ }
+ m_is_open = false;
+}
+
+ZipPtr Zip::createNew(const std::string& filename)
+{
+ LOGD("Entered");
+ return ZipPtr(new Zip(filename, ZOM_CREATE));
+}
+
+ZipPtr Zip::open(const std::string& filename)
+{
+ LOGD("Entered");
+ return ZipPtr(new Zip(filename, ZOM_ADDINZIP));
+}
+
+void Zip::addFile(AddProgressCallback*& callback)
+{
+ LOGD("Entered");
+ if(!callback) {
+ LOGE("callback is NULL!");
+ throw UnknownException("Could not add file(-s) to archive");
+ }
+ if(!m_is_open) {
+ LOGE("Zip file not opened - exiting");
+ throw UnknownException("Could not add file(-s) to archive - zip file closed");
+ }
+
+ ZipAddRequest::execute(*this, callback);
+}
+
+} //namespace Archive
+} //namespace DeviceAPI
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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 __TIZEN_ARCHIVE_ZIP_H__
+#define __TIZEN_ARCHIVE_ZIP_H__
+
+#include <memory>
+#include <string>
+
+#include <zip.h>
+
+#include "archive_callback_data.h"
+
+namespace DeviceAPI {
+namespace Archive {
+
+
+class ZipAddRequest;
+
+class Zip;
+typedef std::shared_ptr<Zip> ZipPtr;
+
+class Zip
+{
+public:
+ static ZipPtr createNew(const std::string& filename);
+ static ZipPtr open(const std::string& filename);
+ ~Zip();
+
+ /**
+ * When request has finished callback is set to NULL and is
+ * deleted on main thread after calling all progress callbacks.
+ * If exception is thrown please delete callback.
+ */
+ void addFile(AddProgressCallback*& callback);
+
+ void close();
+
+private:
+ enum ZipOpenMode {
+ ZOM_CREATE,
+ ZOM_CREATEAFTER,
+ ZOM_ADDINZIP
+ };
+
+ Zip(const std::string& filename, ZipOpenMode open_mode);
+
+ static void generateZipFileInfo(const std::string& filename, zip_fileinfo& out_zi);
+
+ std::string m_zipfile_name;
+ zipFile m_zip;
+ size_t m_default_buffer_size;
+ bool m_is_open;
+
+
+ friend class ZipAddRequest;
+};
+
+} //namespace Archive
+} //namespace DeviceAPI
+
+#endif // __TIZEN_ARCHIVE_ZIP_H__
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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 "zip_add_request.h"
+
+#include "common/logger.h"
+#include "common/platform_exception.h"
+
+#include "archive_file.h"
+#include "archive_file_entry.h"
+#include "archive_utils.h"
+
+using namespace common;
+
+namespace DeviceAPI {
+namespace Archive {
+
+ZipAddRequest::ZipAddRequest(Zip& owner, AddProgressCallback*& callback) :
+ m_owner(owner),
+ m_callback(callback),
+ m_input_file(NULL),
+ m_buffer(NULL),
+ m_buffer_size(m_owner.m_default_buffer_size),
+ m_files_to_compress(0),
+ m_bytes_to_compress(0),
+ m_files_compressed(0),
+ m_bytes_compressed(0),
+ m_compression_level(0),
+ m_new_file_in_zip_opened(false)
+{
+}
+
+ZipAddRequest::~ZipAddRequest()
+{
+ if(m_input_file) {
+ fclose(m_input_file);
+ m_input_file = NULL;
+ }
+
+ delete [] m_buffer;
+ m_buffer = NULL;
+
+
+ if(m_new_file_in_zip_opened) {
+ int err = zipCloseFileInZip(m_owner.m_zip);
+ if (ZIP_OK != err) {
+ LOGE("%s",getArchiveLogMessage(err, "zipCloseFileInZip()").c_str());
+ }
+ }
+}
+
+void ZipAddRequest::execute(Zip& owner, AddProgressCallback*& callback)
+{
+ ZipAddRequest req(owner, callback);
+ req.run();
+}
+
+void ZipAddRequest::run()
+{
+ if(!m_callback) {
+ LOGE("m_callback is NULL");
+ throw UnknownException("Could not add file(-s) to archive");
+ }
+
+ if(!m_callback->getFileEntry()) {
+ LOGE("m_callback->getFileEntry() is NULL");
+ throw InvalidValuesException("Provided ArchiveFileEntry is not correct");
+ }
+
+ if(m_callback->isCanceled()) {
+ LOGD("Operation cancelled");
+ throw OperationCanceledException();
+ }
+
+ m_compression_level = m_callback->getFileEntry()->getCompressionLevel();
+ m_root_src_file = m_callback->getFileEntry()->getFile();
+ m_root_src_file_node = m_root_src_file->getNode();
+
+ //We just need read permission to list files in subdirectories
+ LOGW("STUB Not setting PERM_READ permissions");
+ //m_root_src_file_node->setPermissions(Filesystem::PERM_READ);
+
+ std::string src_basepath, src_name;
+ getBasePathAndName(m_root_src_file_node->getFullPath(), src_basepath,
+ src_name);
+
+ m_absoulte_path_to_extract = src_basepath;
+ LOGD("m_absoulte_path_to_extract: [%s]", m_absoulte_path_to_extract.c_str());
+
+ m_destination_path_in_zip = removeDuplicatedSlashesFromPath(
+ m_callback->getFileEntry()->getDestination());
+
+ // If we have destination set then we need to create all folders and sub folders
+ // inside this zip archive.
+ //
+ if(m_destination_path_in_zip.length() > 0) {
+ LOGD("destination is: [%s]", m_destination_path_in_zip.c_str());
+
+ for(size_t i = 0; i < m_destination_path_in_zip.length(); ++i) {
+ const char cur_char = m_destination_path_in_zip[i];
+
+ if( ((cur_char == '/' || cur_char == '\\') && i > 0 ) ||
+ (i == m_destination_path_in_zip.length() - 1)) {
+
+ //Extract left side with '/':
+ const std::string new_dir = m_destination_path_in_zip.substr(0, i + 1);
+
+ LOGD("Adding empty directory: [%s] to archive", new_dir.c_str());
+ addEmptyDirectoryToZipArchive(new_dir);
+ }
+ }
+ }
+
+ // Generate list of files and all subdirectories
+ //
+ Filesystem::NodeList all_sub_nodes;
+ addNodeAndSubdirsToList(m_root_src_file_node, all_sub_nodes);
+
+ if(m_callback->isCanceled()) {
+ LOGD("Operation cancelled");
+ throw OperationCanceledException();
+ }
+
+ // Calculate total size to be compressed
+ //
+ m_bytes_to_compress = 0;
+ m_files_to_compress = 0;
+
+ int i = 0;
+ for(auto it = all_sub_nodes.begin(); it != all_sub_nodes.end(); ++it, ++i) {
+
+ unsigned long long size = 0;
+ if((*it)->getType() == Filesystem::NT_FILE) {
+ size = (*it)->getSize();
+ m_bytes_to_compress += size;
+ ++m_files_to_compress;
+ }
+
+ LOGD("[%d] : [%s] --zip--> [%s] | size: %s", i, (*it)->getFullPath().c_str(),
+ getNameInZipArchiveFor(*it, m_callback->getFileEntry()->getStriped()).c_str(),
+ bytesToReadableString(size).c_str());
+ }
+
+ LOGD("m_files_to_compress: %d", m_files_to_compress);
+ LOGD("m_bytes_to_compress: %llu (%s)", m_bytes_to_compress,
+ bytesToReadableString(m_bytes_to_compress).c_str());
+
+ if(m_callback->isCanceled()) {
+ LOGD("Operation cancelled");
+ throw OperationCanceledException();
+ }
+
+ // Begin files compression
+ //
+ for(auto it = all_sub_nodes.begin(); it != all_sub_nodes.end(); ++it, ++i) {
+ addToZipArchive(*it);
+ }
+
+ m_callback->callSuccessCallbackOnMainThread();
+ m_callback = NULL;
+}
+
+void ZipAddRequest::addNodeAndSubdirsToList(Filesystem::NodePtr src_node,
+ Filesystem::NodeList& out_list_of_child_nodes)
+{
+ out_list_of_child_nodes.push_back(src_node);
+
+ if(Filesystem::NT_DIRECTORY == src_node->getType()) {
+ LOGW("STUB Not generating recursive list of files in directory");
+ //auto child_nodes = src_node->getChildNodes();
+ //for(auto it = child_nodes.begin(); it != child_nodes.end(); ++it) {
+ // addNodeAndSubdirsToList(*it, out_list_of_child_nodes);
+ //}
+ }
+}
+
+void ZipAddRequest::addEmptyDirectoryToZipArchive(std::string name_in_zip)
+{
+ LOGD("Entered name_in_zip:%s", name_in_zip.c_str());
+
+ if(name_in_zip.length() == 0) {
+ LOGW("Trying to create directory with empty name - \"\"");
+ return;
+ }
+
+ const char last_char = name_in_zip[name_in_zip.length()-1];
+ if(last_char != '/' && last_char != '\\') {
+ name_in_zip += "/";
+ LOGD("Corrected name_in_zip: [%s]", name_in_zip.c_str());
+ }
+
+ if(m_new_file_in_zip_opened) {
+ LOGE("WARNING: Previous new file in zip archive is opened!");
+ int err = zipCloseFileInZip(m_owner.m_zip);
+ if (ZIP_OK != err) {
+ LOGE("%s",getArchiveLogMessage(err, "zipCloseFileInZip()").c_str());
+ }
+ }
+
+ bool is_directory = false;
+ std::string conflicting_name;
+
+ if(m_callback->getArchiveFile()->isEntryWithNameInArchive(name_in_zip,
+ &is_directory, &conflicting_name)) {
+
+ if(!is_directory) {
+ LOGE("Entry: [%s] exists and is NOT directory!", conflicting_name.c_str());
+
+ LOGE("Throwing InvalidValuesException - File with the same name exists");
+ throw InvalidValuesException("File with the same name exists");
+ }
+
+ LOGD("Directory: [%s] already exists -> nothing to do", name_in_zip.c_str());
+ return;
+ }
+
+ if(m_callback->isCanceled()) {
+ LOGD("Operation cancelled");
+ throw OperationCanceledException();
+ }
+
+ zip_fileinfo new_dir_info;
+ memset(&new_dir_info, 0, sizeof(zip_fileinfo));
+
+ //
+ // Since this directory does not exist we will set current time
+ //
+ time_t current_time = time(NULL);
+ struct tm* current_time_tm = localtime(¤t_time);
+ if(current_time_tm) {
+ new_dir_info.tmz_date.tm_sec = current_time_tm->tm_sec;
+ new_dir_info.tmz_date.tm_min = current_time_tm->tm_min;
+ new_dir_info.tmz_date.tm_hour = current_time_tm->tm_hour;
+ new_dir_info.tmz_date.tm_mday = current_time_tm->tm_mday;
+ new_dir_info.tmz_date.tm_mon = current_time_tm->tm_mon ;
+ new_dir_info.tmz_date.tm_year = current_time_tm->tm_year;
+ }
+
+ int err = zipOpenNewFileInZip3(m_owner.m_zip, name_in_zip.c_str(), &new_dir_info,
+ NULL, 0, NULL, 0, NULL,
+ (m_compression_level != 0) ? Z_DEFLATED : 0,
+ m_compression_level, 0,
+ -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
+ NULL, 0);
+
+ if (err != ZIP_OK) {
+ LOGE("ret: %d", err);
+ throwArchiveException(err, "zipOpenNewFileInZip3()");
+ }
+
+ m_new_file_in_zip_opened = true;
+
+ err = zipCloseFileInZip(m_owner.m_zip);
+ if (ZIP_OK != err) {
+ LOGE("%s",getArchiveLogMessage(err, "zipCloseFileInZip()").c_str());
+ }
+
+ LOGD("Added new empty directory to archive: [%s]", name_in_zip.c_str());
+ m_new_file_in_zip_opened = false;
+}
+
+void ZipAddRequest::addToZipArchive(Filesystem::NodePtr src_file_node)
+{
+ const std::string name_in_zip = getNameInZipArchiveFor(src_file_node,
+ m_callback->getFileEntry()->getStriped());
+ const std::string src_file_path = src_file_node->getFullPath();
+
+ LOGD("Compress: [%s] to zip archive as: [%s]", src_file_path.c_str(),
+ name_in_zip.c_str());
+
+ zip_fileinfo new_file_info;
+ Zip::generateZipFileInfo(src_file_path, new_file_info);
+
+ if(m_new_file_in_zip_opened) {
+ LOGE("WARNING: Previous new file in zip archive is opened!");
+ int err = zipCloseFileInZip(m_owner.m_zip);
+ if (ZIP_OK != err) {
+ LOGE("%s",getArchiveLogMessage(err, "zipCloseFileInZip()").c_str());
+ }
+ }
+
+ if(m_callback->isCanceled()) {
+ LOGD("Operation cancelled");
+ throw OperationCanceledException();
+ }
+
+ std::string conflicting_name;
+ if(m_callback->getArchiveFile()->isEntryWithNameInArchive(name_in_zip,
+ NULL, &conflicting_name)) {
+
+ LOGE("Cannot add new entry with name name: [%s] "
+ "it would conflict with existing entry: [%s]",
+ name_in_zip.c_str(), conflicting_name.c_str());
+
+ LOGE("Throwing InvalidModificationException - Archive entry name conflicts");
+ throw InvalidModificationException("Archive entry name conflicts");
+ }
+
+ int err = zipOpenNewFileInZip3(m_owner.m_zip, name_in_zip.c_str(), &new_file_info,
+ NULL, 0, NULL, 0, NULL,
+ (m_compression_level != 0) ? Z_DEFLATED : 0,
+ m_compression_level, 0,
+ -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
+ NULL, 0);
+
+ if (err != ZIP_OK) {
+ LOGE("ret: %d", err);
+ throwArchiveException(err, "zipOpenNewFileInZip3()");
+ }
+
+ m_new_file_in_zip_opened = true;
+
+ if(m_input_file) {
+ LOGW("WARNING: Previous m_input_file has not been closed");
+ fclose(m_input_file);
+ m_input_file = NULL;
+ }
+
+ //Filesystem::File::PermissionList perm_list;
+ //Filesystem::FilePtr cur_file(new Filesystem::File(src_file_node, perm_list));
+
+ LOGW("STUB ignore src_file_node and PermissionList");
+ Filesystem::FilePtr cur_file(new Filesystem::File(src_file_path));
+ ArchiveFileEntryPtr cur_afentry(new ArchiveFileEntry(cur_file));
+ cur_afentry->setCompressionLevel(m_compression_level);
+ cur_afentry->setName(name_in_zip);
+
+ LOGW("STUB Not setting Modified");
+ //cur_afentry->setModified(src_file_node->getModified());
+
+ auto entry = m_callback->getFileEntry();
+ cur_afentry->setDestination(entry->getDestination());
+ cur_afentry->setStriped(entry->getStriped());
+ cur_afentry->setSize(0);
+
+ LOGD("m_bytes_compressed:%llu / m_bytes_to_compress: %llu",
+ m_bytes_compressed, m_bytes_to_compress);
+
+ LOGD("m_files_compressed:%d / m_files_to_compress: %d",
+ m_files_compressed, m_files_to_compress);
+
+ if(src_file_node->getType() == Filesystem::NT_FILE) {
+ m_input_file = fopen(src_file_path.c_str(), "rb");
+ if (!m_input_file) {
+ LOGE("Error opening source file:%s", src_file_path.c_str());
+ throw UnknownException("Could not open file to be added");
+ }
+
+ //Get file length
+ fseek(m_input_file, 0, SEEK_END);
+ const size_t in_file_size = ftell(m_input_file);
+ fseek(m_input_file, 0, SEEK_SET);
+ LOGD("Source file: [%s] size: %d - %s", src_file_path.c_str(),
+ in_file_size,
+ bytesToReadableString(in_file_size).c_str());
+
+ cur_afentry->setSize(in_file_size);
+
+ if(!m_buffer) {
+ m_buffer = new(std::nothrow) char[m_buffer_size];
+ if(!m_buffer) {
+ LOGE("Couldn't allocate m_buffer");
+ throw UnknownException("Memory allocation error");
+ }
+ }
+
+ size_t total_bytes_read = 0;
+ size_t size_read = 0;
+
+ do {
+ size_read = fread(m_buffer, 1, m_buffer_size, m_input_file);
+ if (size_read < m_buffer_size &&
+ feof(m_input_file) == 0) {
+ LOGE("Error reading source file: %s\n", src_file_path.c_str());
+ throw UnknownException("New file addition failed");
+ }
+
+ LOGD("Read: %d bytes from input file:[%s]", size_read,
+ src_file_path.c_str());
+ total_bytes_read += size_read;
+ m_bytes_compressed += size_read;
+
+ if (size_read > 0) {
+ err = zipWriteInFileInZip (m_owner.m_zip, m_buffer, size_read);
+ if (err < 0) {
+ LOGE("Error during adding file: %s into zip archive",
+ src_file_path.c_str());
+ throw UnknownException("New file addition failed");
+ }
+ }
+
+ if(total_bytes_read == in_file_size) {
+ LOGD("Finished reading and compressing source file: [%s]",
+ src_file_path.c_str());
+ ++m_files_compressed;
+ }
+
+ LOGD("Callculatting overall progress: %llu/%llu bytes; "
+ "%d/%d files; current file: [%s] progress: %d/%d bytes; ",
+ m_bytes_compressed, m_bytes_to_compress,
+ m_files_compressed, m_files_to_compress,
+ src_file_path.c_str(),
+ total_bytes_read, in_file_size);
+
+ double progress = 1.0;
+ if(m_bytes_to_compress > 0 || m_files_to_compress > 0) {
+ progress = static_cast<double>(m_bytes_compressed + m_files_compressed) /
+ static_cast<double>(m_bytes_to_compress + m_files_to_compress);
+ }
+
+ LOGD("Wrote: %s total progress: %.2f%% %d/%d files",
+ bytesToReadableString(size_read).c_str(), progress * 100.0,
+ m_files_compressed, m_files_to_compress);
+
+ LOGD("Calling add onprogress callback(%f, %s)", progress,
+ name_in_zip.c_str());
+ m_callback->callProgressCallbackOnMainThread(progress, cur_afentry);
+
+ } while (size_read > 0 && total_bytes_read < in_file_size);
+
+ if(in_file_size != total_bytes_read) {
+ LOGE("in_file_size(%d) != total_bytes_read(%d)", in_file_size,
+ total_bytes_read);
+ throw UnknownException("Could not add file to archive");
+ }
+
+ fclose(m_input_file);
+ m_input_file = NULL;
+ }
+
+ err = zipCloseFileInZip(m_owner.m_zip);
+ if (ZIP_OK != err) {
+ LOGE("%s",getArchiveLogMessage(err, "zipCloseFileInZip()").c_str());
+ }
+
+ m_new_file_in_zip_opened = false;
+}
+
+std::string removeDirCharsFromFront(const std::string& path)
+{
+ for(size_t i = 0; i < path.length(); ++i) {
+ const char& cur = path[i];
+ if(cur != '/' && cur != '\\') {
+ return path.substr(i);
+ }
+ }
+
+ return std::string(); //in case path contained only slashes
+}
+
+std::string generateFullPathForZip(const std::string& path)
+{
+ //Step 1: Remove / from begining
+ const size_t path_len = path.length();
+
+ size_t start_i = 0;
+ for(size_t i = 0; i < path_len; ++i) {
+ const char& cur = path[i];
+ if(cur != '/' && cur != '\\') {
+ start_i = i;
+ break;
+ }
+ }
+
+ std::string out;
+ out.reserve(path_len);
+
+ //Step 1: Remove duplicated / characters
+ bool prev_is_dir = false;
+ for(size_t i = start_i; i < path_len; ++i) {
+ const char& cur = path[i];
+ if(cur == '/' || cur == '\\') {
+ if(!prev_is_dir) {
+ out += cur;
+ }
+ prev_is_dir = true;
+ } else {
+ prev_is_dir = false;
+ out += cur;
+ }
+ }
+
+ return out;
+}
+
+std::string ZipAddRequest::getNameInZipArchiveFor(Filesystem::NodePtr node, bool strip)
+{
+ const std::string node_full_path = node->getPath()->getFullPath();
+ std::string cut_path;
+
+ const size_t pos = node_full_path.find(m_absoulte_path_to_extract);
+ if(std::string::npos == pos) {
+ LOGW("node: [%s] is not containing m_absoulte_path_to_extract: [%s]!",
+ node_full_path.c_str(),
+ m_absoulte_path_to_extract.c_str());
+ }
+
+ cut_path = node_full_path.substr(pos+m_absoulte_path_to_extract.length());
+ LOGD("node_full_path:%s cut_path: %s", node_full_path.c_str(), cut_path.c_str());
+
+ if(!strip) {
+ cut_path = m_callback->getBaseVirtualPath() + "/" + cut_path;
+ LOGD("nonstripped cut_path: %s", cut_path.c_str());
+ }
+
+ std::string name = generateFullPathForZip(m_destination_path_in_zip + "/" + cut_path);
+ if(node->getType() == Filesystem::NT_DIRECTORY) {
+ if(name.length() > 0
+ && name[name.length()-1] != '/'
+ && name[name.length()-1] != '\\') {
+ name += "/";
+ LOGD("Directory: [%s] added \\", name.c_str());
+ }
+ }
+
+ return name;
+}
+
+} //namespace Archive
+} //namespace DeviceAPI
--- /dev/null
+//
+// Tizen Web Device API
+// Copyright (c) 2014 Samsung Electronics Co., Ltd.
+//
+// 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 __TIZEN_ARCHIVE_ZIP_ADD_REQUEST_H__
+#define __TIZEN_ARCHIVE_ZIP_ADD_REQUEST_H__
+
+#include <stdio.h>
+#include <string>
+
+#include "filesystem_file.h"
+
+#include "archive_callback_data.h"
+#include "zip.h"
+
+namespace DeviceAPI {
+namespace Archive {
+
+class ZipAddRequest
+{
+public:
+
+ /**
+ * When request has finished callback is set to NULL and is
+ * deleted on main thread after calling all progress callbacks.
+ * If exception is thrown please delete callback.
+ */
+ static void execute(Zip& owner, AddProgressCallback*& callback);
+ ~ZipAddRequest();
+
+private:
+ ZipAddRequest(Zip& owner, AddProgressCallback*& callback);
+ void run();
+
+ void addNodeAndSubdirsToList(Filesystem::NodePtr src_node,
+ Filesystem::NodeList& out_list_of_child_nodes);
+
+ void addEmptyDirectoryToZipArchive(std::string name_in_zip);
+ void addToZipArchive(Filesystem::NodePtr src_file_node);
+
+ std::string getNameInZipArchiveFor(Filesystem::NodePtr node, bool strip);
+
+ //-----------------------------------------------------------------------------
+ //Input request variables
+ Zip& m_owner;
+ AddProgressCallback* m_callback;
+
+
+ FILE* m_input_file;
+ char* m_buffer;
+ size_t m_buffer_size;
+
+
+ unsigned long m_files_to_compress;
+ unsigned long long m_bytes_to_compress;
+
+ unsigned long m_files_compressed;
+ unsigned long long m_bytes_compressed;
+
+ Filesystem::FilePtr m_root_src_file;
+ Filesystem::NodePtr m_root_src_file_node;
+ std::string m_absoulte_path_to_extract;
+ std::string m_destination_path_in_zip;
+
+ unsigned int m_compression_level;
+
+ bool m_new_file_in_zip_opened;
+};
+
+} //namespace Archive
+} //namespace DeviceAPI
+
+#endif // __TIZEN_ARCHIVE_ZIP_ADD_REQUEST_H__
DEFINE_EXCEPTION(InvalidAccess)
DEFINE_EXCEPTION(Abort)
DEFINE_EXCEPTION(QuotaExceeded)
+DEFINE_EXCEPTION(InvalidState)
+DEFINE_EXCEPTION(InvalidModification)
#undef DEFINE_EXCEPTION
} // namespace common