[DEV] continue rework IO interface with abstract provider

This commit is contained in:
Edouard DUPIN 2018-09-10 21:42:09 +02:00
parent 26d5d87fd7
commit 68a391e7ad
39 changed files with 958 additions and 55 deletions

View File

@ -0,0 +1 @@
file_hidden.txt

View File

@ -0,0 +1 @@
file_A_1.txt

View File

@ -0,0 +1 @@
file_C_1.txt

View File

@ -0,0 +1 @@
file_B_1.txt

View File

@ -0,0 +1 @@
file_B_2.txt

1
data/data/file_1.txt Normal file
View File

@ -0,0 +1 @@
file_1.txt

1
data/data/file_2.txt Normal file
View File

@ -0,0 +1 @@
file_2.txt

1
data/data/file_3.txt Normal file
View File

@ -0,0 +1 @@
file_3.txt

BIN
data/data_sample.zip Normal file

Binary file not shown.

View File

@ -97,7 +97,7 @@ void etest::init(int32_t _argc, const char** _argv) {
return; return;
} }
nbTimeInit++; nbTimeInit++;
elog::init(_argc, _argv); elog::init(_argc, _argv, "etest");
//etk::initDefaultFolder("ewolApplNoName"); //etk::initDefaultFolder("ewolApplNoName");
ETEST_INFO("ETEST system init (BEGIN) "); ETEST_INFO("ETEST system init (BEGIN) ");
for (int32_t iii=0; iii<_argc ; ++iii) { for (int32_t iii=0; iii<_argc ; ++iii) {

View File

@ -318,6 +318,10 @@ namespace etk {
bool empty() const { bool empty() const {
return size() == 0; return size() == 0;
} }
/// @previous
bool isEmpty() const {
return empty();
}
/** /**
* @brief Get a current element in the string * @brief Get a current element in the string
* @param[in] _pos Desired position read * @param[in] _pos Desired position read

View File

@ -308,6 +308,10 @@ namespace etk {
bool empty() const { bool empty() const {
return size() == 0; return size() == 0;
} }
/// @previous
bool isEmpty() const {
return empty();
}
/** /**
* @brief Get a current element in the string * @brief Get a current element in the string
* @param[in] _pos Desired position read * @param[in] _pos Desired position read

View File

@ -999,7 +999,7 @@ namespace etk {
} }
} }
if (swapped == false) { if (swapped == false) {
break; //break;
} }
} }
} }

View File

@ -71,7 +71,22 @@ ememory::SharedPtr<etk::Archive> etk::Archive::load(const etk::Path& _fileName)
TK_ERROR("An error occured when load archive : " << _fileName); TK_ERROR("An error occured when load archive : " << _fileName);
} }
} else { } else {
TK_ERROR("Extention not managed " << _fileName << " Sopported extention : .zip"); TK_ERROR("Extention not managed '" << _fileName << "' Supported extention : .zip");
}
return output;
}
ememory::SharedPtr<etk::Archive> etk::Archive::load(const etk::Uri& _uri) {
ememory::SharedPtr<etk::Archive> output;
etk::String extention = _uri.getPath().getExtention().toLower();
// select the corect Loader :
if( extention == "zip"
|| extention == ".apk") {
output = ememory::makeShared<etk::archive::Zip>(_uri);
if (output == null) {
TK_ERROR("An error occured when load archive : " << _uri);
}
} else {
TK_ERROR("Extention not managed '" << _uri << "' Supported extention : .zip");
} }
return output; return output;
} }
@ -138,4 +153,38 @@ void etk::Archive::close(const etk::Path& _key) {
} }
} }
#endif etk::Vector<etk::Path> etk::Archive::list(const etk::Path& _path) {
etk::Vector<etk::Path> out;
etk::String base = _path.getString();
for (auto& it: m_content) {
etk::String name = it.first.getString();
if (name.size() < base.size()) {
continue;
}
if (etk::start_with(name, base) == true) {
// element or subElement...
if (it.first.getParent() == _path) {
out.pushBack(it.first);
continue;
}
etk::String back = name.extract(base.size());
if ( back.size() == 0
|| back[0] != '/') {
continue;
}
back.erase(back.begin());
size_t pos = back.find('/');
if (pos == etk::String::npos) {
continue;
}
etk::String value = back.extract(0, pos);
etk::Path tmpppp = etk::Path(base) / value;
if (etk::isIn(tmpppp, out) == false) {
out.pushBack(tmpppp);
}
}
}
return out;
}
#endif

View File

@ -12,6 +12,7 @@
#include <ethread/Mutex.hpp> #include <ethread/Mutex.hpp>
#include <ememory/memory.hpp> #include <ememory/memory.hpp>
#include <etk/fs/Path.hpp> #include <etk/fs/Path.hpp>
#include <etk/uri/Uri.hpp>
namespace etk { namespace etk {
/** /**
@ -174,12 +175,24 @@ namespace etk {
* @return A pointer an the specified archive, the user might delete it. * @return A pointer an the specified archive, the user might delete it.
*/ */
static ememory::SharedPtr<Archive> load(const etk::Path& _fileName); static ememory::SharedPtr<Archive> load(const etk::Path& _fileName);
/**
* @brief Load an Achive with a specific name.
* @param[in] _uri Localisation of the file.
* @return A pointer an the specified archive, the user might delete it.
*/
static ememory::SharedPtr<Archive> load(const etk::Uri& _uri);
/** /**
* @brief Load an Achive with a specific name in package mode ==> this mean the data is associated with the basic binary. * @brief Load an Achive with a specific name in package mode ==> this mean the data is associated with the basic binary.
* @param[in] _fileName File name of the specific archive. * @param[in] _fileName File name of the specific archive.
* @return A pointer an the specified archive, the user might delete it. * @return A pointer an the specified archive, the user might delete it.
*/ */
static ememory::SharedPtr<Archive> loadPackage(const etk::Path& _fileName); static ememory::SharedPtr<Archive> loadPackage(const etk::Path& _fileName);
/**
* @brief List the content of a specific path.
* @param[in] Path to parse.
* @return the full list of path in the _path.
*/
etk::Vector<etk::Path> list(const etk::Path& _path);
}; };
} }
#endif #endif

View File

@ -52,6 +52,50 @@ etk::archive::Zip::Zip(const etk::Path& _fileName, uint64_t _offset) :
} }
} }
} }
// TODO: Support the correct URI... ==> do a structure in unzip to manage the read and write of data with a callback...
etk::archive::Zip::Zip(const etk::Uri& _uri) :
etk::Archive(_uri.getPath()),
m_ctx(null) {
if (_uri.getScheme() != "") {
TK_ERROR("Can not read and uri that is not with a scheme != of RAW, we have " << _uri);
return;
}
/* Open the zip file */
m_ctx = unzOpenOffset(m_fileName.getNative().c_str(), 0);
if(!m_ctx) {
TK_ERROR("Unable to open the zip file '" << m_fileName << "'");
return;
}
/* Get info about the zip file */
if(unzGetGlobalInfo(m_ctx, &m_info) != UNZ_OK) {
TK_ERROR("Unable to read the global info related to the '" << m_fileName << "' zip file");
return;
}
// Store all the file in the standard structure
for(uint32_t iii=0; iii<m_info.number_entry; iii++) {
char tmpFileName[FILENAME_MAX];
unz_file_info tmpFileInfo;
/* Get info about current file. */
if(unzGetCurrentFileInfo(m_ctx, &tmpFileInfo, tmpFileName, FILENAME_MAX, null, 0, null, 0) != UNZ_OK) {
TK_ERROR("Could not read file info from the zip file '" << m_fileName << "'");
return;
}
if(tmpFileName[strlen(tmpFileName) - 1] == '/' ) {
// find directory ...
} else {
TK_INFO("find file : " << tmpFileName);
m_content.set(etk::Path(tmpFileName), ememory::makeShared<etk::ArchiveContent>(tmpFileInfo.uncompressed_size));
}
/* Go the the next entry listed in the zip file. */
if((iii+1) < m_info.number_entry) {
if (unzGoToNextFile(m_ctx) != UNZ_OK) {
TK_ERROR("Could not read next file from the zip file '" << m_fileName << "'");
return;
}
}
}
}
etk::archive::Zip::~Zip() { etk::archive::Zip::~Zip() {
if (m_ctx!= null) { if (m_ctx!= null) {

View File

@ -6,6 +6,7 @@
#pragma once #pragma once
#include <etk/archive/Archive.hpp> #include <etk/archive/Archive.hpp>
#include <etk/uri/Uri.hpp>
#ifdef ETK_BUILD_MINIZIP #ifdef ETK_BUILD_MINIZIP
extern "C" { extern "C" {
#include <minizip/unzip.h> #include <minizip/unzip.h>
@ -29,6 +30,11 @@
* @param[in] _offset Offset in the file where to start the parsing of the "zip" * @param[in] _offset Offset in the file where to start the parsing of the "zip"
*/ */
Zip(const etk::Path& _fileName, uint64_t _offset = 0LL); Zip(const etk::Path& _fileName, uint64_t _offset = 0LL);
/**
* @brief constructor of a zip file access
* @param[in] _uri URI of the file to parse (.zip / .apk)
*/
Zip(const etk::Uri& _uri);
/** /**
* @brief basic destructor * @brief basic destructor
*/ */

View File

@ -13,6 +13,8 @@
#include <etk/typeInfo.hpp> #include <etk/typeInfo.hpp>
#include <etk/Allocator.hpp> #include <etk/Allocator.hpp>
#include <etk/theme/theme.hpp> #include <etk/theme/theme.hpp>
#include <etk/fs/fileSystem.hpp>
#include <etk/uri/provider/provider.hpp>
static int32_t nbTimeInit = 0; static int32_t nbTimeInit = 0;
@ -28,8 +30,9 @@ void etk::unInit() {
nbTimeInit = 0; nbTimeInit = 0;
return; return;
} }
etk::theme::unInit();
TK_INFO("ETK system un-init (BEGIN)"); TK_INFO("ETK system un-init (BEGIN)");
etk::theme::unInit();
etk::uri::provider::unInit();
ETK_MEM_SHOW_LOG(); ETK_MEM_SHOW_LOG();
TK_INFO("ETK system un-init (END)"); TK_INFO("ETK system un-init (END)");
} }
@ -46,13 +49,8 @@ void etk::init(int _argc, const char** _argv) {
} else { } else {
TK_INFO("ETK system init (BEGIN) "); TK_INFO("ETK system init (BEGIN) ");
} }
elog::init(_argc, _argv); elog::init(_argc, _argv, etk::fs::getBinaryName());
#if !defined(__TARGET_OS__Android) and !defined(__TARGET_OS__IOs) etk::uri::provider::init();
// This action is done by the main wrapper...
if (_argc >= 1) {
etk::setArgZero(_argv[0]);
}
#endif
etk::theme::init(); etk::theme::init();
for (int32_t iii=0; iii<_argc ; ++iii) { for (int32_t iii=0; iii<_argc ; ++iii) {
etk::String data = _argv[iii]; etk::String data = _argv[iii];

View File

@ -125,6 +125,14 @@ namespace etk {
* @brief Clear data. * @brief Clear data.
*/ */
void clear(); void clear();
/**
* @brief Check if the path ahave data
* @return true The path is empty
* @return famse The path have some element
*/
bool isEmpty() const {
return m_data.isEmpty();
}
/** /**
* @brief Check if the 2 Path are identical. * @brief Check if the 2 Path are identical.
* @param[in] _obj Path to compare. * @param[in] _obj Path to compare.

View File

@ -407,14 +407,33 @@ etk::Path etk::fs::getBinaryPath() {
return out; return out;
} }
etk::Path etk::fs::getBinaryName() { etk::String etk::fs::getBinaryName() {
return getBinaryPath().getFileName(); return getBinaryPath().getFileName();
} }
#if 0
etk::Path etk::fs::getDataPath() { etk::Path etk::fs::getDataPath() {
#if defined(__TARGET_OS__Web)
return "zz_generic_zz";
#elif defined(__TARGET_OS__Android)
return "assets";
#elif defined(__TARGET_OS__Linux)
etk::Path dataPath = etk::Path("/usr/share") / getBinaryName();
etk::Path theoricInstalledName = etk::Path("/usr/bin") / getBinaryName();
TK_DEBUG(" position : '" << getBinaryPath() << "' installed position : '" << theoricInstalledName << "'");
if (getBinaryPath() != theoricInstalledName) {
dataPath = getBinaryPath().getParent() / ".." / "share" / getBinaryName();
}
return dataPath;
#elif defined(__TARGET_OS__Windows)
return getBinaryPath().getParent() / "data";
#elif defined(__TARGET_OS__MacOs)
return getBinaryPath().getParent() / ".." / "Resources" / getBinaryName();
#elif defined(__TARGET_OS__IOs)
return getBinaryPath().getParent() / "share" / getBinaryName();
#endif
return "NO_DATA_PATH";
} }
#endif
uint64_t etk::fs::getCreateTime(const etk::Path& _path) { uint64_t etk::fs::getCreateTime(const etk::Path& _path) {
struct stat statProperty; struct stat statProperty;
if (-1 == stat(_path.getNative().c_str(), &statProperty)) { if (-1 == stat(_path.getNative().c_str(), &statProperty)) {

View File

@ -212,19 +212,17 @@ namespace etk {
* @brief Current binary name. * @brief Current binary name.
* @return executable name. * @return executable name.
*/ */
etk::Path getBinaryName(); etk::String getBinaryName();
/** /**
* @brief Full banary name (with root path). * @brief Full banary name (with root path).
* @return the binary absolute path. * @return the binary absolute path.
*/ */
etk::Path getBinaryPath(); etk::Path getBinaryPath();
#if 0 /**
/** * @brief Get the data path of the application.
* @brief Get the data path of the application. * @return the root path of the data for this application.
* @return the root path of the data for this application. */
*/ etk::Path getDataPath();
etk::Path getDataPath();
#endif
/** /**
* @brief Get the creation time of the path. * @brief Get the creation time of the path.
* @param[in] _path Path of the requested information. * @param[in] _path Path of the requested information.

View File

View File

@ -1,26 +0,0 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include <etk/types.hpp>
#include <etk/fs/Type.hpp>
#include <etk/String.hpp>
#include <etk/Map.hpp>
#include <etk/uri/Query.hpp>
#include <etk/fs/Path.hpp>
namespace etk {
namespace uri {
class IoProviderInterface : public ememory::EnableSharedFromThis<IoProvider> {
public:
};
void addProvider(const etk::String& _scheme, ememory::SharedPtr<IoProviderInterface> _interface);
void removeProvider(const etk::String& _scheme);
ememory::SharedPtr<etk::io::Interface> provideIO(const etk::uri::Uri& _uri);
}
}

View File

@ -147,4 +147,20 @@ etk::Stream& etk::operator <<(etk::Stream& _os, const etk::uri::Query& _obj) {
bool etk::uri::Query::isEmpty() const { bool etk::uri::Query::isEmpty() const {
return m_data.size() == 0; return m_data.size() == 0;
} }
bool etk::uri::Query::operator== (const etk::uri::Query& _obj) const {
return getEncoded() == _obj.getEncoded();
}
bool etk::uri::Query::operator!= (const etk::uri::Query& _obj) const {
return getEncoded() != _obj.getEncoded();
}
bool etk::uri::Query::operator< (const etk::uri::Query& _obj) const {
return getEncoded() < _obj.getEncoded();
}
bool etk::uri::Query::operator> (const etk::uri::Query& _obj) const {
return getEncoded() > _obj.getEncoded();
}

View File

@ -78,6 +78,30 @@ namespace etk {
* @return true The querry have no data. false Otherwise * @return true The querry have no data. false Otherwise
*/ */
bool isEmpty() const; bool isEmpty() const;
/**
* @brief Check if the 2 Query are identical.
* @param[in] _obj Query to compare.
* @return true : same Query, false otherwise.
*/
bool operator== (const etk::uri::Query& _obj) const;
/**
* @brief Check if the 2 Query are different.
* @param[in] _obj Query to compare.
* @return false : same query, true otherwise.
*/
bool operator!= (const etk::uri::Query& _obj) const;
/**
* @brief check if this elemnt is greater than the other.
* @param[in] _obj Query to compare.
* @return true : less Query, false otherwise.
*/
bool operator< (const etk::uri::Query& _obj) const;
/**
* @brief Check if this elemnt is greater than the other.
* @param[in] _obj Query to compare.
* @return false : Greater Query, true otherwise.
*/
bool operator> (const etk::uri::Query& _obj) const;
}; };
} }
//! @not_in_doc //! @not_in_doc

View File

@ -15,10 +15,19 @@ etk::Uri::Uri(const etk::String& _value) {
set(_value); set(_value);
} }
etk::Uri::Uri(const etk::Path& _value) {
m_path = _value;
}
etk::Uri::Uri(const char * _value) { etk::Uri::Uri(const char * _value) {
set(_value); set(_value);
} }
etk::Stream& etk::operator <<(etk::Stream& _os, const etk::Uri& _obj) {
_os << _obj.get();
return _os;
}
void etk::Uri::set(const char * _value) { void etk::Uri::set(const char * _value) {
set(etk::String(_value)); set(etk::String(_value));
} }
@ -34,6 +43,58 @@ void etk::Uri::clear() {
m_fragment.clear(); m_fragment.clear();
} }
bool etk::Uri::isEmpty() const {
return m_scheme.isEmpty() == true
&& m_user.isEmpty() == true
&& m_password.isEmpty() == true
&& m_server.isEmpty() == true
&& m_port == 0
&& m_path.isEmpty() == true
&& m_query.isEmpty() == true
&& m_fragment.isEmpty() == true;
}
bool etk::Uri::operator== (const etk::Uri& _obj) const {
return m_scheme == _obj.m_scheme
&& m_user == _obj.m_user
&& m_password == _obj.m_password
&& m_server == _obj.m_server
&& m_port == _obj.m_port
&& m_path == _obj.m_path
&& m_query == _obj.m_query
&& m_fragment == _obj.m_fragment;
}
bool etk::Uri::operator!= (const etk::Uri& _obj) const {
return m_scheme != _obj.m_scheme
|| m_user != _obj.m_user
|| m_password != _obj.m_password
|| m_server != _obj.m_server
|| m_port != _obj.m_port
|| m_path != _obj.m_path
|| m_query != _obj.m_query
|| m_fragment != _obj.m_fragment;
}
bool etk::Uri::operator< (const etk::Uri& _obj) const {
return m_scheme < _obj.m_scheme
&& m_user < _obj.m_user
&& m_password < _obj.m_password
&& m_server < _obj.m_server
&& m_port < _obj.m_port
&& m_path < _obj.m_path
&& m_query < _obj.m_query
&& m_fragment < _obj.m_fragment;
}
bool etk::Uri::operator> (const etk::Uri& _obj) const {
return m_scheme > _obj.m_scheme
&& m_user > _obj.m_user
&& m_password > _obj.m_password
&& m_server > _obj.m_server
&& m_port > _obj.m_port
&& m_path > _obj.m_path
&& m_query > _obj.m_query
&& m_fragment > _obj.m_fragment;
}
void etk::Uri::set(etk::String _value) { void etk::Uri::set(etk::String _value) {
TK_VERBOSE("parse: '" << _value << "'"); TK_VERBOSE("parse: '" << _value << "'");
size_t pos = _value.find("://"); size_t pos = _value.find("://");
@ -92,7 +153,7 @@ void etk::Uri::set(etk::String _value) {
TK_VERBOSE("find server / port : '" << m_server << "' / '" << m_port << "'"); TK_VERBOSE("find server / port : '" << m_server << "' / '" << m_port << "'");
} }
etk::String etk::Uri::get() { etk::String etk::Uri::get() const {
etk::String out; etk::String out;
if (m_scheme != "") { if (m_scheme != "") {
out += m_scheme; out += m_scheme;

View File

@ -39,6 +39,11 @@ namespace etk {
* @param[in] _value Element basic URI * @param[in] _value Element basic URI
*/ */
Uri(const etk::String& _value); Uri(const etk::String& _value);
/**
* @brief Contructor with basic URI with a generic path.
* @param[in] _value generic path
*/
Uri(const etk::Path& _value);
/** /**
* @brief Contructor with basic URI. * @brief Contructor with basic URI.
* @param[in] _value Element basic URI * @param[in] _value Element basic URI
@ -58,7 +63,7 @@ namespace etk {
* @brief generate the URI string. * @brief generate the URI string.
* @return the uri correctly encoded * @return the uri correctly encoded
*/ */
etk::String get(); etk::String get() const;
/** /**
* @brief Get the scheme of the URI. * @brief Get the scheme of the URI.
* @return Scheme value. * @return Scheme value.
@ -143,6 +148,38 @@ namespace etk {
* @brief Clear the structure. * @brief Clear the structure.
*/ */
void clear(); void clear();
/**
* @brief Check if the uri ahave data
* @return true The uri is empty
* @return famse The uri have some element
*/
bool isEmpty() const;
/**
* @brief Check if the 2 Uri are identical.
* @param[in] _obj Uri to compare.
* @return true : same Uri, false otherwise.
*/
bool operator== (const etk::Uri& _obj) const;
/**
* @brief Check if the 2 Uri are different.
* @param[in] _obj Uri to compare.
* @return false : same Uri, true otherwise.
*/
bool operator!= (const etk::Uri& _obj) const;
/**
* @brief check if this elemnt is greater than the other.
* @param[in] _obj Uri to compare.
* @return true : less Uri, false otherwise.
*/
bool operator< (const etk::Uri& _obj) const;
/**
* @brief Check if this elemnt is greater than the other.
* @param[in] _obj Uri to compare.
* @return false : Greater Uri, true otherwise.
*/
bool operator> (const etk::Uri& _obj) const;
}; };
//! @not_in_doc
etk::Stream& operator <<(etk::Stream& _os, const etk::Uri& _obj);
} }

View File

@ -0,0 +1,31 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include <etk/types.hpp>
#include <etk/uri/Uri.hpp>
#include <etk/io/Interface.hpp>
#include <ememory/SharedPtr.hpp>
namespace etk {
namespace uri {
namespace provider {
class Interface : public ememory::EnableSharedFromThis<Interface> {
public:
/**
* @brief Virtualize detructor:
*/
virtual ~Interface() = default;
public:
virtual ememory::SharedPtr<etk::io::Interface> create(const etk::Uri& _uri) = 0;
virtual bool exist(const etk::Uri& _uri) = 0;
virtual etk::Vector<etk::Uri> list(const etk::Uri& _uri) = 0;
};
}
}
}

View File

@ -0,0 +1,55 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <etk/uri/provider/ProviderFile.hpp>
#include <etk/io/File.hpp>
#include <etk/fs/fileSystem.hpp>
#include <etk/debug.hpp>
etk::uri::provider::ProviderFile::ProviderFile() {
}
etk::uri::provider::ProviderFile::ProviderFile(const etk::Path& _offset) :
m_offset(_offset) {
}
ememory::SharedPtr<etk::io::Interface> etk::uri::provider::ProviderFile::create(const etk::Uri& _uri) {
if (m_offset.isEmpty() == true) {
return ememory::makeShared<etk::io::File>(_uri.getPath());
}
return ememory::makeShared<etk::io::File>(m_offset / _uri.getPath());
}
bool etk::uri::provider::ProviderFile::exist(const etk::Uri& _uri) {
if (m_offset.isEmpty() == true) {
return etk::fs::exist(_uri.getPath());
}
return etk::fs::exist(m_offset / _uri.getPath());
}
etk::Vector<etk::Uri> etk::uri::provider::ProviderFile::list(const etk::Uri& _uri) {
etk::Vector<etk::Path> tmp;
etk::Vector<etk::Uri> out;
if (m_offset.isEmpty() == true) {
tmp = etk::fs::list(_uri.getPath());
for (auto& elem: tmp) {
etk::Uri newUri = _uri;
newUri.setPath(elem);
out.pushBack(newUri);
}
return out;
}
TK_ERROR("list path: " << m_offset / _uri.getPath());
tmp = etk::fs::list(m_offset / _uri.getPath());
int32_t offset = m_offset.getString().size()+1;
for (auto& elem: tmp) {
etk::Uri newUri = _uri;
newUri.setPath(elem.getString().extract(offset));
out.pushBack(newUri);
}
return out;
}

View File

@ -0,0 +1,27 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include <etk/types.hpp>
#include <etk/uri/provider/provider.hpp>
namespace etk {
namespace uri {
namespace provider {
class ProviderFile : public etk::uri::provider::Interface {
protected:
etk::Path m_offset;
public:
ProviderFile();
ProviderFile(const etk::Path& _offset);
public:
ememory::SharedPtr<etk::io::Interface> create(const etk::Uri& _uri) override;
bool exist(const etk::Uri& _uri) override;
etk::Vector<etk::Uri> list(const etk::Uri& _uri) override;
};
}
}
}

View File

@ -0,0 +1,62 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <etk/uri/provider/ProviderFileZip.hpp>
#include <etk/debug.hpp>
#include <etk/io/ZipFile.hpp>
void etk::uri::provider::ProviderFileZip::loadZipFile(const etk::Uri& _zipFile) {
m_archive = etk::Archive::load(_zipFile);
TK_ASSERT(m_archive != null, "Error loading APK ... '" << _zipFile << "'");
#ifdef DEBUG
//Just for debug, print APK contents
m_archive->display();
#endif
}
etk::uri::provider::ProviderFileZip::ProviderFileZip(const etk::Uri& _zipFile) {
loadZipFile(_zipFile);
}
etk::uri::provider::ProviderFileZip::ProviderFileZip(const etk::Uri& _zipFile, const etk::Path& _offset) :
m_offset(_offset) {
loadZipFile(_zipFile);
}
ememory::SharedPtr<etk::io::Interface> etk::uri::provider::ProviderFileZip::create(const etk::Uri& _uri) {
if (m_offset.isEmpty() == true) {
return ememory::makeShared<etk::io::ZipFile>(_uri.getPath(), m_archive);
}
return ememory::makeShared<etk::io::ZipFile>(m_offset / _uri.getPath(), m_archive);
}
bool etk::uri::provider::ProviderFileZip::exist(const etk::Uri& _uri) {
if (m_offset.isEmpty() == true) {
return m_archive->exist(_uri.getPath());
}
return m_archive->exist(m_offset / _uri.getPath());
}
etk::Vector<etk::Uri> etk::uri::provider::ProviderFileZip::list(const etk::Uri& _uri) {
etk::Vector<etk::Path> tmp;
etk::Vector<etk::Uri> out;
if (m_offset.isEmpty() == true) {
tmp = m_archive->list(_uri.getPath());
for (auto& elem: tmp) {
etk::Uri newUri = _uri;
newUri.setPath(elem);
out.pushBack(newUri);
}
return out;
}
tmp = m_archive->list(m_offset / _uri.getPath());
int32_t offset = m_offset.getString().size()+1;
for (auto& elem: tmp) {
etk::Uri newUri = _uri;
newUri.setPath(elem.getString().extract(offset));
out.pushBack(newUri);
}
return out;
}

View File

@ -0,0 +1,32 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include <etk/types.hpp>
#include <etk/uri/provider/provider.hpp>
#include <etk/archive/Archive.hpp>
#include <ememory/SharedPtr.hpp>
namespace etk {
namespace uri {
namespace provider {
class ProviderFileZip : public etk::uri::provider::Interface {
protected:
ememory::SharedPtr<etk::Archive> m_archive;
etk::Path m_offset;
void loadZipFile(const etk::Uri& _zipFile);
public:
ProviderFileZip(const etk::Uri& _zipFile);
ProviderFileZip(const etk::Uri& _zipFile, const etk::Path& _offset);
public:
ememory::SharedPtr<etk::io::Interface> create(const etk::Uri& _uri) override;
bool exist(const etk::Uri& _uri) override;
etk::Vector<etk::Uri> list(const etk::Uri& _uri) override;
};
}
}
}

View File

@ -0,0 +1,68 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <etk/uri/provider/provider.hpp>
#include <etk/uri/provider/ProviderFile.hpp>
#include <etk/Map.hpp>
#include <etk/io/File.hpp>
static etk::Map<etk::String, ememory::SharedPtr<etk::uri::provider::Interface>>& getProviders() {
static etk::Map<etk::String, ememory::SharedPtr<etk::uri::provider::Interface>> g_data;
return g_data;
}
void etk::uri::provider::add(const etk::String& _scheme, ememory::SharedPtr<etk::uri::provider::Interface> _interface) {
etk::String scheme = _scheme;
if (scheme.empty() == true) {
scheme = "RAW";
}
getProviders().set(scheme, _interface);
}
void etk::uri::provider::clear() {
getProviders().clear();
etk::uri::provider::add("", ememory::makeShared<etk::uri::provider::ProviderFile>());
}
void etk::uri::provider::remove(const etk::String& _scheme) {
getProviders().erase(_scheme);
}
bool etk::uri::provider::exist(const etk::String& _scheme) {
etk::String scheme = _scheme;
if (scheme.empty() == true) {
scheme = "RAW";
}
return getProviders().exist(scheme);
}
ememory::SharedPtr<etk::io::Interface> etk::uri::provider::get(const etk::Uri& _uri) {
etk::String scheme = _uri.getScheme();
if (scheme.empty() == true) {
scheme = "RAW";
}
if (getProviders().exist(scheme) == false) {
return null;
}
return getProviders()[scheme]->create(_uri);
}
ememory::SharedPtr<etk::uri::provider::Interface> etk::uri::provider::getProvider(const etk::String& _scheme) {
etk::String scheme = _scheme;
if (scheme.empty() == true) {
scheme = "RAW";
}
if (getProviders().exist(scheme) == false) {
return null;
}
return getProviders()[scheme];
}
void etk::uri::provider::init() {
etk::uri::provider::clear();
}
void etk::uri::provider::unInit() {
getProviders().clear();
}

View File

@ -0,0 +1,65 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#pragma once
#include <etk/types.hpp>
#include <etk/fs/Type.hpp>
#include <etk/String.hpp>
#include <etk/Map.hpp>
#include <etk/uri/Query.hpp>
#include <etk/fs/Path.hpp>
#include <etk/io/Interface.hpp>
#include <etk/uri/provider/Interface.hpp>
#include <ememory/SharedPtr.hpp>
#include <ememory/memory.hpp>
namespace etk {
namespace uri {
namespace provider {
/**
* @brief Add a IO interface provider ==> permit to have simple whangable backend interface.
* @param[in] _scheme URI scheme specific interface (like 'http' for 'http://' or 'RAW' for no scheme or "data" for 'data://')
* @param[in] _interface Provider interface
*/
void add(const etk::String& _scheme, ememory::SharedPtr<etk::uri::provider::Interface> _interface);
/**
* @brief Add a IO interface provider ==> permit to have simple whangable backend interface.
* @param[in] _scheme URI scheme specific interface
*/
void remove(const etk::String& _scheme);
/**
* @brief Check if a provider exist.
* @param[in] _scheme URI scheme specific interface
* @return true The provider is availlable
*/
bool exist(const etk::String& _scheme);
/**
* @brief Clear all providers
*/
void clear();
/**
* @brief Get an IO interface with a specific URI
* @param[in] _uri Data interface requested
* @return The interface requested.
*/
ememory::SharedPtr<etk::io::Interface> get(const etk::Uri& _uri);
/**
* @brief Get an URI provider
* @param[in] _scheme type of provider
* @return The interface requested.
*/
ememory::SharedPtr<etk::uri::provider::Interface> getProvider(const etk::String& _scheme);
/**
* @brief Initialize uri provider
*/
void init();
/**
* @brief Un-Initialize uri provider
*/
void unInit();
}
}
}

View File

@ -33,6 +33,7 @@ def configure(target, my_module):
'test/testTheme.cpp', 'test/testTheme.cpp',
'test/testUri.cpp', 'test/testUri.cpp',
'test/testQuery.cpp', 'test/testQuery.cpp',
'test/testUriProvider.cpp',
]) ])
""" """
'test/ConstructDestruct.cpp', 'test/ConstructDestruct.cpp',
@ -63,5 +64,9 @@ def configure(target, my_module):
'test-debug' 'test-debug'
]) ])
my_module.copy_path('data/*') my_module.copy_path('data/*')
my_module.copy_path('data/data/*', 'data')
my_module.copy_path('data/data/dir_A/*', 'data/dir_A')
my_module.copy_path('data/data/dir_B/*', 'data/dir_B')
my_module.copy_path('data/data/dir_B/dir_C/*', 'data/dir_B/dir_C')
return True return True

