From b8f13e45be884dc12884ebe8f3dcd9eecb23a106 Mon Sep 17 00:00:00 2001 From: Daniel Wilhelm Date: Fri, 18 Apr 2014 17:20:29 +0200 Subject: 5.5 --- wx+/button.cpp | 15 ++- wx+/create_pch.cpp | 8 ++ wx+/dir_picker.h | 8 +- wx+/serialize.h | 322 ++++++++++++++++++++++++++++++++++++++++++++++++----- wx+/zlib_wrap.cpp | 54 +++++++++ wx+/zlib_wrap.h | 115 +++++++++++++++++++ 6 files changed, 488 insertions(+), 34 deletions(-) create mode 100644 wx+/create_pch.cpp create mode 100644 wx+/zlib_wrap.cpp create mode 100644 wx+/zlib_wrap.h (limited to 'wx+') diff --git a/wx+/button.cpp b/wx+/button.cpp index 1e9cb7f0..0b193cfb 100644 --- a/wx+/button.cpp +++ b/wx+/button.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include "image_tools.h" @@ -79,7 +80,7 @@ void makeWhiteTransparent(wxImage& image) //assume black text on white backgroun unsigned char* alphaLast = alphaFirst + image.GetWidth() * image.GetHeight(); //dist(black, white) - double distBlackWhite = std::sqrt(3.0 * 255 * 255); + const double distBlackWhite = 255 * std::sqrt(3.0); const unsigned char* bytePos = image.GetData(); @@ -101,12 +102,14 @@ void makeWhiteTransparent(wxImage& image) //assume black text on white backgroun wxSize getSizeNeeded(const wxString& text, wxFont& font) { - wxCoord width, height; - wxMemoryDC dc; + const wxString& textFormatted = replaceCpy(text, L"&", L"", false); //remove accelerator + + wxCoord width = 0; + wxCoord height = 0; - wxString textFormatted = text; - textFormatted.Replace(wxT("&"), wxT(""), false); //remove accelerator + wxMemoryDC dc; dc.GetMultiLineTextExtent(textFormatted, &width, &height, nullptr, &font); + return wxSize(width, height); } @@ -138,7 +141,7 @@ wxBitmap BitmapButton::createBitmapFromText(const wxString& text) wxString textLabelFormatted = text; if ((accelPos = text.find(wxT("&"))) != wxString::npos) { - textLabelFormatted.Replace(wxT("&"), wxT(""), false); //remove accelerator + replace(textLabelFormatted, L"&", L"", false); //remove accelerator indexAccel = static_cast(accelPos); } diff --git a/wx+/create_pch.cpp b/wx+/create_pch.cpp new file mode 100644 index 00000000..a9b2ea37 --- /dev/null +++ b/wx+/create_pch.cpp @@ -0,0 +1,8 @@ +// ************************************************************************** +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * +// * Copyright (C) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// ************************************************************************** + +//dummy file for Visual Studio to compile precompiled header: +//attaching pch to any other cpp file triggers a full rebuild each time code is changed! \ No newline at end of file diff --git a/wx+/dir_picker.h b/wx+/dir_picker.h index 5f18b6fb..51bd9757 100644 --- a/wx+/dir_picker.h +++ b/wx+/dir_picker.h @@ -22,10 +22,14 @@ public: #ifdef FFS_WIN //fix wxWidgets localization gap: wxButton* button = dynamic_cast(m_pickerIface); - if (button) button->SetLabel(_("Browse")); + if (button) + { + button->SetLabel(_("Browse")); //button width needs to be adapted for very long translations + SetMinSize(button->GetBestSize()); //SetSize and wxButton::SetSize just do nothing!!?? + } #endif } }; } -#endif // DIR_PICKER_I18N_H_INCLUDED +#endif // DIR_PICKER_I18N_H_INCLUDED diff --git a/wx+/serialize.h b/wx+/serialize.h index f49bff04..030b55c7 100644 --- a/wx+/serialize.h +++ b/wx+/serialize.h @@ -8,14 +8,306 @@ #define SERIALIZE_H_INCLUDED #include -#include +#include #include +#ifdef FFS_WIN +warn_static("get rid of wx, then move to zen") +#endif + +#include + namespace zen { +//high-performance unformatted serialization (avoiding wxMemoryOutputStream/wxMemoryInputStream inefficiencies) + +/* +-------------------------- +|Binary Container Concept| +-------------------------- +binary container for data storage: must support "basic" std::vector interface (e.g. std::vector, std::string, Zbase) +*/ + +//binary container reference implementations +typedef Zbase Utf8String; //ref-counted + COW text stream + guaranteed performance: exponential growth +class BinaryStream; //ref-counted byte stream + guaranteed performance: exponential growth -> no COW, but 12% faster than Utf8String (due to no null-termination?) + +class BinaryStream //essentially a std::vector with ref-counted semantics +{ +public: + BinaryStream() : buffer(std::make_shared>()) {} + + typedef std::vector::value_type value_type; + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + + iterator begin() { return buffer->begin(); } + iterator end () { return buffer->end (); } + + const_iterator begin() const { return buffer->begin(); } + const_iterator end () const { return buffer->end (); } + + void resize(size_t len) { buffer->resize(len); } + size_t size() const { return buffer->size(); } + bool empty() const { return buffer->empty(); } + + inline friend bool operator==(const BinaryStream& lhs, const BinaryStream& rhs) { return *lhs.buffer == *rhs.buffer; } + +private: + std::shared_ptr> buffer; //always bound! + //perf: shared_ptr indirection irrelevant: less than 1% slower! +}; + +//---------------------------------------------------------------------- +//functions based on binary container abstraction +template void saveBinStream(const Zstring& filename, const BinContainer& cont); //throw FileError +template BinContainer loadBinStream(const Zstring& filename); //throw FileError, ErrorNotExisting + + +/* +----------------------------- +|Binary Input Stream Concept| +----------------------------- +struct BinInputStream +{ + const void* requestRead(size_t len); //expect external read of len bytes +}; + +------------------------------ +|Binary Output Stream Concept| +------------------------------ +struct BinOutputStream +{ + void* requestWrite(size_t len); //expect external write of len bytes +}; +*/ + +//binary input/output stream reference implementation +class UnexpectedEndOfStreamError {}; + +struct BinStreamIn //throw UnexpectedEndOfStreamError +{ + BinStreamIn(const BinaryStream& cont) : buffer(cont), pos(0) {} //this better be cheap! + + const void* requestRead(size_t len) //throw UnexpectedEndOfStreamError + { + if (pos + len > buffer.size()) + throw UnexpectedEndOfStreamError(); + size_t oldPos = pos; + pos += len; + return &*buffer.begin() + oldPos; + } + +private: + const BinaryStream buffer; + size_t pos; +}; + +struct BinStreamOut +{ + void* requestWrite(size_t len) + { + size_t oldSize = buffer.size(); + buffer.resize(buffer.size() + len); + return &*buffer.begin() + oldSize; + } + + BinaryStream get() { return buffer; } + +private: + BinaryStream buffer; +}; + +//---------------------------------------------------------------------- +//functions based on binary stream abstraction +template void writeNumber (BinOutputStream& stream, const N& num); // +template void writeContainer(BinOutputStream& stream, const C& str); //throw () +template < class BinOutputStream> void writeArray (BinOutputStream& stream, const void* data, size_t len); // + +//---------------------------------------------------------------------- + +template N readNumber (BinInputStream& stream); // +template C readContainer(BinInputStream& stream); //throw UnexpectedEndOfStreamError (corrupted data) +template < class BinInputStream> void readArray (BinInputStream& stream, void* data, size_t len); // + + + + + + + + + + + + + + + + + + + + + + + +//-----------------------implementation------------------------------- +template inline +void saveBinStream(const Zstring& filename, const BinContainer& cont) //throw FileError +{ + assert_static(sizeof(typename BinContainer::value_type) == 1); //expect: bytes (until further) + + FileOutput fileOut(filename, zen::FileOutput::ACC_OVERWRITE); //throw FileError + if (!cont.empty()) + fileOut.write(&*cont.begin(), cont.size()); //throw FileError +} + + +template inline +BinContainer loadBinStream(const Zstring& filename) //throw FileError, ErrorNotExisting +{ + assert_static(sizeof(typename BinContainer::value_type) == 1); //expect: bytes (until further) + + FileInput fileIn(filename); //throw FileError, ErrorNotExisting + + BinContainer contOut; + const size_t blockSize = 64 * 1024; + do + { + contOut.resize(contOut.size() + blockSize); + + const size_t bytesRead = fileIn.read(&*contOut.begin() + contOut.size() - blockSize, blockSize); //throw FileError + if (bytesRead < blockSize) + contOut.resize(contOut.size() - (blockSize - bytesRead)); //caveat: unsigned arithmetics + } + while (!fileIn.eof()); + + return contOut; +} + + +template inline +void writeArray(BinOutputStream& stream, const void* data, size_t len) +{ + std::copy(static_cast(data), + static_cast(data) + len, + static_cast< char*>(stream.requestWrite(len))); +} + + +template inline +void writeNumber(BinOutputStream& stream, const N& num) +{ + assert_static((IsArithmetic::value || IsSameType::value)); + writeArray(stream, &num, sizeof(N)); +} + + +template inline +void writeContainer(BinOutputStream& stream, const C& cont) //don't even consider UTF8 conversions here! "string" is expected to handle arbitrary binary data! +{ + const auto len = cont.size(); + writeNumber(stream, static_cast(len)); + if (len > 0) + writeArray(stream, &*cont.begin(), sizeof(typename C::value_type) * len); //don't use c_str(), but access uniformly via STL interface +} + + +template inline +void readArray(BinInputStream& stream, void* data, size_t len) +{ + const char* const src = static_cast(stream.requestRead(len)); //expect external write of len bytes + std::copy(src, src + len, static_cast(data)); +} + + +template inline +N readNumber(BinInputStream& stream) +{ + assert_static((IsArithmetic::value || IsSameType::value)); + N num = 0; + readArray(stream, &num, sizeof(N)); + return num; +} + + +template inline +C readContainer(BinInputStream& stream) +{ + C cont; + auto strLength = readNumber(stream); + if (strLength > 0) + try + { + cont.resize(strLength); //throw std::bad_alloc + readArray(stream, &*cont.begin(), sizeof(typename C::value_type) * strLength); + } + catch (std::bad_alloc&) //most likely this is due to data corruption! + { + throw UnexpectedEndOfStreamError(); + } + return cont; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifdef FFS_WIN +warn_static("get rid of wx, then move to zen") +#endif + + + //unchecked, unformatted serialization -template T readPOD (wxInputStream& stream); +template T readPOD (wxInputStream& stream); template void readPOD (wxInputStream& stream, T& pod); template void writePOD(wxOutputStream& stream, const T& pod); @@ -116,29 +408,6 @@ private: }; - - - - - - - - - - - - - - - - - - - - - - -//-----------------------implementation------------------------------- template inline T readPOD(wxInputStream& stream) { @@ -235,7 +504,7 @@ void CheckedReader::readString(S& str) const //checked read operation } catch (std::exception&) { throwException(); } check(); - if (stream_.LastRead() != str.length() * sizeof(typename S::value_type)) //some additional check + if (stream_.LastRead() != str.size() * sizeof(typename S::value_type)) //some additional check throwException(); } @@ -260,6 +529,7 @@ void CheckedWriter::writeString(const S& str) const //checked write operation { zen::writeString(stream_, str); check(); + //warn_static("buggy check if length 0!") if (stream_.LastWrite() != str.length() * sizeof(typename S::value_type)) //some additional check throwException(); } diff --git a/wx+/zlib_wrap.cpp b/wx+/zlib_wrap.cpp new file mode 100644 index 00000000..22285bab --- /dev/null +++ b/wx+/zlib_wrap.cpp @@ -0,0 +1,54 @@ +// ************************************************************************** +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * +// * Copyright (C) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// ************************************************************************** + +#include "zlib_wrap.h" +#ifdef FFS_WIN +#include <../src/zlib/zlib.h> //not really a "nice" place to look for a stable solution +#elif defined FFS_LINUX +#include //let's pray this is the same version wxWidgets is linking against! +#endif + +using namespace zen; + + +size_t zen::impl::zlib_compressBound(size_t len) +{ + return ::compressBound(static_cast(len)); //upper limit for buffer size, larger than input size!!! +} + + +size_t zen::impl::zlib_compress(const void* src, size_t srcLen, void* trg, size_t trgLen, int level) //throw ZlibInternalError +{ + uLongf bufferSize = static_cast(trgLen); + const int rv = ::compress2(static_cast(trg), //Bytef* dest, + &bufferSize, //uLongf* destLen, + static_cast(src), //const Bytef* source, + static_cast(srcLen), //uLong sourceLen, + level); //int level + // Z_OK: success + // Z_MEM_ERROR: not enough memory + // Z_BUF_ERROR: not enough room in the output buffer + if (rv != Z_OK || bufferSize > trgLen) + throw ZlibInternalError(); + return bufferSize; +} + + +size_t zen::impl::zlib_decompress(const void* src, size_t srcLen, void* trg, size_t trgLen) //throw ZlibInternalError +{ + uLongf bufferSize = static_cast(trgLen); + const int rv = ::uncompress(static_cast(trg), //Bytef* dest, + &bufferSize, //uLongf* destLen, + static_cast(src), //const Bytef* source, + static_cast(srcLen)); //uLong sourceLen + // Z_OK: success + // Z_MEM_ERROR: not enough memory + // Z_BUF_ERROR: not enough room in the output buffer + // Z_DATA_ERROR: input data was corrupted or incomplete + if (rv != Z_OK || bufferSize > trgLen) + throw ZlibInternalError(); + return bufferSize; +} diff --git a/wx+/zlib_wrap.h b/wx+/zlib_wrap.h new file mode 100644 index 00000000..7b196a75 --- /dev/null +++ b/wx+/zlib_wrap.h @@ -0,0 +1,115 @@ +// ************************************************************************** +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * +// * Copyright (C) ZenJu (zhnmju123 AT gmx DOT de) - All Rights Reserved * +// ************************************************************************** + +#ifndef SIMPLE_H_INCLUDED_18134135134135345489 +#define SIMPLE_H_INCLUDED_18134135134135345489 + +#include + +namespace zen +{ +class ZlibInternalError {}; + +// compression level must be between 0 and 9: +// 0: no compression +// 9: best compression +template //as specified in serialize.h +BinContainer compress(const BinContainer& stream, int level); //throw ZlibInternalError +//caveat: output stream is physically larger than input! => strip additional reserved space if needed: "BinContainer(output.begin(), output.end())" + +template +BinContainer decompress(const BinContainer& stream); //throw ZlibInternalError + + + + + + + + + + + + + + + + + + + + +//######################## implementation ########################## +namespace impl +{ +size_t zlib_compressBound(size_t len); +size_t zlib_compress (const void* src, size_t srcLen, void* trg, size_t trgLen, int level); //throw ZlibInternalError +size_t zlib_decompress(const void* src, size_t srcLen, void* trg, size_t trgLen); //throw ZlibInternalError +} + + +template +BinContainer compress(const BinContainer& stream, int level) //throw ZlibInternalError +{ + BinContainer contOut; + + //save uncompressed stream size for decompression + const std::uint64_t uncompressedSize = stream.size(); //use portable number type! + contOut.resize(sizeof(uncompressedSize)); + std::copy(reinterpret_cast(&uncompressedSize), + reinterpret_cast(&uncompressedSize) + sizeof(uncompressedSize), + &*contOut.begin()); + + const size_t bufferEstimate = impl::zlib_compressBound(stream.size()); //upper limit for buffer size, larger than input size!!! + + contOut.resize(contOut.size() + bufferEstimate); + + const size_t bytesWritten = impl::zlib_compress(&*stream.begin(), + stream.size(), + &*contOut.begin() + contOut.size() - bufferEstimate, + bufferEstimate, + level); //throw ZlibInternalError + if (bytesWritten < bufferEstimate) + contOut.resize(contOut.size() - (bufferEstimate - bytesWritten)); //caveat: unsigned arithmetics + //caveat: physical memory consumption still *unchanged*! + + return contOut; +} + + +template +BinContainer decompress(const BinContainer& stream) //throw ZlibInternalError +{ + //retrieve size of uncompressed data + std::uint64_t uncompressedSize = 0; //use portable number type! + if (stream.size() < sizeof(uncompressedSize)) + throw ZlibInternalError(); + std::copy(&*stream.begin(), + &*stream.begin() + sizeof(uncompressedSize), + reinterpret_cast(&uncompressedSize)); + + BinContainer contOut; + try + { + contOut.resize(uncompressedSize); //throw std::bad_alloc + } + catch (std::bad_alloc&) //most likely due to data corruption! + { + throw ZlibInternalError(); + } + + const size_t bytesWritten = impl::zlib_decompress(&*stream.begin() + sizeof(uncompressedSize), + stream.size() - sizeof(uncompressedSize), + &*contOut.begin(), + uncompressedSize); //throw ZlibInternalError + if (bytesWritten != uncompressedSize) + throw ZlibInternalError(); + + return contOut; +} +} + +#endif //SIMPLE_H_INCLUDED_18134135134135345489 -- cgit