From 388effd4152650789374c73fddc0ce74d2849672 Mon Sep 17 00:00:00 2001 From: "heesung84.kim" Date: Wed, 10 Dec 2014 14:00:13 +0900 Subject: [PATCH] Added Plugin Manager Configuration Feature - application developer can modify plugin manager configuration(xml) like plugin path, max number of plugins. Added More Plugin Manager APIs - int getState() getState API can get plugin's state - int rescanPlugin() Rescan the plugin folder Removed Unnecessary Plugin Manager APIs - std::string getSupportedType(void) - int addSupportedType(const std::string rscType) Disabled Auto Plugin Detection Feature - In previous version, PPM used iNotify to detect new Plugin detection. However, iNotify have platform porting issue and heavy. We will find better way in next version. Change-Id: I0efac20efbc39b3fb0b2bcc1a34685acad1c7517 Signed-off-by: heesung84.kim --- service/protocol-plugin/build/linux/Makefile | 8 +- service/protocol-plugin/lib/rapidxml/rapidxml.hpp | 2601 ++++++++++++++++++++ .../lib/rapidxml/rapidxml_iterators.hpp | 174 ++ .../lib/rapidxml/rapidxml_print.hpp | 422 ++++ .../lib/rapidxml/rapidxml_utils.hpp | 122 + .../plugin-manager/build/linux/Makefile | 12 +- .../protocol-plugin/plugin-manager/src/Config.cpp | 157 ++ .../protocol-plugin/plugin-manager/src/Config.h | 122 + .../plugin-manager/src/CpluffAdapter.cpp | 68 +- .../plugin-manager/src/CpluffAdapter.h | 22 +- .../plugin-manager/src/FelixAdapter.cpp | 17 +- .../plugin-manager/src/FelixAdapter.h | 5 +- .../protocol-plugin/plugin-manager/src/Plugin.cpp | 10 - .../protocol-plugin/plugin-manager/src/Plugin.h | 16 - .../plugin-manager/src/PluginManager.cpp | 13 +- .../plugin-manager/src/PluginManager.h | 24 +- .../plugin-manager/src/PluginManagerImpl.cpp | 17 + .../plugin-manager/src/PluginManagerImpl.h | 15 +- .../plugins/mqtt-fan/build/linux/Makefile | 7 +- .../protocol-plugin/plugins/mqtt-fan/lib/Makefile | 2 +- .../plugins/mqtt-fan/lib/python/Makefile | 2 - .../plugins/mqtt-fan/src/fanserver.cpp | 155 +- .../plugins/mqtt-light/build/linux/Makefile | 7 +- .../plugins/mqtt-light/lib/Makefile | 2 +- .../plugins/mqtt-light/lib/python/Makefile | 2 - .../plugins/mqtt-light/src/lightserver.cpp | 153 +- service/protocol-plugin/readme | 81 +- .../linux/{fan-control => mqtt}/Makefile | 17 +- .../fanclient.cpp => mqtt/mqttclient.cpp} | 106 +- .../sample-app/linux/mqtt/pluginmanager.xml | 12 + 30 files changed, 4059 insertions(+), 312 deletions(-) create mode 100644 service/protocol-plugin/lib/rapidxml/rapidxml.hpp create mode 100644 service/protocol-plugin/lib/rapidxml/rapidxml_iterators.hpp create mode 100644 service/protocol-plugin/lib/rapidxml/rapidxml_print.hpp create mode 100644 service/protocol-plugin/lib/rapidxml/rapidxml_utils.hpp create mode 100644 service/protocol-plugin/plugin-manager/src/Config.cpp create mode 100644 service/protocol-plugin/plugin-manager/src/Config.h rename service/protocol-plugin/sample-app/linux/{fan-control => mqtt}/Makefile (69%) rename service/protocol-plugin/sample-app/linux/{fan-control/fanclient.cpp => mqtt/mqttclient.cpp} (83%) create mode 100644 service/protocol-plugin/sample-app/linux/mqtt/pluginmanager.xml diff --git a/service/protocol-plugin/build/linux/Makefile b/service/protocol-plugin/build/linux/Makefile index 7def475..53f0396 100644 --- a/service/protocol-plugin/build/linux/Makefile +++ b/service/protocol-plugin/build/linux/Makefile @@ -20,14 +20,14 @@ plugins: cd $(PROTOCOL_ROOT)plugins/mqtt-light/build/linux && $(MAKE) sample-app: - cd $(PROTOCOL_ROOT)sample-app/linux/fan-control && $(MAKE) - cp -Rdp $(PROTOCOL_ROOT)sample-app/linux/fan-control/fanclient release/ + cd $(PROTOCOL_ROOT)sample-app/linux/mqtt && $(MAKE) + cp -Rdp $(PROTOCOL_ROOT)plugin-manager/build/linux/libpmimpl.so $(PROTOCOL_ROOT)sample-app/linux/mqtt/ + cp -Rdp $(PROTOCOL_ROOT)sample-app/linux/mqtt/mqttclient release/ clean: cd $(PROTOCOL_ROOT)plugin-manager/build/linux && $(MAKE) clean cd $(PROTOCOL_ROOT)plugins/mqtt-fan/build/linux && $(MAKE) clean cd $(PROTOCOL_ROOT)plugins/mqtt-light/build/linux && $(MAKE) clean - cd $(PROTOCOL_ROOT)plugins/hue/build/linux && $(MAKE) clean - cd $(PROTOCOL_ROOT)sample-app/linux/fan-control && $(MAKE) clean + cd $(PROTOCOL_ROOT)sample-app/linux/mqtt && $(MAKE) clean rm -rf release diff --git a/service/protocol-plugin/lib/rapidxml/rapidxml.hpp b/service/protocol-plugin/lib/rapidxml/rapidxml.hpp new file mode 100644 index 0000000..9ddf195 --- /dev/null +++ b/service/protocol-plugin/lib/rapidxml/rapidxml.hpp @@ -0,0 +1,2601 @@ +#ifndef RAPIDXML_HPP_INCLUDED +#define RAPIDXML_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml.hpp This file contains rapidxml parser and DOM implementation + +// If standard library is disabled, user must provide implementations of required functions and typedefs +#if !defined(RAPIDXML_NO_STDLIB) + #include // For std::size_t + #include // For assert + #include // For placement new +#endif + +// On MSVC, disable "conditional expression is constant" warning (level 4). +// This warning is almost impossible to avoid with certain types of templated code +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable:4127) // Conditional expression is constant +#endif + +/////////////////////////////////////////////////////////////////////////// +// RAPIDXML_PARSE_ERROR + +#if defined(RAPIDXML_NO_EXCEPTIONS) + +#define RAPIDXML_PARSE_ERROR(what, where) { parse_error_handler(what, where); assert(0); } + +namespace rapidxml +{ + //! When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, + //! this function is called to notify user about the error. + //! It must be defined by the user. + //!

+ //! This function cannot return. If it does, the results are undefined. + //!

+ //! A very simple definition might look like that: + //!
+    //! void %rapidxml::%parse_error_handler(const char *what, void *where)
+    //! {
+    //!     std::cout << "Parse error: " << what << "\n";
+    //!     std::abort();
+    //! }
+    //! 
+ //! \param what Human readable description of the error. + //! \param where Pointer to character data where error was detected. + void parse_error_handler(const char *what, void *where); +} + +#else + +#include // For std::exception + +#define RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where) + +namespace rapidxml +{ + + //! Parse error exception. + //! This exception is thrown by the parser when an error occurs. + //! Use what() function to get human-readable error message. + //! Use where() function to get a pointer to position within source text where error was detected. + //!

+ //! If throwing exceptions by the parser is undesirable, + //! it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included. + //! This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception. + //! This function must be defined by the user. + //!

+ //! This class derives from std::exception class. + class parse_error: public std::exception + { + + public: + + //! Constructs parse error + parse_error(const char *what, void *where) + : m_what(what) + , m_where(where) + { + } + + //! Gets human readable description of error. + //! \return Pointer to null terminated description of the error. + virtual const char *what() const throw() + { + return m_what; + } + + //! Gets pointer to character data where error happened. + //! Ch should be the same as char type of xml_document that produced the error. + //! \return Pointer to location within the parsed string where error occured. + template + Ch *where() const + { + return reinterpret_cast(m_where); + } + + private: + + const char *m_what; + void *m_where; + + }; +} + +#endif + +/////////////////////////////////////////////////////////////////////////// +// Pool sizes + +#ifndef RAPIDXML_STATIC_POOL_SIZE + // Size of static memory block of memory_pool. + // Define RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. + // No dynamic memory allocations are performed by memory_pool until static memory is exhausted. + #define RAPIDXML_STATIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef RAPIDXML_DYNAMIC_POOL_SIZE + // Size of dynamic memory block of memory_pool. + // Define RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. + // After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool. + #define RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef RAPIDXML_ALIGNMENT + // Memory allocation alignment. + // Define RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer. + // All memory allocations for nodes, attributes and strings will be aligned to this value. + // This must be a power of 2 and at least 1, otherwise memory_pool will not work. + #define RAPIDXML_ALIGNMENT sizeof(void *) +#endif + +namespace rapidxml +{ + // Forward declarations + template class xml_node; + template class xml_attribute; + template class xml_document; + + //! Enumeration listing all node types produced by the parser. + //! Use xml_node::type() function to query node type. + enum node_type + { + node_document, //!< A document node. Name and value are empty. + node_element, //!< An element node. Name contains element name. Value contains text of first data node. + node_data, //!< A data node. Name is empty. Value contains data text. + node_cdata, //!< A CDATA node. Name is empty. Value contains data text. + node_comment, //!< A comment node. Name is empty. Value contains comment text. + node_declaration, //!< A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes. + node_doctype, //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text. + node_pi //!< A PI node. Name contains target. Value contains instructions. + }; + + /////////////////////////////////////////////////////////////////////// + // Parsing flags + + //! Parse flag instructing the parser to not create data nodes. + //! Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_data_nodes = 0x1; + + //! Parse flag instructing the parser to not use text of first data node as a value of parent element. + //! Can be combined with other flags by use of | operator. + //! Note that child data nodes of element node take precendence over its value when printing. + //! That is, if element has one or more child data nodes and a value, the value will be ignored. + //! Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements. + //!

+ //! See xml_document::parse() function. + const int parse_no_element_values = 0x2; + + //! Parse flag instructing the parser to not place zero terminators after strings in the source text. + //! By default zero terminators are placed, modifying source text. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_string_terminators = 0x4; + + //! Parse flag instructing the parser to not translate entities in the source text. + //! By default entities are translated, modifying source text. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_entity_translation = 0x8; + + //! Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters. + //! By default, UTF-8 handling is enabled. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_utf8 = 0x10; + + //! Parse flag instructing the parser to create XML declaration node. + //! By default, declaration node is not created. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_declaration_node = 0x20; + + //! Parse flag instructing the parser to create comments nodes. + //! By default, comment nodes are not created. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_comment_nodes = 0x40; + + //! Parse flag instructing the parser to create DOCTYPE node. + //! By default, doctype node is not created. + //! Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_doctype_node = 0x80; + + //! Parse flag instructing the parser to create PI nodes. + //! By default, PI nodes are not created. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_pi_nodes = 0x100; + + //! Parse flag instructing the parser to validate closing tag names. + //! If not set, name inside closing tag is irrelevant to the parser. + //! By default, closing tags are not validated. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_validate_closing_tags = 0x200; + + //! Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes. + //! By default, whitespace is not trimmed. + //! This flag does not cause the parser to modify source text. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_trim_whitespace = 0x400; + + //! Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character. + //! Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag. + //! By default, whitespace is not normalized. + //! If this flag is specified, source text will be modified. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_normalize_whitespace = 0x800; + + // Compound flags + + //! Parse flags which represent default behaviour of the parser. + //! This is always equal to 0, so that all other flags can be simply ored together. + //! Normally there is no need to inconveniently disable flags by anding with their negated (~) values. + //! This also means that meaning of each flag is a negation of the default setting. + //! For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is enabled by default, + //! and using the flag will disable it. + //!

+ //! See xml_document::parse() function. + const int parse_default = 0; + + //! A combination of parse flags that forbids any modifications of the source text. + //! This also results in faster parsing. However, note that the following will occur: + //!
    + //!
  • names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends
  • + //!
  • entities will not be translated
  • + //!
  • whitespace will not be normalized
  • + //!
+ //! See xml_document::parse() function. + const int parse_non_destructive = parse_no_string_terminators | parse_no_entity_translation; + + //! A combination of parse flags resulting in fastest possible parsing, without sacrificing important data. + //!

+ //! See xml_document::parse() function. + const int parse_fastest = parse_non_destructive | parse_no_data_nodes; + + //! A combination of parse flags resulting in largest amount of data being extracted. + //! This usually results in slowest parsing. + //!

+ //! See xml_document::parse() function. + const int parse_full = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags; + + /////////////////////////////////////////////////////////////////////// + // Internals + + //! \cond internal + namespace internal + { + + // Struct that contains lookup tables for the parser + // It must be a template to allow correct linking (because it has static data members, which are defined in a header file). + template + struct lookup_tables + { + static const unsigned char lookup_whitespace[256]; // Whitespace table + static const unsigned char lookup_node_name[256]; // Node name table + static const unsigned char lookup_text[256]; // Text table + static const unsigned char lookup_text_pure_no_ws[256]; // Text table + static const unsigned char lookup_text_pure_with_ws[256]; // Text table + static const unsigned char lookup_attribute_name[256]; // Attribute name table + static const unsigned char lookup_attribute_data_1[256]; // Attribute data table with single quote + static const unsigned char lookup_attribute_data_1_pure[256]; // Attribute data table with single quote + static const unsigned char lookup_attribute_data_2[256]; // Attribute data table with double quotes + static const unsigned char lookup_attribute_data_2_pure[256]; // Attribute data table with double quotes + static const unsigned char lookup_digits[256]; // Digits + static const unsigned char lookup_upcase[256]; // To uppercase conversion table for ASCII characters + }; + + // Find length of the string + template + inline std::size_t measure(const Ch *p) + { + const Ch *tmp = p; + while (*tmp) + ++tmp; + return tmp - p; + } + + // Compare strings for equality + template + inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, std::size_t size2, bool case_sensitive) + { + if (size1 != size2) + return false; + if (case_sensitive) + { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (*p1 != *p2) + return false; + } + else + { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (lookup_tables<0>::lookup_upcase[static_cast(*p1)] != lookup_tables<0>::lookup_upcase[static_cast(*p2)]) + return false; + } + return true; + } + } + //! \endcond + + /////////////////////////////////////////////////////////////////////// + // Memory pool + + //! This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation. + //! In most cases, you will not need to use this class directly. + //! However, if you need to create nodes manually or modify names/values of nodes, + //! you are encouraged to use memory_pool of relevant xml_document to allocate the memory. + //! Not only is this faster than allocating them by using new operator, + //! but also their lifetime will be tied to the lifetime of document, + //! possibly simplyfing memory management. + //!

+ //! Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool. + //! You can also call allocate_string() function to allocate strings. + //! Such strings can then be used as names or values of nodes without worrying about their lifetime. + //! Note that there is no free() function -- all allocations are freed at once when clear() function is called, + //! or when the pool is destroyed. + //!

+ //! It is also possible to create a standalone memory_pool, and use it + //! to allocate nodes, whose lifetime will not be tied to any document. + //!

+ //! Pool maintains RAPIDXML_STATIC_POOL_SIZE bytes of statically allocated memory. + //! Until static memory is exhausted, no dynamic memory allocations are done. + //! When static memory is exhausted, pool allocates additional blocks of memory of size RAPIDXML_DYNAMIC_POOL_SIZE each, + //! by using global new[] and delete[] operators. + //! This behaviour can be changed by setting custom allocation routines. + //! Use set_allocator() function to set them. + //!

+ //! Allocations for nodes, attributes and strings are aligned at RAPIDXML_ALIGNMENT bytes. + //! This value defaults to the size of pointer on target architecture. + //!