View File

@ -59,6 +59,9 @@ def configure(target, my_module):
'etk/archive/Zip.cpp', 'etk/archive/Zip.cpp',
'etk/uri/Uri.cpp', 'etk/uri/Uri.cpp',
'etk/uri/Query.cpp', 'etk/uri/Query.cpp',
'etk/uri/provider/provider.cpp',
'etk/uri/provider/ProviderFile.cpp',
'etk/uri/provider/ProviderFileZip.cpp',
]) ])
my_module.add_header_file([ my_module.add_header_file([
@ -96,6 +99,10 @@ def configure(target, my_module):
'etk/FlatTree.hpp', 'etk/FlatTree.hpp',
'etk/uri/Uri.hpp', 'etk/uri/Uri.hpp',
'etk/uri/Query.hpp', 'etk/uri/Query.hpp',
'etk/uri/provider/provider.hpp',
'etk/uri/provider/Interface.hpp',
'etk/uri/provider/ProviderFile.hpp',
'etk/uri/provider/ProviderFileZip.hpp',
]) ])
# build in C++ mode # build in C++ mode
@ -112,7 +119,7 @@ def configure(target, my_module):
my_module.add_depend(['cxx']) my_module.add_depend(['cxx'])
# add some optionnal libraries # add some optionnal libraries
my_module.add_optionnal_depend('minizip', ["c++", "-DETK_BUILD_MINIZIP"]) my_module.add_optionnal_depend('minizip', ["c++", "-DETK_BUILD_MINIZIP"], export=True)
my_module.add_optionnal_depend('linearmath', ["c", "-DETK_BUILD_LINEARMATH"], export=True) my_module.add_optionnal_depend('linearmath', ["c", "-DETK_BUILD_LINEARMATH"], export=True)
if "Android" in target.get_type(): if "Android" in target.get_type():

