diff --git a/CMakeLists.txt b/CMakeLists.txt index d0d973c..cd1d4d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,13 +11,14 @@ set(CMAKE_CXX_VISIBILITY_PRESET hidden) option(BUILD_SHARED_LIBS "Build using shared libraries" ON) add_library(XISF + bytearray.cpp + bytearray.h libXISF_global.h libxisf.cpp libxisf.h utils.cpp - utils.h - propertyvariant.cpp - propertyvariant.h + variant.cpp + variant.h lz4/lz4.c lz4/lz4.h lz4/lz4hc.c diff --git a/bytearray.cpp b/bytearray.cpp new file mode 100644 index 0000000..4b909fc --- /dev/null +++ b/bytearray.cpp @@ -0,0 +1,162 @@ +#include "libxisf.h" + +namespace LibXISF +{ + +void ByteArray::makeUnique() +{ + if(!_data.unique()) + _data = std::make_unique(_data->begin(), _data->end()); +} + +ByteArray::ByteArray(size_t size) +{ + _data = std::make_shared>(); + _data->resize(size); +} + +ByteArray::ByteArray(const char *ptr) : ByteArray((size_t)0) +{ + size_t len = std::strlen(ptr); + if(len) + { + _data->resize(len); + std::memcpy(data(), ptr, len); + } +} + +ByteArray::ByteArray(const ByteArray &d) +{ + _data = d._data; +} + +char& ByteArray::operator[](size_t i) +{ + makeUnique(); + return (*_data)[i]; +} + +const char& ByteArray::operator[](size_t i) const +{ + return (*_data)[i]; +} + +size_t ByteArray::size() const +{ + return _data->size(); +} + +void ByteArray::resize(size_t newsize) +{ + makeUnique(); + _data->resize(newsize); +} + +void ByteArray::append(char c) +{ + _data->push_back(c); +} + +void ByteArray::decodeBase64() +{ + int i = 0; + Ptr tmp = std::make_unique(); + + uint8_t c4[4] = {0}; + for(uint8_t c : *_data) + { + if(c >= 'A' && c <= 'Z')c4[i++] = c - 'A'; + else if(c >= 'a' && c <= 'z')c4[i++] = c - 'a' + 26; + else if(c >= '0' && c <= '9')c4[i++] = c - '0' + 52; + else if(c == '+')c4[i++] = 62; + else if(c == '/')c4[i++] = 63; + + if(i == 4) + { + tmp->push_back((c4[0] << 2) | (c4[1] >> 4)); + tmp->push_back((c4[1] << 4) | (c4[2] >> 2)); + tmp->push_back((c4[2] << 6) | c4[3]); + i = 0; + } + } + + if(i > 1)tmp->push_back((c4[0] << 2) | (c4[1] >> 4)); + if(i > 2)tmp->push_back((c4[1] << 4) | (c4[2] >> 2)); + + std::swap(_data, tmp); +} + +void ByteArray::encodeBase64() +{ + static const char *base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + Ptr tmp = std::make_unique(); + int i = 0; + uint8_t sextet[4] = {0}; + for(uint8_t c : *_data) + { + switch(i) + { + case 0: + sextet[0] |= c >> 2 & 0x3f; + sextet[1] |= c << 4 & 0x3f; + i++; + break; + case 1: + sextet[1] |= c >> 4 & 0x3f; + sextet[2] |= c << 2 & 0x3f; + i++; + break; + case 2: + sextet[2] |= c >> 6 & 0x3f; + sextet[3] = c & 0x3f; + i = 0; + for(int o=0; o<4; o++) + tmp->push_back(base64[sextet[o]]); + std::memset(sextet, 0, sizeof(sextet)); + break; + } + } + for(int o = 0; o <= i && i; o++) + tmp->push_back(base64[sextet[o]]); + + if(tmp->size() % 4) + tmp->resize(tmp->size() + 4 - (tmp->size() % 4), '='); + std::swap(_data, tmp); +} + + +void ByteArray::encodeHex() +{ + static const char *hex = "0123456789abcdef"; + Ptr tmp = std::make_unique(_data->size() * 2); + for(size_t i = 0; i< _data->size(); i++) + { + uint8_t t = static_cast(_data->at(i)); + (*tmp)[2*i + 0] = hex[(t & 0xf0) >> 4]; + (*tmp)[2*i + 1] = hex[t & 0xf]; + } + std::swap(_data, tmp); +} + +void ByteArray::decodeHex() +{ + auto toByte = [](char c) -> char + { + if(c >= '0' && c <= '9') + return c - '0'; + if(c >= 'A' && c <= 'F') + return c - '7'; + if(c >= 'a' && c <= 'f') + return c - 'W'; + return 0; + }; + + Ptr tmp = std::make_unique(size() / 2); + for(size_t i = 0; i< tmp->size(); i++) + { + (*tmp)[i] = (toByte(_data->at(i*2)) << 4) | toByte(_data->at(i*2+1)); + } + std::swap(_data, tmp); +} + +} diff --git a/utils.h b/bytearray.h similarity index 88% rename from utils.h rename to bytearray.h index 53a945c..92bfb50 100644 --- a/utils.h +++ b/bytearray.h @@ -16,12 +16,14 @@ * along with this program. If not, see .* ************************************************************************/ -#ifndef UTILS_H -#define UTILS_H +#ifndef LIBXISF_BYTEARRAY_H +#define LIBXISF_BYTEARRAY_H -#include -#include +namespace LibXISF +{ -std::vector split_string(const std::string &str, char delimiter); -#endif // UTILS_H + +} + +#endif // LIBXISF_BYTEARRAY_H diff --git a/libxisf.cpp b/libxisf.cpp index 64cf60d..d35ef03 100644 --- a/libxisf.cpp +++ b/libxisf.cpp @@ -27,11 +27,11 @@ #include "lz4/lz4hc.h" #include "pugixml/pugixml.hpp" #include "zlib/zlib.h" -#include "utils.h" namespace LibXISF { +std::vector splitString(const std::string &str, char delimiter); void deserializeVariant(const pugi::xml_node &node, Variant &variant, const ByteArray &data); void serializeVariant(pugi::xml_node &node, const Variant &variant); @@ -118,9 +118,9 @@ void DataBlock::decompress(const ByteArray &input, const String &encoding) ByteArray tmp = input; if(encoding == "base64") - tmp.decode_base64(); + tmp.decodeBase64(); else if(encoding == "base16") - tmp.decode_hex(); + tmp.decodeHex(); switch(codec) { @@ -625,7 +625,7 @@ void XISFReaderPrivate::readSignature() void XISFReaderPrivate::parseCompression(const pugi::xml_node &node, DataBlock &dataBlock) { - std::vector compression = split_string(node.attribute("compression").as_string(), ':'); + std::vector compression = splitString(node.attribute("compression").as_string(), ':'); if(compression.size() >= 2) { if(compression[0].find("zlib") == 0) @@ -652,7 +652,7 @@ void XISFReaderPrivate::parseCompression(const pugi::xml_node &node, DataBlock & DataBlock XISFReaderPrivate::parseDataBlock(const pugi::xml_node &node) { DataBlock dataBlock; - std::vector location = split_string(node.attribute("location").as_string(), ':'); + std::vector location = splitString(node.attribute("location").as_string(), ':'); parseCompression(node, dataBlock); @@ -749,14 +749,14 @@ Image XISFReaderPrivate::parseImage(const pugi::xml_node &node) { Image image; - std::vector geometry = split_string(node.attribute("geometry").as_string(), ':'); + std::vector geometry = splitString(node.attribute("geometry").as_string(), ':'); if(geometry.size() != 3)throw Error("We support only 2D images"); image._width = std::stoul(geometry[0]); image._height = std::stoul(geometry[1]); image._channelCount = std::stoul(geometry[2]); if(!image._width || !image._height || !image._channelCount)throw Error("Invalid image geometry"); - std::vector bounds = split_string(node.attribute("bounds").as_string(), ':'); + std::vector bounds = splitString(node.attribute("bounds").as_string(), ':'); if(bounds.size() == 2) { image._bounds.first = std::stod(bounds[0]); @@ -921,7 +921,7 @@ void XISFWriterPrivate::writeImageElement(pugi::xml_node &node, const Image &ima if(image._iccProfile.size()) { ByteArray base64 = image._iccProfile; - base64.decode_base64(); + base64.decodeBase64(); pugi::xml_node icc_node = image_node.append_child("ICCProfile"); icc_node.append_attribute("location").set_value("inline:base64"); icc_node.append_child(pugi::node_pcdata).set_value(base64.data()); diff --git a/libxisf.h b/libxisf.h index e5713a7..5dae177 100644 --- a/libxisf.h +++ b/libxisf.h @@ -25,7 +25,7 @@ #include #include #include -#include "propertyvariant.h" +#include "variant.h" namespace LibXISF { @@ -33,6 +33,37 @@ namespace LibXISF class XISFReaderPrivate; class XISFWriterPrivate; +class LIBXISF_EXPORT ByteArray +{ + using PtrType = std::vector; + using Ptr = std::shared_ptr; + Ptr _data; + void makeUnique(); +public: + ByteArray() : ByteArray((size_t)0) {} + explicit ByteArray(size_t size); + explicit ByteArray(const char *ptr); + ByteArray(const char *ptr, size_t size) + { + _data = std::make_shared>(); + _data->resize(size); + std::memcpy(data(), ptr, size); + } + ByteArray(const ByteArray &d); + char& operator[](size_t i); + const char& operator[](size_t i) const; + char* data() { return &_data->at(0); } + const char* data() const { return &_data->at(0); } + const char* constData() const { return &_data->at(0); } + size_t size() const; + void resize(size_t newsize); + void append(char c); + void decodeBase64(); + void encodeBase64(); + void encodeHex(); + void decodeHex(); +}; + struct LIBXISF_EXPORT DataBlock { enum CompressionCodec diff --git a/utils.cpp b/utils.cpp index c0f023c..e071328 100644 --- a/utils.cpp +++ b/utils.cpp @@ -16,9 +16,14 @@ * along with this program. If not, see .* ************************************************************************/ -#include "utils.h" +#include +#include +#include -std::vector split_string(const std::string &str, char delimiter) +namespace LibXISF +{ + +std::vector splitString(const std::string &str, char delimiter) { std::vector ret; size_t cur = 0; @@ -122,3 +127,5 @@ void sha1(uint8_t *data, size_t len, uint8_t *hash) hash[12] = h3 >> 24 & 0xff; hash[13] = h3 >> 16 & 0xff; hash[14] = h3 >> 8 & 0xff; hash[15] = h3 & 0xff; hash[16] = h4 >> 24 & 0xff; hash[17] = h4 >> 16 & 0xff; hash[18] = h4 >> 8 & 0xff; hash[19] = h4 & 0xff; } + +} diff --git a/propertyvariant.cpp b/variant.cpp similarity index 75% rename from propertyvariant.cpp rename to variant.cpp index 9ba645b..9a3b967 100644 --- a/propertyvariant.cpp +++ b/variant.cpp @@ -16,20 +16,15 @@ * along with this program. If not, see .* ************************************************************************/ -#include "propertyvariant.h" +#include "variant.h" #include #include -#include #include -#include #include #include #include "libxisf.h" #include "pugixml/pugixml.hpp" -template struct overload : Ts... { bool fail = true; using Ts::operator()...; }; -template overload(Ts...) -> overload; - namespace LibXISF { @@ -180,7 +175,7 @@ void toCharsVector(const Variant &v, size_t &len, ByteArray &data) size_t size = len * sizeof(typename T::value_type); data.resize(size); std::memcpy(data.data(), &v.value()[0], size); - data.encode_base64(); + data.encodeBase64(); } template @@ -191,7 +186,7 @@ void toCharsMatrix(const Variant &v, size_t &rows, size_t &cols, ByteArray &data size_t size = rows * cols * sizeof(typename T::value_type); data.resize(size); std::memcpy(data.data(), &v.value()(0, 0), size); - data.encode_base64(); + data.encodeBase64(); } void deserializeVariant(const pugi::xml_node &node, Variant &variant, const ByteArray &data) @@ -378,243 +373,6 @@ void serializeVariant(pugi::xml_node &node, const Variant &variant) } } -void ByteArray::makeUnique() -{ - if(!_data.unique()) - _data = std::make_unique(_data->begin(), _data->end()); -} - -ByteArray::ByteArray(size_t size) -{ - _data = std::make_shared>(); - _data->resize(size); -} - -ByteArray::ByteArray(const char *ptr) : ByteArray((size_t)0) -{ - size_t len = std::strlen(ptr); - if(len) - { - _data->resize(len); - std::memcpy(data(), ptr, len); - } -} - -ByteArray::ByteArray(const ByteArray &d) -{ - _data = d._data; -} - -char& ByteArray::operator[](size_t i) -{ - makeUnique(); - return (*_data)[i]; -} - -const char& ByteArray::operator[](size_t i) const -{ - return (*_data)[i]; -} - -size_t ByteArray::size() const -{ - return _data->size(); -} - -void ByteArray::resize(size_t newsize) -{ - makeUnique(); - _data->resize(newsize); -} - -void ByteArray::append(char c) -{ - _data->push_back(c); -} - -void ByteArray::decode_base64() -{ - int i = 0; - Ptr tmp = std::make_unique(); - - uint8_t c4[4] = {0}; - for(uint8_t c : *_data) - { - if(c >= 'A' && c <= 'Z')c4[i++] = c - 'A'; - else if(c >= 'a' && c <= 'z')c4[i++] = c - 'a' + 26; - else if(c >= '0' && c <= '9')c4[i++] = c - '0' + 52; - else if(c == '+')c4[i++] = 62; - else if(c == '/')c4[i++] = 63; - - if(i == 4) - { - tmp->push_back((c4[0] << 2) | (c4[1] >> 4)); - tmp->push_back((c4[1] << 4) | (c4[2] >> 2)); - tmp->push_back((c4[2] << 6) | c4[3]); - i = 0; - } - } - - if(i > 1)tmp->push_back((c4[0] << 2) | (c4[1] >> 4)); - if(i > 2)tmp->push_back((c4[1] << 4) | (c4[2] >> 2)); - - std::swap(_data, tmp); -} - -void ByteArray::encode_base64() -{ - static const char *base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - Ptr tmp = std::make_unique(); - int i = 0; - uint8_t sextet[4] = {0}; - for(uint8_t c : *_data) - { - switch(i) - { - case 0: - sextet[0] |= c >> 2 & 0x3f; - sextet[1] |= c << 4 & 0x3f; - i++; - break; - case 1: - sextet[1] |= c >> 4 & 0x3f; - sextet[2] |= c << 2 & 0x3f; - i++; - break; - case 2: - sextet[2] |= c >> 6 & 0x3f; - sextet[3] = c & 0x3f; - i = 0; - for(int o=0; o<4; o++) - tmp->push_back(base64[sextet[o]]); - std::memset(sextet, 0, sizeof(sextet)); - break; - } - } - for(int o = 0; o <= i && i; o++) - tmp->push_back(base64[sextet[o]]); - - if(tmp->size() % 4) - tmp->resize(tmp->size() + 4 - (tmp->size() % 4), '='); - std::swap(_data, tmp); -} - - -void ByteArray::encode_hex() -{ - static const char *hex = "0123456789abcdef"; - Ptr tmp = std::make_unique(_data->size() * 2); - for(size_t i = 0; i< _data->size(); i++) - { - uint8_t t = static_cast(_data->at(i)); - (*tmp)[2*i + 0] = hex[(t & 0xf0) >> 4]; - (*tmp)[2*i + 1] = hex[t & 0xf]; - } - std::swap(_data, tmp); -} - -void ByteArray::decode_hex() -{ - auto toByte = [](char c) -> char - { - if(c >= '0' && c <= '9') - return c - '0'; - if(c >= 'A' && c <= 'F') - return c - '7'; - if(c >= 'a' && c <= 'f') - return c - 'W'; - return 0; - }; - - Ptr tmp = std::make_unique(size() / 2); - for(size_t i = 0; i< tmp->size(); i++) - { - (*tmp)[i] = (toByte(_data->at(i*2)) << 4) | toByte(_data->at(i*2+1)); - } - std::swap(_data, tmp); -} - -ByteStream::ByteStream() -{ - //setg(_buffer.data(), _buffer.data(), _buffer.data() + _buffer.size()); -} - -ByteStream::~ByteStream() -{ - -} - -const ByteArray &ByteStream::buffer() const -{ - return _buffer; -} - -void ByteStream::stats() -{ - std::cout << "pbase " << (void*)pbase() << std::endl; - std::cout << "pptr " << (void*)pptr() << std::endl; - std::cout << "epptr " << (void*)epptr() << std::endl; - std::cout << "eback " << (void*)eback() << std::endl; - std::cout << "gptr " << (void*)gptr() << std::endl; - std::cout << "egptr " << (void*)egptr() << std::endl; -} - -ByteStream::pos_type ByteStream::seekoff(off_type, std::ios_base::seekdir, std::ios_base::openmode) -{ - return pos_type(off_type(-1)); -} - -ByteStream::pos_type ByteStream::seekpos(pos_type, std::ios_base::openmode) -{ - return pos_type(off_type(-1)); -} - -/*std::streamsize ByteStream::showmanyc() -{ - return _buffer.size() - ipos; -} - -std::streamsize ByteStream::xsgetn(char_type *s, std::streamsize n) -{ - if((std::streamoff)_buffer.size() > ipos + n) - { - std::memcpy(s, _buffer.data() + ipos, n); - return n; - } - return pos_type(off_type(-1)); -} - -ByteStream::int_type ByteStream::underflow() -{ - if(ipos >= (std::streamoff)_buffer.size())return traits_type::eof(); - return traits_type::to_int_type(_buffer[ipos]); -}*/ - -std::streamsize ByteStream::xsputn(const char_type *s, std::streamsize n) -{ - if(opos + n >= (std::streamsize)_buffer.size()) - { - _buffer.resize(opos + n); - setoptr(); - } - - std::memcpy(_buffer.data() + opos, s, n); - opos += n; - return n; -} - -ByteStream::int_type ByteStream::overflow(int_type c) -{ - _buffer.append(c); - return c; -} - -void ByteStream::setoptr() -{ - size_t off = gptr() - eback(); - setg(_buffer.data(), _buffer.data() + off, _buffer.data() + _buffer.size()); -} - Variant::Type Variant::type() const { return (Variant::Type)_value.index(); diff --git a/propertyvariant.h b/variant.h similarity index 72% rename from propertyvariant.h rename to variant.h index d909bc3..19993fd 100644 --- a/propertyvariant.h +++ b/variant.h @@ -16,8 +16,8 @@ * along with this program. If not, see .* ************************************************************************/ -#ifndef PROPERTYVARIANT_H -#define PROPERTYVARIANT_H +#ifndef LIBXISF_VARIANT_H +#define LIBXISF_VARIANT_H #include #include @@ -32,61 +32,6 @@ namespace LibXISF { -class LIBXISF_EXPORT ByteArray -{ - using PtrType = std::vector; - using Ptr = std::shared_ptr; - Ptr _data; - void makeUnique(); -public: - ByteArray() : ByteArray((size_t)0) {} - explicit ByteArray(size_t size); - explicit ByteArray(const char *ptr); - ByteArray(const char *ptr, size_t size) - { - _data = std::make_shared>(); - _data->resize(size); - std::memcpy(data(), ptr, size); - } - ByteArray(const ByteArray &d); - char& operator[](size_t i); - const char& operator[](size_t i) const; - char* data() { return &_data->at(0); } - const char* data() const { return &_data->at(0); } - const char* constData() const { return &_data->at(0); } - size_t size() const; - void resize(size_t newsize); - void append(char c); - void decode_base64(); - void encode_base64(); - void encode_hex(); - void decode_hex(); -}; - -class ByteStream : public std::basic_streambuf -{ - ByteArray _buffer; - pos_type opos = 0; - pos_type ipos = 0; -public: - ByteStream(); - ~ByteStream(); - const ByteArray& buffer() const; - void stats(); -protected: - pos_type seekoff(off_type, std::ios_base::seekdir, std::ios_base::openmode = std::ios_base::in | std::ios_base::out) override; - pos_type seekpos(pos_type, std::ios_base::openmode = std::ios_base::in | std::ios_base::out) override; - - /*std::streamsize showmanyc() override; - std::streamsize xsgetn(char_type *s, std::streamsize n) override; - int_type underflow() override;*/ - - std::streamsize xsputn(const char_type *s, std::streamsize n) override; - int_type overflow(int_type c = traits_type::eof()) override; - - void setoptr(); -}; - struct Complex32 { float real; @@ -186,4 +131,4 @@ public: } -#endif // PROPERTYVARIANT_H +#endif // LIBXISF_VARIANT_H