+ //! To obtain absolutely top performance from the parser, + //! it is important that all nodes are allocated from a single, contiguous block of memory. + //! Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably. + //! If required, you can tweak RAPIDXML_STATIC_POOL_SIZE, RAPIDXML_DYNAMIC_POOL_SIZE and RAPIDXML_ALIGNMENT + //! to obtain best wasted memory to performance compromise. + //! To do it, define their values before rapidxml.hpp file is included. + //! \param Ch Character type of created nodes. + template + class memory_pool + { + + public: + + //! \cond internal + typedef void *(alloc_func)(std::size_t); // Type of user-defined function used to allocate memory + typedef void (free_func)(void *); // Type of user-defined function used to free memory + //! \endcond + + //! Constructs empty pool with default allocator functions. + memory_pool() + : m_alloc_func(0) + , m_free_func(0) + { + init(); + } + + //! Destroys pool and frees all the memory. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Nodes allocated from the pool are no longer valid. + ~memory_pool() + { + clear(); + } + + //! Allocates a new node from the pool, and optionally assigns name and value to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param type Type of node to create. + //! \param name Name to assign to the node, or 0 to assign no name. + //! \param value Value to assign to the node, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. + //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. + //! \return Pointer to allocated node. This pointer will never be NULL. + xml_node *allocate_node(node_type type, + const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, std::size_t value_size = 0) + { + void *memory = allocate_aligned(sizeof(xml_node)); + xml_node *node = new(memory) xml_node(type); + if (name) + { + if (name_size > 0) + node->name(name, name_size); + else + node->name(name); + } + if (value) + { + if (value_size > 0) + node->value(value, value_size); + else + node->value(value); + } + return node; + } + + //! Allocates a new attribute from the pool, and optionally assigns name and value to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param name Name to assign to the attribute, or 0 to assign no name. + //! \param value Value to assign to the attribute, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. + //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. + //! \return Pointer to allocated attribute. This pointer will never be NULL. + xml_attribute *allocate_attribute(const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, std::size_t value_size = 0) + { + void *memory = allocate_aligned(sizeof(xml_attribute)); + xml_attribute *attribute = new(memory) xml_attribute; + if (name) + { + if (name_size > 0) + attribute->name(name, name_size); + else + attribute->name(name); + } + if (value) + { + if (value_size > 0) + attribute->value(value, value_size); + else + attribute->value(value); + } + return attribute; + } + + //! Allocates a char array of given size from the pool, and optionally copies a given string to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param source String to initialize the allocated memory with, or 0 to not initialize it. + //! \param size Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated. + //! \return Pointer to allocated char array. This pointer will never be NULL. + Ch *allocate_string(const Ch *source = 0, std::size_t size = 0) + { + assert(source || size); // Either source or size (or both) must be specified + if (size == 0) + size = internal::measure(source) + 1; + Ch *result = static_cast(allocate_aligned(size * sizeof(Ch))); + if (source) + for (std::size_t i = 0; i < size; ++i) + result[i] = source[i]; + return result; + } + + //! Clones an xml_node and its hierarchy of child nodes and attributes. + //! Nodes and attributes are allocated from this memory pool. + //! Names and values are not cloned, they are shared between the clone and the source. + //! Result node can be optionally specified as a second parameter, + //! in which case its contents will be replaced with cloned source node. + //! This is useful when you want to clone entire document. + //! \param source Node to clone. + //! \param result Node to put results in, or 0 to automatically allocate result node + //! \return Pointer to cloned node. This pointer will never be NULL. + xml_node *clone_node(const xml_node *source, xml_node *result = 0) + { + // Prepare result node + if (result) + { + result->remove_all_attributes(); + result->remove_all_nodes(); + result->type(source->type()); + } + else + result = allocate_node(source->type()); + + // Clone name and value + result->name(source->name(), source->name_size()); + result->value(source->value(), source->value_size()); + + // Clone child nodes and attributes + for (xml_node *child = source->first_node(); child; child = child->next_sibling()) + result->append_node(clone_node(child)); + for (xml_attribute *attr = source->first_attribute(); attr; attr = attr->next_attribute()) + result->append_attribute(allocate_attribute(attr->name(), attr->value(), attr->name_size(), attr->value_size())); + + return result; + } + + //! Clears the pool. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Any nodes or strings allocated from the pool will no longer be valid. + void clear() + { + while (m_begin != m_static_memory) + { + char *previous_begin = reinterpret_cast
(align(m_begin))->previous_begin; + if (m_free_func) + m_free_func(m_begin); + else + delete[] m_begin; + m_begin = previous_begin; + } + init(); + } + + //! Sets or resets the user-defined memory allocation functions for the pool. + //! This can only be called when no memory is allocated from the pool yet, otherwise results are undefined. + //! Allocation function must not return invalid pointer on failure. It should either throw, + //! stop the program, or use longjmp() function to pass control to other place of program. + //! If it returns invalid pointer, results are undefined. + //!

+ //! User defined allocation functions must have the following forms: + //!
+ //!
void *allocate(std::size_t size); + //!
void free(void *pointer); + //!

+ //! \param af Allocation function, or 0 to restore default function + //! \param ff Free function, or 0 to restore default function + void set_allocator(alloc_func *af, free_func *ff) + { + assert(m_begin == m_static_memory && m_ptr == align(m_begin)); // Verify that no memory is allocated yet + m_alloc_func = af; + m_free_func = ff; + } + + private: + + struct header + { + char *previous_begin; + }; + + void init() + { + m_begin = m_static_memory; + m_ptr = align(m_begin); + m_end = m_static_memory + sizeof(m_static_memory); + } + + char *align(char *ptr) + { + std::size_t alignment = ((RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (RAPIDXML_ALIGNMENT - 1))) & (RAPIDXML_ALIGNMENT - 1)); + return ptr + alignment; + } + + char *allocate_raw(std::size_t size) + { + // Allocate + void *memory; + if (m_alloc_func) // Allocate memory using either user-specified allocation function or global operator new[] + { + memory = m_alloc_func(size); + assert(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the program or use longjmp + } + else + { + memory = new char[size]; +#ifdef RAPIDXML_NO_EXCEPTIONS + if (!memory) // If exceptions are disabled, verify memory allocation, because new will not be able to throw bad_alloc + RAPIDXML_PARSE_ERROR("out of memory", 0); +#endif + } + return static_cast(memory); + } + + void *allocate_aligned(std::size_t size) + { + // Calculate aligned pointer + char *result = align(m_ptr); + + // If not enough memory left in current pool, allocate a new pool + if (result + size > m_end) + { + // Calculate required pool size (may be bigger than RAPIDXML_DYNAMIC_POOL_SIZE) + std::size_t pool_size = RAPIDXML_DYNAMIC_POOL_SIZE; + if (pool_size < size) + pool_size = size; + + // Allocate + std::size_t alloc_size = sizeof(header) + (2 * RAPIDXML_ALIGNMENT - 2) + pool_size; // 2 alignments required in worst case: one for header, one for actual allocation + char *raw_memory = allocate_raw(alloc_size); + + // Setup new pool in allocated memory + char *pool = align(raw_memory); + header *new_header = reinterpret_cast
(pool); + new_header->previous_begin = m_begin; + m_begin = raw_memory; + m_ptr = pool + sizeof(header); + m_end = raw_memory + alloc_size; + + // Calculate aligned pointer again using new pool + result = align(m_ptr); + } + + // Update pool and return aligned pointer + m_ptr = result + size; + return result; + } + + char *m_begin; // Start of raw memory making up current pool + char *m_ptr; // First free byte in current pool + char *m_end; // One past last available byte in current pool + char m_static_memory[RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory + alloc_func *m_alloc_func; // Allocator function, or 0 if default is to be used + free_func *m_free_func; // Free function, or 0 if default is to be used + }; + + /////////////////////////////////////////////////////////////////////////// + // XML base + + //! Base class for xml_node and xml_attribute implementing common functions: + //! name(), name_size(), value(), value_size() and parent(). + //! \param Ch Character type to use + template + class xml_base + { + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + // Construct a base with empty name, value and parent + xml_base() + : m_name(0) + , m_value(0) + , m_parent(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets name of the node. + //! Interpretation of name depends on type of node. + //! Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. + //!

+ //! Use name_size() function to determine length of the name. + //! \return Name of node, or empty string if node has no name. + Ch *name() const + { + return m_name ? m_name : nullstr(); + } + + //! Gets size of node name, not including terminator character. + //! This function works correctly irrespective of whether name is or is not zero terminated. + //! \return Size of node name, in characters. + std::size_t name_size() const + { + return m_name ? m_name_size : 0; + } + + //! Gets value of node. + //! Interpretation of value depends on type of node. + //! Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. + //!

+ //! Use value_size() function to determine length of the value. + //! \return Value of node, or empty string if node has no value. + Ch *value() const + { + return m_value ? m_value : nullstr(); + } + + //! Gets size of node value, not including terminator character. + //! This function works correctly irrespective of whether value is or is not zero terminated. + //! \return Size of node value, in characters. + std::size_t value_size() const + { + return m_value ? m_value_size : 0; + } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets name of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //!

+ //! Note that node does not own its name or value, it only stores a pointer to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is reponsibility of the user to properly manage lifetime of the string. + //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - + //! on destruction of the document the string will be automatically freed. + //!

+ //! Size of name must be specified separately, because name does not have to be zero terminated. + //! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated). + //! \param name Name of node to set. Does not have to be zero terminated. + //! \param size Size of name, in characters. This does not include zero terminator, if one is present. + void name(const Ch *name, std::size_t size) + { + m_name = const_cast(name); + m_name_size = size; + } + + //! Sets name of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t). + //! \param name Name of node to set. Must be zero terminated. + void name(const Ch *name) + { + this->name(name, internal::measure(name)); + } + + //! Sets value of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //!

+ //! Note that node does not own its name or value, it only stores a pointer to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is reponsibility of the user to properly manage lifetime of the string. + //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - + //! on destruction of the document the string will be automatically freed. + //!

+ //! Size of value must be specified separately, because it does not have to be zero terminated. + //! Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated). + //!

+ //! If an element has a child node of type node_data, it will take precedence over element value when printing. + //! If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser. + //! \param value value of node to set. Does not have to be zero terminated. + //! \param size Size of value, in characters. This does not include zero terminator, if one is present. + void value(const Ch *value, std::size_t size) + { + m_value = const_cast(value); + m_value_size = size; + } + + //! Sets value of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t). + //! \param value Vame of node to set. Must be zero terminated. + void value(const Ch *value) + { + this->value(value, internal::measure(value)); + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets node parent. + //! \return Pointer to parent node, or 0 if there is no parent. + xml_node *parent() const + { + return m_parent; + } + + protected: + + // Return empty string + static Ch *nullstr() + { + static Ch zero = Ch('\0'); + return &zero; + } + + Ch *m_name; // Name of node, or 0 if no name + Ch *m_value; // Value of node, or 0 if no value + std::size_t m_name_size; // Length of node name, or undefined of no name + std::size_t m_value_size; // Length of node value, or undefined if no value + xml_node *m_parent; // Pointer to parent node, or 0 if none + + }; + + //! Class representing attribute node of XML document. + //! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base). + //! Note that after parse, both name and value of attribute will point to interior of source text used for parsing. + //! Thus, this text must persist in memory for the lifetime of attribute. + //! \param Ch Character type to use. + template + class xml_attribute: public xml_base + { + + friend class xml_node; + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty attribute with the specified type. + //! Consider using memory_pool of appropriate xml_document if allocating attributes manually. + xml_attribute() + { + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which attribute is a child. + //! \return Pointer to document that contains this attribute, or 0 if there is no parent document. + xml_document *document() const + { + if (xml_node *node = this->parent()) + { + while (node->parent()) + node = node->parent(); + return node->type() == node_document ? static_cast *>(node) : 0; + } + else + return 0; + } + + //! Gets previous attribute, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *previous_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_prev_attribute; attribute; attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return this->m_parent ? m_prev_attribute : 0; + } + + //! Gets next attribute, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *next_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return this->m_parent ? m_next_attribute : 0; + } + + private: + + xml_attribute *m_prev_attribute; // Pointer to previous sibling of attribute, or 0 if none; only valid if parent is non-zero + xml_attribute *m_next_attribute; // Pointer to next sibling of attribute, or 0 if none; only valid if parent is non-zero + + }; + + /////////////////////////////////////////////////////////////////////////// + // XML node + + //! Class representing a node of XML document. + //! Each node may have associated name and value strings, which are available through name() and value() functions. + //! Interpretation of name and value depends on type of the node. + //! Type of node can be determined by using type() function. + //!