View File

@ -17,7 +17,11 @@
int main(int argc, const char *argv[]) { int main(int argc, const char *argv[]) {
// init test engine: // init test engine:
etk::init(argc, argv);
etest::init(argc, argv); etest::init(argc, argv);
TEST_INFO("TEST ETK"); TEST_INFO("TEST ETK");
return RUN_ALL_TESTS(); int out = RUN_ALL_TESTS();
etest::unInit();
etk::unInit();
return out;
} }

View File

@ -151,6 +151,20 @@ TEST(TestUri, base_9) {
} }
TEST(TestUri, base_10) { TEST(TestUri, base_10) {
etk::String value = "__SCHEME__:////__PATH__?__QUERY__";
etk::Uri uri(value);
EXPECT_EQ(uri.get(), value);
EXPECT_EQ(uri.getScheme(), "__SCHEME__");
EXPECT_EQ(uri.getUser(), "");
EXPECT_EQ(uri.getPassword(), "");
EXPECT_EQ(uri.getServer(), "");
EXPECT_EQ(uri.getPort(), 0);
EXPECT_EQ(uri.getPath(), etk::Path("/__PATH__"));
EXPECT_EQ(uri.getQuery().getEncoded(), "__QUERY__");
EXPECT_EQ(uri.getFragment(), "");
}
TEST(TestUri, base_10_2) {
etk::String value = "__SCHEME__:///__PATH__?__QUERY__"; etk::String value = "__SCHEME__:///__PATH__?__QUERY__";
etk::Uri uri(value); etk::Uri uri(value);
EXPECT_EQ(uri.get(), value); EXPECT_EQ(uri.get(), value);
@ -163,3 +177,35 @@ TEST(TestUri, base_10) {
EXPECT_EQ(uri.getQuery().getEncoded(), "__QUERY__"); EXPECT_EQ(uri.getQuery().getEncoded(), "__QUERY__");
EXPECT_EQ(uri.getFragment(), ""); EXPECT_EQ(uri.getFragment(), "");
} }
TEST(TestUri, base_11_1) {
etk::String value = "//hello/txt";
etk::Path valuePath = "/hello/txt";
etk::Uri uri(valuePath);
EXPECT_EQ(uri.get(), value);
EXPECT_EQ(uri.getScheme(), "");
EXPECT_EQ(uri.getUser(), "");
EXPECT_EQ(uri.getPassword(), "");
EXPECT_EQ(uri.getServer(), "");
EXPECT_EQ(uri.getPort(), 0);
EXPECT_EQ(uri.getPath(), valuePath);
EXPECT_EQ(uri.getQuery().getEncoded(), "");
EXPECT_EQ(uri.getFragment(), "");
}
TEST(TestUri, base_11_2) {
etk::String value = "/hello/txt";
etk::Path valuePath = "hello/txt";
etk::Uri uri(valuePath);
EXPECT_EQ(uri.get(), value);
EXPECT_EQ(uri.getScheme(), "");
EXPECT_EQ(uri.getUser(), "");
EXPECT_EQ(uri.getPassword(), "");
EXPECT_EQ(uri.getServer(), "");
EXPECT_EQ(uri.getPort(), 0);
EXPECT_EQ(uri.getPath(), valuePath);
EXPECT_EQ(uri.getQuery().getEncoded(), "");
EXPECT_EQ(uri.getFragment(), "");
}
// "audio://alsa/front?mode=I16"

238
test/testUriProvider.cpp Normal file
View File

@ -0,0 +1,238 @@
/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license MPL v2.0 (see license file)
*/
#include <etest/etest.hpp>
#include <test-debug/debug.hpp>
#include <etk/uri/Uri.hpp>
#include <etk/uri/provider/provider.hpp>
#include <etk/uri/provider/ProviderFile.hpp>
#include <etk/uri/provider/ProviderFileZip.hpp>
#include <etk/fs/fileSystem.hpp>
TEST(TestUriProvider, defaultContructor) {
etk::uri::provider::clear();
EXPECT_EQ(etk::uri::provider::exist(""), true);
}
static int32_t s_plouf = 0;
namespace {
class ProviderTest1 : public etk::uri::provider::Interface {
public:
ememory::SharedPtr<etk::io::Interface> create(const etk::Uri& _uri) override {
s_plouf = 5555;
return null;
}
bool exist(const etk::Uri& _uri) override {
return false;
}
etk::Vector<etk::Uri> list(const etk::Uri& _uri) override {
etk::Vector<etk::Uri> out;
return out;
}
};
class ProviderTest2 : public etk::uri::provider::Interface {
public:
ememory::SharedPtr<etk::io::Interface> create(const etk::Uri& _uri) override {
s_plouf = 9999;
return null;
}
bool exist(const etk::Uri& _uri) override {
return false;
}
etk::Vector<etk::Uri> list(const etk::Uri& _uri) override {
etk::Vector<etk::Uri> out;
return out;
}
};
}
TEST(TestUriProvider, checkPlouf) {
etk::uri::provider::clear();
s_plouf = 0;
EXPECT_EQ(etk::uri::provider::exist(""), true);
EXPECT_EQ(etk::uri::provider::exist("RAW"), true);
EXPECT_EQ(etk::uri::provider::exist("PLOUF_1"), false);
EXPECT_EQ(etk::uri::provider::exist("PLOUF_2"), false);
etk::uri::provider::add("PLOUF_1", ememory::makeShared<::ProviderTest1>());
EXPECT_EQ(etk::uri::provider::exist(""), true);
EXPECT_EQ(etk::uri::provider::exist("PLOUF_1"), true);
EXPECT_EQ(etk::uri::provider::exist("PLOUF_2"), false);
etk::uri::provider::add("PLOUF_2", ememory::makeShared<::ProviderTest2>());
EXPECT_EQ(etk::uri::provider::exist(""), true);
EXPECT_EQ(etk::uri::provider::exist("PLOUF_1"), true);
EXPECT_EQ(etk::uri::provider::exist("PLOUF_2"), true);
EXPECT_EQ(s_plouf, 0);
etk::uri::provider::get("PLOUF_1:///qsdfqsdfqsdfqsdf.txt");
EXPECT_EQ(s_plouf, 5555);
etk::uri::provider::get("PLOUF_2:///qsdfqsdfqsdfqsdf.txt");
EXPECT_EQ(s_plouf, 9999);
etk::uri::provider::remove("PLOUF_1");
EXPECT_EQ(etk::uri::provider::exist(""), true);
EXPECT_EQ(etk::uri::provider::exist("PLOUF_1"), false);
EXPECT_EQ(etk::uri::provider::exist("PLOUF_2"), true);
etk::uri::provider::remove("PLOUF_2");
EXPECT_EQ(etk::uri::provider::exist(""), true);
EXPECT_EQ(etk::uri::provider::exist("PLOUF_1"), false);
EXPECT_EQ(etk::uri::provider::exist("PLOUF_2"), false);
}
etk::Vector<etk::Uri> listDirect = {
"DATA:///filePresent.txt",
"DATA:///fileEmpty.txt",
"DATA:///data",
"DATA:///data_sample.zip",
};
/* This function takes last element as pivot, places
the pivot element at its correct position in sorted
array, and places all smaller (smaller than pivot)
to left of pivot and all greater elements to right
of pivot */
int_t partition (etk::Vector<etk::Uri>& _data, int _low, int _high) {
int_t iii = (_low - 1); // Index of smaller element
for (int_t jjj = _low; jjj < _high; ++jjj) {
// If current element is smaller than or equal to pivot
if (_data[jjj] < _data[_high]) {
iii++; // increment index of smaller element
etk::swap(_data[iii], _data[jjj]);
}
}
etk::swap(_data[iii + 1], _data[_high]);
return (iii + 1);
}
/* The main function that implements QuickSort
arr[] --> Array to be sorted,
low --> Starting index,
high --> Ending index */
void quickSort(etk::Vector<etk::Uri>& _data, int _low, int _high) {
if (_low >= _high) {
return;
}
// pi is partitioning index, arr[p] is now at right place
int_t pi = partition(_data, _low, _high);
// Separately sort elements before partition and after partition
quickSort(_data, _low, pi - 1);
quickSort(_data, pi + 1, _high);
}
TEST(TestUriProvider, checkDirectAccess) {
etk::uri::provider::clear();
TEST_VERBOSE("data path: " << etk::fs::getDataPath());
etk::uri::provider::add("DATA", ememory::makeShared<etk::uri::provider::ProviderFile>(etk::fs::getDataPath()));
EXPECT_EQ(etk::uri::provider::exist("DATA"), true);
ememory::SharedPtr<etk::uri::provider::Interface> provider = etk::uri::provider::getProvider("DATA");
EXPECT_NE(provider, null);
etk::Uri searchBase("DATA:///");
auto elems = provider->list(searchBase);
TEST_WARNING("List DATA path: (A)");
for (auto& it: elems) {
TEST_WARNING(" " << it);
}
elems.sort(0, elems.size(), [] (const etk::Uri& _left, const etk::Uri& _right) {
TEST_WARNING("compare " << _left << " " << (_left < _right?"<":">=") << " " << _right);
return _left < _right;
});
TEST_WARNING("List DATA path: (B)");
for (auto& it: elems) {
TEST_WARNING(" " << it);
}
quickSort(elems, 0, elems.size()-1);
TEST_WARNING("List DATA path: (C)");
for (auto& it: elems) {
TEST_WARNING(" " << it);
}
EXPECT_EQ(elems, listDirect);
}
etk::Vector<etk::Uri> listDirect2 = {
"DATA:///data/.file_hidden.txt",
"DATA:///data/dir_A",
"DATA:///data/dir_B",
"DATA:///data/file_1.txt",
"DATA:///data/file_2.txt",
"DATA:///data/file_3.txt"
};
TEST(TestUriProvider, checkDirectAccess2) {
etk::uri::provider::clear();
TEST_VERBOSE("data path: " << etk::fs::getDataPath());
etk::uri::provider::add("DATA", ememory::makeShared<etk::uri::provider::ProviderFile>(etk::fs::getDataPath()));
EXPECT_EQ(etk::uri::provider::exist("DATA"), true);
ememory::SharedPtr<etk::uri::provider::Interface> provider = etk::uri::provider::getProvider("DATA");
EXPECT_NE(provider, null);
etk::Uri searchBase("DATA:///data");
auto elems = provider->list(searchBase);
TEST_WARNING("List DATA path: (A)");
for (auto& it: elems) {
TEST_WARNING(" " << it);
}
elems.sort(0, elems.size(), [] (const etk::Uri& _left, const etk::Uri& _right) {
return _left < _right;
});
TEST_WARNING("List DATA path: (B)");
for (auto& it: elems) {
TEST_WARNING(" " << it);
}
EXPECT_EQ(elems, listDirect2);
}
etk::Vector<etk::Uri> listZip = {
"DATA:///.file_hidden.txt",
"DATA:///dir_A",
"DATA:///dir_B",
"DATA:///file_1.txt",
"DATA:///file_2.txt",
"DATA:///file_3.txt"
};
TEST(TestUriProvider, checkZipAccess) {
etk::uri::provider::clear();
TEST_VERBOSE("data path: " << etk::fs::getDataPath());
etk::uri::provider::add("DATA", ememory::makeShared<etk::uri::provider::ProviderFileZip>(etk::fs::getDataPath() / "data_sample.zip", "data"));
EXPECT_EQ(etk::uri::provider::exist("DATA"), true);
ememory::SharedPtr<etk::uri::provider::Interface> provider = etk::uri::provider::getProvider("DATA");
EXPECT_NE(provider, null);
TEST_WARNING("List DATA path:");
etk::Uri searchBase("DATA://");
auto elems = provider->list(searchBase);
for (auto& it: elems) {
TEST_WARNING(" " << it);
}
EXPECT_EQ(elems, listZip);
}
etk::Vector<etk::Uri> listZip2 = {
"DATA:///dir_B/dir_C",
"DATA:///dir_B/file_B_1.txt",
"DATA:///dir_B/file_B_2.txt",
};
TEST(TestUriProvider, checkZipAccess2) {
etk::uri::provider::clear();
TEST_VERBOSE("data path: " << etk::fs::getDataPath());
etk::uri::provider::add("DATA", ememory::makeShared<etk::uri::provider::ProviderFileZip>(etk::fs::getDataPath() / "data_sample.zip", "data"));
EXPECT_EQ(etk::uri::provider::exist("DATA"), true);
ememory::SharedPtr<etk::uri::provider::Interface> provider = etk::uri::provider::getProvider("DATA");
EXPECT_NE(provider, null);
TEST_WARNING("List DATA path:");
etk::Uri searchBase("DATA:///dir_B");
auto elems = provider->list(searchBase);
for (auto& it: elems) {
TEST_WARNING(" " << it);
}
EXPECT_EQ(elems, listZip2);
}