/* The MIT License (MIT) Copyright (c) 2015 Martin Richter Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef TWPP_DETAIL_FILE_EXTIMAGEINFO_HPP #define TWPP_DETAIL_FILE_EXTIMAGEINFO_HPP #include "../twpp.hpp" namespace Twpp { namespace Detail { /// Mapping of info type to type identifier and data type. template struct Ext {}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef BarCodeRotation DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::Handle; typedef char DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef BarCodeType DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef PatchCode DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef DeskewStatus DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::Str255; typedef Str255 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::Str255; typedef Str255 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::Str255; typedef Str255 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::Str255; typedef Str255 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::Frame; typedef Frame DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt16; typedef PixelFlavor DataType;}; template<> struct Ext {static constexpr const Type twty = Type::Str255; typedef Str255 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt16; typedef MagType DataType;}; template<> struct Ext {static constexpr const Type twty = Type::Str255; typedef Str255 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::Bool; typedef Bool DataType;}; template<> struct Ext {static constexpr const Type twty = Type::Str255; typedef char DataType;}; // NOTE: InfoId::MagData may also contain Handle template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt16; typedef PageSide DataType;}; template<> struct Ext {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; template<> struct Ext {static constexpr const Type twty = Type::Str255; typedef Str255 DataType;}; } class Info; class ExtImageInfo; namespace Detail { static Handle handleItem(Info& info) noexcept; static void deleteInfo(Info& info) noexcept; } TWPP_DETAIL_PACK_BEGIN /// Extended image information entry. class Info { friend class ExtImageInfo; friend Handle Detail::handleItem(Info& info) noexcept; friend void Detail::deleteInfo(Info& info) noexcept; static constexpr const UInt32 DATA_HANDLE_THRESHOLD = sizeof(UIntPtr); // NOTE: specification says 4 bytes, yet pointer size makes more sense public: template class Items { friend class Info; public: typedef Detail::MaybeLock Data; constexpr Items() noexcept : m_parent(nullptr){} Items(const Items&) = default; Items& operator=(const Items&) = default; Items(Items&&) = default; Items& operator=(Items&&) = default; operator bool() const noexcept{ return m_data; } Data at(UInt32 i) const{ if (m_parent->hasDataHandle() && m_parent->type() == Type::Handle){ return reinterpret_cast(m_data.data())[i]; } else { return reinterpret_cast(m_data.data() + i * typeSize(m_parent->type())); } } Data operator[](UInt32 i) const{ return at(i); } private: Items(Info& parent, Detail::MaybeLock data) noexcept : m_parent(&parent), m_data(data){} Info* m_parent; Detail::MaybeLock m_data; // [items] <=> !(big and handle) // [handles]->handles*[items] <=> big and handle (this should teoretically not happen) }; Info(const Info&) = delete; Info& operator=(const Info&) = delete; Info(Info&&) = delete; Info& operator=(Info&&) = delete; /// Information type ID. InfoId id() const noexcept{ return m_infoId; } /// Information data type ID. Type type() const noexcept{ return m_itemType; } /// Number of items in this entry. UInt16 size() const noexcept{ return m_numItems; } /// Allocates space for the supplied number of items. /// Allocating handles is not supported. /// \tparam id Information type ID. Data types are set accordingly. /// \param count Number of items to allocate. /// \throw TypeException When `type` is handle or invalid. /// \throw std::bad_alloc template void allocSimple(UInt16 count = 1){ allocSimple(Detail::Ext::twty, count); } /// Allocates space for the supplied number of items. /// Allocating handles is not supported. /// \param type Data type ID. /// \param count Number of items to allocate. /// \throw TypeException When `type` is handle or invalid. /// \throw std::bad_alloc void allocSimple(Type type, UInt16 count = 1){ if (type == Type::Handle){ throw TypeException(); } if (type == m_itemType && count == m_numItems){ return; } auto itemSize = typeSize(type); bool big = hasDataHandle(type, count); // [items] <=> !big // handle->[items] <=> big Detail::UniqueHandle newItem; if (big){ newItem = Detail::alloc(itemSize * count); } Detail::deleteInfo(*this); if (big){ *Detail::alias_cast(&m_item) = newItem.release(); } m_itemType = type; m_numItems = count; } /// Allocates a single memory area owned by a handle. /// Info type changes to handle. /// \param itemSize Number of bytes to allocate. /// \throw std::bad_alloc void allocHandle(UInt32 itemSize){ // handle->[chars] auto newItem = Detail::UniqueHandle(Detail::alloc(itemSize)); Detail::deleteInfo(*this); *Detail::alias_cast(&m_item) = newItem.release(); m_itemType = Type::Handle; m_numItems = 1; } /// Status of this entry. ReturnCode returnCode() const noexcept{ return m_returnCode; } /// Sets status of this entry. void setReturnCode(ReturnCode rc) noexcept{ m_returnCode = rc; } /// Returns items contained in this entry. /// \tparam type ID of the internal data type. /// \tparam DataType Exported data type. /// \throw TypeException When types don't match. template Items items(){ if (type != m_itemType || (type != Type::Handle && typeSize(type) != sizeof(DataType))){ throw TypeException(); } return itemsPriv(); } /// Returns items contained in this entry. /// \tparam type ID of the internal data type. /// \throw TypeException When types don't match. template Items::Type> items(){ if (type != m_itemType){ throw TypeException(); } return itemsPriv::Type>(); } /// Returns items contained in this entry. /// \tparam id Information type ID. Data types are set accordingly. /// \throw TypeException When types don't match. template Items::DataType> items(){ if (Detail::Ext::twty != m_itemType){ throw TypeException(); } return itemsPriv::DataType>(); } private: bool hasDataHandle() const{ return hasDataHandle(type(), size()); } static bool hasDataHandle(Type type, UInt16 size){ return type != Type::DontCare && size * typeSize(type) > DATA_HANDLE_THRESHOLD; } template Items itemsPriv(){ bool big = hasDataHandle(); bool handle = m_itemType == Type::Handle; Detail::MaybeLock lock; if (!big && !handle){ lock = Detail::alias_cast(&m_item); } else { lock = *Detail::alias_cast(&m_item); } return {*this, std::move(lock)}; } template static bool arrContains(const T(& arr)[len], const T& val) noexcept{ for (std::size_t i = 0; i < len; i++){ if (arr[i] == val){ return true; } } return false; } InfoId m_infoId; Type m_itemType; UInt16 m_numItems; ReturnCode m_returnCode; UIntPtr m_item; // [items] <=> !big and !handle // handle->[items] <=> big xor handle // handle->[handles]->handles*[items] <=> big and handle (this should teoretically not happen) }; namespace Detail { static inline Handle handleItem(Info& info) noexcept{ return Handle(*Detail::alias_cast(&info.m_item)); } static inline void deleteInfo(Info& info) noexcept{ bool big = isType(info.type()) && info.hasDataHandle(); bool handle = info.type() == Type::Handle; // [items] <=> !big and !handle // handle->[items] <=> big xor handle // handle->[handles]->handles*[items] <=> big and handle (this should teoretically not happen) if (big && handle){ Detail::Lock lock(handleItem(info)); for (UInt16 i = 0; i < info.size(); i++){ Detail::free(lock.data()[i]); } } if (big || handle){ Detail::free(handleItem(info)); } } struct ExtImageInfoData { UInt32 m_numInfos; Info m_infos[1]; }; } TWPP_DETAIL_PACK_END /// Extended image information. /// Application sends list of info IDs, /// source sets their data. class ExtImageInfo { public: typedef Info* iterator; typedef const Info* const_iterator; /// Creates an invalid object. ExtImageInfo() noexcept {} /// Creates a new structure for all supplied info IDs. /// Sources must not call this constructor, they /// are required to fill data in existing instance. /// \param ids List of requested info IDs to be filled in by the source. ExtImageInfo(std::initializer_list ids) : m_data(new char[sizeof(Detail::ExtImageInfoData) - sizeof(Info) + ids.size() * sizeof(Info)]()){ d()->m_numInfos = static_cast(ids.size()); Info* infos = d()->m_infos; UInt32 i = 0; for (auto id : ids){ auto& info = infos[i]; i++; info.m_infoId = id; info.m_itemType = Type::DontCare; } } ExtImageInfo(ExtImageInfo&&) = default; ExtImageInfo& operator=(ExtImageInfo&&) = default; operator bool() const noexcept{ return isValid(); } bool isValid() const noexcept{ return static_cast(m_data); } /// Number of requested entries. UInt32 size() const noexcept{ assert(isValid()); return d()->m_numInfos; } /// Information entry. Info& at(UInt32 i) noexcept{ assert(isValid()); return d()->m_infos[i]; } /// Information entry. const Info& at(UInt32 i) const noexcept{ assert(isValid()); return d()->m_infos[i]; } Info& operator[](UInt32 i) noexcept{ return at(i); } const Info& operator[](UInt32 i) const noexcept{ return at(i); } iterator begin() noexcept{ assert(isValid()); return d()->m_infos; } const_iterator begin() const noexcept{ return cbegin(); } const_iterator cbegin() const noexcept{ assert(isValid()); return d()->m_infos; } iterator end() noexcept{ assert(isValid()); return d()->m_infos + d()->m_numInfos; } const_iterator end() const noexcept{ return cend(); } const_iterator cend() const noexcept{ assert(isValid()); return d()->m_infos + d()->m_numInfos; } private: Detail::ExtImageInfoData* d() noexcept{ return reinterpret_cast(m_data.get()); } Detail::ExtImageInfoData* d() const noexcept{ return reinterpret_cast(m_data.get()); } struct Deleter { void operator()(char* ptr) noexcept{ Detail::ExtImageInfoData* data = reinterpret_cast(ptr); if (data){ for (UInt32 i = 0; i < data->m_numInfos; i++){ Detail::deleteInfo(data->m_infos[i]); } delete [] ptr; } } }; std::unique_ptr m_data; }; } #endif // TWPP_DETAIL_FILE_EXTIMAGEINFO_HPP