+ //! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. + //! Thus, this text must persist in the memory for the lifetime of node. + //! \param Ch Character type to use. + template + class xml_node: public xml_base + { + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty node with the specified type. + //! Consider using memory_pool of appropriate document to allocate nodes manually. + //! \param type Type of node to construct. + xml_node(node_type type) + : m_type(type) + , m_first_node(0) + , m_first_attribute(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets type of node. + //! \return Type of node. + node_type type() const + { + return m_type; + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which node is a child. + //! \return Pointer to document that contains this node, or 0 if there is no parent document. + xml_document *document() const + { + xml_node *node = const_cast *>(this); + while (node->parent()) + node = node->parent(); + return node->type() == node_document ? static_cast *>(node) : 0; + } + + //! Gets first child node, optionally matching node name. + //! \param name Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node *first_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *child = m_first_node; child; child = child->next_sibling()) + if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) + return child; + return 0; + } + else + return m_first_node; + } + + //! Gets last child node, optionally matching node name. + //! Behaviour is undefined if node has no children. + //! Use first_node() to test if node has children. + //! \param name Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node *last_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(m_first_node); // Cannot query for last child if node has no children + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *child = m_last_node; child; child = child->previous_sibling()) + if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) + return child; + return 0; + } + else + return m_last_node; + } + + //! Gets previous sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param name Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node *previous_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(this->m_parent); // Cannot query for siblings if node has no parent + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling) + if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) + return sibling; + return 0; + } + else + return m_prev_sibling; + } + + //! Gets next sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param name Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node *next_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(this->m_parent); // Cannot query for siblings if node has no parent + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling) + if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) + return sibling; + return 0; + } + else + return m_next_sibling; + } + + //! Gets first attribute of node, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *first_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return m_first_attribute; + } + + //! Gets last attribute of node, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *last_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_last_attribute; attribute; attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return m_first_attribute ? m_last_attribute : 0; + } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets type of node. + //! \param type Type of node to set. + void type(node_type type) + { + m_type = type; + } + + /////////////////////////////////////////////////////////////////////////// + // Node manipulation + + //! Prepends a new child node. + //! The prepended child becomes the first child, and all existing children are moved one position back. + //! \param child Node to prepend. + void prepend_node(xml_node *child) + { + assert(child && !child->parent() && child->type() != node_document); + if (first_node()) + { + child->m_next_sibling = m_first_node; + m_first_node->m_prev_sibling = child; + } + else + { + child->m_next_sibling = 0; + m_last_node = child; + } + m_first_node = child; + child->m_parent = this; + child->m_prev_sibling = 0; + } + + //! Appends a new child node. + //! The appended child becomes the last child. + //! \param child Node to append. + void append_node(xml_node *child) + { + assert(child && !child->parent() && child->type() != node_document); + if (first_node()) + { + child->m_prev_sibling = m_last_node; + m_last_node->m_next_sibling = child; + } + else + { + child->m_prev_sibling = 0; + m_first_node = child; + } + m_last_node = child; + child->m_parent = this; + child->m_next_sibling = 0; + } + + //! Inserts a new child node at specified place inside the node. + //! All children after and including the specified node are moved one position back. + //! \param where Place where to insert the child, or 0 to insert at the back. + //! \param child Node to insert. + void insert_node(xml_node *where, xml_node *child) + { + assert(!where || where->parent() == this); + assert(child && !child->parent() && child->type() != node_document); + if (where == m_first_node) + prepend_node(child); + else if (where == 0) + append_node(child); + else + { + child->m_prev_sibling = where->m_prev_sibling; + child->m_next_sibling = where; + where->m_prev_sibling->m_next_sibling = child; + where->m_prev_sibling = child; + child->m_parent = this; + } + } + + //! Removes first child node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_first_node() + { + assert(first_node()); + xml_node *child = m_first_node; + m_first_node = child->m_next_sibling; + if (child->m_next_sibling) + child->m_next_sibling->m_prev_sibling = 0; + else + m_last_node = 0; + child->m_parent = 0; + } + + //! Removes last child of the node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_last_node() + { + assert(first_node()); + xml_node *child = m_last_node; + if (child->m_prev_sibling) + { + m_last_node = child->m_prev_sibling; + child->m_prev_sibling->m_next_sibling = 0; + } + else + m_first_node = 0; + child->m_parent = 0; + } + + //! Removes specified child from the node + // \param where Pointer to child to be removed. + void remove_node(xml_node *where) + { + assert(where && where->parent() == this); + assert(first_node()); + if (where == m_first_node) + remove_first_node(); + else if (where == m_last_node) + remove_last_node(); + else + { + where->m_prev_sibling->m_next_sibling = where->m_next_sibling; + where->m_next_sibling->m_prev_sibling = where->m_prev_sibling; + where->m_parent = 0; + } + } + + //! Removes all child nodes (but not attributes). + void remove_all_nodes() + { + for (xml_node *node = first_node(); node; node = node->m_next_sibling) + node->m_parent = 0; + m_first_node = 0; + } + + //! Prepends a new attribute to the node. + //! \param attribute Attribute to prepend. + void prepend_attribute(xml_attribute *attribute) + { + assert(attribute && !attribute->parent()); + if (first_attribute()) + { + attribute->m_next_attribute = m_first_attribute; + m_first_attribute->m_prev_attribute = attribute; + } + else + { + attribute->m_next_attribute = 0; + m_last_attribute = attribute; + } + m_first_attribute = attribute; + attribute->m_parent = this; + attribute->m_prev_attribute = 0; + } + + //! Appends a new attribute to the node. + //! \param attribute Attribute to append. + void append_attribute(xml_attribute *attribute) + { + assert(attribute && !attribute->parent()); + if (first_attribute()) + { + attribute->m_prev_attribute = m_last_attribute; + m_last_attribute->m_next_attribute = attribute; + } + else + { + attribute->m_prev_attribute = 0; + m_first_attribute = attribute; + } + m_last_attribute = attribute; + attribute->m_parent = this; + attribute->m_next_attribute = 0; + } + + //! Inserts a new attribute at specified place inside the node. + //! All attributes after and including the specified attribute are moved one position back. + //! \param where Place where to insert the attribute, or 0 to insert at the back. + //! \param attribute Attribute to insert. + void insert_attribute(xml_attribute *where, xml_attribute *attribute) + { + assert(!where || where->parent() == this); + assert(attribute && !attribute->parent()); + if (where == m_first_attribute) + prepend_attribute(attribute); + else if (where == 0) + append_attribute(attribute); + else + { + attribute->m_prev_attribute = where->m_prev_attribute; + attribute->m_next_attribute = where; + where->m_prev_attribute->m_next_attribute = attribute; + where->m_prev_attribute = attribute; + attribute->m_parent = this; + } + } + + //! Removes first attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_first_attribute() + { + assert(first_attribute()); + xml_attribute *attribute = m_first_attribute; + if (attribute->m_next_attribute) + { + attribute->m_next_attribute->m_prev_attribute = 0; + } + else + m_last_attribute = 0; + attribute->m_parent = 0; + m_first_attribute = attribute->m_next_attribute; + } + + //! Removes last attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_last_attribute() + { + assert(first_attribute()); + xml_attribute *attribute = m_last_attribute; + if (attribute->m_prev_attribute) + { + attribute->m_prev_attribute->m_next_attribute = 0; + m_last_attribute = attribute->m_prev_attribute; + } + else + m_first_attribute = 0; + attribute->m_parent = 0; + } + + //! Removes specified attribute from node. + //! \param where Pointer to attribute to be removed. + void remove_attribute(xml_attribute *where) + { + assert(first_attribute() && where->parent() == this); + if (where == m_first_attribute) + remove_first_attribute(); + else if (where == m_last_attribute) + remove_last_attribute(); + else + { + where->m_prev_attribute->m_next_attribute = where->m_next_attribute; + where->m_next_attribute->m_prev_attribute = where->m_prev_attribute; + where->m_parent = 0; + } + } + + //! Removes all attributes of node. + void remove_all_attributes() + { + for (xml_attribute *attribute = first_attribute(); attribute; attribute = attribute->m_next_attribute) + attribute->m_parent = 0; + m_first_attribute = 0; + } + + private: + + /////////////////////////////////////////////////////////////////////////// + // Restrictions + + // No copying + xml_node(const xml_node &); + void operator =(const xml_node &); + + /////////////////////////////////////////////////////////////////////////// + // Data members + + // Note that some of the pointers below have UNDEFINED values if certain other pointers are 0. + // This is required for maximum performance, as it allows the parser to omit initialization of + // unneded/redundant values. + // + // The rules are as follows: + // 1. first_node and first_attribute contain valid pointers, or 0 if node has no children/attributes respectively + // 2. last_node and last_attribute are valid only if node has at least one child/attribute respectively, otherwise they contain garbage + // 3. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage + + node_type m_type; // Type of node; always valid + xml_node *m_first_node; // Pointer to first child node, or 0 if none; always valid + xml_node *m_last_node; // Pointer to last child node, or 0 if none; this value is only valid if m_first_node is non-zero + xml_attribute *m_first_attribute; // Pointer to first attribute of node, or 0 if none; always valid + xml_attribute *m_last_attribute; // Pointer to last attribute of node, or 0 if none; this value is only valid if m_first_attribute is non-zero + xml_node *m_prev_sibling; // Pointer to previous sibling of node, or 0 if none; this value is only valid if m_parent is non-zero + xml_node *m_next_sibling; // Pointer to next sibling of node, or 0 if none; this value is only valid if m_parent is non-zero + + }; + + /////////////////////////////////////////////////////////////////////////// + // XML document + + //! This class represents root of the DOM hierarchy. + //! It is also an xml_node and a memory_pool through public inheritance. + //! Use parse() function to build a DOM tree from a zero-terminated XML text string. + //! parse() function allocates memory for nodes and attributes by using functions of xml_document, + //! which are inherited from memory_pool. + //! To access root node of the document, use the document itself, as if it was an xml_node. + //! \param Ch Character type to use. + template + class xml_document: public xml_node, public memory_pool + { + + public: + + //! Constructs empty XML document + xml_document() + : xml_node(node_document) + { + } + + //! Parses zero-terminated XML string according to given flags. + //! Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used. + //! The string must persist for the lifetime of the document. + //! In case of error, rapidxml::parse_error exception will be thrown. + //!

+ //! If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning. + //! Make sure that data is zero-terminated. + //!

