// Copyright (c) 2013 by István Váradi // This file is part of XPLRA, a remote-access plugin for X-Plane // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // 1. Redistributions of source code must retain the above copyright notice, this // list of conditions and the following disclaimer. // 2. Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // The views and conclusions contained in the software and documentation are those // of the authors and should not be interpreted as representing official policies, // either expressed or implied, of the FreeBSD Project. #ifndef HU_VARADIISTVAN_XPLRA_MULTIBUFFER_H #define HU_VARADIISTVAN_XPLRA_MULTIBUFFER_H //------------------------------------------------------------------------------ #include "Exception.h" #include #include #include //------------------------------------------------------------------------------ namespace hu { namespace varadiistvan { namespace xplra { //------------------------------------------------------------------------------ class XPlane; //------------------------------------------------------------------------------ /** * Base class for the multi-get and multi-set handlers. It contains * the meta-data of the datarefs as well as a buffer for storing the * data. */ class MultiBuffer { protected: /** * Information about a dataref. */ class DataRef { public: /** * The name. */ std::string name; /** * The type (the protocol constant). */ uint8_t type; /** * The length in case of array types. */ size_t length; /** * The offset in case of array types. */ size_t offset; /** * The offset within the data buffer. */ size_t dataOffset; /** * Construct the dataref with the given data. */ DataRef(const std::string& name, uint8_t type, const DataRef* previous = 0, size_t length = 0, size_t offset = 0) throw(); /** * Get the size of the data represented by this object. */ size_t getSize() const throw(); /** * Get the alignment requirement of the data represented by * this dataref. */ size_t getAlignment() const throw(); /** * Determine if the dataref is an array. */ bool isArray() const throw(); /** * Get the length of the data the can be copied for the given * user parameters. */ size_t getCopyLength(size_t userLength, size_t userOffset) const throw(); }; /** * The datarefs. */ std::vector dataRefs; /** * The data buffer. */ mutable unsigned char* data; /** * The XPlane object this buffer belongs to. */ XPlane& xplane; /** * The command to use for registering the buffer. */ uint8_t registerCommand; /** * The command to unregister the buffer. */ uint8_t unregisterCommand; /** * The ID with which this buffer is registered in the plugin. If * negative, the buffer is not registerd yet. */ int registeredID; protected: /** * Construct an empty buffer for the given XPlane instance. */ MultiBuffer(XPlane& xplane, uint8_t registerCommand, uint8_t unregisterCommand) throw(); /** * Destroy the buffer. If it is registered, an attempt will be * made to unregister it. */ virtual ~MultiBuffer() throw(); public: /** * Get the X-Plane object this buffer belongs to. */ XPlane& getXPlane() const throw(); /** * Add an integer dataref. * * @return the ID of the dataref, that can be used later to set or * get the value. */ size_t addInt(const std::string& name) throw(); /** * Add a float dataref. * * @return the ID of the dataref, that can be used later to set or * get the value. */ size_t addFloat(const std::string& name) throw(); /** * Add a double dataref. * * @return the ID of the dataref, that can be used later to set or * get the value. */ size_t addDouble(const std::string& name) throw(); /** * Add a float array dataref. * * @return the ID of the dataref, that can be used later to set or * get the value. */ size_t addFloatArray(const std::string& name, size_t length, size_t offset = 0) throw(); /** * Add an integer array dataref. * * @return the ID of the dataref, that can be used later to set or * get the value. */ size_t addIntArray(const std::string& name, size_t length, size_t offset = 0) throw(); /** * Add a byte array dataref. * * @return the ID of the dataref, that can be used later to set or * get the value. */ size_t addByteArray(const std::string& name, size_t length, size_t offset = 0) throw(); /** * Finalize the buffer, if not finalized yet. * * @return if there is any data in it */ bool finalize() const; /** * Register this buffer in X-Plane the for either getting or * setting, depending on the actual subclass. It will be finalized * too. */ void registerInXPlane() throw(Exception); /** * Unregister this buffer from X-Plane. */ void unregisterFromXPlane() throw(Exception); /** * Unregister this buffer from X-Plane safely, i.e. without * throwing any exceptions. If unregistration fails, the * registered ID will be cleared anyway. * * @return whether unregistration succeeded. */ bool unregisterSafelyFromXPlane() throw(); /** * Execute the buffer by either reading or writing it. If the * buffer is not finalized, it will be finalized. If it is not * finalized, but registered, the registration will be cleared, * and it will be re-registered after finalizing. */ void execute() throw(Exception); /** * Set the value of an integer dataref with the given ID. */ void setInt(size_t id, int value) throw(InvalidIDException, TypeMismatchException); /** * Get the value of an integer dataref with the given ID. */ int getInt(size_t id) const throw(InvalidIDException, TypeMismatchException); /** * Get a reference to the integer dataref with the given ID */ const int32_t& getIntRef(size_t id) const throw(InvalidIDException, TypeMismatchException); /** * Get a reference to the integer dataref with the given ID */ int32_t& getIntRef(size_t id) throw(InvalidIDException, TypeMismatchException); /** * Set the value of a float dataref with the given ID. */ void setFloat(size_t id, float value) throw(InvalidIDException, TypeMismatchException); /** * Get the value of a float dataref with the given ID. */ float getFloat(size_t id) const throw(InvalidIDException, TypeMismatchException); /** * Get a reference to the float dataref with the given ID */ const float& getFloatRef(size_t id) const throw(InvalidIDException, TypeMismatchException); /** * Get a reference to the integer dataref with the given ID */ float& getFloatRef(size_t id) throw(InvalidIDException, TypeMismatchException); /** * Set the value of a double dataref with the given ID. */ void setDouble(size_t id, double value) throw(InvalidIDException, TypeMismatchException); /** * Get the value of a double dataref with the given ID. */ double getDouble(size_t id) const throw(InvalidIDException, TypeMismatchException); /** * Get a reference to the double dataref with the given ID */ const double& getDoubleRef(size_t id) const throw(InvalidIDException, TypeMismatchException); /** * Get a reference to the double dataref with the given ID */ double& getDoubleRef(size_t id) throw(InvalidIDException, TypeMismatchException); /** * Set the value of the float array dataref with the given ID. * * @param length the amount of data, i.e. you can set only a part * of the data in the buffer. If 0, it is assumed to be the length * of the data in the buffer minus the offset (see below). * * @param offset the offset within the buffer to set the data from * * @return the number of data items set */ size_t setFloatArray(size_t id, const float* value, size_t length = 0, size_t offset = 0) throw(InvalidIDException, TypeMismatchException); /** * Get the value of the float array dataref with the given ID * * @param length the size of the buffer. If 0, it is assumed to be * the length of the data in the buffer minus the offset (see * below). * * @param offset the offset within the buffer to get the data from * * @return the number of data items retrieved. */ size_t getFloatArray(size_t id, float* value, size_t length = 0, size_t offset = 0) const throw(InvalidIDException, TypeMismatchException); /** * Get the array of floating point values as a directly readable * buffer. * * @param offset the offset within the buffer. If it is not less * than the length of the buffer, 0 is returned. */ const float* getFloatArray(size_t id, size_t offset = 0) const throw(InvalidIDException, TypeMismatchException); /** * Set the value of the integer array dataref with the given ID. * * @param length the amount of data, i.e. you can set only a part * of the data in the buffer. If 0, it is assumed to be the length * of the data in the buffer minus the offset (see below). * * @param offset the offset within the buffer to set the data from * * @return the number of data items set */ size_t setIntArray(size_t id, const int32_t* value, size_t length = 0, size_t offset = 0) throw(InvalidIDException, TypeMismatchException); /** * Get the value of the integer array dataref with the given ID * * @param length the size of the buffer. If 0, it is assumed to be * the length of the data in the buffer minus the offset (see * below). * * @param offset the offset within the buffer to get the data from * * @return the number of data items retrieved. */ size_t getIntArray(size_t id, int32_t* value, size_t length = 0, size_t offset = 0) const throw(InvalidIDException, TypeMismatchException); /** * Get the array of integer values as a directly readable buffer. * * @param offset the offset within the buffer. If it is not less * than the length of the buffer, 0 is returned. */ const int32_t* getIntArray(size_t id, size_t offset = 0) const throw(InvalidIDException, TypeMismatchException); /** * Set the value of the byte array dataref with the given ID. * * @param length the amount of data, i.e. you can set only a part * of the data in the buffer. If 0, it is assumed to be the length * of the data in the buffer minus the offset (see below). * * @param offset the offset within the buffer to set the data from * * @return the number of data items set */ size_t setByteArray(size_t id, const uint8_t* value, size_t length = 0, size_t offset = 0) throw(InvalidIDException, TypeMismatchException); /** * Get the value of the byte array dataref with the given ID * * @param length the size of the buffer. If 0, it is assumed to be * the length of the data in the buffer minus the offset (see * below). * * @param offset the offset within the buffer to get the data from * * @return the number of data items retrieved. */ size_t getByteArray(size_t id, uint8_t* value, size_t length = 0, size_t offset = 0) const throw(InvalidIDException, TypeMismatchException); /** * Get the array of byte values as a directly readable buffer. * * @param offset the offset within the buffer. If it is not less * than the length of the buffer, 0 is returned. */ const uint8_t* getByteArray(size_t id, size_t offset = 0) const throw(InvalidIDException, TypeMismatchException); /** * Set the value of the byte array dataref with the given ID * from the given string. If the string contains less characters * than the array's length, the rest will be filled with 0s. * * @return the number of bytes set */ size_t setString(size_t id, const std::string& value, size_t offset = 0) throw(InvalidIDException, TypeMismatchException); /** * Get the value of the byte array dataref with the given ID as * a string. */ std::string getString(size_t id, size_t offset = 0) const throw(InvalidIDException, TypeMismatchException); /** * Get a string pointer to the value of the byte array dataref * with the given ID. */ const char* getStringPtr(size_t id, size_t offset = 0) const throw(InvalidIDException, TypeMismatchException); protected: /** * Perform the main part of the execution if the buffer is * registered. */ virtual void doExecute() throw(Exception) = 0; /** * Perform the main part of the execution if the buffer is * not registered. */ virtual void doExecuteUnregistered() throw(Exception) = 0; /** * Write the data specification with the given command. It also * checks the result */ void writeSpec(uint8_t command) const throw(Exception); /** * Re-register the buffer in X-Plane, if it has been registered * earlier. * * it has not been registered, nothing is done. Otherwise the * buffer gets registered, and the old ID is forgotten. This * function is meant to be used by the XPlane object when it * creates a new connection. If the registration fails, the * original ID is restored, so that this function could be called * again */ void reregisterInXPlane() throw(Exception); private: /** * Unfinalize the buffer, if it is finalized. */ void unfinalize() throw(); /** * Forget the registration of this buffer. This is called from the * destructor of the XPlane object, since that closes the * connection anyway, so there is no need to unregister the * multi-buffers. */ void forgetRegistration() throw(); /** * Get the last dataref, or 0 if there are not datarefs yet. */ const DataRef* getLastDataRef() const throw(); /** * Get the dataref with the given ID if it is of the given * type. Otherwise throw an exception. */ const DataRef& getDataRef(size_t id, uint8_t type) const throw(InvalidIDException, TypeMismatchException); /** * Get the data area belonging to the given dataref it is of the * given type. If the buffer is not finalized yet, it will be. */ void* getData(size_t id, uint8_t type) throw(InvalidIDException, TypeMismatchException); /** * Get the data area belonging to the given dataref it is of the * given type. If the buffer is not finalized yet, it will be. */ const void* getData(size_t id, uint8_t type) const throw(InvalidIDException, TypeMismatchException); /** * Template function for setting an array of a certain type. */ template size_t setArray(size_t id, const T* value, size_t length, size_t offset) throw(InvalidIDException, TypeMismatchException); /** * Template function for getting the elements of an array of a * certain type. */ template size_t getArray(size_t id, T* value, size_t length, size_t offset) const throw(InvalidIDException, TypeMismatchException); /** * Template function for getting the elements of an array of a * certain type. */ template const T* getArray(size_t id, size_t offset) const throw(InvalidIDException, TypeMismatchException); friend class XPlane; }; //------------------------------------------------------------------------------ // Inline definitions //------------------------------------------------------------------------------ inline XPlane& MultiBuffer::getXPlane() const throw() { return xplane; } //------------------------------------------------------------------------------ } /* namespace hu::varadiistvan::xplra */ } /* namespace hu::varadiistvan */ } /* namespace hu */ //------------------------------------------------------------------------------ #endif // HU_VARADIISTVAN_XPLRA_MULTIBUFFER_H // Local Variables: // mode: C++ // c-basic-offset: 4 // indent-tabs-mode: nil // End: