mirror of http://192.168.1.51:8099/lmh188/twain3.0
2204 lines
62 KiB
C++
2204 lines
62 KiB
C++
/*
|
|
|
|
The MIT License (MIT)
|
|
|
|
Copyright (c) 2015-2018 Martin Richter
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
|
|
*/
|
|
|
|
#ifndef TWPP_DETAIL_FILE_DATASOURCE_HPP
|
|
#define TWPP_DETAIL_FILE_DATASOURCE_HPP
|
|
|
|
#include "../twpp.hpp"
|
|
|
|
namespace Twpp {
|
|
|
|
namespace Detail {
|
|
|
|
TWPP_DETAIL_PACK_BEGIN
|
|
struct AppCapability {
|
|
|
|
CapType m_cap;
|
|
ConType m_conType;
|
|
Handle m_cont;
|
|
|
|
};
|
|
TWPP_DETAIL_PACK_END
|
|
|
|
struct DoNotFreeHandle {
|
|
|
|
DoNotFreeHandle(Handle handle) {
|
|
Detail::GlobalMemFuncs<void>::doNotFreeHandle = handle;
|
|
}
|
|
|
|
~DoNotFreeHandle() {
|
|
Detail::GlobalMemFuncs<void>::doNotFreeHandle = Handle();
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
#define TWPP_ENTRY(SourceClass)\
|
|
extern "C" TWPP_DETAIL_EXPORT Twpp::ReturnCode TWPP_DETAIL_CALLSTYLE \
|
|
DS_Entry(Twpp::Identity* origin, Twpp::DataGroup dg, Twpp::Dat dat, Twpp::Msg msg, void* data){\
|
|
static_assert(\
|
|
std::is_base_of<Twpp::SourceFromThis<SourceClass, false>, SourceClass>::value ||\
|
|
std::is_base_of<Twpp::SourceFromThis<SourceClass, true>, SourceClass>::value,\
|
|
"Class " #SourceClass " is not derived from SourceFromThis."\
|
|
);\
|
|
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<typename Derived, bool enabled> // false
|
|
struct StaticCustomBaseProc {
|
|
Result operator()(Dat, Msg, void*) {
|
|
return { ReturnCode::Failure, ConditionCode::BadProtocol };
|
|
}
|
|
};
|
|
|
|
template<typename Derived>
|
|
struct StaticCustomBaseProc<Derived, true> {
|
|
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(<name-of-your-class>)
|
|
/// 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<typename Derived, bool hasStaticCustomBaseProc = false>
|
|
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<Capability*>(data));
|
|
case Dat::CustomData:
|
|
return customData(origin, msg, *static_cast<CustomData*>(data));
|
|
case Dat::DeviceEvent:
|
|
return deviceEvent(origin, msg, *static_cast<DeviceEvent*>(data));
|
|
case Dat::Event: // Windows only
|
|
return event(origin, msg, *static_cast<Event*>(data));
|
|
case Dat::FileSystem:
|
|
return fileSystem(origin, msg, *static_cast<FileSystem*>(data));
|
|
case Dat::Identity:
|
|
return identity(origin, msg, *static_cast<Identity*>(data));
|
|
case Dat::PassThrough:
|
|
return passThrough(origin, msg, *static_cast<PassThrough*>(data));
|
|
case Dat::PendingXfers:
|
|
return pendingXfers(origin, msg, *static_cast<PendingXfers*>(data));
|
|
case Dat::SetupFileXfer:
|
|
return setupFileXfer(origin, msg, *static_cast<SetupFileXfer*>(data));
|
|
case Dat::SetupMemXfer:
|
|
return setupMemXfer(origin, msg, *static_cast<SetupMemXfer*>(data));
|
|
case Dat::Status:
|
|
return status(origin, msg, *static_cast<Status*>(data));
|
|
case Dat::StatusUtf8:
|
|
return statusUtf8(origin, msg, *static_cast<StatusUtf8*>(data));
|
|
case Dat::UserInterface:
|
|
return userInterface(origin, msg, *static_cast<UserInterface*>(data));
|
|
case Dat::XferGroup: {
|
|
return xferGroup(origin, msg, *static_cast<DataGroup*>(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;
|
|
#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();
|
|
}
|
|
#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) = 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)) {
|
|
setState(DsState::Enabled);
|
|
}
|
|
|
|
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<ExtImageInfo&>(data)
|
|
/// GrayResponse: reinterpret_cast<GrayResponse&>(data)
|
|
/// RgbResponse: reinterpret_cast<RgbResponse&>(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<CieColor*>(data));*/
|
|
case Dat::ExtImageInfo:
|
|
return extImageInfo(origin, msg, reinterpret_cast<ExtImageInfo&>(data)); // ExtImageInfo is simply a `pointer to TW_EXTIMAGEINFO`
|
|
case Dat::GrayResponse:
|
|
return grayResponse(origin, msg, reinterpret_cast<GrayResponse&>(data)); // GrayResponse is simply a `pointer to TW_GRAYRESPONSE`
|
|
case Dat::IccProfile:
|
|
return iccProfile(origin, msg, *static_cast<Memory*>(data));
|
|
case Dat::ImageFileXfer:
|
|
return imageFileXfer(origin, msg);
|
|
case Dat::ImageInfo:
|
|
return imageInfo(origin, msg, *static_cast<ImageInfo*>(data));
|
|
case Dat::ImageLayout:
|
|
return imageLayout(origin, msg, *static_cast<ImageLayout*>(data));
|
|
case Dat::ImageMemFileXfer:
|
|
return imageMemFileXfer(origin, msg, *static_cast<ImageMemFileXfer*>(data));
|
|
case Dat::ImageMemXfer:
|
|
return imageMemXfer(origin, msg, *static_cast<ImageMemXfer*>(data));
|
|
case Dat::ImageNativeXfer:
|
|
return imageNativeXfer(origin, msg, *static_cast<ImageNativeXfer*>(data));
|
|
case Dat::JpegCompression:
|
|
return jpegCompression(origin, msg, *static_cast<JpegCompression*>(data));
|
|
case Dat::Palette8:
|
|
return palette8(origin, msg, *static_cast<Palette8*>(data));
|
|
case Dat::RgbResponse:
|
|
return rgbResponse(origin, msg, reinterpret_cast<RgbResponse&>(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<AudioInfo*>(data));
|
|
case Dat::AudioNativeXfer:
|
|
return audioNativeXfer(origin, msg, *static_cast<AudioNativeXfer*>(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<Detail::AppCapability*>(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<Derived>::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();
|
|
#endif
|
|
}
|
|
|
|
static Result staticCall(typename std::list<Derived>::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();
|
|
}
|
|
|
|
g_entry = g_dsm.resolve();
|
|
}
|
|
#endif
|
|
|
|
if (!g_entry) {
|
|
return bummer();
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
auto& e = *static_cast<Detail::EntryPoint*>(data);
|
|
g_entry = e.m_entry;
|
|
Detail::setMemFuncs(e.m_alloc, e.m_free, e.m_lock, e.m_unlock);
|
|
return success();
|
|
}
|
|
|
|
break;
|
|
|
|
case Dat::Status: {
|
|
if (msg == Msg::Get) {
|
|
if (!data) {
|
|
return badValue();
|
|
}
|
|
|
|
*static_cast<Status*>(data) = g_lastStatus;
|
|
return success();
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case Dat::Identity: {
|
|
switch (msg) {
|
|
case Msg::Get: {
|
|
if (!data) {
|
|
return badValue();
|
|
}
|
|
|
|
static_assert(Detail::HasStaticMethod_defaultIdentity<Derived, const Identity& ()>::value,
|
|
"Your source class lacks `static const Identity& defaultIdentity()` method.");
|
|
|
|
auto& ident = *static_cast<Identity*>(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();
|
|
}
|
|
|
|
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();
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
if (dat >= Dat::CustomBase) {
|
|
static_assert(Detail::HasStaticMethod_staticCustomBase<Derived, Result(Dat, Msg, void*)>::value ||
|
|
!hasStaticCustomBaseProc,
|
|
"Your source class lacks `static Result staticCustomBase(Dat, Msg, void*)` method.");
|
|
|
|
return Detail::StaticCustomBaseProc<Derived, hasStaticCustomBaseProc>()(dat, msg, data);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
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);
|
|
|
|
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<Derived> 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
|
|
#endif
|
|
|
|
};
|
|
|
|
template<typename Derived, bool proc>
|
|
std::list<Derived> SourceFromThis<Derived, proc>::g_sources;
|
|
|
|
template<typename Derived, bool proc>
|
|
Detail::DsmEntry SourceFromThis<Derived, proc>::g_entry;
|
|
|
|
template<typename Derived, bool proc>
|
|
Status SourceFromThis<Derived, proc>::g_lastStatus = ConditionCode::Bummer;
|
|
|
|
#if defined(TWPP_DETAIL_OS_WIN32)
|
|
template<typename Derived, bool proc>
|
|
Detail::DsmLib SourceFromThis<Derived, proc>::g_dsm;
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif // TWPP_DETAIL_FILE_DATASOURCE_HPP
|
|
|