+ //! Document can be parsed into multiple times. + //! Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool. + //! \param text XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser. + template + void parse(Ch *text) + { + assert(text); + + // Remove current contents + this->remove_all_nodes(); + this->remove_all_attributes(); + + // Parse BOM, if any + parse_bom(text); + + // Parse children + while (1) + { + // Skip whitespace before node + skip(text); + if (*text == 0) + break; + + // Parse and append new child + if (*text == Ch('<')) + { + ++text; // Skip '<' + if (xml_node *node = parse_node(text)) + this->append_node(node); + } + else + RAPIDXML_PARSE_ERROR("expected <", text); + } + + } + + //! Clears the document by deleting all nodes and clearing the memory pool. + //! All nodes owned by document pool are destroyed. + void clear() + { + this->remove_all_nodes(); + this->remove_all_attributes(); + memory_pool::clear(); + } + + private: + + /////////////////////////////////////////////////////////////////////// + // Internal character utility functions + + // Detect whitespace character + struct whitespace_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_whitespace[static_cast(ch)]; + } + }; + + // Detect node name character + struct node_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_node_name[static_cast(ch)]; + } + }; + + // Detect attribute name character + struct attribute_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_attribute_name[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) + struct text_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_no_ws_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text_pure_no_ws[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_with_ws_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text_pure_with_ws[static_cast(ch)]; + } + }; + + // Detect attribute value character + template + struct attribute_value_pred + { + static unsigned char test(Ch ch) + { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1[static_cast(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2[static_cast(ch)]; + return 0; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Detect attribute value character + template + struct attribute_value_pure_pred + { + static unsigned char test(Ch ch) + { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1_pure[static_cast(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2_pure[static_cast(ch)]; + return 0; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Insert coded character, using UTF8 or 8-bit ASCII + template + static void insert_coded_character(Ch *&text, unsigned long code) + { + if (Flags & parse_no_utf8) + { + // Insert 8-bit ASCII character + // Todo: possibly verify that code is less than 256 and use replacement char otherwise? + text[0] = static_cast(code); + text += 1; + } + else + { + // Insert UTF8 sequence + if (code < 0x80) // 1 byte sequence + { + text[0] = static_cast(code); + text += 1; + } + else if (code < 0x800) // 2 byte sequence + { + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xC0); + text += 2; + } + else if (code < 0x10000) // 3 byte sequence + { + text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xE0); + text += 3; + } + else if (code < 0x110000) // 4 byte sequence + { + text[3] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xF0); + text += 4; + } + else // Invalid, only codes up to 0x10FFFF are allowed in Unicode + { + RAPIDXML_PARSE_ERROR("invalid numeric character entity", text); + } + } + } + + // Skip characters until predicate evaluates to true + template + static void skip(Ch *&text) + { + Ch *tmp = text; + while (StopPred::test(*tmp)) + ++tmp; + text = tmp; + } + + // Skip characters until predicate evaluates to true while doing the following: + // - replacing XML character entity references with proper characters (' & " < > &#...;) + // - condensing whitespace sequences to single space character + template + static Ch *skip_and_expand_character_refs(Ch *&text) + { + // If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip + if (Flags & parse_no_entity_translation && + !(Flags & parse_normalize_whitespace) && + !(Flags & parse_trim_whitespace)) + { + skip(text); + return text; + } + + // Use simple skip until first modification is detected + skip(text); + + // Use translation skip + Ch *src = text; + Ch *dest = src; + while (StopPred::test(*src)) + { + // If entity translation is enabled + if (!(Flags & parse_no_entity_translation)) + { + // Test if replacement is needed + if (src[0] == Ch('&')) + { + switch (src[1]) + { + + // & ' + case Ch('a'): + if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';')) + { + *dest = Ch('&'); + ++dest; + src += 5; + continue; + } + if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') && src[5] == Ch(';')) + { + *dest = Ch('\''); + ++dest; + src += 6; + continue; + } + break; + + // " + case Ch('q'): + if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') && src[5] == Ch(';')) + { + *dest = Ch('"'); + ++dest; + src += 6; + continue; + } + break; + + // > + case Ch('g'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('>'); + ++dest; + src += 4; + continue; + } + break; + + // < + case Ch('l'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('<'); + ++dest; + src += 4; + continue; + } + break; + + // &#...; - assumes ASCII + case Ch('#'): + if (src[2] == Ch('x')) + { + unsigned long code = 0; + src += 3; // Skip &#x + while (1) + { + unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; + if (digit == 0xFF) + break; + code = code * 16 + digit; + ++src; + } + insert_coded_character(dest, code); // Put character in output + } + else + { + unsigned long code = 0; + src += 2; // Skip &# + while (1) + { + unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; + if (digit == 0xFF) + break; + code = code * 10 + digit; + ++src; + } + insert_coded_character(dest, code); // Put character in output + } + if (*src == Ch(';')) + ++src; + else + RAPIDXML_PARSE_ERROR("expected ;", src); + continue; + + // Something else + default: + // Ignore, just copy '&' verbatim + break; + + } + } + } + + // If whitespace condensing is enabled + if (Flags & parse_normalize_whitespace) + { + // Test if condensing is needed + if (whitespace_pred::test(*src)) + { + *dest = Ch(' '); ++dest; // Put single space in dest + ++src; // Skip first whitespace char + // Skip remaining whitespace chars + while (whitespace_pred::test(*src)) + ++src; + continue; + } + } + + // No replacement, only copy character + *dest++ = *src++; + + } + + // Return new end + text = src; + return dest; + + } + + /////////////////////////////////////////////////////////////////////// + // Internal parsing functions + + // Parse BOM, if any + template + void parse_bom(Ch *&text) + { + // UTF-8? + if (static_cast(text[0]) == 0xEF && + static_cast(text[1]) == 0xBB && + static_cast(text[2]) == 0xBF) + { + text += 3; // Skup utf-8 bom + } + } + + // Parse XML declaration ( + xml_node *parse_xml_declaration(Ch *&text) + { + // If parsing of declaration is disabled + if (!(Flags & parse_declaration_node)) + { + // Skip until end of declaration + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 2; // Skip '?>' + return 0; + } + + // Create declaration + xml_node *declaration = this->allocate_node(node_declaration); + + // Skip whitespace before attributes or ?> + skip(text); + + // Parse declaration attributes + parse_node_attributes(text, declaration); + + // Skip ?> + if (text[0] != Ch('?') || text[1] != Ch('>')) + RAPIDXML_PARSE_ERROR("expected ?>", text); + text += 2; + + return declaration; + } + + // Parse XML comment (' + return 0; // Do not produce comment node + } + + // Remember value start + Ch *value = text; + + // Skip until end of comment + while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Create comment node + xml_node *comment = this->allocate_node(node_comment); + comment->value(value, text - value); + + // Place zero terminator after comment value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 3; // Skip '-->' + return comment; + } + + // Parse DOCTYPE + template + xml_node *parse_doctype(Ch *&text) + { + // Remember value start + Ch *value = text; + + // Skip to > + while (*text != Ch('>')) + { + // Determine character type + switch (*text) + { + + // If '[' encountered, scan for matching ending ']' using naive algorithm with depth + // This works for all W3C test files except for 2 most wicked + case Ch('['): + { + ++text; // Skip '[' + int depth = 1; + while (depth > 0) + { + switch (*text) + { + case Ch('['): ++depth; break; + case Ch(']'): --depth; break; + case 0: RAPIDXML_PARSE_ERROR("unexpected end of data", text); + default: break; + } + ++text; + } + break; + } + + // Error on end of text + case Ch('\0'): + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + + // Other character, skip it + default: + ++text; + + } + } + + // If DOCTYPE nodes enabled + if (Flags & parse_doctype_node) + { + // Create a new doctype node + xml_node *doctype = this->allocate_node(node_doctype); + doctype->value(value, text - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 1; // skip '>' + return doctype; + } + else + { + text += 1; // skip '>' + return 0; + } + + } + + // Parse PI + template + xml_node *parse_pi(Ch *&text) + { + // If creation of PI nodes is enabled + if (Flags & parse_pi_nodes) + { + // Create pi node + xml_node *pi = this->allocate_node(node_pi); + + // Extract PI target name + Ch *name = text; + skip(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected PI target", text); + pi->name(name, text - name); + + // Skip whitespace between pi target and pi + skip(text); + + // Remember start of pi + Ch *value = text; + + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (*text == Ch('\0')) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Set pi value (verbatim, no entity expansion or whitespace normalization) + pi->value(value, text - value); + + // Place zero terminator after name and value + if (!(Flags & parse_no_string_terminators)) + { + pi->name()[pi->name_size()] = Ch('\0'); + pi->value()[pi->value_size()] = Ch('\0'); + } + + text += 2; // Skip '?>' + return pi; + } + else + { + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (*text == Ch('\0')) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 2; // Skip '?>' + return 0; + } + } + + // Parse and append data + // Return character that ends data. + // This is necessary because this character might have been overwritten by a terminating 0 + template + Ch parse_and_append_data(xml_node *node, Ch *&text, Ch *contents_start) + { + // Backup to contents start if whitespace trimming is disabled + if (!(Flags & parse_trim_whitespace)) + text = contents_start; + + // Skip until end of data + Ch *value = text, *end; + if (Flags & parse_normalize_whitespace) + end = skip_and_expand_character_refs(text); + else + end = skip_and_expand_character_refs(text); + + // Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after > + if (Flags & parse_trim_whitespace) + { + if (Flags & parse_normalize_whitespace) + { + // Whitespace is already condensed to single space characters by skipping function, so just trim 1 char off the end + if (*(end - 1) == Ch(' ')) + --end; + } + else + { + // Backup until non-whitespace character is found + while (whitespace_pred::test(*(end - 1))) + --end; + } + } + + // If characters are still left between end and value (this test is only necessary if normalization is enabled) + // Create new data node + if (!(Flags & parse_no_data_nodes)) + { + xml_node *data = this->allocate_node(node_data); + data->value(value, end - value); + node->append_node(data); + } + + // Add data to parent node if no data exists yet + if (!(Flags & parse_no_element_values)) + if (*node->value() == Ch('\0')) + node->value(value, end - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + { + Ch ch = *text; + *end = Ch('\0'); + return ch; // Return character that ends data; this is required because zero terminator overwritten it + } + + // Return character that ends data + return *text; + } + + // Parse CDATA + template + xml_node *parse_cdata(Ch *&text) + { + // If CDATA is disabled + if (Flags & parse_no_data_nodes) + { + // Skip until end of cdata + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 3; // Skip ]]> + return 0; // Do not produce CDATA node + } + + // Skip until end of cdata + Ch *value = text; + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Create new cdata node + xml_node *cdata = this->allocate_node(node_cdata); + cdata->value(value, text - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 3; // Skip ]]> + return cdata; + } + + // Parse element node + template + xml_node *parse_element(Ch *&text) + { + // Create element node + xml_node *element = this->allocate_node(node_element); + + // Extract element name + Ch *name = text; + skip(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected element name", text); + element->name(name, text - name); + + // Skip whitespace between element name and attributes or > + skip(text); + + // Parse attributes, if any + parse_node_attributes(text, element); + + // Determine ending type + if (*text == Ch('>')) + { + ++text; + parse_node_contents(text, element); + } + else if (*text == Ch('/')) + { + ++text; + if (*text != Ch('>')) + RAPIDXML_PARSE_ERROR("expected >", text); + ++text; + } + else + RAPIDXML_PARSE_ERROR("expected >", text); + + // Place zero terminator after name + if (!(Flags & parse_no_string_terminators)) + element->name()[element->name_size()] = Ch('\0'); + + // Return parsed element + return element; + } + + // Determine node type, and parse it + template + xml_node *parse_node(Ch *&text) + { + // Parse proper node type + switch (text[0]) + { + + // <... + default: + // Parse and append element node + return parse_element(text); + + // (text); + } + else + { + // Parse PI + return parse_pi(text); + } + + // (text); + } + break; + + // (text); + } + break; + + // (text); + } + break; + + default: + break; + + } // switch + + // Attempt to skip other, unrecognized node types starting with ')) + { + if (*text == 0) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + ++text; // Skip '>' + return 0; // No node recognized + + } + } + + // Parse contents of the node - children, data etc. + template + void parse_node_contents(Ch *&text, xml_node *node) + { + // For all children and text + while (1) + { + // Skip whitespace between > and node contents + Ch *contents_start = text; // Store start of node contents before whitespace is skipped + skip(text); + Ch next_char = *text; + + // After data nodes, instead of continuing the loop, control jumps here. + // This is because zero termination inside parse_and_append_data() function + // would wreak havoc with the above code. + // Also, skipping whitespace after data nodes is unnecessary. + after_data_node: + + // Determine what comes next: node closing, child node, data node, or 0? + switch (next_char) + { + + // Node closing or child node + case Ch('<'): + if (text[1] == Ch('/')) + { + // Node closing + text += 2; // Skip '(text); + if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name, true)) + RAPIDXML_PARSE_ERROR("invalid closing tag name", text); + } + else + { + // No validation, just skip name + skip(text); + } + // Skip remaining whitespace after node name + skip(text); + if (*text != Ch('>')) + RAPIDXML_PARSE_ERROR("expected >", text); + ++text; // Skip '>' + return; // Node closed, finished parsing contents + } + else + { + // Child node + ++text; // Skip '<' + if (xml_node *child = parse_node(text)) + node->append_node(child); + } + break; + + // End of data - error + case Ch('\0'): + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + + // Data node + default: + next_char = parse_and_append_data(node, text, contents_start); + goto after_data_node; // Bypass regular processing after data nodes + + } + } + } + + // Parse XML attributes of the node + template + void parse_node_attributes(Ch *&text, xml_node *node) + { + // For all attributes + while (attribute_name_pred::test(*text)) + { + // Extract attribute name + Ch *name = text; + ++text; // Skip first character of attribute name + skip(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected attribute name", name); + + // Create new attribute + xml_attribute *attribute = this->allocate_attribute(); + attribute->name(name, text - name); + node->append_attribute(attribute); + + // Skip whitespace after attribute name + skip(text); + + // Skip = + if (*text != Ch('=')) + RAPIDXML_PARSE_ERROR("expected =", text); + ++text; + + // Add terminating zero after name + if (!(Flags & parse_no_string_terminators)) + attribute->name()[attribute->name_size()] = 0; + + // Skip whitespace after = + skip(text); + + // Skip quote and remember if it was ' or " + Ch quote = *text; + if (quote != Ch('\'') && quote != Ch('"')) + RAPIDXML_PARSE_ERROR("expected ' or \"", text); + ++text; + + // Extract attribute value and expand char refs in it + Ch *value = text, *end; + const int AttFlags = Flags & ~parse_normalize_whitespace; // No whitespace normalization in attributes + if (quote == Ch('\'')) + end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); + else + end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); + + // Set attribute value + attribute->value(value, end - value); + + // Make sure that end quote is present + if (*text != quote) + RAPIDXML_PARSE_ERROR("expected ' or \"", text); + ++text; // Skip quote + + // Add terminating zero after value + if (!(Flags & parse_no_string_terminators)) + attribute->value()[attribute->value_size()] = 0; + + // Skip whitespace after attribute value + skip(text); + } + } + + }; + + //! \cond internal + namespace internal + { + + // Whitespace (space \n \r \t) + template + const unsigned char lookup_tables::lookup_whitespace[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, // 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F + }; + + // Node name (anything but space \n \r \t / > ? \0) + template + const unsigned char lookup_tables::lookup_node_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) (anything but < \0) + template + const unsigned char lookup_tables::lookup_text[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) that does not require processing when ws normalization is disabled + // (anything but < \0 &) + template + const unsigned char lookup_tables::lookup_text_pure_no_ws[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) that does not require processing when ws normalizationis is enabled + // (anything but < \0 & space \n \r \t) + template + const unsigned char lookup_tables::lookup_text_pure_with_ws[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute name (anything but space \n \r \t / < > = ? ! \0) + template + const unsigned char lookup_tables::lookup_attribute_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with single quote (anything but ' \0) + template + const unsigned char lookup_tables::lookup_attribute_data_1[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with single quote that does not require processing (anything but ' \0 &) + template + const unsigned char lookup_tables::lookup_attribute_data_1_pure[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with double quote (anything but " \0) + template + const unsigned char lookup_tables::lookup_attribute_data_2[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with double quote that does not require processing (anything but " \0 &) + template + const unsigned char lookup_tables::lookup_attribute_data_2_pure[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Digits (dec and hex, 255 denotes end of numeric character reference) + template + const unsigned char lookup_tables::lookup_digits[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 0 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 1 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 2 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,255,255,255,255,255,255, // 3 + 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 4 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 5 + 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 6 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 7 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 8 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 9 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // A + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // B + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // C + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // D + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // E + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 // F + }; + + // Upper case conversion + template + const unsigned char lookup_tables::lookup_upcase[256] = + { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A B C D E F + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 0 + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, // 1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 2 + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 3 + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 4 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, // 5 + 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 6 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123,124,125,126,127, // 7 + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 8 + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, // 9 + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // A + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // B + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // C + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // D + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // E + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // F + }; + } + //! \endcond + +} + +// Undefine internal macros +#undef RAPIDXML_PARSE_ERROR + +// On MSVC, restore warnings state +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +#endif diff --git a/service/protocol-plugin/lib/rapidxml/rapidxml_iterators.hpp b/service/protocol-plugin/lib/rapidxml/rapidxml_iterators.hpp new file mode 100644 index 0000000..52ebc29 --- /dev/null +++ b/service/protocol-plugin/lib/rapidxml/rapidxml_iterators.hpp @@ -0,0 +1,174 @@ +#ifndef RAPIDXML_ITERATORS_HPP_INCLUDED +#define RAPIDXML_ITERATORS_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_iterators.hpp This file contains rapidxml iterators + +#include "rapidxml.hpp" + +namespace rapidxml +{ + + //! Iterator of child nodes of xml_node + template + class node_iterator + { + + public: + + typedef typename xml_node value_type; + typedef typename xml_node &reference; + typedef typename xml_node *pointer; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + node_iterator() + : m_node(0) + { + } + + node_iterator(xml_node *node) + : m_node(node->first_node()) + { + } + + reference operator *() const + { + assert(m_node); + return *m_node; + } + + pointer operator->() const + { + assert(m_node); + return m_node; + } + + node_iterator& operator++() + { + assert(m_node); + m_node = m_node->next_sibling(); + return *this; + } + + node_iterator operator++(int) + { + node_iterator tmp = *this; + ++this; + return tmp; + } + + node_iterator& operator--() + { + assert(m_node && m_node->previous_sibling()); + m_node = m_node->previous_sibling(); + return *this; + } + + node_iterator operator--(int) + { + node_iterator tmp = *this; + ++this; + return tmp; + } + + bool operator ==(const node_iterator &rhs) + { + return m_node == rhs.m_node; + } + + bool operator !=(const node_iterator &rhs) + { + return m_node != rhs.m_node; + } + + private: + + xml_node *m_node; + + }; + + //! Iterator of child attributes of xml_node + template + class attribute_iterator + { + + public: + + typedef typename xml_attribute value_type; + typedef typename xml_attribute &reference; + typedef typename xml_attribute *pointer; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + attribute_iterator() + : m_attribute(0) + { + } + + attribute_iterator(xml_node *node) + : m_attribute(node->first_attribute()) + { + } + + reference operator *() const + { + assert(m_attribute); + return *m_attribute; + } + + pointer operator->() const + { + assert(m_attribute); + return m_attribute; + } + + attribute_iterator& operator++() + { + assert(m_attribute); + m_attribute = m_attribute->next_attribute(); + return *this; + } + + attribute_iterator operator++(int) + { + attribute_iterator tmp = *this; + ++this; + return tmp; + } + + attribute_iterator& operator--() + { + assert(m_attribute && m_attribute->previous_attribute()); + m_attribute = m_attribute->previous_attribute(); + return *this; + } + + attribute_iterator operator--(int) + { + attribute_iterator tmp = *this; + ++this; + return tmp; + } + + bool operator ==(const attribute_iterator &rhs) + { + return m_attribute == rhs.m_attribute; + } + + bool operator !=(const attribute_iterator &rhs) + { + return m_attribute != rhs.m_attribute; + } + + private: + + xml_attribute *m_attribute; + + }; + +} + +#endif diff --git a/service/protocol-plugin/lib/rapidxml/rapidxml_print.hpp b/service/protocol-plugin/lib/rapidxml/rapidxml_print.hpp new file mode 100644 index 0000000..f929b3c --- /dev/null +++ b/service/protocol-plugin/lib/rapidxml/rapidxml_print.hpp @@ -0,0 +1,422 @@ +#ifndef RAPIDXML_PRINT_HPP_INCLUDED +#define RAPIDXML_PRINT_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_print.hpp This file contains rapidxml printer implementation + +#include "rapidxml.hpp" + +// Only include streams if not disabled +#ifndef RAPIDXML_NO_STREAMS + #include + #include +#endif + +namespace rapidxml +{ + + /////////////////////////////////////////////////////////////////////// + // Printing flags + + const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function. + + /////////////////////////////////////////////////////////////////////// + // Internal + + //! \cond internal + namespace internal + { + + /////////////////////////////////////////////////////////////////////////// + // Internal character operations + + // Copy characters from given range to given output iterator + template + inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out) + { + while (begin != end) + *out++ = *begin++; + return out; + } + + // Copy characters from given range to given output iterator and expand + // characters into references (< > ' " &) + template + inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out) + { + while (begin != end) + { + if (*begin == noexpand) + { + *out++ = *begin; // No expansion, copy character + } + else + { + switch (*begin) + { + case Ch('<'): + *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('>'): + *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('\''): + *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';'); + break; + case Ch('"'): + *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('&'): + *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';'); + break; + default: + *out++ = *begin; // No expansion, copy character + } + } + ++begin; // Step to next character + } + return out; + } + + // Fill given output iterator with repetitions of the same character + template + inline OutIt fill_chars(OutIt out, int n, Ch ch) + { + for (int i = 0; i < n; ++i) + *out++ = ch; + return out; + } + + // Find character + template + inline bool find_char(const Ch *begin, const Ch *end) + { + while (begin != end) + if (*begin++ == ch) + return true; + return false; + } + + template + inline OutIt print_node(OutIt out, const xml_node *node, int flags, int indent); + + // Print children of the node + template + inline OutIt print_children(OutIt out, const xml_node *node, int flags, int indent) + { + for (xml_node *child = node->first_node(); child; child = child->next_sibling()) + out = print_node(out, child, flags, indent); + return out; + } + + // Print attributes of the node + template + inline OutIt print_attributes(OutIt out, const xml_node *node, int flags) + { + for (xml_attribute *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute()) + { + if (attribute->name() && attribute->value()) + { + // Print attribute name + *out = Ch(' '), ++out; + out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out); + *out = Ch('='), ++out; + // Print attribute value using appropriate quote type + if (find_char(attribute->value(), attribute->value() + attribute->value_size())) + { + *out = Ch('\''), ++out; + out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out); + *out = Ch('\''), ++out; + } + else + { + *out = Ch('"'), ++out; + out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out); + *out = Ch('"'), ++out; + } + } + } + return out; + } + + // Print data node + template + inline OutIt print_data_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_data); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); + return out; + } + + // Print data node + template + inline OutIt print_cdata_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_cdata); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'); ++out; + *out = Ch('!'); ++out; + *out = Ch('['); ++out; + *out = Ch('C'); ++out; + *out = Ch('D'); ++out; + *out = Ch('A'); ++out; + *out = Ch('T'); ++out; + *out = Ch('A'); ++out; + *out = Ch('['); ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch(']'); ++out; + *out = Ch(']'); ++out; + *out = Ch('>'); ++out; + return out; + } + + // Print element node + template + inline OutIt print_element_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_element); + + // Print element name and attributes, if any + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + out = print_attributes(out, node, flags); + + // If node is childless + if (node->value_size() == 0 && !node->first_node()) + { + // Print childless node tag ending + *out = Ch('/'), ++out; + *out = Ch('>'), ++out; + } + else + { + // Print normal node tag ending + *out = Ch('>'), ++out; + + // Test if node contains a single data node only (and no other nodes) + xml_node *child = node->first_node(); + if (!child) + { + // If node has no children, only print its value without indenting + out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); + } + else if (child->next_sibling() == 0 && child->type() == node_data) + { + // If node has a sole data child, only print its value without indenting + out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out); + } + else + { + // Print all children with full indenting + if (!(flags & print_no_indenting)) + *out = Ch('\n'), ++out; + out = print_children(out, node, flags, indent + 1); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + } + + // Print node end + *out = Ch('<'), ++out; + *out = Ch('/'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + *out = Ch('>'), ++out; + } + return out; + } + + // Print declaration node + template + inline OutIt print_declaration_node(OutIt out, const xml_node *node, int flags, int indent) + { + // Print declaration start + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('?'), ++out; + *out = Ch('x'), ++out; + *out = Ch('m'), ++out; + *out = Ch('l'), ++out; + + // Print attributes + out = print_attributes(out, node, flags); + + // Print declaration end + *out = Ch('?'), ++out; + *out = Ch('>'), ++out; + + return out; + } + + // Print comment node + template + inline OutIt print_comment_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_comment); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('!'), ++out; + *out = Ch('-'), ++out; + *out = Ch('-'), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('-'), ++out; + *out = Ch('-'), ++out; + *out = Ch('>'), ++out; + return out; + } + + // Print doctype node + template + inline OutIt print_doctype_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_doctype); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('!'), ++out; + *out = Ch('D'), ++out; + *out = Ch('O'), ++out; + *out = Ch('C'), ++out; + *out = Ch('T'), ++out; + *out = Ch('Y'), ++out; + *out = Ch('P'), ++out; + *out = Ch('E'), ++out; + *out = Ch(' '), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('>'), ++out; + return out; + } + + // Print pi node + template + inline OutIt print_pi_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_pi); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('?'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + *out = Ch(' '), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('?'), ++out; + *out = Ch('>'), ++out; + return out; + } + /////////////////////////////////////////////////////////////////////////// + // Internal printing operations + + // Print node + template + inline OutIt print_node(OutIt out, const xml_node *node, int flags, int indent) + { + // Print proper node type + switch (node->type()) + { + + // Document + case node_document: + out = print_children(out, node, flags, indent); + break; + + // Element + case node_element: + out = print_element_node(out, node, flags, indent); + break; + + // Data + case node_data: + out = print_data_node(out, node, flags, indent); + break; + + // CDATA + case node_cdata: + out = print_cdata_node(out, node, flags, indent); + break; + + // Declaration + case node_declaration: + out = print_declaration_node(out, node, flags, indent); + break; + + // Comment + case node_comment: + out = print_comment_node(out, node, flags, indent); + break; + + // Doctype + case node_doctype: + out = print_doctype_node(out, node, flags, indent); + break; + + // Pi + case node_pi: + out = print_pi_node(out, node, flags, indent); + break; + + // Unknown + default: + assert(0); + break; + } + + // If indenting not disabled, add line break after node + if (!(flags & print_no_indenting)) + *out = Ch('\n'), ++out; + + // Return modified iterator + return out; + } + } + //! \endcond + + /////////////////////////////////////////////////////////////////////////// + // Printing + + //! Prints XML to given output iterator. + //! \param out Output iterator to print to. + //! \param node Node to be printed. Pass xml_document to print entire document. + //! \param flags Flags controlling how XML is printed. + //! \return Output iterator pointing to position immediately after last character of printed text. + template + inline OutIt print(OutIt out, const xml_node &node, int flags = 0) + { + return internal::print_node(out, &node, flags, 0); + } + +#ifndef RAPIDXML_NO_STREAMS + + //! Prints XML to given output stream. + //! \param out Output stream to print to. + //! \param node Node to be printed. Pass xml_document to print entire document. + //! \param flags Flags controlling how XML is printed. + //! \return Output stream. + template + inline std::basic_ostream &print(std::basic_ostream &out, const xml_node &node, int flags = 0) + { + print(std::ostream_iterator(out), node, flags); + return out; + } + + //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process. + //! \param out Output stream to print to. + //! \param node Node to be printed. + //! \return Output stream. + template + inline std::basic_ostream &operator <<(std::basic_ostream &out, const xml_node &node) + { + return print(out, node); + } + +#endif + +} + +#endif diff --git a/service/protocol-plugin/lib/rapidxml/rapidxml_utils.hpp b/service/protocol-plugin/lib/rapidxml/rapidxml_utils.hpp new file mode 100644 index 0000000..37c2953 --- /dev/null +++ b/service/protocol-plugin/lib/rapidxml/rapidxml_utils.hpp @@ -0,0 +1,122 @@ +#ifndef RAPIDXML_UTILS_HPP_INCLUDED +#define RAPIDXML_UTILS_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful +//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective. + +#include "rapidxml.hpp" +#include +#include +#include +#include + +namespace rapidxml +{ + + //! Represents data loaded from a file + template + class file + { + + public: + + //! Loads file into the memory. Data will be automatically destroyed by the destructor. + //! \param filename Filename to load. + file(const char *filename) + { + using namespace std; + + // Open stream + basic_ifstream stream(filename, ios::binary); + if (!stream) + throw runtime_error(string("cannot open file ") + filename); + stream.unsetf(ios::skipws); + + // Determine stream size + stream.seekg(0, ios::end); + size_t size = stream.tellg(); + stream.seekg(0); + + // Load data and add terminating 0 + m_data.resize(size + 1); + stream.read(&m_data.front(), static_cast(size)); + m_data[size] = 0; + } + + //! Loads file into the memory. Data will be automatically destroyed by the destructor + //! \param stream Stream to load from + file(std::basic_istream &stream) + { + using namespace std; + + // Load data and add terminating 0 + stream.unsetf(ios::skipws); + m_data.assign(istreambuf_iterator(stream), istreambuf_iterator()); + if (stream.fail() || stream.bad()) + throw runtime_error("error reading stream"); + m_data.push_back(0); + } + + //! Gets file data. + //! \return Pointer to data of file. + Ch *data() + { + return &m_data.front(); + } + + //! Gets file data. + //! \return Pointer to data of file. + const Ch *data() const + { + return &m_data.front(); + } + + //! Gets file data size. + //! \return Size of file data, in characters. + std::size_t size() const + { + return m_data.size(); + } + + private: + + std::vector m_data; // File data + + }; + + //! Counts children of node. Time complexity is O(n). + //! \return Number of children of node + template + inline std::size_t count_children(xml_node *node) + { + xml_node *child = node->first_node(); + std::size_t count = 0; + while (child) + { + ++count; + child = child->next_sibling(); + } + return count; + } + + //! Counts attributes of node. Time complexity is O(n). + //! \return Number of attributes of node + template + inline std::size_t count_attributes(xml_node *node) + { + xml_attribute *attr = node->first_attribute(); + std::size_t count = 0; + while (attr) + { + ++count; + attr = attr->next_attribute(); + } + return count; + } + +} + +#endif diff --git a/service/protocol-plugin/plugin-manager/build/linux/Makefile b/service/protocol-plugin/plugin-manager/build/linux/Makefile index f6187f4..453451f 100644 --- a/service/protocol-plugin/plugin-manager/build/linux/Makefile +++ b/service/protocol-plugin/plugin-manager/build/linux/Makefile @@ -1,12 +1,13 @@ CXX = g++ CXX_FLAGS = -std=c++0x -Wall - -CPLUFF_DIR = ../../../lib/cpluff/libcpluff +LIB = ../../../lib +CPLUFF_DIR = $(LIB)/cpluff/libcpluff SRC = ../../src/ CXX_INC = -I. -I$(CPLUFF_DIR) +CXX_INC += -I$(LIB)/rapidxml LINK_LIB = -lboost_system -ldl -lexpat -lboost_thread CXX_LIBS = $(CPLUFF_DIR)/.libs/libcpluff.a @@ -22,8 +23,8 @@ PluginManager.o : $(SRC)PluginManager.cpp $(CXX) $(CXX_INC) -c $(CXX_FLAGS) -Wsign-compare $(SRC)PluginManager.cpp -libpmimpl.so:PluginManagerImpl.o Plugin.o CpluffAdapter.o FelixAdapter.o $(CPLUFF_DIR)/.libs/libcpluff.a - $(CXX) -shared -o libpmimpl.so PluginManagerImpl.o Plugin.o CpluffAdapter.o FelixAdapter.o $(CXX_LIBS) $(LINK_LIB) +libpmimpl.so:PluginManagerImpl.o Plugin.o CpluffAdapter.o FelixAdapter.o Config.o $(CPLUFF_DIR)/.libs/libcpluff.a + $(CXX) -shared -o libpmimpl.so PluginManagerImpl.o Plugin.o CpluffAdapter.o FelixAdapter.o Config.o $(CXX_LIBS) $(LINK_LIB) PluginManagerImpl.o : $(SRC)PluginManagerImpl.cpp $(CXX) $(CXX_INC) -fPIC -c $(CXX_FLAGS) -Wsign-compare $(SRC)PluginManagerImpl.cpp @@ -31,6 +32,9 @@ PluginManagerImpl.o : $(SRC)PluginManagerImpl.cpp Plugin.o : $(SRC)Plugin.cpp $(CXX) $(CXX_INC) -fPIC -c $(SRC)Plugin.cpp +Config.o : $(SRC)Config.cpp + $(CXX) $(CXX_INC) -fPIC -c $(SRC)Config.cpp + CpluffAdapter.o : $(SRC)CpluffAdapter.cpp $(CXX) $(CXX_INC) -c $(CXX_FLAGS) -Wsign-compare $(SRC)CpluffAdapter.cpp diff --git a/service/protocol-plugin/plugin-manager/src/Config.cpp b/service/protocol-plugin/plugin-manager/src/Config.cpp new file mode 100644 index 0000000..528c7dd --- /dev/null +++ b/service/protocol-plugin/plugin-manager/src/Config.cpp @@ -0,0 +1,157 @@ +//****************************************************************** +// +// Copyright 2014 Samsung Electronics All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +/// @file Config.cpp + +/// @brief + + +#include "Config.h" + + +using namespace OIC; +using namespace rapidxml; +using namespace std; + +Config *Config::s_configinstance = NULL; + +Config::Config() +{ + if (loadConfigFile("./pluginmanager.xml") != PM_S_OK) + { + fprintf(stderr, "PM Configuration file is not exist current Folder.\n" ); + exit(EXIT_FAILURE); + } +} + +Config::~Config(void) +{ + s_configinstance->deleteinstance(); + s_configinstance = NULL; +} + +PMRESULT Config::loadConfigFile(const std::string configfilepath) +{ + // Read the xml file + std::ifstream xmlFile(configfilepath.c_str()); + xml_document<> doc; + //into a vector + std::vector buffer((istreambuf_iterator(xmlFile)), istreambuf_iterator()); + buffer.push_back('\0'); + + // Parse the buffer using the xml file parsing library into doc + parsing(buffer, &doc); + + // Find our root node + xml_node<> *root_node = doc.first_node("pluginManager"); + xml_node<> *pluginInfo = root_node->first_node("pluginInfo"); + + getXmlData(pluginInfo, "pluginPath"); + getXmlData(pluginInfo, "maxMEM"); + getXmlData(pluginInfo, "version"); + getXmlData(pluginInfo, "name"); + + return PM_S_OK; +} + +PMRESULT Config::parsing(std::vector buffer, xml_document<> *doc) +{ + // Parse the buffer using the xml file parsing library into doc + try + { + doc->parse<0>(&buffer[0]); + } + catch (rapidxml::parse_error err) + { + //print errors to screen + fprintf(stderr, "PM Configuration file parsing error \n"); + exit(EXIT_FAILURE); //then exit + } + return PM_S_OK; +} + +PMRESULT Config::getXmlData(xml_node<> *pluginInfo, std::string key) +{ + xml_attribute<> *iAttr = NULL; + std::string value = ""; + if (iAttr = pluginInfo->first_attribute(key.c_str())) + { + value = iAttr->value(); + setValue(key, value); + return PM_S_OK; + } + else + { + return PM_S_FALSE; + } +} + +void Config::setValue(const std::string key, const std::string value) +{ + m_configurationMap.insert( std::pair(key, value)); +} + +std::string Config::getValue(const std::string key) +{ + std::map::iterator m_iterator; + + m_iterator = m_configurationMap.find(key.c_str()); + + if (m_iterator != m_configurationMap.end()) + { + return m_iterator->second; + } + else + { + return ""; + } +} + +std::string Config::getVersion() +{ + std::map::iterator m_iterator; + + m_iterator = m_configurationMap.find("version"); + + if (m_iterator != m_configurationMap.end()) + { + return m_iterator->second; + } + else + { + return ""; + } +} + +std::string Config::getPluginPath() +{ + std::map::iterator m_iterator; + + m_iterator = m_configurationMap.find("pluginPath"); + + if (m_iterator != m_configurationMap.end()) + { + return m_iterator->second; + } + else + { + return ""; + } +} \ No newline at end of file diff --git a/service/protocol-plugin/plugin-manager/src/Config.h b/service/protocol-plugin/plugin-manager/src/Config.h new file mode 100644 index 0000000..33f7f39 --- /dev/null +++ b/service/protocol-plugin/plugin-manager/src/Config.h @@ -0,0 +1,122 @@ +//****************************************************************** +// +// Copyright 2014 Samsung Electronics All Rights Reserved. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +/// @file Config.h + +/// @brief + +#ifndef __CONFIG_H +#define __CONFIG_H +#include +#include +#include +#include +#include +#include "rapidxml.hpp" +#include +#include + +using namespace rapidxml; + +namespace OIC +{ + + enum PMRESULT + { + PM_S_OK + , PM_S_FALSE + , PM_E_POINTER + , PM_E_OUTOFMEMORY + , PM_E_FAIL + , PM_E_NOINTERFACE + , PM_E_NOTIMPL + }; + /** + * @brief Configuration class + * + * + */ + class Config + { + public: + /** + * A function to register pluins in the path. + * This function will load plugins in plugin manager table. + * + * @param path plugin file path to be registered. + * @return int, 1 is success, 0 is fail. + * + * NOTE: + * + */ + /** + * + * new Singleton pattern instance. + * + * @return config pointer Address. + */ + static Config *Getinstance() + { + if (NULL == s_configinstance) + { + s_configinstance = new Config(); + } + + return s_configinstance; + } + std::string getPluginPath(); + std::string getVersion(); + std::string getValue(const std::string key); + + private: + static Config *s_configinstance; + typedef std::map configmap; + configmap m_configurationMap; + /** + * Constructor for Config. + * During construction time, configuration file will be loaded. + * + */ + Config(); + + /** + * Virtual destructor + */ + virtual ~Config(void); + + /** + * delete Singleton pattern instance. + */ + static void deleteinstance() + { + if (NULL != s_configinstance) + { + delete s_configinstance; + s_configinstance = NULL; + } + } + void setValue(const std::string key, const std::string value); + PMRESULT loadConfigFile(const std::string configfilepath); + PMRESULT parsing(std::vector buffer, xml_document<> *doc); + PMRESULT getXmlData( xml_node<> *pluginInfo, std::string key); + }; +} + +#endif \ No newline at end of file diff --git a/service/protocol-plugin/plugin-manager/src/CpluffAdapter.cpp b/service/protocol-plugin/plugin-manager/src/CpluffAdapter.cpp index b3d60e4..addc2a7 100644 --- a/service/protocol-plugin/plugin-manager/src/CpluffAdapter.cpp +++ b/service/protocol-plugin/plugin-manager/src/CpluffAdapter.cpp @@ -34,14 +34,27 @@ CpluffAdapter::CpluffAdapter() m_context = cp_create_context(&m_status); m_cp_plugins = nullptr; m_plugin = nullptr; - registerAllPlugin("../../../plugins"); + + config = Config::Getinstance(); + std::string pluginpath = config->getPluginPath(); + if (pluginpath != "") + { + printf("Current path is %s\n", pluginpath.c_str()); + } + else + { + fprintf(stderr, "Pluing path does not exist\n"); + pluginpath = ""; + } + registerAllPlugin(pluginpath); } CpluffAdapter::~CpluffAdapter(void) { cp_release_info(m_context, m_cp_plugins); - m_thread_g.interrupt_all(); - m_thread_g.join_all(); + //Auto plugin detection is disabled + //m_thread_g.interrupt_all(); + //m_thread_g.join_all(); s_pinstance->deleteinstance(); s_pinstance = nullptr; } @@ -57,7 +70,12 @@ int CpluffAdapter::installPlugin(const std::string path) } else if ((m_status = cp_install_plugin(m_context, m_plugin)) != 0) { - printf("cp_install_plugin failed\n"); + if (m_status == CP_ERR_CONFLICT) + { + printf("Plugin is already installed or conflicts symbol.\n"); + } + printf("cp_install_plugin failed : %d \n" , m_status); + return false; } @@ -70,8 +88,7 @@ int CpluffAdapter::findPluginRecursive(const std::string path) File_list file_list; getFileList(file_list, path); File_list::iterator itr; - int flag = FALSE; - + int flag = TRUE; for (itr = file_list.begin(); itr != file_list.end(); itr++) { if (itr->second == true) @@ -91,9 +108,10 @@ int CpluffAdapter::findPluginRecursive(const std::string path) } } std::string filename = filepath.substr(0, count ); - //char *temp_char = const_cast(filename.c_str()); - flag = installPlugin(filename); - //printf("plugin file path %s \n", plugin->plugin_path); + if (!installPlugin(filename)) + { + printf("installPlugin failed path : %s \n", filename.c_str()); + } } } @@ -110,7 +128,7 @@ int CpluffAdapter::loadPluginInfoToManager(const std::string path) } else { - printPluginList(m_cp_plugins); + printPluginList(); } for (int i = 0 ; m_cp_plugins[i] != nullptr; i++) @@ -176,7 +194,8 @@ int CpluffAdapter::loadPluginInfoToManager(const std::string path) } if (plugin_compare_flag) { - m_plugins.push_back(*plugin); + //Auto plugin detection is disabled + /* try { boost::thread *t = new boost::thread(boost::bind(&CpluffAdapter::observePluginPath, @@ -188,6 +207,8 @@ int CpluffAdapter::loadPluginInfoToManager(const std::string path) { printf("thread throw exception\n"); } + */ + m_plugins.push_back(*plugin); delete(plugin); } //printf("plugin size = %d\n",m_plugins.size()); @@ -208,11 +229,10 @@ int CpluffAdapter::registerPlugin(const std::string path) } //non recursive - - flag = installPlugin(path); - - flag = loadPluginInfoToManager(path); - + if (installPlugin(path)) + { + flag = loadPluginInfoToManager(path); + } return flag; } @@ -227,11 +247,10 @@ int CpluffAdapter::registerAllPlugin(const std::string path) } //recursive - - flag = findPluginRecursive(path); - - flag = loadPluginInfoToManager(path); - + if (findPluginRecursive(path)) + { + flag = loadPluginInfoToManager(path); + } return flag; } @@ -403,7 +422,7 @@ const char *CpluffAdapter::state_to_string(int state) } } -void CpluffAdapter::printPluginList(cp_plugin_info_t **plugins) +void CpluffAdapter::printPluginList() { const char format[] = " %-30s %-15s %-15s %-20s\n"; printf("\n====== Plugins List ======\n"); @@ -491,7 +510,8 @@ bool CpluffAdapter::isStarted(Plugin *plugin) } return FALSE; } - +//Auto plugin detection is disabled +/* void CpluffAdapter::observePluginPath(void *str) { //printf("start observePluginPath\n"); @@ -568,7 +588,7 @@ void CpluffAdapter::observePluginPath(void *str) ( void ) close( fd ); //printf("observePluginPath end\n"); } - +*/ const std::string CpluffAdapter::getState(const std::string plugID) { return state_to_string(cp_get_plugin_state(m_context, plugID.c_str())); diff --git a/service/protocol-plugin/plugin-manager/src/CpluffAdapter.h b/service/protocol-plugin/plugin-manager/src/CpluffAdapter.h index ec565d3..e0b934f 100644 --- a/service/protocol-plugin/plugin-manager/src/CpluffAdapter.h +++ b/service/protocol-plugin/plugin-manager/src/CpluffAdapter.h @@ -38,6 +38,7 @@ #include #include "Plugin.h" +#include "Config.h" #define EVENT_SIZE ( sizeof (struct inotify_event) ) #define BUF_LEN (int)( 1024 * ( EVENT_SIZE + 16 ) ) @@ -160,6 +161,13 @@ namespace OIC */ const std::string getState(const std::string plugID); + /** + * print whole plugin info. + * + * @param cpluff plugins + */ + void printPluginList(); + /** * @@ -181,15 +189,14 @@ namespace OIC private: + Config *config; typedef std::map File_list; std::vector m_plugins; cp_context_t *m_context; cp_status_t m_status; cp_plugin_info_t **m_cp_plugins; cp_plugin_info_t *m_plugin; - boost::thread m_file_detect_thread; - boost::thread_group m_thread_g; - std::string m_path; + //boost::thread_group m_thread_g; static CpluffAdapter *s_pinstance; /** @@ -222,7 +229,7 @@ namespace OIC * @param plugin file path. * @return void */ - void observePluginPath(void *); + //void observePluginPath(void *); /** @@ -243,13 +250,6 @@ namespace OIC bool getFileList(File_list &list, const std::string strDir); /** - * print whole plugin info. - * - * @param cpluff plugins - */ - void printPluginList(cp_plugin_info_t **plugins); - - /** * install plugin using c-pluff. * * @param Root path. diff --git a/service/protocol-plugin/plugin-manager/src/FelixAdapter.cpp b/service/protocol-plugin/plugin-manager/src/FelixAdapter.cpp index 0247e74..50a92e2 100644 --- a/service/protocol-plugin/plugin-manager/src/FelixAdapter.cpp +++ b/service/protocol-plugin/plugin-manager/src/FelixAdapter.cpp @@ -30,7 +30,18 @@ FelixAdapter *FelixAdapter::s_pinstance; FelixAdapter::FelixAdapter() { - + config = Config::Getinstance(); + std::string pluginpath = config->getPluginPath(); + if (pluginpath != "") + { + printf("Current path is %s\n", pluginpath.c_str()); + } + else + { + fprintf(stderr, "Pluing path is not exist\n"); + pluginpath = ""; + } + registerAllPlugin(pluginpath); } FelixAdapter::~FelixAdapter(void) @@ -113,12 +124,12 @@ bool FelixAdapter::isStarted(Plugin *plugin) { return FALSE; } - +/* void FelixAdapter::observePluginPath(void *str) { } - +*/ const std::string FelixAdapter::getState(const std::string plugID) { return ""; diff --git a/service/protocol-plugin/plugin-manager/src/FelixAdapter.h b/service/protocol-plugin/plugin-manager/src/FelixAdapter.h index 3842184..7c6398c 100644 --- a/service/protocol-plugin/plugin-manager/src/FelixAdapter.h +++ b/service/protocol-plugin/plugin-manager/src/FelixAdapter.h @@ -38,6 +38,7 @@ #include #include "Plugin.h" +#include "Config.h" #define EVENT_SIZE ( sizeof (struct inotify_event) ) #define BUF_LEN (int)( 1024 * ( EVENT_SIZE + 16 ) ) @@ -180,7 +181,7 @@ namespace OIC private: - + Config *config; typedef std::map File_list; std::vector m_plugins; boost::thread m_file_detect_thread; @@ -224,7 +225,7 @@ namespace OIC * @param plugin file path. * @return void */ - void observePluginPath(void *); + //void observePluginPath(void *); /** * Get whole "SO" file list. diff --git a/service/protocol-plugin/plugin-manager/src/Plugin.cpp b/service/protocol-plugin/plugin-manager/src/Plugin.cpp index d77f68f..7ef312c 100644 --- a/service/protocol-plugin/plugin-manager/src/Plugin.cpp +++ b/service/protocol-plugin/plugin-manager/src/Plugin.cpp @@ -136,16 +136,6 @@ namespace OIC return false; } } - - std::vector Plugin::getSupportedType(void) - { - return m_supportedType; - } - - void Plugin::addSupportedType(const std::string rscType) - { - m_supportedType.push_back(rscType); - } } diff --git a/service/protocol-plugin/plugin-manager/src/Plugin.h b/service/protocol-plugin/plugin-manager/src/Plugin.h index bd823d8..5b1e3a6 100644 --- a/service/protocol-plugin/plugin-manager/src/Plugin.h +++ b/service/protocol-plugin/plugin-manager/src/Plugin.h @@ -141,22 +141,6 @@ namespace OIC */ bool operator==(Plugin &plugin); - /** - * Get supported resourc type - * - * - * @return vector of surported resource type - */ - std::vector getSupportedType(void); - /** - * Add supported resource type for a plugin - * - * @param resource type string - * @return void - * - */ - void addSupportedType(const std::string rscType); - private: std::map m_attributeMap; std::vector m_supportedType; diff --git a/service/protocol-plugin/plugin-manager/src/PluginManager.cpp b/service/protocol-plugin/plugin-manager/src/PluginManager.cpp index 7c158ca..c3abdb8 100644 --- a/service/protocol-plugin/plugin-manager/src/PluginManager.cpp +++ b/service/protocol-plugin/plugin-manager/src/PluginManager.cpp @@ -56,18 +56,17 @@ int PluginManager::stopPlugins(const std::string key, const std::string value) return pluginManagerImpl->stopPlugins(key, value); } -int PluginManager::startPlugins(Plugin *const plugin) +int PluginManager::rescanPlugin() { - printf("PluginManager::startPlugins\n"); - return pluginManagerImpl->startPlugins(plugin); + return pluginManagerImpl->rescanPlugin(); } -int PluginManager::stopPlugins(Plugin *const plugin) +std::vector PluginManager::getPlugins(void) { - return pluginManagerImpl->stopPlugins(plugin); + return pluginManagerImpl->getAllPlugins(); } -std::vector PluginManager::getPlugins(void) +std::string PluginManager::getState(const std::string plugID) { - return pluginManagerImpl->getAllPlugins(); + return pluginManagerImpl->getState(plugID); } \ No newline at end of file diff --git a/service/protocol-plugin/plugin-manager/src/PluginManager.h b/service/protocol-plugin/plugin-manager/src/PluginManager.h index 41a631e..2ae8b73 100644 --- a/service/protocol-plugin/plugin-manager/src/PluginManager.h +++ b/service/protocol-plugin/plugin-manager/src/PluginManager.h @@ -68,23 +68,13 @@ namespace OIC int stopPlugins(const std::string key, const std::string value); /** - * Start plugin - * This function will load dynamic plugin library on memory and call start function of plugin to be initialized. + * Rescan Plugin. + * This function will call rescan function of plugins in the configuration folder * * @param Plugin * @return int, 1 is success, 0 is fail. */ - int startPlugins(Plugin *const plugin); - - - /** - * Stop Plugin. - * This function will call stop function of plugin and unload dynamic plugin library from memory. - * - * @param Plugin - * @return int, 1 is success, 0 is fail. - */ - int stopPlugins(Plugin *const plugin); + int rescanPlugin(); /** * Get Plugin list. @@ -95,6 +85,14 @@ namespace OIC */ std::vector getPlugins(void); + /** + * Get Plugin state. + * + * @param Plugin ID + * @return Plugin state. + */ + std::string getState(const std::string plugID); + private: PluginManagerImpl *pluginManagerImpl; void (*destroy)(PluginManagerImpl *); diff --git a/service/protocol-plugin/plugin-manager/src/PluginManagerImpl.cpp b/service/protocol-plugin/plugin-manager/src/PluginManagerImpl.cpp index d501786..2795e83 100644 --- a/service/protocol-plugin/plugin-manager/src/PluginManagerImpl.cpp +++ b/service/protocol-plugin/plugin-manager/src/PluginManagerImpl.cpp @@ -110,6 +110,23 @@ int PluginManagerImpl::unregisterAllPlugin() return flag; } +int PluginManagerImpl::rescanPlugin() +{ + Config *config = Config::Getinstance(); + std::string pluginpath = config->getPluginPath(); + if (pluginpath != "") + { + printf("Current path is %s\n", pluginpath.c_str()); + } + else + { + fprintf(stderr, "Pluing path does not exist\n"); + pluginpath = ""; + } + int result = registerAllPlugin(pluginpath); + return result; +} + std::vector &PluginManagerImpl::getAllPlugins(void) { diff --git a/service/protocol-plugin/plugin-manager/src/PluginManagerImpl.h b/service/protocol-plugin/plugin-manager/src/PluginManagerImpl.h index f42236a..3beb8e8 100644 --- a/service/protocol-plugin/plugin-manager/src/PluginManagerImpl.h +++ b/service/protocol-plugin/plugin-manager/src/PluginManagerImpl.h @@ -120,7 +120,7 @@ namespace OIC * @param Plugin ID * @return Plugin state. */ - std::string getState(const std::string plugID); + virtual std::string getState(const std::string plugID); /** * Start plugins by resource type @@ -145,7 +145,7 @@ namespace OIC * @param Plugin * @return int, 1 is success, 0 is fail. */ - virtual int startPlugins(Plugin *const plugin); + int startPlugins(Plugin *const plugin); /** @@ -155,7 +155,16 @@ namespace OIC * @param Plugin * @return int, 1 is success, 0 is fail. */ - virtual int stopPlugins(Plugin *const plugin); + int stopPlugins(Plugin *const plugin); + + /** + * Rescan Plugin. + * This function will call rescan function of plugins in the configuration folder + * + * @param Plugin + * @return int, 1 is success, 0 is fail. + */ + virtual int rescanPlugin(); /** * get all plugins which currently registered. diff --git a/service/protocol-plugin/plugins/mqtt-fan/build/linux/Makefile b/service/protocol-plugin/plugins/mqtt-fan/build/linux/Makefile index bf4db27..9f258f1 100644 --- a/service/protocol-plugin/plugins/mqtt-fan/build/linux/Makefile +++ b/service/protocol-plugin/plugins/mqtt-fan/build/linux/Makefile @@ -1,5 +1,3 @@ -include ../../../../config.mk - CXX = g++ CXX_FLAGS = -std=c++0x -Wall -pthread @@ -8,6 +6,9 @@ LIB_DIR = ../../../../../../resource SRC_DIR = ../../src +DEPEND_DIR:= $(LIB_DIR)/dependencies +CEREAL_DIR:= $(DEPEND_DIR)/cereal + CXX_INC := -I$(LIB_DIR)/include/ CXX_INC += -I$(LIB_DIR)/oc_logger/include/ CXX_INC += -I$(LIB_DIR)/csdk/stack/include/ @@ -17,6 +18,8 @@ CXX_INC += -I$(LIB_DIR)/csdk/logger/include/ CXX_INC += -I$(BOOST_DIR) CXX_INC += -I../../lib CXX_INC += -I../../../../lib/cpluff/libcpluff +CXX_INC += -I../csdk/libcoap +CXX_INC += -I$(CEREAL_DIR)/include LIB_OC_LOGGER := $(LIB_DIR)/oc_logger/lib/oc_logger.a CXX_LIBS := $(LIB_DIR)/release/obj/liboc.a $(LIB_DIR)/csdk/linux/release/liboctbstack.a $(LIB_OC_LOGGER) ../../../../lib/cpluff/libcpluff/.libs/libcpluff.a diff --git a/service/protocol-plugin/plugins/mqtt-fan/lib/Makefile b/service/protocol-plugin/plugins/mqtt-fan/lib/Makefile index 64329d3..7c10ecb 100644 --- a/service/protocol-plugin/plugins/mqtt-fan/lib/Makefile +++ b/service/protocol-plugin/plugins/mqtt-fan/lib/Makefile @@ -1,4 +1,4 @@ -include config.mk +include config.mk .PHONY : really clean install diff --git a/service/protocol-plugin/plugins/mqtt-fan/lib/python/Makefile b/service/protocol-plugin/plugins/mqtt-fan/lib/python/Makefile index ed5b926..2a54111 100644 --- a/service/protocol-plugin/plugins/mqtt-fan/lib/python/Makefile +++ b/service/protocol-plugin/plugins/mqtt-fan/lib/python/Makefile @@ -1,5 +1,3 @@ -include ../config.mk - # Set DESTDIR if it isn't given DESTDIR?=/ diff --git a/service/protocol-plugin/plugins/mqtt-fan/src/fanserver.cpp b/service/protocol-plugin/plugins/mqtt-fan/src/fanserver.cpp index 544679a..12111e0 100644 --- a/service/protocol-plugin/plugins/mqtt-fan/src/fanserver.cpp +++ b/service/protocol-plugin/plugins/mqtt-fan/src/fanserver.cpp @@ -45,23 +45,22 @@ struct tm *tblock; // Define a structure for time block int gObservation = 0; void *ChangeFanRepresentation (void *param); +void *handleSlowResponse (void *param, std::shared_ptr pRequest); // Specifies where to notify all observers or list of observers -// 0 - notifies all observers -// 1 - notifies list of observers -int isListOfObservers = 0; - -// Forward declaring the entityHandler - -/// This class represents a single resource named 'fanResource'. This resource has -/// two simple properties named 'state' and 'power' +// false: notifies all observers +// true: notifies list of observers +bool isListOfObservers = false; +// Specifies secure or non-secure +// false: non-secure resource +// true: secure resource +bool isSecure = false; +/// Specifies whether Entity handler is going to do slow response or not +bool isSlowResponse = false; // Forward declaring the entityHandler -// void entityHandler(std::shared_ptr request, -// std::shared_ptr response); - /// This class represents a single resource named 'fanResource'. This resource has /// two simple properties named 'state' and 'power' typedef struct plugin_data_t plugin_data_t; @@ -114,7 +113,7 @@ class FanResource // OCResourceProperty is defined ocstack.h uint8_t resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE; - EntityHandler cb = std::bind(&FanResource::entityHandler, this, PH::_1, PH::_2); + EntityHandler cb = std::bind(&FanResource::entityHandler, this, PH::_1); // This will internally create and register the resource. OCStackResult result = OCPlatform::registerResource( @@ -136,7 +135,7 @@ class FanResource // OCResourceProperty is defined ocstack.h uint8_t resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE; - EntityHandler cb = std::bind(&FanResource::entityHandler, this, PH::_1, PH::_2); + EntityHandler cb = std::bind(&FanResource::entityHandler, this, PH::_1); OCResourceHandle resHandle; @@ -251,13 +250,10 @@ class FanResource private: // This is just a sample implementation of entity handler. // Entity handler can be implemented in several ways by the manufacturer - OCEntityHandlerResult entityHandler(std::shared_ptr request, - std::shared_ptr response) + OCEntityHandlerResult entityHandler(std::shared_ptr request) { - OCEntityHandlerResult result = OC_EH_OK; - cout << "\tIn Server CPP entity handler:\n"; - + OCEntityHandlerResult ehResult = OC_EH_ERROR; if (request) { // Get the request type and request flag @@ -272,40 +268,52 @@ class FanResource } if (requestFlag & RequestHandlerFlag::RequestFlag) { - cout << "\t\trequestFlag : Request === Handle by FanServer\n"; + cout << "\t\trequestFlag : Request === Handle by FanServer\n"; + auto pResponse = std::make_shared(); + pResponse->setRequestHandle(request->getRequestHandle()); + pResponse->setResourceHandle(request->getResourceHandle()); // If the request type is GET if (requestType == "GET") { cout << "\t\t\trequestType : GET\n"; - - if (response) + if (isSlowResponse) // Slow response case { - // TODO Error Code - response->setErrorCode(200); - - response->setResourceRepresentation(get()); + static int startedThread = 0; + if (!startedThread) + { + std::thread t(handleSlowResponse, (void *)this, request); + startedThread = 1; + t.detach(); + } + ehResult = OC_EH_SLOW; + } + else // normal response case. + { + pResponse->setErrorCode(200); + pResponse->setResponseResult(OC_EH_OK); + pResponse->setResourceRepresentation(get()); + if (OC_STACK_OK == OCPlatform::sendResponse(pResponse)) + { + ehResult = OC_EH_OK; + } } } else if (requestType == "PUT") { cout << "\t\t\trequestType : PUT\n"; - OCRepresentation rep = request->getResourceRepresentation(); // Do related operations related to PUT request - // Update the fanResource put(rep); - - if (response) + pResponse->setErrorCode(200); + pResponse->setResponseResult(OC_EH_OK); + pResponse->setResourceRepresentation(get()); + if (OC_STACK_OK == OCPlatform::sendResponse(pResponse)) { - // TODO Error Code - response->setErrorCode(200); - - response->setResourceRepresentation(get()); + ehResult = OC_EH_OK; } - } else if (requestType == "POST") { @@ -314,26 +322,19 @@ class FanResource OCRepresentation rep = request->getResourceRepresentation(); // Do related operations related to POST request - OCRepresentation rep_post = post(rep); - - if (response) + pResponse->setResourceRepresentation(rep_post); + pResponse->setErrorCode(200); + if (rep_post.hasAttribute("createduri")) { - // TODO Error Code - response->setErrorCode(200); - - response->setResourceRepresentation(rep_post); - - if (rep_post.hasAttribute("createduri")) - { - result = OC_EH_RESOURCE_CREATED; - - response->setNewResourceUri(rep_post.getValue("createduri")); - } - + pResponse->setResponseResult(OC_EH_RESOURCE_CREATED); + pResponse->setNewResourceUri(rep_post.getValue("createduri")); } - // POST request operations + if (OC_STACK_OK == OCPlatform::sendResponse(pResponse)) + { + ehResult = OC_EH_OK; + } } else if (requestType == "DELETE") { @@ -370,6 +371,7 @@ class FanResource pthread_create (&threadId, NULL, ChangeFanRepresentation, (void *)this); startedThread = 1; } + ehResult = OC_EH_OK; } } else @@ -377,7 +379,7 @@ class FanResource std::cout << "Request invalid" << std::endl; } - return result; + return ehResult; } }; @@ -436,34 +438,36 @@ void *ChangeFanRepresentation (void *param) return NULL; } +void *handleSlowResponse (void *param, std::shared_ptr pRequest) +{ + // This function handles slow response case + FanResource *fanPtr = (FanResource *) param; + // Induce a case for slow response by using sleep + std::cout << "SLOW response" << std::endl; + sleep (10); + + auto pResponse = std::make_shared(); + pResponse->setRequestHandle(pRequest->getRequestHandle()); + pResponse->setResourceHandle(pRequest->getResourceHandle()); + pResponse->setResourceRepresentation(fanPtr->get()); + pResponse->setErrorCode(200); + pResponse->setResponseResult(OC_EH_OK); + + // Set the slow response flag back to false + isSlowResponse = false; + OCPlatform::sendResponse(pResponse); + return NULL; +} + //int start_fanserver(void*) // 1 void *start_fanserver(void *d) // 2 { - /*PlatformConfig cfg; - cfg.ipAddress = "192.168.2.5"; - cfg.port = 56832; - cfg.mode = ModeType::Server; - cfg.serviceType = ServiceType::InProc;*/ - // PlatformConfig cfg - // { - // OC::ServiceType::InProc, - // OC::ModeType::Server, - // "192.168.2.5", - // 56832, - // OC::QualityOfService::NonConfirmable - // }; - - // Create PlatformConfig object - - // Create a OCPlatform instance. - // Note: Platform creation is synchronous call. - // Create PlatformConfig object PlatformConfig cfg { OC::ServiceType::InProc, - OC::ModeType::Server, + OC::ModeType::Both, "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces 0, // Uses randomly available port OC::QualityOfService::LowQos @@ -487,18 +491,9 @@ void *start_fanserver(void *d) // 2 printf("Mosquitto is working\n"); } - //plugin_data_t *data = (plugin_data_t *)d; - //OCPlatform *platform = (OCPlatform*)data->str; - //myFanResource.m_platform = (OCPlatform*)data->str; - //OCPlatform platform(cfg); - // Invoke createResource function of class fan. - - //mosquitto_connect(myMosquitto, "192.168.2.5", 1883, 60); mosquitto_connect(myMosquitto, "127.0.0.1", 1883, 60); printf("Mosquitto Connection is done\n"); myFanResource.createResource(); - //myFanResource.addType(std::string("core.fan")); - //myFanResource.addInterface(std::string("oc.mi.ll")); // Get time of day timer = time(NULL); // Converts date/time to a structure diff --git a/service/protocol-plugin/plugins/mqtt-light/build/linux/Makefile b/service/protocol-plugin/plugins/mqtt-light/build/linux/Makefile index 9b2aca2..026b3a9 100644 --- a/service/protocol-plugin/plugins/mqtt-light/build/linux/Makefile +++ b/service/protocol-plugin/plugins/mqtt-light/build/linux/Makefile @@ -1,5 +1,3 @@ -include ../../../../config.mk - CXX = g++ CXX_FLAGS = -std=c++0x -Wall -pthread @@ -8,6 +6,9 @@ LIB_DIR = ../../../../../../resource SRC_DIR = ../../src +DEPEND_DIR:= $(LIB_DIR)/dependencies +CEREAL_DIR:= $(DEPEND_DIR)/cereal + CXX_INC := -I$(LIB_DIR)/include/ CXX_INC += -I$(LIB_DIR)/oc_logger/include/ CXX_INC += -I$(LIB_DIR)/csdk/stack/include/ @@ -17,6 +18,8 @@ CXX_INC += -I$(LIB_DIR)/csdk/logger/include/ CXX_INC += -I$(BOOST_DIR) CXX_INC += -I../../lib CXX_INC += -I../../../../lib/cpluff/libcpluff +CXX_INC += -I../csdk/libcoap +CXX_INC += -I$(CEREAL_DIR)/include LIB_OC_LOGGER := $(LIB_DIR)/oc_logger/lib/oc_logger.a CXX_LIBS := $(LIB_DIR)/release/obj/liboc.a $(LIB_DIR)/csdk/linux/release/liboctbstack.a $(LIB_OC_LOGGER) ../../../../lib/cpluff/libcpluff/.libs/libcpluff.a diff --git a/service/protocol-plugin/plugins/mqtt-light/lib/Makefile b/service/protocol-plugin/plugins/mqtt-light/lib/Makefile index 64329d3..7c10ecb 100644 --- a/service/protocol-plugin/plugins/mqtt-light/lib/Makefile +++ b/service/protocol-plugin/plugins/mqtt-light/lib/Makefile @@ -1,4 +1,4 @@ -include config.mk +include config.mk .PHONY : really clean install diff --git a/service/protocol-plugin/plugins/mqtt-light/lib/python/Makefile b/service/protocol-plugin/plugins/mqtt-light/lib/python/Makefile index ed5b926..2a54111 100644 --- a/service/protocol-plugin/plugins/mqtt-light/lib/python/Makefile +++ b/service/protocol-plugin/plugins/mqtt-light/lib/python/Makefile @@ -1,5 +1,3 @@ -include ../config.mk - # Set DESTDIR if it isn't given DESTDIR?=/ diff --git a/service/protocol-plugin/plugins/mqtt-light/src/lightserver.cpp b/service/protocol-plugin/plugins/mqtt-light/src/lightserver.cpp index 93bad63..9f30718 100644 --- a/service/protocol-plugin/plugins/mqtt-light/src/lightserver.cpp +++ b/service/protocol-plugin/plugins/mqtt-light/src/lightserver.cpp @@ -43,18 +43,19 @@ struct tm *tblock; // Define a structure for time block int gObservation = 0; void *ChangeLightRepresentation (void *param); - +void *handleSlowResponse (void *param, std::shared_ptr pRequest); // Specifies where to notify all observers or list of observers -// 0 - notifies all observers -// 1 - notifies list of observers -int isListOfObservers = 0; - -// Forward declaring the entityHandler - -/// This class represents a single resource named 'lightResource'. This resource has -/// two simple properties named 'state' and 'power' +// false: notifies all observers +// true: notifies list of observers +bool isListOfObservers = false; +// Specifies secure or non-secure +// false: non-secure resource +// true: secure resource +bool isSecure = false; +/// Specifies whether Entity handler is going to do slow response or not +bool isSlowResponse = false; // Forward declaring the entityHandler // void entityHandler(std::shared_ptr request, @@ -112,7 +113,7 @@ class LightResource // OCResourceProperty is defined ocstack.h uint8_t resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE; - EntityHandler cb = std::bind(&LightResource::entityHandler, this, PH::_1, PH::_2); + EntityHandler cb = std::bind(&LightResource::entityHandler, this, PH::_1); // This will internally create and register the resource. OCStackResult result = OCPlatform::registerResource( @@ -134,7 +135,7 @@ class LightResource // OCResourceProperty is defined ocstack.h uint8_t resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE; - EntityHandler cb = std::bind(&LightResource::entityHandler, this, PH::_1, PH::_2); + EntityHandler cb = std::bind(&LightResource::entityHandler, this, PH::_1); OCResourceHandle resHandle; @@ -249,13 +250,10 @@ class LightResource private: // This is just a sample implementation of entity handler. // Entity handler can be implemented in several ways by the manufacturer - OCEntityHandlerResult entityHandler(std::shared_ptr request, - std::shared_ptr response) + OCEntityHandlerResult entityHandler(std::shared_ptr request) { - OCEntityHandlerResult result = OC_EH_OK; - cout << "\tIn Server CPP entity handler:\n"; - + OCEntityHandlerResult ehResult = OC_EH_ERROR; if (request) { // Get the request type and request flag @@ -270,40 +268,52 @@ class LightResource } if (requestFlag & RequestHandlerFlag::RequestFlag) { - cout << "\t\trequestFlag : Request === Handle by LightServer\n"; + cout << "\t\trequestFlag : Request === Handle by FanServer\n"; + auto pResponse = std::make_shared(); + pResponse->setRequestHandle(request->getRequestHandle()); + pResponse->setResourceHandle(request->getResourceHandle()); // If the request type is GET if (requestType == "GET") { cout << "\t\t\trequestType : GET\n"; - - if (response) + if (isSlowResponse) // Slow response case { - // TODO Error Code - response->setErrorCode(200); - - response->setResourceRepresentation(get()); + static int startedThread = 0; + if (!startedThread) + { + std::thread t(handleSlowResponse, (void *)this, request); + startedThread = 1; + t.detach(); + } + ehResult = OC_EH_SLOW; + } + else // normal response case. + { + pResponse->setErrorCode(200); + pResponse->setResponseResult(OC_EH_OK); + pResponse->setResourceRepresentation(get()); + if (OC_STACK_OK == OCPlatform::sendResponse(pResponse)) + { + ehResult = OC_EH_OK; + } } } else if (requestType == "PUT") { cout << "\t\t\trequestType : PUT\n"; - OCRepresentation rep = request->getResourceRepresentation(); // Do related operations related to PUT request - // Update the lightResource put(rep); - - if (response) + pResponse->setErrorCode(200); + pResponse->setResponseResult(OC_EH_OK); + pResponse->setResourceRepresentation(get()); + if (OC_STACK_OK == OCPlatform::sendResponse(pResponse)) { - // TODO Error Code - response->setErrorCode(200); - - response->setResourceRepresentation(get()); + ehResult = OC_EH_OK; } - } else if (requestType == "POST") { @@ -312,26 +322,19 @@ class LightResource OCRepresentation rep = request->getResourceRepresentation(); // Do related operations related to POST request - OCRepresentation rep_post = post(rep); - - if (response) + pResponse->setResourceRepresentation(rep_post); + pResponse->setErrorCode(200); + if (rep_post.hasAttribute("createduri")) { - // TODO Error Code - response->setErrorCode(200); - - response->setResourceRepresentation(rep_post); - - if (rep_post.hasAttribute("createduri")) - { - result = OC_EH_RESOURCE_CREATED; - - response->setNewResourceUri(rep_post.getValue("createduri")); - } - + pResponse->setResponseResult(OC_EH_RESOURCE_CREATED); + pResponse->setNewResourceUri(rep_post.getValue("createduri")); } - // POST request operations + if (OC_STACK_OK == OCPlatform::sendResponse(pResponse)) + { + ehResult = OC_EH_OK; + } } else if (requestType == "DELETE") { @@ -368,6 +371,7 @@ class LightResource pthread_create (&threadId, NULL, ChangeLightRepresentation, (void *)this); startedThread = 1; } + ehResult = OC_EH_OK; } } else @@ -375,7 +379,7 @@ class LightResource std::cout << "Request invalid" << std::endl; } - return result; + return ehResult; } }; @@ -434,36 +438,36 @@ void *ChangeLightRepresentation (void *param) return NULL; } - +void *handleSlowResponse (void *param, std::shared_ptr pRequest) +{ + // This function handles slow response case + LightResource *lightPtr = (LightResource *) param; + // Induce a case for slow response by using sleep + std::cout << "SLOW response" << std::endl; + sleep (10); + + auto pResponse = std::make_shared(); + pResponse->setRequestHandle(pRequest->getRequestHandle()); + pResponse->setResourceHandle(pRequest->getResourceHandle()); + pResponse->setResourceRepresentation(lightPtr->get()); + pResponse->setErrorCode(200); + pResponse->setResponseResult(OC_EH_OK); + + // Set the slow response flag back to false + isSlowResponse = false; + OCPlatform::sendResponse(pResponse); + return NULL; +} //int start_lightserver(void*) // 1 void *start_lightserver(void *d) // 2 { - /*PlatformConfig cfg; - cfg.ipAddress = "192.168.2.5"; - cfg.port = 56832; - cfg.mode = ModeType::Server; - cfg.serviceType = ServiceType::InProc;*/ - // PlatformConfig cfg - // { - // OC::ServiceType::InProc, - // OC::ModeType::Server, - // "192.168.2.5", - // 56832, - // OC::QualityOfService::NonConfirmable - // }; - - // Create PlatformConfig object - - // Create a OCPlatform instance. - // Note: Platform creation is synchronous call. - // Create PlatformConfig object PlatformConfig cfg { OC::ServiceType::InProc, - OC::ModeType::Server, + OC::ModeType::Both, "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces 0, // Uses randomly available port OC::QualityOfService::LowQos @@ -487,18 +491,9 @@ void *start_lightserver(void *d) // 2 printf("Mosquitto is working\n"); } - //plugin_data_t *data = (plugin_data_t *)d; - //OCPlatform *platform = (OCPlatform*)data->str; - //myLightResource.m_platform = (OCPlatform*)data->str; - //OCPlatform platform(cfg); - // Invoke createResource function of class light. - - //mosquitto_connect(myMosquitto, "192.168.2.5", 1883, 60); mosquitto_connect(myMosquitto, "127.0.0.1", 1883, 60); printf("Mosquitto Connection is done\n"); myLightResource.createResource(); - //myLightResource.addType(std::string("core.light")); - //myLightResource.addInterface(std::string("oc.mi.ll")); // Get time of day timer = time(NULL); // Converts date/time to a structure diff --git a/service/protocol-plugin/readme b/service/protocol-plugin/readme index 935bc7e..351756b 100644 --- a/service/protocol-plugin/readme +++ b/service/protocol-plugin/readme @@ -1,20 +1,75 @@ +This guide will help you setup your developing environment for Protocol plug-in Manager and Protocol plug-ins in Ubuntu. + +1. Preparings +Before starting, following tools should be installed. + +Automake +Automake is a tool for automatically generating Makefile.in files compiliant with the GNU Coding Standards. This tool is used for compiling C-Pluff open source which used in Plug-in Manager. +$ sudo apt-get install automake + +Libtool +GNU libtool is a generic library support script. This tool is used for compiling C-Pluff open source which used in Plug-in Manager. + $ sudo apt-get install libtool + +gettext +GNU `gettext' utilities are a set of tools that provides a framework to help other GNU packages produce multi-lingual messages. This tool is used for compiling C-Pluff open source which used in Plug-in Manager. + $ sudo apt-get install gettext + +Expat +Expat is a stream-oriented XML parser library. This library is used for compiling C-Pluff open source which used in Plug-in Manager. + $ sudo apt-get install expat + +Building and Using Protocol Plug-in Manager + +Once the source code is downloaded into a specific folder, oic in this context, you may follow the steps to build and execute Protocol Plug-in Manager. +The path for Protocol Plugin is as following; + +~/oic/oic-resource/service/protocol-plugin $_ + + +The Protocol Plug-in directory includes following sub directories; + +/plugin-manager Directory for Plug-in Manager +/plugins Directory for Reference Plugins +/lib Directory for Common Library +/sample-app Directory for Iotivity Sample Application +/doc Directory for Developers Document +/build Directory for Building and Binary Release + + +2. Compiling C-Pluff library +Before building Protocol-Plugin Manager, C-Pluff library should be compiled as follows. + +~/oic/oic-service/protocol-plugin/lib/cpluff$ aclocal +~/oic/oic-service/protocol-plugin/lib/cpluff$ autoconf +~/oic/oic-service/protocol-plugin/lib/cpluff$ autoheader +~/oic/oic-service/protocol-plugin/lib/cpluff$ automake +~/oic/oic-service/protocol-plugin/lib/cpluff$ ./configure +~/oic/oic-service/protocol-plugin/lib/cpluff$ make + + +3. Run make +By running make in the protocol-plugin path, protocol-plugin manager, all plugins and sample applications will be created. + +NOTE: To build plugins in 64-bit Ubuntu Linux, OCLib.a and libcoap.a library should be re-compiled with ?fPIC option. + +~/oic/oic-service/protocol-plugin/build/linux$make + + +4. Using Plugins This version of protocol plug-in source code has following functionality. -1. provides plug-in manager which can register, unregister, start and stop plug-in library. -2. provides plug-in library which can communicate with MQTT protocol FAN. -3. provides OIC Sample Client which can turn on/off FAN. +1) provides plug-in manager which can start and stop plug-in library. +2) provides plug-in library which can communicate with MQTT protocol Fan and Light. +3) provides OIC Sample Client which can get info about Fan and Light with configuration file(pluginmanager.xml). So, to test a plug-in, follow below steps. -1. Locate shared plug-in library and XML file in a specific folder. -2. Register the plug-in with directory path input from plug-in manager sample. -3. Start the plug-in from plug-in manager sample. -4. Run OIC sample client. - -If you have any questions about protocol plug-in component, please contact with following addresses. +1) Locate shared plug-in library and XML file in a specific folder. +2) Register the plug-in with directory path input from plug-in manager sample. +3) Start the plug-in from plug-in manager sample. +4) Run OIC sample client. + ex)service/protocol-plugin/sample-app/linux/mqtt$./mqttclient + (mqtt broker is already installed in the local system.) -kc7576.park@samsung.com -heesung84.kim@samsung.com -junho13.lee@samsung.com -yh_.joo@samsung.com \ No newline at end of file diff --git a/service/protocol-plugin/sample-app/linux/fan-control/Makefile b/service/protocol-plugin/sample-app/linux/mqtt/Makefile similarity index 69% rename from service/protocol-plugin/sample-app/linux/fan-control/Makefile rename to service/protocol-plugin/sample-app/linux/mqtt/Makefile index 6b5d664..e3b3841 100644 --- a/service/protocol-plugin/sample-app/linux/fan-control/Makefile +++ b/service/protocol-plugin/sample-app/linux/mqtt/Makefile @@ -4,6 +4,9 @@ CXX_FLAGS = -std=c++0x -Wall -pthread LIB_DIR = ../../../../../resource +DEPEND_DIR:= $(LIB_DIR)/dependencies +CEREAL_DIR:= $(DEPEND_DIR)/cereal + CXX_INC := -I$(LIB_DIR)/include/ CXX_INC += -I$(LIB_DIR)/oc_logger/include/ CXX_INC += -I$(LIB_DIR)/csdk/stack/include/ @@ -14,22 +17,24 @@ CXX_INC += -I$(BOOST_DIR) CXX_INC += -I../../lib CXX_INC += -I../../../lib/cpluff/libcpluff CXX_INC += -I../../../plugin-manager/src +CXX_INC += -I$(CEREAL_DIR)/include +CXX_INC += -I../../../lib/rapidxml LIB_OC_LOGGER := $(LIB_DIR)/oc_logger/lib/oc_logger.a CXX_LIBS := $(LIB_DIR)/release/obj/liboc.a $(LIB_DIR)/csdk/linux/release/liboctbstack.a $(LIB_OC_LOGGER) ../../../build/linux/release/libppm.a ../../../lib/cpluff/libcpluff/.libs/libcpluff.a LINK_LIB = -lboost_system -ldl -lexpat -lboost_thread -.PHONY: fanclient +.PHONY: mqttclient all: .PHONY -fanclient: fanclient.o - $(CXX) $(CXX_FLAGS) -o fanclient fanclient.o $(CXX_LIBS) $(LINK_LIB) +mqttclient: mqttclient.o + $(CXX) $(CXX_FLAGS) -o mqttclient mqttclient.o $(CXX_LIBS) $(LINK_LIB) -fanclient.o: fanclient.cpp - $(CXX) $(CXX_FLAGS) -c fanclient.cpp $(CXX_INC) +mqttclient.o: mqttclient.cpp + $(CXX) $(CXX_FLAGS) -c mqttclient.cpp $(CXX_INC) clean: rm -f *.o - rm -f fanclient + rm -f mqttclient diff --git a/service/protocol-plugin/sample-app/linux/fan-control/fanclient.cpp b/service/protocol-plugin/sample-app/linux/mqtt/mqttclient.cpp similarity index 83% rename from service/protocol-plugin/sample-app/linux/fan-control/fanclient.cpp rename to service/protocol-plugin/sample-app/linux/mqtt/mqttclient.cpp index 64f4154..eda93d4 100644 --- a/service/protocol-plugin/sample-app/linux/fan-control/fanclient.cpp +++ b/service/protocol-plugin/sample-app/linux/mqtt/mqttclient.cpp @@ -32,7 +32,8 @@ using namespace OC; using namespace OIC; -std::shared_ptr curResource; +std::shared_ptr curFanResource; +std::shared_ptr curLightResource; static ObserveType OBSERVE_TYPE_TO_USE = ObserveType::Observe; time_t timer; // Define the timer @@ -78,7 +79,7 @@ void onObserve(const HeaderOptions headerOptions, const OCRepresentation &rep, if (observe_count() > 30) { std::cout << "Cancelling Observe..." << std::endl; - OCStackResult result = curResource->cancelObserve(); + OCStackResult result = curFanResource->cancelObserve(); std::cout << "Cancel result: " << result << std::endl; sleep(10); @@ -120,7 +121,7 @@ void onPost2(const HeaderOptions &headerOptions, const OCRepresentation &rep, co else if (OBSERVE_TYPE_TO_USE == ObserveType::ObserveAll) std::cout << endl << "ObserveAll is used." << endl << endl; - curResource->observe(OBSERVE_TYPE_TO_USE, QueryParamsMap(), &onObserve); + //curFanResource->observe(OBSERVE_TYPE_TO_USE, QueryParamsMap(), &onObserve); } else @@ -162,7 +163,7 @@ void onPost(const HeaderOptions &headerOptions, const OCRepresentation &rep, con rep2.setValue("state", myfan.m_state); rep2.setValue("power", myfan.m_power); - curResource->post(rep2, QueryParamsMap(), &onPost2); + curFanResource->post(rep2, QueryParamsMap(), &onPost2); } else { @@ -206,7 +207,7 @@ void onPut(const HeaderOptions &headerOptions, const OCRepresentation &rep, cons std::cout << "\tpower: " << myfan.m_power << std::endl; std::cout << "\tname: " << myfan.m_name << std::endl; - postFanRepresentation(curResource); + postFanRepresentation(curFanResource); } else { @@ -251,7 +252,7 @@ void onGet(const HeaderOptions &headerOptions, const OCRepresentation &rep, cons std::cout << "\tpower: " << myfan.m_power << std::endl; std::cout << "\tname: " << myfan.m_name << std::endl; - putFanRepresentation(curResource); + putFanRepresentation(curFanResource); } else { @@ -288,7 +289,7 @@ void getLightRepresentation(std::shared_ptr resource) // Callback to found resources void foundResourceFan(std::shared_ptr resource) { - if (curResource) + if (curFanResource) { std::cout << "Found another resource, ignoring" << std::endl; } @@ -325,7 +326,7 @@ void foundResourceFan(std::shared_ptr resource) if (resourceURI == "/a/fan") { - curResource = resource; + curFanResource = resource; // Call a local function which will internally invoke get API on the resource pointer getFanRepresentation(resource); } @@ -346,7 +347,7 @@ void foundResourceFan(std::shared_ptr resource) // Callback to found resources void foundResourceLight(std::shared_ptr resource) { - if (curResource) + if (curLightResource) { std::cout << "Found another resource, ignoring" << std::endl; } @@ -383,7 +384,7 @@ void foundResourceLight(std::shared_ptr resource) if (resourceURI == "/a/light") { - curResource = resource; + curLightResource = resource; // Call a local function which will internally invoke get API on the resource pointer getLightRepresentation(resource); } @@ -425,7 +426,9 @@ void client1() std::cout << "Finding Fan Resource... time : " << asctime(tblock) << std::endl; while (1) { - // client1 related operations + std::cout << "Get Fan Resource....." << std::endl; + sleep(5); + getFanRepresentation(curFanResource); } } @@ -449,7 +452,9 @@ void client2() while (1) { - // client2 related operations + std::cout << "Get Light Resource....." << std::endl; + sleep(5); + getLightRepresentation(curLightResource); } } @@ -457,6 +462,11 @@ void client2() int main(int argc, char *argv[]) { + std::string name; + std::string key = "Name"; + std::string state = ""; + std::string id = ""; + if (argc == 1) { OBSERVE_TYPE_TO_USE = ObserveType::Observe; @@ -494,41 +504,83 @@ int main(int argc, char *argv[]) std::cout << "Created Platform..." << std::endl; - PluginManager *m_pm = new PluginManager(); + std::cout << "==== 1st TEST CASE ===" << std::endl; std::cout << "======================" << std::endl; - std::cout << "start light Plugin by Resource Type" << std::endl; + m_pm->startPlugins("ResourceType", "oic.light"); sleep(2); + std::cout << "\n==== 2nd TEST CASE =====" << std::endl; std::cout << "======================" << std::endl; - std::cout << "get Plugin List" << std::endl; + std::cout << "Get Plugin List\n" << std::endl; std::vector user_plugin; + user_plugin = m_pm->getPlugins(); + for (unsigned int i = 0; i < user_plugin.size(); i++) { - printf("value Name = %s\n", user_plugin[i].getName().c_str()); - printf("value ID = %s\n", user_plugin[i].getID().c_str()); + std::cout << "value Name = " << user_plugin[i].getName() << std::endl; + std::cout << "value ID = " << user_plugin[i].getID() << std::endl; + id = user_plugin[i].getID(); } - + std::cout << "\n===== 3rd TEST CASE =====" << std::endl; std::cout << "======================" << std::endl; - std::cout << "start Fan Plugin by Name" << std::endl; - m_pm->startPlugins("Name", "mqtt-fan"); + std::cout << "Start Fan Plugin by Name\n" << std::endl; + + name = user_plugin[0].getName().c_str(); + m_pm->startPlugins(key, name); + + sleep(5); + + std::cout << "\n====== 4th TEST CASE ======" << std::endl; + std::cout << "========================" << std::endl; + std::cout << "Get Plugin Status\n" << std::endl; + + state = m_pm->getState(id); + std::cout << "last plugin status : " << state << std::endl; + std::cout << "sleep 15 seconds please add new plugin in the plugin folder " << std::endl; + sleep(15); + + std::cout << "\n==== 5th TEST CASE ====" << std::endl; + std::cout << "========================" << std::endl; + std::cout << "Rescan Plugins.........\n" << std::endl; + + m_pm->rescanPlugin(); + + std::cout << "\n==== 6th TEST CASE ====" << std::endl; + std::cout << "========================" << std::endl; + std::cout << "Try to start new resource type.........\n" << std::endl; + std::cout << "start oic.test resource" << std::endl; + + sleep(5); + + int flag = m_pm->startPlugins("ResourceType", "oic.test"); + + if (!flag) + std::cout << "There are no resouce type. Start plugin failed" << std::endl; // Start each client in a seperate thread -// std::thread t1(client1); -// t1.detach(); -///* -// sleep(5); + sleep(10); + + std::cout << "\n====== 7th TEST CASE =======" << std::endl; + std::cout << "========================" << std::endl; + std::cout << " start client to find resource" << std::endl; + + std::thread t1(client1); + t1.detach(); + + sleep(5); + // Start each client in a seperate thread -// std::thread t2(client2); -// t2.detach(); -//*/ + std::thread t2(client2); + t2.detach(); + while (true) { // some operations diff --git a/service/protocol-plugin/sample-app/linux/mqtt/pluginmanager.xml b/service/protocol-plugin/sample-app/linux/mqtt/pluginmanager.xml new file mode 100644 index 0000000..c90bb9f --- /dev/null +++ b/service/protocol-plugin/sample-app/linux/mqtt/pluginmanager.xml @@ -0,0 +1,12 @@ + + + + + + + -- 2.7.4