diff --git a/.gitignore b/.gitignore index 1c94aa38..9e3fa922 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ ################################################################################ /huagao/.vs/huagaotwds/v15 +/3rdparty/nick /huagao/debug/qmake /huagao/debug /huagao/Win32/Debug diff --git a/huagao/huagaotwds.pro b/huagao/huagaotwds.pro index b8989ac8..640d1b0b 100644 --- a/huagao/huagaotwds.pro +++ b/huagao/huagaotwds.pro @@ -65,7 +65,7 @@ SOURCES += huagaods.cpp \ Device/CJsonObject.cpp \ Device/JsonConfig.cpp \ Device/GetMemoryUsage.cpp \ - Device/G400ScanConfig.cpp \ + Device/G400ScanConfig.cpp \ ImageProcess/ImageApply.cpp \ ImageProcess/ImageApplyAdjustColors.cpp \ ImageProcess/ImageApplyAutoCrop.cpp \ @@ -79,7 +79,7 @@ SOURCES += huagaods.cpp \ ImageProcess/ImageApplySharpen.cpp \ ImageProcess/ImageProcess_Public.cpp \ ImageProcess/ImageApplyConcatenation.cpp \ - G400ScanConfig.cpp \ + GscanJsonConfig.cpp \ Sliders.cpp \ SmartEdit.cpp \ TabCtrlSSL.cpp \ @@ -119,7 +119,7 @@ HEADERS += huagaods.hpp \ Device/cJSON.h \ Device/JsonConfig.h \ Device/CJsonObject.hpp \ - Device/G400ScanConfig.h \ + Device/G400ScanConfig.h \ ImageProcess/ImageApply.h \ ImageProcess/ImageApplyAdjustColors.h \ ImageProcess/ImageApplyAutoCrop.h \ @@ -134,6 +134,8 @@ HEADERS += huagaods.hpp \ ImageProcess/ImageApplySharpen.h \ ImageProcess/ImageProcess_Public.h \ ImageProcess/ImageApplyConcatenation.h \ + GscanJsonConfig.h \ + MapFinder.h \ Sliders.h \ SmartEdit.h \ TabCtrlSSL.h \ diff --git a/twpp/capability.hpp b/twpp/capability.hpp index 728e2068..886a00a8 100644 --- a/twpp/capability.hpp +++ b/twpp/capability.hpp @@ -89,7 +89,7 @@ template<> struct Cap {static constexpr co template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef SearchMode DataType;}; template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef BarCodeType DataType;}; template<> struct Cap {static constexpr const Type twty = Type::UInt32; typedef UInt32 DataType;}; -template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef UInt16 DataType;}; +template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef UInt16 DataType;}; template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef BitDepthReduction DataType;}; template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef BitOrder DataType;}; template<> struct Cap {static constexpr const Type twty = Type::UInt16; typedef BitOrder DataType;}; diff --git a/twpp/datasource.hpp b/twpp/datasource.hpp index 58a2b601..2576c539 100644 --- a/twpp/datasource.hpp +++ b/twpp/datasource.hpp @@ -31,31 +31,31 @@ SOFTWARE. namespace Twpp { -namespace Detail { + namespace Detail { -TWPP_DETAIL_PACK_BEGIN -struct AppCapability { + TWPP_DETAIL_PACK_BEGIN + struct AppCapability { - CapType m_cap; - ConType m_conType; - Handle m_cont; + CapType m_cap; + ConType m_conType; + Handle m_cont; -}; -TWPP_DETAIL_PACK_END + }; + TWPP_DETAIL_PACK_END -struct DoNotFreeHandle { + struct DoNotFreeHandle { - DoNotFreeHandle(Handle handle){ - Detail::GlobalMemFuncs::doNotFreeHandle = handle; - } + DoNotFreeHandle(Handle handle) { + Detail::GlobalMemFuncs::doNotFreeHandle = handle; + } - ~DoNotFreeHandle(){ - Detail::GlobalMemFuncs::doNotFreeHandle = Handle(); - } + ~DoNotFreeHandle() { + Detail::GlobalMemFuncs::doNotFreeHandle = Handle(); + } -}; + }; -} + } #define TWPP_ENTRY(SourceClass)\ extern "C" TWPP_DETAIL_EXPORT Twpp::ReturnCode TWPP_DETAIL_CALLSTYLE \ @@ -68,2146 +68,2133 @@ struct DoNotFreeHandle { return SourceClass::entry(origin, dg, dat, msg, data);\ } -/// Result of a data source operation. -/// Contains both return code and status. -class Result { - -public: - /// Creates successful result. - constexpr Result() noexcept : - m_status(), m_rc(ReturnCode::Success){} - - /// Creates result with supplied return code and status. - constexpr Result(ReturnCode rc, Status status) noexcept : - m_status(status), m_rc(rc){} - - /// Status part of the result. - constexpr Status status() const noexcept{ - return m_status; - } - - /// Return code part of the result. - constexpr ReturnCode returnCode() const noexcept{ - return m_rc; - } - - /// Sets status part of the result. - void setStatus(Status status) noexcept{ - m_status = status; - } - - /// Sets return code part of the result. - void setReturnCode(ReturnCode rc) noexcept{ - m_rc = rc; - } - - constexpr operator ReturnCode() const noexcept{ - return m_rc; - } - - constexpr operator Status() const noexcept{ - return m_status; - } - -private: - Status m_status; - ReturnCode m_rc; - -}; - -static constexpr inline bool success(const Result& res) noexcept{ - return success(res.returnCode()); -} - - -namespace Detail { - -template // false -struct StaticCustomBaseProc { - Result operator()(Dat, Msg, void*){ - return {ReturnCode::Failure, ConditionCode::BadProtocol}; - } -}; - -template -struct StaticCustomBaseProc { - Result operator()(Dat dat, Msg msg, void* data){ - return Derived::staticCustomBase(dat, msg, data); - } -}; - -TWPP_DETAIL_CREATE_HAS_STATIC_METHOD(defaultIdentity) -TWPP_DETAIL_CREATE_HAS_STATIC_METHOD(staticCustomBase) - -} - -namespace SourceFromThisProcs { - -/// Returns data source identity not associated with any instance. -const Identity& defaultIdentity(); - -/// Processes custom TWAIN operations without having any opened connection. -/// DataGroup is always Control. -/// \param dat Type of data. Dat::CustomBase + X. -/// \param msg Message, action to perform. -/// \param data The data, may be null. -/// \return Operation result code. -Result staticCustomBase(Dat dat, Msg msg, void* data); - -} - -/// Base class of a TWAIN data source. -/// It handles instances creation and all static calls. -/// -/// The derived class must: -/// 1) Implement at least all pure virtual methods. -/// 2) Provide `static const Identity& defaultIdentity()`. -/// 3) If hasStaticCustomBaseProc == true, provide -/// `static Result staticCustomBase(Dat dat, Msg msg, void* data)`. -/// -/// After defining your source class, do not forget to use macro -/// TWPP_ENTRY() -/// where the name is a literal, not string: -/// -/// TWPP_ENTRY(Source) // <- no semicolon required -/// \tparam Derived The class inheriting from this. -/// \tparam hasStaticCustomBaseProc {Whether the Derived -/// class handles static custom base operations, see above.} -template -class SourceFromThis { - -public: - SourceFromThis(const SourceFromThis&) = delete; - SourceFromThis& operator=(const SourceFromThis&) = delete; - - SourceFromThis(SourceFromThis&&) = delete; - SourceFromThis& operator=(SourceFromThis&&) = delete; - - virtual ~SourceFromThis() noexcept = default; - -protected: - /// Creates closed instance. - constexpr SourceFromThis() noexcept : - m_lastStatus(ConditionCode::Bummer), m_state(DsState::Closed){} - - /// The last TWAIN status. - Status lastStatus() const noexcept{ - return m_lastStatus; - } - - /// Current TWAIN state. - DsState state() const noexcept{ - return m_state; - } - - /// Whether the source is in the supplied TWAIN state. - bool inState(DsState state) const noexcept{ - return m_state == state; - } - - /// Whether the source is between min and max states (both inclusive). - bool inState(DsState min, DsState max) const noexcept{ - return m_state >= min && m_state <= max; - } - - /// Whether there exists an enabled source. - static bool hasEnabled() noexcept{ - for (auto& src : g_sources){ - if (src.inState(DsState::Enabled, DsState::Xferring)){ - return true; - } - } - - return false; - } - - /// Source identity. - const Identity& sourceIdentity() const noexcept{ - return m_srcId; - } - - /// Identity of the application that opened the source. - const Identity& applicationIdentity() const noexcept{ - return m_appId; - } - - /// Sets current TWAIN state, use with care. - void setState(DsState state) noexcept{ - m_state = state; - } - - /// Sets current source identity, use with care. - void setSourceIdentity(const Identity& sourceIdentity) noexcept{ - m_srcId = sourceIdentity; - } - - /// Sets current application identity, use with care. - void setApplicationIdentity(const Identity& appIdentity) noexcept{ - m_appId = appIdentity; - } - - /// Shortcut for Result(RC::Success, CC::Success). - static constexpr Result success() noexcept{ - return {ReturnCode::Success, ConditionCode::Success}; - } - - /// Shortcut for Result(RC::Failure, CC::BadValue). - static constexpr Result badValue() noexcept{ - return {ReturnCode::Failure, ConditionCode::BadValue}; - } - - /// Shortcut for Result(RC::Failure, CC::BadProtocol). - static constexpr Result badProtocol() noexcept{ - return {ReturnCode::Failure, ConditionCode::BadProtocol}; - } - - /// Shortcut for Result(RC::Failure, CC::SeqError). - static constexpr Result seqError() noexcept{ - return {ReturnCode::Failure, ConditionCode::SeqError}; - } - - /// Shortcut for Result(RC::Failure, CC::CapBadOperation). - static constexpr Result capBadOperation() noexcept{ - return {ReturnCode::Failure, ConditionCode::CapBadOperation}; - } - - /// Shortcut for Result(RC::Failure, CC::CapUnsupported). - static constexpr Result capUnsupported() noexcept{ - return {ReturnCode::Failure, ConditionCode::CapUnsupported}; - } - - /// Shortcut for Result(RC::Failure, CC::Bummber). - static constexpr Result bummer() noexcept{ - return {ReturnCode::Failure, ConditionCode::Bummer}; - } - - - /// Notifies application about clicking on OK button. - ReturnCode notifyCloseOk() noexcept{ - return notifyApp(Msg::CloseDsOk); - } - - /// Notifies application about clicking on Cancel button. - ReturnCode notifyCloseCancel() noexcept{ - return notifyApp(Msg::CloseDsReq); - } - - /// Notifies application about a device event. - ReturnCode notifyDeviceEvent() noexcept{ - return notifyApp(Msg::DeviceEvent); - } - - /// Notifies application about ready transfer (after clicking scan button is GUI is shown). - ReturnCode notifyXferReady() noexcept{ - return notifyApp(Msg::XferReady); - } - - - - /// Root of source TWAIN calls. - /// \param origin Identity of the caller. - /// \param dg Data group of the call. - /// \param dat Type of data. - /// \param msg Message, action to perform. - /// \param data The data, may be null. - virtual Result call(const Identity& origin, DataGroup dg, Dat dat, Msg msg, void* data){ - switch (dg){ - case DataGroup::Control: - return control(origin, dat, msg, data); - - case DataGroup::Image: - return image(origin, dat, msg, data); - - case DataGroup::Audio: - return audio(origin, dat, msg, data); - - default: - return badProtocol(); - - } - } - - /// Root of source control TWAIN calls. - /// \param origin Identity of the caller. - /// \param dat Type of data. - /// \param msg Message, action to perform. - /// \param data The data, may be null. - virtual Result control(const Identity& origin, Dat dat, Msg msg, void* data){ - if (!data){ - // all control triplets require data - return badValue(); - } - - switch (dat){ - case Dat::Capability: - return capability(origin, msg, *static_cast(data)); - case Dat::CustomData: - return customData(origin, msg, *static_cast(data)); - case Dat::DeviceEvent: - return deviceEvent(origin, msg, *static_cast(data)); - case Dat::Event: // Windows only - return event(origin, msg, *static_cast(data)); - case Dat::FileSystem: - return fileSystem(origin, msg, *static_cast(data)); - case Dat::Identity: - return identity(origin, msg, *static_cast(data)); - case Dat::PassThrough: - return passThrough(origin, msg, *static_cast(data)); - case Dat::PendingXfers: - return pendingXfers(origin, msg, *static_cast(data)); - case Dat::SetupFileXfer: - return setupFileXfer(origin, msg, *static_cast(data)); - case Dat::SetupMemXfer: - return setupMemXfer(origin, msg, *static_cast(data)); - case Dat::Status: - return status(origin, msg, *static_cast(data)); - case Dat::StatusUtf8: - return statusUtf8(origin, msg, *static_cast(data)); - case Dat::UserInterface: - return userInterface(origin, msg, *static_cast(data)); - case Dat::XferGroup: { - return xferGroup(origin, msg, *static_cast(data)); - } - default: - return badProtocol(); - } - } - - /// Capability TWAIN call. - /// Reset, set and set constraint operations are limited to - /// state DsState::Open (4), override this method if you - /// support CapType::ExtendedCaps. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Capability data. - virtual Result capability(const Identity& origin, Msg msg, Capability& data){ - switch (msg){ - case Msg::Get: - // 4 - 7 - return capabilityGet(origin, data); - - case Msg::GetCurrent: - // 4 - 7 - return capabilityGetCurrent(origin, data); - - case Msg::GetDefault: - // 4 - 7 - return capabilityGetDefault(origin, data); - - case Msg::GetHelp: - if (!inState(DsState::Open)){ - return seqError(); - } - - return capabilityGetHelp(origin, data); - - case Msg::GetLabel: - if (!inState(DsState::Open)){ - return seqError(); - } - - return capabilityGetLabel(origin, data); - - case Msg::GetLabelEnum: - if (!inState(DsState::Open)){ - return seqError(); - } - - return capabilityGetLabelEnum(origin, data); - - case Msg::QuerySupport: - // 4 - 7 - return capabilityQuerySupport(origin, data); - - case Msg::Reset: - // 4, extended: 5, 6, 7 - if (!inState(DsState::Open)){ - return seqError(); - } - - return capabilityReset(origin, data); - - case Msg::ResetAll: - if (!inState(DsState::Open)){ - return seqError(); - } - - return capabilityResetAll(origin); // data has no meaning here - - case Msg::Set: - // 4, extended: 5, 6, 7 - if (!inState(DsState::Open)){ - return seqError(); - } - - if (!data){ - return badValue(); - } - - return capabilitySet(origin, data); - - case Msg::SetConstraint: - // 4, extended: 5, 6, 7 - if (!inState(DsState::Open)){ - return seqError(); - } - - if (!data){ - return badValue(); - } - - return capabilitySetConstraint(origin, data); - - default: - return badProtocol(); - } - } - - /// Get capability TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - /// \param data Capability data. - virtual Result capabilityGet(const Identity& origin, Capability& data) = 0; - - /// Get current capability TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - /// \param data Capability data. - virtual Result capabilityGetCurrent(const Identity& origin, Capability& data) = 0; - - /// Get default capability TWAIN call. - /// \param origin Identity of the caller. - /// \param data Capability data. - virtual Result capabilityGetDefault(const Identity& origin, Capability& data) = 0; - - /// Get help capability TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Capability data. - virtual Result capabilityGetHelp(const Identity& origin, Capability& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Get label capability TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Capability data. - virtual Result capabilityGetLabel(const Identity& origin, Capability& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Get label enum capability TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Capability data. - virtual Result capabilityGetLabelEnum(const Identity& origin, Capability& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Query support capability TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - /// \param data Capability data. - virtual Result capabilityQuerySupport(const Identity& origin, Capability& data) = 0; - - /// Reset capability TWAIN call. - /// Always called in correct state: 4, if you support extended - /// capabilities, override `capability` method. - /// \param origin Identity of the caller. - /// \param data Capability data. - virtual Result capabilityReset(const Identity& origin, Capability& data) = 0; - - /// Reset all capability TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - virtual Result capabilityResetAll(const Identity& origin) = 0; - - /// Set capability TWAIN call. - /// Always called in correct state: 4, if you support extended - /// capabilities, override `capability` method. - /// \param origin Identity of the caller. - /// \param data Capability data. - virtual Result capabilitySet(const Identity& origin, Capability& data) = 0; - - /// Set capability TWAIN call. - /// Always called in correct state: 4, if you support extended - /// capabilities, override `capability` method. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Capability data. - virtual Result capabilitySetConstraint(const Identity& origin, Capability& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - - - /// Custom data TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Custom data. - virtual Result customData(const Identity& origin, Msg msg, CustomData& data){ - if (!inState(DsState::Open)){ - return seqError(); - } - - switch (msg){ - case Msg::Get: - return customDataGet(origin, data); - - case Msg::Set: - return customDataSet(origin, data); - - default: - return badProtocol(); - } - } - - /// Get custom data TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Custom data. - virtual Result customDataGet(const Identity& origin, CustomData& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Set custom data TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Custom data. - virtual Result customDataSet(const Identity& origin, CustomData& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Device event TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Device event data. - virtual Result deviceEvent(const Identity& origin, Msg msg, DeviceEvent& data){ - if (msg != Msg::Get){ - return badProtocol(); - } - - return deviceEventGet(origin, data); - } - - /// Get device event TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Device event data. - virtual Result deviceEventGet(const Identity& origin, DeviceEvent& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - - - /// Event TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Event data. - virtual Result event(const Identity& origin, Msg msg, Event& data){ - if (msg != Msg::ProcessEvent){ - return badProtocol(); - } - - if (!inState(DsState::Enabled, DsState::Xferring)){ - return seqError(); - } - - return eventProcess(origin, data); - } + /// Result of a data source operation. + /// Contains both return code and status. + class Result { + + public: + /// Creates successful result. + constexpr Result() noexcept : + m_status(), m_rc(ReturnCode::Success) {} + + /// Creates result with supplied return code and status. + constexpr Result(ReturnCode rc, Status status) noexcept : + m_status(status), m_rc(rc) {} + + /// Status part of the result. + constexpr Status status() const noexcept { + return m_status; + } + + /// Return code part of the result. + constexpr ReturnCode returnCode() const noexcept { + return m_rc; + } + + /// Sets status part of the result. + void setStatus(Status status) noexcept { + m_status = status; + } + + /// Sets return code part of the result. + void setReturnCode(ReturnCode rc) noexcept { + m_rc = rc; + } + + constexpr operator ReturnCode() const noexcept { + return m_rc; + } + + constexpr operator Status() const noexcept { + return m_status; + } + + private: + Status m_status; + ReturnCode m_rc; + + }; + + static constexpr inline bool success(const Result& res) noexcept { + return success(res.returnCode()); + } + + + namespace Detail { + + template // false + struct StaticCustomBaseProc { + Result operator()(Dat, Msg, void*) { + return { ReturnCode::Failure, ConditionCode::BadProtocol }; + } + }; + + template + struct StaticCustomBaseProc { + Result operator()(Dat dat, Msg msg, void* data) { + return Derived::staticCustomBase(dat, msg, data); + } + }; + + TWPP_DETAIL_CREATE_HAS_STATIC_METHOD(defaultIdentity) + TWPP_DETAIL_CREATE_HAS_STATIC_METHOD(staticCustomBase) + + } + + namespace SourceFromThisProcs { + + /// Returns data source identity not associated with any instance. + const Identity& defaultIdentity(); + + /// Processes custom TWAIN operations without having any opened connection. + /// DataGroup is always Control. + /// \param dat Type of data. Dat::CustomBase + X. + /// \param msg Message, action to perform. + /// \param data The data, may be null. + /// \return Operation result code. + Result staticCustomBase(Dat dat, Msg msg, void* data); + + } + + /// Base class of a TWAIN data source. + /// It handles instances creation and all static calls. + /// + /// The derived class must: + /// 1) Implement at least all pure virtual methods. + /// 2) Provide `static const Identity& defaultIdentity()`. + /// 3) If hasStaticCustomBaseProc == true, provide + /// `static Result staticCustomBase(Dat dat, Msg msg, void* data)`. + /// + /// After defining your source class, do not forget to use macro + /// TWPP_ENTRY() + /// where the name is a literal, not string: + /// + /// TWPP_ENTRY(Source) // <- no semicolon required + /// \tparam Derived The class inheriting from this. + /// \tparam hasStaticCustomBaseProc {Whether the Derived + /// class handles static custom base operations, see above.} + template + class SourceFromThis { + + public: + SourceFromThis(const SourceFromThis&) = delete; + SourceFromThis& operator=(const SourceFromThis&) = delete; + + SourceFromThis(SourceFromThis&&) = delete; + SourceFromThis& operator=(SourceFromThis&&) = delete; + + virtual ~SourceFromThis() noexcept = default; + + protected: + /// Creates closed instance. + constexpr SourceFromThis() noexcept : + m_lastStatus(ConditionCode::Bummer), m_state(DsState::Closed) {} + + /// The last TWAIN status. + Status lastStatus() const noexcept { + return m_lastStatus; + } + + /// Current TWAIN state. + DsState state() const noexcept { + return m_state; + } + + /// Whether the source is in the supplied TWAIN state. + bool inState(DsState state) const noexcept { + return m_state == state; + } + + /// Whether the source is between min and max states (both inclusive). + bool inState(DsState min, DsState max) const noexcept { + return m_state >= min && m_state <= max; + } + + /// Whether there exists an enabled source. + static bool hasEnabled() noexcept { + for (auto& src : g_sources) { + if (src.inState(DsState::Enabled, DsState::Xferring)) { + return true; + } + } + + return false; + } + + /// Source identity. + const Identity& sourceIdentity() const noexcept { + return m_srcId; + } + + /// Identity of the application that opened the source. + const Identity& applicationIdentity() const noexcept { + return m_appId; + } + + /// Sets current TWAIN state, use with care. + void setState(DsState state) noexcept { + m_state = state; + } + + /// Sets current source identity, use with care. + void setSourceIdentity(const Identity& sourceIdentity) noexcept { + m_srcId = sourceIdentity; + } + + /// Sets current application identity, use with care. + void setApplicationIdentity(const Identity& appIdentity) noexcept { + m_appId = appIdentity; + } + + /// Shortcut for Result(RC::Success, CC::Success). + static constexpr Result success() noexcept { + return { ReturnCode::Success, ConditionCode::Success }; + } + + /// Shortcut for Result(RC::Failure, CC::BadValue). + static constexpr Result badValue() noexcept { + return { ReturnCode::Failure, ConditionCode::BadValue }; + } + + /// Shortcut for Result(RC::Failure, CC::BadProtocol). + static constexpr Result badProtocol() noexcept { + return { ReturnCode::Failure, ConditionCode::BadProtocol }; + } + + /// Shortcut for Result(RC::Failure, CC::SeqError). + static constexpr Result seqError() noexcept { + return { ReturnCode::Failure, ConditionCode::SeqError }; + } + + /// Shortcut for Result(RC::Failure, CC::CapBadOperation). + static constexpr Result capBadOperation() noexcept { + return { ReturnCode::Failure, ConditionCode::CapBadOperation }; + } + + /// Shortcut for Result(RC::Failure, CC::CapUnsupported). + static constexpr Result capUnsupported() noexcept { + return { ReturnCode::Failure, ConditionCode::CapUnsupported }; + } + + /// Shortcut for Result(RC::Failure, CC::Bummber). + static constexpr Result bummer() noexcept { + return { ReturnCode::Failure, ConditionCode::Bummer }; + } + + + /// Notifies application about clicking on OK button. + ReturnCode notifyCloseOk() noexcept { + return notifyApp(Msg::CloseDsOk); + } + + /// Notifies application about clicking on Cancel button. + ReturnCode notifyCloseCancel() noexcept { + return notifyApp(Msg::CloseDsReq); + } + + /// Notifies application about a device event. + ReturnCode notifyDeviceEvent() noexcept { + return notifyApp(Msg::DeviceEvent); + } + + /// Notifies application about ready transfer (after clicking scan button is GUI is shown). + ReturnCode notifyXferReady() noexcept { + return notifyApp(Msg::XferReady); + } + + + + /// Root of source TWAIN calls. + /// \param origin Identity of the caller. + /// \param dg Data group of the call. + /// \param dat Type of data. + /// \param msg Message, action to perform. + /// \param data The data, may be null. + virtual Result call(const Identity& origin, DataGroup dg, Dat dat, Msg msg, void* data) { + switch (dg) { + case DataGroup::Control: + return control(origin, dat, msg, data); + + case DataGroup::Image: + return image(origin, dat, msg, data); + + case DataGroup::Audio: + return audio(origin, dat, msg, data); + + default: + return badProtocol(); + + } + } + + /// Root of source control TWAIN calls. + /// \param origin Identity of the caller. + /// \param dat Type of data. + /// \param msg Message, action to perform. + /// \param data The data, may be null. + virtual Result control(const Identity& origin, Dat dat, Msg msg, void* data) { + if (!data) { + // all control triplets require data + return badValue(); + } + + switch (dat) { + case Dat::Capability: + return capability(origin, msg, *static_cast(data)); + case Dat::CustomData: + return customData(origin, msg, *static_cast(data)); + case Dat::DeviceEvent: + return deviceEvent(origin, msg, *static_cast(data)); + case Dat::Event: // Windows only + return event(origin, msg, *static_cast(data)); + case Dat::FileSystem: + return fileSystem(origin, msg, *static_cast(data)); + case Dat::Identity: + return identity(origin, msg, *static_cast(data)); + case Dat::PassThrough: + return passThrough(origin, msg, *static_cast(data)); + case Dat::PendingXfers: + return pendingXfers(origin, msg, *static_cast(data)); + case Dat::SetupFileXfer: + return setupFileXfer(origin, msg, *static_cast(data)); + case Dat::SetupMemXfer: + return setupMemXfer(origin, msg, *static_cast(data)); + case Dat::Status: + return status(origin, msg, *static_cast(data)); + case Dat::StatusUtf8: + return statusUtf8(origin, msg, *static_cast(data)); + case Dat::UserInterface: + return userInterface(origin, msg, *static_cast(data)); + case Dat::XferGroup: { + return xferGroup(origin, msg, *static_cast(data)); + } + default: + return badProtocol(); + } + } + + /// Capability TWAIN call. + /// Reset, set and set constraint operations are limited to + /// state DsState::Open (4), override this method if you + /// support CapType::ExtendedCaps. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Capability data. + virtual Result capability(const Identity& origin, Msg msg, Capability& data) { + switch (msg) { + case Msg::Get: + // 4 - 7 + return capabilityGet(origin, data); + + case Msg::GetCurrent: + // 4 - 7 + return capabilityGetCurrent(origin, data); + + case Msg::GetDefault: + // 4 - 7 + return capabilityGetDefault(origin, data); + + case Msg::GetHelp: + if (!inState(DsState::Open)) { + return seqError(); + } + + return capabilityGetHelp(origin, data); + + case Msg::GetLabel: + if (!inState(DsState::Open)) { + return seqError(); + } + + return capabilityGetLabel(origin, data); + + case Msg::GetLabelEnum: + if (!inState(DsState::Open)) { + return seqError(); + } + + return capabilityGetLabelEnum(origin, data); + + case Msg::QuerySupport: + // 4 - 7 + return capabilityQuerySupport(origin, data); + + case Msg::Reset: + // 4, extended: 5, 6, 7 + if (!inState(DsState::Open)) { + return seqError(); + } + + return capabilityReset(origin, data); + + case Msg::ResetAll: + if (!inState(DsState::Open)) { + return seqError(); + } + + return capabilityResetAll(origin); // data has no meaning here + + case Msg::Set: + // 4, extended: 5, 6, 7 + if (!inState(DsState::Open)) { + return seqError(); + } + + if (!data) { + return badValue(); + } + + return capabilitySet(origin, data); + + case Msg::SetConstraint: + // 4, extended: 5, 6, 7 + if (!inState(DsState::Open)) { + return seqError(); + } + + if (!data) { + return badValue(); + } + + return capabilitySetConstraint(origin, data); + + default: + return badProtocol(); + } + } + + /// Get capability TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Capability data. + virtual Result capabilityGet(const Identity& origin, Capability& data) = 0; + + /// Get current capability TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Capability data. + virtual Result capabilityGetCurrent(const Identity& origin, Capability& data) = 0; + + /// Get default capability TWAIN call. + /// \param origin Identity of the caller. + /// \param data Capability data. + virtual Result capabilityGetDefault(const Identity& origin, Capability& data) = 0; + + /// Get help capability TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Capability data. + virtual Result capabilityGetHelp(const Identity& origin, Capability& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Get label capability TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Capability data. + virtual Result capabilityGetLabel(const Identity& origin, Capability& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Get label enum capability TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Capability data. + virtual Result capabilityGetLabelEnum(const Identity& origin, Capability& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Query support capability TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Capability data. + virtual Result capabilityQuerySupport(const Identity& origin, Capability& data) = 0; + + /// Reset capability TWAIN call. + /// Always called in correct state: 4, if you support extended + /// capabilities, override `capability` method. + /// \param origin Identity of the caller. + /// \param data Capability data. + virtual Result capabilityReset(const Identity& origin, Capability& data) = 0; + + /// Reset all capability TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + virtual Result capabilityResetAll(const Identity& origin) = 0; + + /// Set capability TWAIN call. + /// Always called in correct state: 4, if you support extended + /// capabilities, override `capability` method. + /// \param origin Identity of the caller. + /// \param data Capability data. + virtual Result capabilitySet(const Identity& origin, Capability& data) = 0; + + /// Set capability TWAIN call. + /// Always called in correct state: 4, if you support extended + /// capabilities, override `capability` method. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Capability data. + virtual Result capabilitySetConstraint(const Identity& origin, Capability& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + + + /// Custom data TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Custom data. + virtual Result customData(const Identity& origin, Msg msg, CustomData& data) { + if (!inState(DsState::Open)) { + return seqError(); + } + + switch (msg) { + case Msg::Get: + return customDataGet(origin, data); + + case Msg::Set: + return customDataSet(origin, data); + + default: + return badProtocol(); + } + } + + /// Get custom data TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Custom data. + virtual Result customDataGet(const Identity& origin, CustomData& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Set custom data TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Custom data. + virtual Result customDataSet(const Identity& origin, CustomData& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Device event TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Device event data. + virtual Result deviceEvent(const Identity& origin, Msg msg, DeviceEvent& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + return deviceEventGet(origin, data); + } + + /// Get device event TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Device event data. + virtual Result deviceEventGet(const Identity& origin, DeviceEvent& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + + + /// Event TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Event data. + virtual Result event(const Identity& origin, Msg msg, Event& data) { + if (msg != Msg::ProcessEvent) { + return badProtocol(); + } + + if (!inState(DsState::Enabled, DsState::Xferring)) { + return seqError(); + } + + return eventProcess(origin, data); + } #if defined(TWPP_DETAIL_OS_WIN) || defined(TWPP_DETAIL_OS_MAC) - /// Process event TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - /// \param data Event data. - virtual Result eventProcess(const Identity& origin, Event& data) = 0; + /// Process event TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Event data. + virtual Result eventProcess(const Identity& origin, Event& data) = 0; #elif defined(TWPP_DETAIL_OS_LINUX) - /// Process event TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Event data. - virtual Result eventProcess(const Identity& origin, Event& data){ - Detail::unused(origin, data); - return badProtocol(); - } + /// Process event TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Event data. + virtual Result eventProcess(const Identity& origin, Event& data) { + Detail::unused(origin, data); + return badProtocol(); + } #else # error "eventProcess for your platform here" #endif - /// Identity TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Identity data. - virtual Result identity(const Identity& origin, Msg msg, Identity& data){ - Result rc; - switch (msg){ - case Msg::Get: - // any state - data = sourceIdentity(); - return success(); - - case Msg::OpenDs: { - if (!inState(DsState::Closed)){ - return seqError(); - } - - setSourceIdentity(data); - setApplicationIdentity(origin); - rc = identityOpenDs(origin); - if (Twpp::success(rc)){ - setState(DsState::Open); - } - - return rc; - } - - case Msg::CloseDs: { - if (inState(DsState::Enabled)) { - setState(DsState::Open); - } - if (!inState(DsState::Open)){ - return seqError(); - } - - rc = identityCloseDs(origin); - if (Twpp::success(rc)){ - setState(DsState::Closed); - } - - return rc; - } - - default: - return badProtocol(); - } - } - - /// Open source identity TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - virtual Result identityOpenDs(const Identity& origin) = 0; - - /// Close source identity TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - virtual Result identityCloseDs(const Identity& origin) = 0; - - /// File system TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data File system data. - virtual Result fileSystem(const Identity& origin, Msg msg, FileSystem& data){ - switch (msg){ - case Msg::AutomaticCaptureDir: - if (!inState(DsState::Open)){ - return seqError(); - } - - return fileSystemAutomatic(origin, data); - - case Msg::ChangeDir: - if (!inState(DsState::Open)){ - return seqError(); - } - - return fileSystemChange(origin, data); - - case Msg::Copy: - if (!inState(DsState::Open)){ - return seqError(); - } - - return fileSystemCopy(origin, data); - - case Msg::CreateDir: - if (!inState(DsState::Open)){ - return seqError(); - } - - return fileSystemCreate(origin, data); - - case Msg::Delete: - if (!inState(DsState::Open)){ - return seqError(); - } - - return fileSystemDelete(origin, data); - - case Msg::FormatMedia: - if (!inState(DsState::Open)){ - return seqError(); - } - - return fileSystemFormat(origin, data); - - case Msg::GetClose: - if (!inState(DsState::Open, DsState::XferReady)){ - return seqError(); - } - - return fileSystemGetClose(origin, data); - - case Msg::GetFirstFile: - if (!inState(DsState::Open, DsState::XferReady)){ - return seqError(); - } - - return fileSystemGetFirst(origin, data); - - case Msg::GetInfo: - // 4 - 7 - return fileSystemGetInfo(origin, data); - - case Msg::GetNextFile: - if (!inState(DsState::Open, DsState::XferReady)){ - return seqError(); - } - - return fileSystemGetNext(origin, data); - - case Msg::Rename: - if (!inState(DsState::Open)){ - return seqError(); - } - - return fileSystemRename(origin, data); - - default: - return badProtocol(); - } - } - - /// Automatic capture directory file system TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data File system data. - virtual Result fileSystemAutomatic(const Identity& origin, FileSystem& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Change directory file system TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data File system data. - virtual Result fileSystemChange(const Identity& origin, FileSystem& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - - /// Copy file system TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data File system data. - virtual Result fileSystemCopy(const Identity& origin, FileSystem& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Create directory file system TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data File system data. - virtual Result fileSystemCreate(const Identity& origin, FileSystem& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Delete file system TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data File system data. - virtual Result fileSystemDelete(const Identity& origin, FileSystem& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Format media file system TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data File system data. - virtual Result fileSystemFormat(const Identity& origin, FileSystem& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Get close file system TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data File system data. - virtual Result fileSystemGetClose(const Identity& origin, FileSystem& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Get first file file system TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data File system data. - virtual Result fileSystemGetFirst(const Identity& origin, FileSystem& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Get info file system TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data File system data. - virtual Result fileSystemGetInfo(const Identity& origin, FileSystem& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Get next file file system TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data File system data. - virtual Result fileSystemGetNext(const Identity& origin, FileSystem& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Rename file system TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data File system data. - virtual Result fileSystemRename(const Identity& origin, FileSystem& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - - /// Pass through TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Pass through data. - virtual Result passThrough(const Identity& origin, Msg msg, PassThrough& data){ - if (msg != Msg::PassThrough){ - return badProtocol(); - } - - // 4 - 7 - return passThroughPass(origin, data); - } - - /// Pass through pass through TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Pass through data. - virtual Result passThroughPass(const Identity& origin, PassThrough& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Pending xfers TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Pending xfers data. - virtual Result pendingXfers(const Identity& origin, Msg msg, PendingXfers& data){ - switch (msg){ - case Msg::EndXfer: { - if (!inState(DsState::XferReady, DsState::Xferring)){ - return seqError(); - } - - auto rc = pendingXfersEnd(origin, data); - if (Twpp::success(rc)){ - DataGroup xferGroup = DataGroup::Image; - if (!Twpp::success(this->xferGroup(origin, Msg::Get, xferGroup))){ - xferGroup = DataGroup::Image; - } - - if (xferGroup == DataGroup::Audio){ - setState(DsState::XferReady); - } else { - setState(data.count() ? DsState::XferReady : DsState::Enabled); - } - } - - return rc; - } - - - case Msg::Reset: { - if (!inState(DsState::XferReady)){ - return seqError(); - } - - auto rc = pendingXfersReset(origin, data); - if (Twpp::success(rc)){ - DataGroup xferGroup = DataGroup::Image; - if (!Twpp::success(this->xferGroup(origin, Msg::Get, xferGroup))){ - xferGroup = DataGroup::Image; - } - - if (xferGroup != DataGroup::Audio){ - setState(DsState::Enabled); - } - } - - return rc; - } - - case Msg::StopFeeder: - if (!inState(DsState::XferReady)){ - return seqError(); - } - - return pendingXfersStopFeeder(origin, data); - - case Msg::Get: - if (!inState(DsState::Open, DsState::Xferring)){ - return seqError(); - } - - return pendingXfersGet(origin, data); - - default: - return badProtocol(); - } - } - - /// Get pending xfers TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - /// \param data Pending xfers data. - virtual Result pendingXfersGet(const Identity& origin, PendingXfers& data) = 0; - - /// End xfer pending xfers TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - /// \param data Pending xfers data. - virtual Result pendingXfersEnd(const Identity& origin, PendingXfers& data) = 0; - - /// Reset xfers pending xfers TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - /// \param data Pending xfers data. - virtual Result pendingXfersReset(const Identity& origin, PendingXfers& data) = 0; - - /// Stop feeder pending xfers TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Pending xfers data. - virtual Result pendingXfersStopFeeder(const Identity& origin, PendingXfers& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Setup file xfer TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Setup file xfer data. - virtual Result setupFileXfer(const Identity& origin, Msg msg, SetupFileXfer& data){ - switch (msg){ - case Msg::Get: - if (!inState(DsState::Open, DsState::XferReady)){ - return seqError(); - } - - return setupFileXferGet(origin, data); - - case Msg::GetDefault: - if (!inState(DsState::Open, DsState::XferReady)){ - return seqError(); - } - - return setupFileXferGetDefault(origin, data); - - case Msg::Set: - if (!inState(DsState::Open, DsState::XferReady)){ - return seqError(); - } - - return setupFileXferSet(origin, data); - - case Msg::Reset: - if (!inState(DsState::Open)){ - return seqError(); - } - - return setupFileXferReset(origin, data); - - default: - return badProtocol(); - } - } - - /// Get setup file xfer TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Setup file xfer data. - virtual Result setupFileXferGet(const Identity& origin, SetupFileXfer& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Get default setup file xfer TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Setup file xfer data. - virtual Result setupFileXferGetDefault(const Identity& origin, SetupFileXfer& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Set setup file xfer TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Setup file xfer data. - virtual Result setupFileXferSet(const Identity& origin, SetupFileXfer& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Reset setup file xfer TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Setup file xfer data. - virtual Result setupFileXferReset(const Identity& origin, SetupFileXfer& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Setup memory xfer TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Setup memory xfer data. - virtual Result setupMemXfer(const Identity& origin, Msg msg, SetupMemXfer& data){ - if (msg != Msg::Get){ - return badProtocol(); - } - - if (!inState(DsState::Open, DsState::XferReady)){ - return seqError(); - } - - return setupMemXferGet(origin, data); - } - - /// Get setup memory xfer TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - /// \param data Setup memory xfer data. - virtual Result setupMemXferGet(const Identity& origin, SetupMemXfer& data) = 0; - - /// Status TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Status data. - virtual Result status(const Identity& origin, Msg msg, Status& data){ - if (msg != Msg::Get){ - return badProtocol(); - } - - return statusGet(origin, data); - } - - /// Get status TWAIN call. - /// Always called in correct state. - /// Default implementation returns last status. - /// \param origin Identity of the caller. - /// \param data Status data. - virtual Result statusGet(const Identity& origin, Status& data){ - Detail::unused(origin); - data = lastStatus(); - return success(); - } - - /// Status utf8 TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Status utf8 data. - virtual Result statusUtf8(const Identity& origin, Msg msg, StatusUtf8& data){ - if (msg != Msg::Get){ - return badProtocol(); - } - - // 3 - 7 - return statusUtf8Get(origin, data); - } - - /// Get status utf8 TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Status utf8 data. - virtual Result statusUtf8Get(const Identity& origin, StatusUtf8& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// User interface TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data User interface data. - virtual Result userInterface(const Identity& origin, Msg msg, UserInterface& data){ - Result rc; - switch (msg){ - case Msg::DisableDs: - if (!inState(DsState::Enabled)){ - return seqError(); - } - - rc = userInterfaceDisable(origin, data); - if (Twpp::success(rc)){ - setState(DsState::Open); - } - - return rc; - - case Msg::EnableDs: - if (!inState(DsState::Open) || hasEnabled()){ // only a single source can be enabled at any given time - return seqError(); - } - - rc = userInterfaceEnable(origin, data); - if (Twpp::success(rc) || rc == ReturnCode::CheckStatus){ - if (inState(DsState::Open)){ // allow userInterfaceEnable to transfer to higher states - setState(DsState::Enabled); - } - } - - return rc; - - case Msg::EnableDsUiOnly: - if (!inState(DsState::Open)){ - return seqError(); - } - - rc = userInterfaceEnableUiOnly(origin, data); - if (Twpp::success(rc)){ - setState(DsState::Enabled); - } - - return rc; - - default: - return badProtocol(); - } - } - - /// Disable user interface TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - /// \param data User interface data. - virtual Result userInterfaceDisable(const Identity& origin, UserInterface& data) = 0; - - /// Enable user interface TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - /// \param data User interface data. - virtual Result userInterfaceEnable(const Identity& origin, UserInterface& data) = 0; - - /// Enable UI only user interface TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - /// \param data User interface data. - virtual Result userInterfaceEnableUiOnly(const Identity& origin, UserInterface& data) = 0; - - /// Xfer group TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Xfer group data. - virtual Result xferGroup(const Identity& origin, Msg msg, DataGroup& data){ - switch (msg){ - case Msg::Get: - if (!inState(DsState::Open, DsState::XferReady)){ - return seqError(); - } - - return xferGroupGet(origin, data); - - case Msg::Set: - if (!inState(DsState::XferReady)){ - return seqError(); - } - - return xferGroupSet(origin, data); - - default: - return badProtocol(); - } - } - - /// Get xfer group TWAIN call. - /// Always called in correct state. - /// Default implementation returns DataGroup::Image. - /// \param origin Identity of the caller. - /// \param data Xfer group data. - virtual Result xferGroupGet(const Identity& origin, DataGroup& data){ - Detail::unused(origin); - data = DataGroup::Image; - return success(); - } - - /// Set xfer group TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Xfer group data. - virtual Result xferGroupSet(const Identity& origin, DataGroup& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Root of source image TWAIN calls. - /// - /// Special data to type casts: - /// ExtImageInfo: reinterpret_cast(data) - /// GrayResponse: reinterpret_cast(data) - /// RgbResponse: reinterpret_cast(data) - /// - /// \param origin Identity of the caller. - /// \param dat Type of data. - /// \param msg Message, action to perform. - /// \param data The data, may be null. - virtual Result image(const Identity& origin, Dat dat, Msg msg, void* data){ - if (dat != Dat::ImageFileXfer && !data){ - return badValue(); - } - - switch (dat){ - // TODO CieColor - /*case Dat::CieColor: - return cieColor(origin, msg, *static_cast(data));*/ - case Dat::ExtImageInfo: - return extImageInfo(origin, msg, reinterpret_cast(data)); // ExtImageInfo is simply a `pointer to TW_EXTIMAGEINFO` - case Dat::GrayResponse: - return grayResponse(origin, msg, reinterpret_cast(data)); // GrayResponse is simply a `pointer to TW_GRAYRESPONSE` - case Dat::IccProfile: - return iccProfile(origin, msg, *static_cast(data)); - case Dat::ImageFileXfer: - return imageFileXfer(origin, msg); - case Dat::ImageInfo: - return imageInfo(origin, msg, *static_cast(data)); - case Dat::ImageLayout: - return imageLayout(origin, msg, *static_cast(data)); - case Dat::ImageMemFileXfer: - return imageMemFileXfer(origin, msg, *static_cast(data)); - case Dat::ImageMemXfer: - return imageMemXfer(origin, msg, *static_cast(data)); - case Dat::ImageNativeXfer: - return imageNativeXfer(origin, msg, *static_cast(data)); - case Dat::JpegCompression: - return jpegCompression(origin, msg, *static_cast(data)); - case Dat::Palette8: - return palette8(origin, msg, *static_cast(data)); - case Dat::RgbResponse: - return rgbResponse(origin, msg, reinterpret_cast(data)); // RgbResponse is simply a `pointer to TW_RGBRESPONSE` - default: - return badProtocol(); - } - } - - // TODO CieColor - /* - /// Cie color TWAIN call. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Cie color data. - virtual Result cieColor(const Identity& origin, Msg msg, CieColor& data){ - Detail::unused(origin, msg, data); - return badProtocol(); - }*/ - - /// Ext image info TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Ext image info data. - virtual Result extImageInfo(const Identity& origin, Msg msg, ExtImageInfo& data){ - if (msg != Msg::Get){ - return badProtocol(); - } - - if (!inState(DsState::Xferring)){ - return seqError(); - } - - return extImageInfoGet(origin, data); - } - - /// Get ext image info TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Ext image info data. - virtual Result extImageInfoGet(const Identity& origin, ExtImageInfo& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Gray response TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Gray response data. - virtual Result grayResponse(const Identity& origin, Msg msg, GrayResponse& data){ - if (!inState(DsState::Open)){ - return seqError(); - } - - switch (msg){ - case Msg::Set: - return grayResponseSet(origin, data); - - case Msg::Reset: - return grayResponseReset(origin, data); - - default: - return badProtocol(); - } - } - - /// Set gray response TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Gray response data. - virtual Result grayResponseSet(const Identity& origin, GrayResponse& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Reset gray response TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Gray response data. - virtual Result grayResponseReset(const Identity& origin, GrayResponse& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// ICC profile TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data ICC profile data. - virtual Result iccProfile(const Identity& origin, Msg msg, IccProfileMemory& data){ - if (msg != Msg::Get){ - return badProtocol(); - } - - if (!inState(DsState::XferReady, DsState::Xferring)){ - return seqError(); - } - - return iccProfileGet(origin, data); - } - - /// Get ICC profile TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data ICC profile data. - virtual Result iccProfileGet(const Identity& origin, IccProfileMemory& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Image file xfer TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - virtual Result imageFileXfer(const Identity& origin, Msg msg){ - if (msg != Msg::Get){ - return badProtocol(); - } - - if (!inState(DsState::XferReady)){ - return seqError(); - } - - auto rc = imageFileXferGet(origin); - if (rc == ReturnCode::XferDone){ - setState(DsState::Xferring); - } - - return rc; - } - - /// Get image file xfer TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// Always called in correct state. - /// \param origin Identity of the caller. - virtual Result imageFileXferGet(const Identity& origin){ - Detail::unused(origin); - return badProtocol(); - } - - /// Image info TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Image info data. - virtual Result imageInfo(const Identity& origin, Msg msg, ImageInfo& data){ - if (msg != Msg::Get){ - return badProtocol(); - } - - if (!inState(DsState::XferReady, DsState::Xferring)){ - return seqError(); - } - - return imageInfoGet(origin, data); - } - - /// Get image info TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - /// \param data Image info data. - virtual Result imageInfoGet(const Identity& origin, ImageInfo& data) = 0; - - - /// Image layout TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Image layout data. - virtual Result imageLayout(const Identity& origin, Msg msg, ImageLayout& data){ - switch (msg){ - case Msg::Get: - if (!inState(DsState::Open, DsState::XferReady)){ - return seqError(); - } - - return imageLayoutGet(origin, data); - - case Msg::GetDefault: - if (!inState(DsState::Open, DsState::XferReady)){ - return seqError(); - } - - return imageLayoutGetDefault(origin, data); - - case Msg::Set: - if (!inState(DsState::Open)){ - return seqError(); - } - - return imageLayoutSet(origin, data); - - case Msg::Reset: - if (!inState(DsState::Open)){ - return seqError(); - } - - return imageLayoutReset(origin, data); - - default: - return badProtocol(); - } - } - - /// Get image layout TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - /// \param data Image layout data. - virtual Result imageLayoutGet(const Identity& origin, ImageLayout& data) = 0; - - /// Get default image layout TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - /// \param data Image layout data. - virtual Result imageLayoutGetDefault(const Identity& origin, ImageLayout& data) = 0; - - /// Set image layout TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - /// \param data Image layout data. - virtual Result imageLayoutSet(const Identity& origin, ImageLayout& data) = 0; - - /// Reset image layout TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - /// \param data Image layout data. - virtual Result imageLayoutReset(const Identity& origin, ImageLayout& data) = 0; - - - /// Image memory file xfer TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Image memory file xfer data. - virtual Result imageMemFileXfer(const Identity& origin, Msg msg, ImageMemFileXfer& data){ - if (msg != Msg::Get){ - return badProtocol(); - } - - if (!inState(DsState::XferReady)){ - return seqError(); - } - - auto rc = imageMemFileXferGet(origin, data); - if (rc == ReturnCode::XferDone){ - setState(DsState::Xferring); - } - - return rc; - } - - /// Get image memory file xfer TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Image memory file xfer data. - virtual Result imageMemFileXferGet(const Identity& origin, ImageMemFileXfer& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Image memory xfer TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Image memory xfer data. - virtual Result imageMemXfer(const Identity& origin, Msg msg, ImageMemXfer& data){ - if (msg != Msg::Get){ - return badProtocol(); - } - - if (!inState(DsState::XferReady, DsState::Xferring)){ - return seqError(); - } - - auto rc = imageMemXferGet(origin, data); - if (Twpp::success(rc) || rc == ReturnCode::XferDone){ - setState(DsState::Xferring); - } - - return rc; - } - - /// Get image memory xfer TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - /// \param data Image memory xfer data. - virtual Result imageMemXferGet(const Identity& origin, ImageMemXfer& data) = 0; - - /// Image native xfer TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Handle to image native xfer data. - virtual Result imageNativeXfer(const Identity& origin, Msg msg, ImageNativeXfer& data){ - if (msg != Msg::Get){ - return badProtocol(); - } - - if (!inState(DsState::XferReady)){ - return seqError(); - } - - auto rc = imageNativeXferGet(origin, data); - if (rc == ReturnCode::XferDone){ - setState(DsState::Xferring); - } - - return rc; - } - - /// Get image native xfer TWAIN call. - /// Always called in correct state. - /// \param origin Identity of the caller. - /// \param data Handle to image native xfer data. - virtual Result imageNativeXferGet(const Identity& origin, ImageNativeXfer& data) = 0; - - /// JPEG compression TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data JPEG compression data. - virtual Result jpegCompression(const Identity& origin, Msg msg, JpegCompression& data){ - switch (msg){ - case Msg::Get: - if (!inState(DsState::Open, DsState::XferReady)){ - return seqError(); - } - - return jpegCompressionGet(origin, data); - - case Msg::GetDefault: - if (!inState(DsState::Open, DsState::XferReady)){ - return seqError(); - } - - return jpegCompressionGetDefault(origin, data); - - case Msg::Set: - if (!inState(DsState::Open)){ - return seqError(); - } - - return jpegCompressionSet(origin, data); - - case Msg::Reset: - if (!inState(DsState::Open)){ - return seqError(); - } - - return jpegCompressionReset(origin, data); - - default: - return badProtocol(); - } - } - - /// Get JPEG compression TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data JPEG compression data. - virtual Result jpegCompressionGet(const Identity& origin, JpegCompression& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Get default JPEG compression TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data JPEG compression data. - virtual Result jpegCompressionGetDefault(const Identity& origin, JpegCompression& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Set JPEG compression TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data JPEG compression data. - virtual Result jpegCompressionSet(const Identity& origin, JpegCompression& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Reset JPEG compression TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data JPEG compression data. - virtual Result jpegCompressionReset(const Identity& origin, JpegCompression& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Palette8 TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Palette8 data. - virtual Result palette8(const Identity& origin, Msg msg, Palette8& data){ - switch (msg){ - case Msg::Get: - if (!inState(DsState::Open, DsState::XferReady)){ - return seqError(); - } - - return palette8Get(origin, data); - - case Msg::GetDefault: - if (!inState(DsState::Open, DsState::XferReady)){ - return seqError(); - } - - return palette8GetDefault(origin, data); - - case Msg::Set: - if (!inState(DsState::Open)){ - return seqError(); - } - - return palette8Set(origin, data); - - case Msg::Reset: - if (!inState(DsState::Open)){ - return seqError(); - } - - return palette8Reset(origin, data); - - default: - return badProtocol(); - } - } - - /// Get Palette8 TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Palette8 data. - virtual Result palette8Get(const Identity& origin, Palette8& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Get default Palette8 TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Palette8 data. - virtual Result palette8GetDefault(const Identity& origin, Palette8& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Set Palette8 TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Palette8 data. - virtual Result palette8Set(const Identity& origin, Palette8& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Reset Palette8 TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Palette8 data. - virtual Result palette8Reset(const Identity& origin, Palette8& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// RGB response TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data RGB response data. - virtual Result rgbResponse(const Identity& origin, Msg msg, RgbResponse& data){ - if (!inState(DsState::Open)){ - return seqError(); - } - - switch (msg){ - case Msg::Set: - return rgbResponseSet(origin, data); - - case Msg::Reset: - return rgbResponseReset(origin, data); - - default: - return badProtocol(); - } - } - - /// Set RGB response TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data RGB response data. - virtual Result rgbResponseSet(const Identity& origin, RgbResponse& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Reset RGB response TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data RGB response data. - virtual Result rgbResponseReset(const Identity& origin, RgbResponse& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - - /// Root of source audio TWAIN calls. - /// \param origin Identity of the caller. - /// \param dat Type of data. - /// \param msg Message, action to perform. - /// \param data The data, may be null. - virtual Result audio(const Identity& origin, Dat dat, Msg msg, void* data){ - if (dat != Dat::AudioFileXfer && !data){ - return badValue(); - } - - switch (dat){ - case Dat::AudioFileXfer: - return audioFileXfer(origin, msg); - case Dat::AudioInfo: - return audioInfo(origin, msg, *static_cast(data)); - case Dat::AudioNativeXfer: - return audioNativeXfer(origin, msg, *static_cast(data)); - default: - return badProtocol(); - } - } - - /// Audio file xfer TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - virtual Result audioFileXfer(const Identity& origin, Msg msg){ - if (msg != Msg::Get){ - return badProtocol(); - } - - if (!inState(DsState::XferReady)){ - return seqError(); - } - - auto rc = audioFileXferGet(origin); - if (rc == ReturnCode::XferDone){ - setState(DsState::Xferring); - } - - return rc; - } - - /// Get audio file xfer TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - virtual Result audioFileXferGet(const Identity& origin){ - Detail::unused(origin); - return badProtocol(); - } - - /// Audio info TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Audio info data. - virtual Result audioInfo(const Identity& origin, Msg msg, AudioInfo& data){ - if (msg != Msg::Get){ - return badProtocol(); - } - - if (!inState(DsState::XferReady, DsState::Xferring)){ - return seqError(); - } - - return audioInfoGet(origin, data); - } - - /// Get audio info TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Audio info data. - virtual Result audioInfoGet(const Identity& origin, AudioInfo& data){ - Detail::unused(origin, data); - return badProtocol(); - } - - /// Audio native xfer TWAIN call. - /// \param origin Identity of the caller. - /// \param msg Message, action to perform. - /// \param data Handle to audio native xfer data. - virtual Result audioNativeXfer(const Identity& origin, Msg msg, AudioNativeXfer& data){ - if (msg != Msg::Get){ - return badProtocol(); - } - - if (!inState(DsState::XferReady)){ - return seqError(); - } - - auto rc = audioNativeXferGet(origin, data); - if (Twpp::success(rc)){ - setState(DsState::Xferring); - } - - return rc; - } - - /// Get audio native xfer TWAIN call. - /// Always called in correct state. - /// Default implementation does nothing. - /// \param origin Identity of the caller. - /// \param data Handle to audio native xfer data. - virtual Result audioNativeXferGet(const Identity& origin, AudioNativeXfer& data){ - Detail::unused(origin, data); - return badProtocol(); - } - -private: - ReturnCode notifyApp(Msg msg) noexcept{ - switch (msg){ - case Msg::XferReady: - if (!inState(DsState::Enabled)){ - return ReturnCode::Failure; - } - - break; - case Msg::CloseDsOk: - case Msg::CloseDsReq: - if (!inState(DsState::Enabled, DsState::Xferring)){ - return ReturnCode::Failure; - } - - break; - default: - break; - } - - auto rc = g_entry(&m_srcId, &m_appId, DataGroup::Control, Dat::Null, msg, nullptr); - if (Twpp::success(rc)){ - switch (msg){ - case Msg::XferReady: - setState(DsState::XferReady); - break; - case Msg::CloseDsOk: - case Msg::CloseDsReq: - setState(DsState::Enabled); - break; - default: - break; - } - } - - return rc; - } - - Result callRoot(Identity* origin, DataGroup dg, Dat dat, Msg msg, void* data) noexcept{ - if (!origin){ - return badProtocol(); - } - - bool isCapability = dg == DataGroup::Control && dat == Dat::Capability && data != nullptr; - try { - return isCapability - ? callCapability(*origin, dg, dat, msg, data) - : call(*origin, dg, dat, msg, data); - } catch (const std::bad_alloc&){ - return {ReturnCode::Failure, ConditionCode::LowMemory}; - } catch (...){ - // the exception would be caught in the static handler below - // that would set static status, we want to set local one - return bummer(); - } - } - - Result callCapability(const Identity& origin, DataGroup dg, Dat dat, Msg msg, void* data){ - // it is the responsibility of the APP to free capability handle - // we must assume the APP does not set the handle to zero after freeing it - // that would break capability (handle) move-assignment operator - // make sure such handle is not freed - Detail::AppCapability& cap = *static_cast(data); - Detail::DoNotFreeHandle doNotFree(cap.m_cont); - Detail::unused(doNotFree); - - return call(origin, dg, dat, msg, data); - } - - - Identity m_srcId; - Identity m_appId; - Status m_lastStatus; - DsState m_state; - - - static typename std::list::iterator find(Identity* origin) noexcept{ - if (origin){ - for (auto it = g_sources.begin(); it != g_sources.end(); ++it){ - if (it->m_appId.id() == origin->id()){ - return it; - } - } - } - - return g_sources.end(); - } - - static void resetDsm(){ - g_entry = nullptr; + /// Identity TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Identity data. + virtual Result identity(const Identity& origin, Msg msg, Identity& data) { + Result rc; + switch (msg) { + case Msg::Get: + // any state + data = sourceIdentity(); + return success(); + + case Msg::OpenDs: { + if (!inState(DsState::Closed)) { + return seqError(); + } + + setSourceIdentity(data); + setApplicationIdentity(origin); + rc = identityOpenDs(origin); + if (Twpp::success(rc)) { + setState(DsState::Open); + } + + return rc; + } + + case Msg::CloseDs: { + if (inState(DsState::Enabled)) { + setState(DsState::Open); + } + if (!inState(DsState::Open)) { + return seqError(); + } + + rc = identityCloseDs(origin); + if (Twpp::success(rc)) { + setState(DsState::Closed); + } + + return rc; + } + + default: + return badProtocol(); + } + } + + /// Open source identity TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + virtual Result identityOpenDs(const Identity& origin) = 0; + + /// Close source identity TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + virtual Result identityCloseDs(const Identity& origin) = 0; + + /// File system TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data File system data. + virtual Result fileSystem(const Identity& origin, Msg msg, FileSystem& data) { + switch (msg) { + case Msg::AutomaticCaptureDir: + if (!inState(DsState::Open)) { + return seqError(); + } + + return fileSystemAutomatic(origin, data); + + case Msg::ChangeDir: + if (!inState(DsState::Open)) { + return seqError(); + } + + return fileSystemChange(origin, data); + + case Msg::Copy: + if (!inState(DsState::Open)) { + return seqError(); + } + + return fileSystemCopy(origin, data); + + case Msg::CreateDir: + if (!inState(DsState::Open)) { + return seqError(); + } + + return fileSystemCreate(origin, data); + + case Msg::Delete: + if (!inState(DsState::Open)) { + return seqError(); + } + + return fileSystemDelete(origin, data); + + case Msg::FormatMedia: + if (!inState(DsState::Open)) { + return seqError(); + } + + return fileSystemFormat(origin, data); + + case Msg::GetClose: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return fileSystemGetClose(origin, data); + + case Msg::GetFirstFile: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return fileSystemGetFirst(origin, data); + + case Msg::GetInfo: + // 4 - 7 + return fileSystemGetInfo(origin, data); + + case Msg::GetNextFile: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return fileSystemGetNext(origin, data); + + case Msg::Rename: + if (!inState(DsState::Open)) { + return seqError(); + } + + return fileSystemRename(origin, data); + + default: + return badProtocol(); + } + } + + /// Automatic capture directory file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemAutomatic(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Change directory file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemChange(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + + /// Copy file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemCopy(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Create directory file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemCreate(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Delete file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemDelete(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Format media file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemFormat(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Get close file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemGetClose(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Get first file file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemGetFirst(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Get info file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemGetInfo(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Get next file file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemGetNext(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Rename file system TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data File system data. + virtual Result fileSystemRename(const Identity& origin, FileSystem& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + + /// Pass through TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Pass through data. + virtual Result passThrough(const Identity& origin, Msg msg, PassThrough& data) { + if (msg != Msg::PassThrough) { + return badProtocol(); + } + + // 4 - 7 + return passThroughPass(origin, data); + } + + /// Pass through pass through TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Pass through data. + virtual Result passThroughPass(const Identity& origin, PassThrough& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Pending xfers TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Pending xfers data. + virtual Result pendingXfers(const Identity& origin, Msg msg, PendingXfers& data) { + switch (msg) { + case Msg::EndXfer: { + if (!inState(DsState::XferReady, DsState::Xferring)) { + return seqError(); + } + + auto rc = pendingXfersEnd(origin, data); + if (Twpp::success(rc)) { + DataGroup xferGroup = DataGroup::Image; + if (!Twpp::success(this->xferGroup(origin, Msg::Get, xferGroup))) { + xferGroup = DataGroup::Image; + } + + if (xferGroup == DataGroup::Audio) { + setState(DsState::XferReady); + } + else { + setState(data.count() ? DsState::XferReady : DsState::Enabled); + } + } + + return rc; + } + + + case Msg::Reset: { + if (!inState(DsState::XferReady)) { + return seqError(); + } + + auto rc = pendingXfersReset(origin, data); + if (Twpp::success(rc)) { + DataGroup xferGroup = DataGroup::Image; + if (!Twpp::success(this->xferGroup(origin, Msg::Get, xferGroup))) { + xferGroup = DataGroup::Image; + } + + if (xferGroup != DataGroup::Audio) { + setState(DsState::Enabled); + } + } + + return rc; + } + + case Msg::StopFeeder: + if (!inState(DsState::XferReady)) { + return seqError(); + } + + return pendingXfersStopFeeder(origin, data); + + case Msg::Get: + if (!inState(DsState::Open, DsState::Xferring)) { + return seqError(); + } + + return pendingXfersGet(origin, data); + + default: + return badProtocol(); + } + } + + /// Get pending xfers TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Pending xfers data. + virtual Result pendingXfersGet(const Identity& origin, PendingXfers& data) = 0; + + /// End xfer pending xfers TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Pending xfers data. + virtual Result pendingXfersEnd(const Identity& origin, PendingXfers& data) = 0; + + /// Reset xfers pending xfers TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Pending xfers data. + virtual Result pendingXfersReset(const Identity& origin, PendingXfers& data) = 0; + + /// Stop feeder pending xfers TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Pending xfers data. + virtual Result pendingXfersStopFeeder(const Identity& origin, PendingXfers& data) = 0; + + /// Setup file xfer TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Setup file xfer data. + virtual Result setupFileXfer(const Identity& origin, Msg msg, SetupFileXfer& data) { + switch (msg) { + case Msg::Get: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return setupFileXferGet(origin, data); + + case Msg::GetDefault: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return setupFileXferGetDefault(origin, data); + + case Msg::Set: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return setupFileXferSet(origin, data); + + case Msg::Reset: + if (!inState(DsState::Open)) { + return seqError(); + } + + return setupFileXferReset(origin, data); + + default: + return badProtocol(); + } + } + + /// Get setup file xfer TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Setup file xfer data. + virtual Result setupFileXferGet(const Identity& origin, SetupFileXfer& data) = 0; + + /// Get default setup file xfer TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Setup file xfer data. + virtual Result setupFileXferGetDefault(const Identity& origin, SetupFileXfer& data) = 0; + + /// Set setup file xfer TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Setup file xfer data. + virtual Result setupFileXferSet(const Identity& origin, SetupFileXfer& data) = 0; + + /// Reset setup file xfer TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Setup file xfer data. + virtual Result setupFileXferReset(const Identity& origin, SetupFileXfer& data) = 0; + + /// Setup memory xfer TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Setup memory xfer data. + virtual Result setupMemXfer(const Identity& origin, Msg msg, SetupMemXfer& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return setupMemXferGet(origin, data); + } + + /// Get setup memory xfer TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Setup memory xfer data. + virtual Result setupMemXferGet(const Identity& origin, SetupMemXfer& data) = 0; + + /// Status TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Status data. + virtual Result status(const Identity& origin, Msg msg, Status& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + return statusGet(origin, data); + } + + /// Get status TWAIN call. + /// Always called in correct state. + /// Default implementation returns last status. + /// \param origin Identity of the caller. + /// \param data Status data. + virtual Result statusGet(const Identity& origin, Status& data) { + Detail::unused(origin); + data = lastStatus(); + return success(); + } + + /// Status utf8 TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Status utf8 data. + virtual Result statusUtf8(const Identity& origin, Msg msg, StatusUtf8& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + // 3 - 7 + return statusUtf8Get(origin, data); + } + + /// Get status utf8 TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Status utf8 data. + virtual Result statusUtf8Get(const Identity& origin, StatusUtf8& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// User interface TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data User interface data. + virtual Result userInterface(const Identity& origin, Msg msg, UserInterface& data) { + Result rc; + switch (msg) { + case Msg::DisableDs: + if (!inState(DsState::Enabled)) { + return seqError(); + } + + rc = userInterfaceDisable(origin, data); + if (Twpp::success(rc)) { + setState(DsState::Open); + } + + return rc; + + case Msg::EnableDs: + if (!inState(DsState::Open) || hasEnabled()) { // only a single source can be enabled at any given time + return seqError(); + } + + rc = userInterfaceEnable(origin, data); + if (Twpp::success(rc) || rc == ReturnCode::CheckStatus) { + if (inState(DsState::Open)) { // allow userInterfaceEnable to transfer to higher states + setState(DsState::Enabled); + } + } + + return rc; + + case Msg::EnableDsUiOnly: + if (!inState(DsState::Open)) { + return seqError(); + } + + rc = userInterfaceEnableUiOnly(origin, data); + if (Twpp::success(rc)) { + setState(DsState::Enabled); + } + + return rc; + + default: + return badProtocol(); + } + } + + /// Disable user interface TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data User interface data. + virtual Result userInterfaceDisable(const Identity& origin, UserInterface& data) = 0; + + /// Enable user interface TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data User interface data. + virtual Result userInterfaceEnable(const Identity& origin, UserInterface& data) = 0; + + /// Enable UI only user interface TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data User interface data. + virtual Result userInterfaceEnableUiOnly(const Identity& origin, UserInterface& data) = 0; + + /// Xfer group TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Xfer group data. + virtual Result xferGroup(const Identity& origin, Msg msg, DataGroup& data) { + switch (msg) { + case Msg::Get: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return xferGroupGet(origin, data); + + case Msg::Set: + if (!inState(DsState::XferReady)) { + return seqError(); + } + + return xferGroupSet(origin, data); + + default: + return badProtocol(); + } + } + + /// Get xfer group TWAIN call. + /// Always called in correct state. + /// Default implementation returns DataGroup::Image. + /// \param origin Identity of the caller. + /// \param data Xfer group data. + virtual Result xferGroupGet(const Identity& origin, DataGroup& data) { + Detail::unused(origin); + data = DataGroup::Image; + return success(); + } + + /// Set xfer group TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Xfer group data. + virtual Result xferGroupSet(const Identity& origin, DataGroup& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Root of source image TWAIN calls. + /// + /// Special data to type casts: + /// ExtImageInfo: reinterpret_cast(data) + /// GrayResponse: reinterpret_cast(data) + /// RgbResponse: reinterpret_cast(data) + /// + /// \param origin Identity of the caller. + /// \param dat Type of data. + /// \param msg Message, action to perform. + /// \param data The data, may be null. + virtual Result image(const Identity& origin, Dat dat, Msg msg, void* data) { + if (dat != Dat::ImageFileXfer && !data) { + return badValue(); + } + + switch (dat) { + // TODO CieColor + /*case Dat::CieColor: + return cieColor(origin, msg, *static_cast(data));*/ + case Dat::ExtImageInfo: + return extImageInfo(origin, msg, reinterpret_cast(data)); // ExtImageInfo is simply a `pointer to TW_EXTIMAGEINFO` + case Dat::GrayResponse: + return grayResponse(origin, msg, reinterpret_cast(data)); // GrayResponse is simply a `pointer to TW_GRAYRESPONSE` + case Dat::IccProfile: + return iccProfile(origin, msg, *static_cast(data)); + case Dat::ImageFileXfer: + return imageFileXfer(origin, msg); + case Dat::ImageInfo: + return imageInfo(origin, msg, *static_cast(data)); + case Dat::ImageLayout: + return imageLayout(origin, msg, *static_cast(data)); + case Dat::ImageMemFileXfer: + return imageMemFileXfer(origin, msg, *static_cast(data)); + case Dat::ImageMemXfer: + return imageMemXfer(origin, msg, *static_cast(data)); + case Dat::ImageNativeXfer: + return imageNativeXfer(origin, msg, *static_cast(data)); + case Dat::JpegCompression: + return jpegCompression(origin, msg, *static_cast(data)); + case Dat::Palette8: + return palette8(origin, msg, *static_cast(data)); + case Dat::RgbResponse: + return rgbResponse(origin, msg, reinterpret_cast(data)); // RgbResponse is simply a `pointer to TW_RGBRESPONSE` + default: + return badProtocol(); + } + } + + // TODO CieColor + /* + /// Cie color TWAIN call. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Cie color data. + virtual Result cieColor(const Identity& origin, Msg msg, CieColor& data){ + Detail::unused(origin, msg, data); + return badProtocol(); + }*/ + + /// Ext image info TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Ext image info data. + virtual Result extImageInfo(const Identity& origin, Msg msg, ExtImageInfo& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::Xferring)) { + return seqError(); + } + + return extImageInfoGet(origin, data); + } + + /// Get ext image info TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Ext image info data. + virtual Result extImageInfoGet(const Identity& origin, ExtImageInfo& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Gray response TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Gray response data. + virtual Result grayResponse(const Identity& origin, Msg msg, GrayResponse& data) { + if (!inState(DsState::Open)) { + return seqError(); + } + + switch (msg) { + case Msg::Set: + return grayResponseSet(origin, data); + + case Msg::Reset: + return grayResponseReset(origin, data); + + default: + return badProtocol(); + } + } + + /// Set gray response TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Gray response data. + virtual Result grayResponseSet(const Identity& origin, GrayResponse& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Reset gray response TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Gray response data. + virtual Result grayResponseReset(const Identity& origin, GrayResponse& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// ICC profile TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data ICC profile data. + virtual Result iccProfile(const Identity& origin, Msg msg, IccProfileMemory& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::XferReady, DsState::Xferring)) { + return seqError(); + } + + return iccProfileGet(origin, data); + } + + /// Get ICC profile TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data ICC profile data. + virtual Result iccProfileGet(const Identity& origin, IccProfileMemory& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Image file xfer TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + virtual Result imageFileXfer(const Identity& origin, Msg msg) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::XferReady)) { + return seqError(); + } + + auto rc = imageFileXferGet(origin); + if (rc == ReturnCode::XferDone) { + setState(DsState::Xferring); + } + + return rc; + } + + /// Get image file xfer TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// Always called in correct state. + /// \param origin Identity of the caller. + virtual Result imageFileXferGet(const Identity& origin) = 0; + + /// Image info TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Image info data. + virtual Result imageInfo(const Identity& origin, Msg msg, ImageInfo& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::XferReady, DsState::Xferring)) { + return seqError(); + } + + return imageInfoGet(origin, data); + } + + /// Get image info TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Image info data. + virtual Result imageInfoGet(const Identity& origin, ImageInfo& data) = 0; + + + /// Image layout TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Image layout data. + virtual Result imageLayout(const Identity& origin, Msg msg, ImageLayout& data) { + switch (msg) { + case Msg::Get: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return imageLayoutGet(origin, data); + + case Msg::GetDefault: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return imageLayoutGetDefault(origin, data); + + case Msg::Set: + if (!inState(DsState::Open)) { + return seqError(); + } + + return imageLayoutSet(origin, data); + + case Msg::Reset: + if (!inState(DsState::Open)) { + return seqError(); + } + + return imageLayoutReset(origin, data); + + default: + return badProtocol(); + } + } + + /// Get image layout TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Image layout data. + virtual Result imageLayoutGet(const Identity& origin, ImageLayout& data) = 0; + + /// Get default image layout TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Image layout data. + virtual Result imageLayoutGetDefault(const Identity& origin, ImageLayout& data) = 0; + + /// Set image layout TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Image layout data. + virtual Result imageLayoutSet(const Identity& origin, ImageLayout& data) = 0; + + /// Reset image layout TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Image layout data. + virtual Result imageLayoutReset(const Identity& origin, ImageLayout& data) = 0; + + + /// Image memory file xfer TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Image memory file xfer data. + virtual Result imageMemFileXfer(const Identity& origin, Msg msg, ImageMemFileXfer& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::XferReady)) { + return seqError(); + } + + auto rc = imageMemFileXferGet(origin, data); + if (rc == ReturnCode::XferDone) { + setState(DsState::Xferring); + } + + return rc; + } + + /// Get image memory file xfer TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Image memory file xfer data. + virtual Result imageMemFileXferGet(const Identity& origin, ImageMemFileXfer& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Image memory xfer TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Image memory xfer data. + virtual Result imageMemXfer(const Identity& origin, Msg msg, ImageMemXfer& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::XferReady, DsState::Xferring)) { + return seqError(); + } + + auto rc = imageMemXferGet(origin, data); + if (Twpp::success(rc) || rc == ReturnCode::XferDone) { + setState(DsState::Xferring); + } + + return rc; + } + + /// Get image memory xfer TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Image memory xfer data. + virtual Result imageMemXferGet(const Identity& origin, ImageMemXfer& data) = 0; + + /// Image native xfer TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Handle to image native xfer data. + virtual Result imageNativeXfer(const Identity& origin, Msg msg, ImageNativeXfer& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::XferReady)) { + return seqError(); + } + + auto rc = imageNativeXferGet(origin, data); + if (rc == ReturnCode::XferDone) { + setState(DsState::Xferring); + } + + return rc; + } + + /// Get image native xfer TWAIN call. + /// Always called in correct state. + /// \param origin Identity of the caller. + /// \param data Handle to image native xfer data. + virtual Result imageNativeXferGet(const Identity& origin, ImageNativeXfer& data) = 0; + + /// JPEG compression TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data JPEG compression data. + virtual Result jpegCompression(const Identity& origin, Msg msg, JpegCompression& data) { + switch (msg) { + case Msg::Get: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return jpegCompressionGet(origin, data); + + case Msg::GetDefault: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return jpegCompressionGetDefault(origin, data); + + case Msg::Set: + if (!inState(DsState::Open)) { + return seqError(); + } + + return jpegCompressionSet(origin, data); + + case Msg::Reset: + if (!inState(DsState::Open)) { + return seqError(); + } + + return jpegCompressionReset(origin, data); + + default: + return badProtocol(); + } + } + + /// Get JPEG compression TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data JPEG compression data. + virtual Result jpegCompressionGet(const Identity& origin, JpegCompression& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Get default JPEG compression TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data JPEG compression data. + virtual Result jpegCompressionGetDefault(const Identity& origin, JpegCompression& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Set JPEG compression TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data JPEG compression data. + virtual Result jpegCompressionSet(const Identity& origin, JpegCompression& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Reset JPEG compression TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data JPEG compression data. + virtual Result jpegCompressionReset(const Identity& origin, JpegCompression& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Palette8 TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Palette8 data. + virtual Result palette8(const Identity& origin, Msg msg, Palette8& data) { + switch (msg) { + case Msg::Get: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return palette8Get(origin, data); + + case Msg::GetDefault: + if (!inState(DsState::Open, DsState::XferReady)) { + return seqError(); + } + + return palette8GetDefault(origin, data); + + case Msg::Set: + if (!inState(DsState::Open)) { + return seqError(); + } + + return palette8Set(origin, data); + + case Msg::Reset: + if (!inState(DsState::Open)) { + return seqError(); + } + + return palette8Reset(origin, data); + + default: + return badProtocol(); + } + } + + /// Get Palette8 TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Palette8 data. + virtual Result palette8Get(const Identity& origin, Palette8& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Get default Palette8 TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Palette8 data. + virtual Result palette8GetDefault(const Identity& origin, Palette8& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Set Palette8 TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Palette8 data. + virtual Result palette8Set(const Identity& origin, Palette8& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Reset Palette8 TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Palette8 data. + virtual Result palette8Reset(const Identity& origin, Palette8& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// RGB response TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data RGB response data. + virtual Result rgbResponse(const Identity& origin, Msg msg, RgbResponse& data) { + if (!inState(DsState::Open)) { + return seqError(); + } + + switch (msg) { + case Msg::Set: + return rgbResponseSet(origin, data); + + case Msg::Reset: + return rgbResponseReset(origin, data); + + default: + return badProtocol(); + } + } + + /// Set RGB response TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data RGB response data. + virtual Result rgbResponseSet(const Identity& origin, RgbResponse& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Reset RGB response TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data RGB response data. + virtual Result rgbResponseReset(const Identity& origin, RgbResponse& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + + /// Root of source audio TWAIN calls. + /// \param origin Identity of the caller. + /// \param dat Type of data. + /// \param msg Message, action to perform. + /// \param data The data, may be null. + virtual Result audio(const Identity& origin, Dat dat, Msg msg, void* data) { + if (dat != Dat::AudioFileXfer && !data) { + return badValue(); + } + + switch (dat) { + case Dat::AudioFileXfer: + return audioFileXfer(origin, msg); + case Dat::AudioInfo: + return audioInfo(origin, msg, *static_cast(data)); + case Dat::AudioNativeXfer: + return audioNativeXfer(origin, msg, *static_cast(data)); + default: + return badProtocol(); + } + } + + /// Audio file xfer TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + virtual Result audioFileXfer(const Identity& origin, Msg msg) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::XferReady)) { + return seqError(); + } + + auto rc = audioFileXferGet(origin); + if (rc == ReturnCode::XferDone) { + setState(DsState::Xferring); + } + + return rc; + } + + /// Get audio file xfer TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + virtual Result audioFileXferGet(const Identity& origin) { + Detail::unused(origin); + return badProtocol(); + } + + /// Audio info TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Audio info data. + virtual Result audioInfo(const Identity& origin, Msg msg, AudioInfo& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::XferReady, DsState::Xferring)) { + return seqError(); + } + + return audioInfoGet(origin, data); + } + + /// Get audio info TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Audio info data. + virtual Result audioInfoGet(const Identity& origin, AudioInfo& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + /// Audio native xfer TWAIN call. + /// \param origin Identity of the caller. + /// \param msg Message, action to perform. + /// \param data Handle to audio native xfer data. + virtual Result audioNativeXfer(const Identity& origin, Msg msg, AudioNativeXfer& data) { + if (msg != Msg::Get) { + return badProtocol(); + } + + if (!inState(DsState::XferReady)) { + return seqError(); + } + + auto rc = audioNativeXferGet(origin, data); + if (Twpp::success(rc)) { + setState(DsState::Xferring); + } + + return rc; + } + + /// Get audio native xfer TWAIN call. + /// Always called in correct state. + /// Default implementation does nothing. + /// \param origin Identity of the caller. + /// \param data Handle to audio native xfer data. + virtual Result audioNativeXferGet(const Identity& origin, AudioNativeXfer& data) { + Detail::unused(origin, data); + return badProtocol(); + } + + private: + ReturnCode notifyApp(Msg msg) noexcept { + switch (msg) { + case Msg::XferReady: + if (!inState(DsState::Enabled)) { + return ReturnCode::Failure; + } + + break; + case Msg::CloseDsOk: + case Msg::CloseDsReq: + if (!inState(DsState::Enabled, DsState::Xferring)) { + return ReturnCode::Failure; + } + + break; + default: + break; + } + + auto rc = g_entry(&m_srcId, &m_appId, DataGroup::Control, Dat::Null, msg, nullptr); + if (Twpp::success(rc)) { + switch (msg) { + case Msg::XferReady: + setState(DsState::XferReady); + break; + case Msg::CloseDsOk: + case Msg::CloseDsReq: + setState(DsState::Enabled); + break; + default: + break; + } + } + + return rc; + } + + Result callRoot(Identity* origin, DataGroup dg, Dat dat, Msg msg, void* data) noexcept { + if (!origin) { + return badProtocol(); + } + + bool isCapability = dg == DataGroup::Control && dat == Dat::Capability && data != nullptr; + try { + return isCapability + ? callCapability(*origin, dg, dat, msg, data) + : call(*origin, dg, dat, msg, data); + } + catch (const std::bad_alloc&) { + return { ReturnCode::Failure, ConditionCode::LowMemory }; + } + catch (...) { + // the exception would be caught in the static handler below + // that would set static status, we want to set local one + return bummer(); + } + } + + Result callCapability(const Identity& origin, DataGroup dg, Dat dat, Msg msg, void* data) { + // it is the responsibility of the APP to free capability handle + // we must assume the APP does not set the handle to zero after freeing it + // that would break capability (handle) move-assignment operator + // make sure such handle is not freed + Detail::AppCapability& cap = *static_cast(data); + Detail::DoNotFreeHandle doNotFree(cap.m_cont); + Detail::unused(doNotFree); + + return call(origin, dg, dat, msg, data); + } + + + Identity m_srcId; + Identity m_appId; + Status m_lastStatus; + DsState m_state; + + + static typename std::list::iterator find(Identity* origin) noexcept { + if (origin) { + for (auto it = g_sources.begin(); it != g_sources.end(); ++it) { + if (it->m_appId.id() == origin->id()) { + return it; + } + } + } + + return g_sources.end(); + } + + static void resetDsm() { + g_entry = nullptr; #if defined(TWPP_DETAIL_OS_WIN32) - g_dsm.unload(); + g_dsm.unload(); #endif - } + } - static Result staticCall(typename std::list::iterator src, Identity* origin, - DataGroup dg, Dat dat, Msg msg, void* data){ + static Result staticCall(typename std::list::iterator src, Identity* origin, + DataGroup dg, Dat dat, Msg msg, void* data) { #if defined(TWPP_DETAIL_OS_WIN32) - if (!g_entry){ - if (!g_dsm && !g_dsm.load(true)){ - return bummer(); - } + if (!g_entry) { + if (!g_dsm && !g_dsm.load(true)) { + return bummer(); + } - g_entry = g_dsm.resolve(); - } + g_entry = g_dsm.resolve(); + } #endif - if (!g_entry){ - return bummer(); - } + if (!g_entry) { + return bummer(); + } - auto rc = src->callRoot(origin, dg, dat, msg, data); - src->m_lastStatus = rc.status(); + auto rc = src->callRoot(origin, dg, dat, msg, data); + src->m_lastStatus = rc.status(); - if (dg == DataGroup::Control && dat == Dat::Identity && ( - (msg == Msg::CloseDs && Twpp::success(rc)) || - (msg == Msg::OpenDs && !Twpp::success(rc)) - ) - ){ - g_sources.erase(src); - if (g_sources.empty()){ - resetDsm(); - } - } + if (dg == DataGroup::Control && dat == Dat::Identity && ( + (msg == Msg::CloseDs && Twpp::success(rc)) || + (msg == Msg::OpenDs && !Twpp::success(rc)) + ) + ) { + g_sources.erase(src); + if (g_sources.empty()) { + resetDsm(); + } + } - return rc; - } + return rc; + } - static Result staticControl(Identity* origin, DataGroup dg, Dat dat, Msg msg, void* data){ - if (dg != DataGroup::Control){ - return seqError(); - } + static Result staticControl(Identity* origin, DataGroup dg, Dat dat, Msg msg, void* data) { + if (dg != DataGroup::Control) { + return seqError(); + } - switch (dat){ - case Dat::EntryPoint: - if (msg == Msg::Set){ - if (!data){ - return badValue(); - } + switch (dat) { + case Dat::EntryPoint: + if (msg == Msg::Set) { + if (!data) { + return badValue(); + } - auto& e = *static_cast(data); - g_entry = e.m_entry; - Detail::setMemFuncs(e.m_alloc, e.m_free, e.m_lock, e.m_unlock); - return success(); - } + auto& e = *static_cast(data); + g_entry = e.m_entry; + Detail::setMemFuncs(e.m_alloc, e.m_free, e.m_lock, e.m_unlock); + return success(); + } - break; + break; - case Dat::Status: { - if (msg == Msg::Get){ - if (!data){ - return badValue(); - } + case Dat::Status: { + if (msg == Msg::Get) { + if (!data) { + return badValue(); + } - *static_cast(data) = g_lastStatus; - return success(); - } + *static_cast(data) = g_lastStatus; + return success(); + } - break; - } + break; + } - case Dat::Identity: { - switch (msg){ - case Msg::Get: { - if (!data){ - return badValue(); - } + case Dat::Identity: { + switch (msg) { + case Msg::Get: { + if (!data) { + return badValue(); + } - static_assert(Detail::HasStaticMethod_defaultIdentity::value, - "Your source class lacks `static const Identity& defaultIdentity()` method."); + static_assert(Detail::HasStaticMethod_defaultIdentity::value, + "Your source class lacks `static const Identity& defaultIdentity()` method."); - auto& ident = *static_cast(data); - const Identity& def = Derived::defaultIdentity(); - ident = Identity(ident.id(), def.version(), def.protocolMajor(), - def.protocolMinor(), def.dataGroupsRaw(), def.manufacturer(), - def.productFamily(), def.productName()); + auto& ident = *static_cast(data); + const Identity& def = Derived::defaultIdentity(); + ident = Identity(ident.id(), def.version(), def.protocolMajor(), + def.protocolMinor(), def.dataGroupsRaw(), def.manufacturer(), + def.productFamily(), def.productName()); - return success(); - } + return success(); + } - case Msg::OpenDs: { - g_sources.emplace_back(); - return staticCall(--g_sources.end(), origin, dg, dat, msg, data); - } + case Msg::OpenDs: { + g_sources.emplace_back(); + return staticCall(--g_sources.end(), origin, dg, dat, msg, data); + } - case Msg::CloseDs: - // not open yet - return success(); + case Msg::CloseDs: + // not open yet + return success(); - default: - break; - } + default: + break; + } - break; - } + break; + } - default: - if (dat >= Dat::CustomBase){ - static_assert(Detail::HasStaticMethod_staticCustomBase::value || - !hasStaticCustomBaseProc, - "Your source class lacks `static Result staticCustomBase(Dat, Msg, void*)` method."); + default: + if (dat >= Dat::CustomBase) { + static_assert(Detail::HasStaticMethod_staticCustomBase::value || + !hasStaticCustomBaseProc, + "Your source class lacks `static Result staticCustomBase(Dat, Msg, void*)` method."); - return Detail::StaticCustomBaseProc()(dat, msg, data); - } + return Detail::StaticCustomBaseProc()(dat, msg, data); + } - break; - } + break; + } - return badProtocol(); - } + return badProtocol(); + } -public: - /// TWAIN entry, do not call from data source. - static ReturnCode entry(Identity* origin, DataGroup dg, Dat dat, Msg msg, void* data) noexcept{ - auto src = find(origin); - try { - auto rc = src == g_sources.end() ? - staticControl(origin, dg, dat, msg, data) : - staticCall(src, origin, dg, dat, msg, data); + public: + /// TWAIN entry, do not call from data source. + static ReturnCode entry(Identity* origin, DataGroup dg, Dat dat, Msg msg, void* data) noexcept { + auto src = find(origin); + try { + auto rc = src == g_sources.end() ? + staticControl(origin, dg, dat, msg, data) : + staticCall(src, origin, dg, dat, msg, data); - g_lastStatus = rc.status(); - return rc.returnCode(); - } catch (const std::bad_alloc&) { - g_lastStatus = ConditionCode::LowMemory; - return ReturnCode::Failure; - } catch (...){ - // we can't throw exceptions out of data sources - // the C interface can't really handle them - // especially when there are different implementations - g_lastStatus = ConditionCode::Bummer; - return ReturnCode::Failure; - } - } + g_lastStatus = rc.status(); + return rc.returnCode(); + } + catch (const std::bad_alloc&) { + g_lastStatus = ConditionCode::LowMemory; + return ReturnCode::Failure; + } + catch (...) { + // we can't throw exceptions out of data sources + // the C interface can't really handle them + // especially when there are different implementations + g_lastStatus = ConditionCode::Bummer; + return ReturnCode::Failure; + } + } -private: - static std::list g_sources; - static Detail::DsmEntry g_entry; - static Status g_lastStatus; + private: + static std::list g_sources; + static Detail::DsmEntry g_entry; + static Status g_lastStatus; #if defined(TWPP_DETAIL_OS_WIN32) - static Detail::DsmLib g_dsm; // only old windows dsm requires this + static Detail::DsmLib g_dsm; // only old windows dsm requires this #endif -}; + }; -template -std::list SourceFromThis::g_sources; + template + std::list SourceFromThis::g_sources; -template -Detail::DsmEntry SourceFromThis::g_entry; + template + Detail::DsmEntry SourceFromThis::g_entry; -template -Status SourceFromThis::g_lastStatus = ConditionCode::Bummer; + template + Status SourceFromThis::g_lastStatus = ConditionCode::Bummer; #if defined(TWPP_DETAIL_OS_WIN32) -template -Detail::DsmLib SourceFromThis::g_dsm; + template + Detail::DsmLib SourceFromThis::g_dsm; #endif }