mbed.org implementation of the abstract SmartREST library for the Cumulocity Platform SmartREST protocol.
Dependents: MbedSmartRestMain MbedSmartRestMain
Revision 0:099f76422485, committed 2014-07-03
- Comitter:
- Cumulocity
- Date:
- Thu Jul 03 20:38:04 2014 +0200
- Child:
- 1:9a11a331e340
- Commit message:
- Updated from revision 0413a0179eb6
Changed in this revision
Binary file .AbstractDataSink.h.swp has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AbstractClient.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,122 @@ +/* + * AbstractClient.h + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @file AbstractClient.h + * An abstraction layer for the SmartREST http client. + */ + +#ifndef ABSTRACTCLIENT_H +#define ABSTRACTCLIENT_H + +#include "config.h" +#include "DataGenerator.h" +#include "AbstractDataSource.h" +#include "AbstractDataSink.h" + +/** Return value indicating that the operation has been successful. */ +#define CLIENT_OK 0 +/** Return value indicating that there has been a connection error. */ +#define CLIENT_CONNECTION_ERROR 1 +/** Return value indicating that an internal error occurred. */ +#define CLIENT_INTERNAL_ERROR 2 + +/* + * An abstraction layer for the SmartREST http client. + * Constructor arguments such as username and password strings must + * not be cpoied but instead stored as pointer as they are subject to + * change. + * + * All methods have to be called in the following order: + * - beginRequest() + * - sendIdentifier() (optional) + * - sendData() (optional) + * - endRequest() + * - awaitResponse() + * - receiveData() (optional) + * - stop() + * + * Additionally, stop() can be called at any time to reset the state of + * this instance. + */ +class AbstractClient +{ +public: + virtual ~AbstractClient() { }; + + /** + * Begins a new request. This method has to be the first call for + * any request. A connection to the server will be established + * and the start of a HTTP post request will be sent over the + * connection including Host and Authorization headers. + */ + virtual uint8_t beginRequest() = 0; + + /** + * Sends the X-Id device identifier header. + * @param identifier the identifier to be sent. The value has to remain + * valid for the entire request. + */ + virtual uint8_t sendIdentifier(const char*) = 0; + + /** + * Sends POST data over the connection. Before the data is sent, + * a Content-Length header is also sent over the connection. if the + * estimated length does not match the actual conten length, + * unexpected behavior will occur. + * @param generator the data generator for the data to be sent + */ + virtual uint8_t sendData(DataGenerator& generator) = 0; + + /** + * Finishes the request. In case no data has been sent over the + * connection, this method will send twice carriage-return new-line. + */ + virtual uint8_t endRequest() = 0; + + /** + * Blocks until the start of a response has been received. + */ + virtual uint8_t awaitResponse() = 0; + + /** + * Returns a data source for reading data. + * When no data can be read for whatever reason, + * a data source with an error state may be returned. + * @return the data source to read from + */ + virtual AbstractDataSource& receiveData() = 0; + + /** + * Resets the connection. This method can be called at any time + * and resets the state of this instance. + */ + virtual void stop() = 0; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AbstractDataSink.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,86 @@ +/* + * AbstractDataSink.h + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @file AbstractDataSink.h + * An abstraction for a data sink which can be used to send data + * over a connection. + * + * Following write actions are supported: + * - write a character + * - write a buffer of certain length + * - write a character string + * - write an unsigned number + */ + +#ifndef ABSTRACTDATASINK_H +#define ABSTRACTDATASINK_H + +#include "config.h" +#include <stddef.h> + +/* + * The AbstractDataSink class provides a way to write data to a + * connection. + */ +class AbstractDataSink +{ +public: + virtual ~AbstractDataSink() { }; + + /** + * Writes a single character. + * @param c the character to write + * @return the number of characters written, in this case 1 or 0 + */ + virtual size_t write(char c) = 0; + + /** + * Writes a buffer. + * @param buf the buffer to write + * @param length the length of the buffer in bytes + * @return the number of characters written + */ + virtual size_t write(void *buf, size_t length) = 0; + + /** + * Writes a character string. + * @param str the string to write + * @return the number of characters written + */ + virtual size_t write(const char *str) = 0; + + /** + * Writes a number with base 10. + * @param number the number to write + * @return the number of digits written + */ + virtual size_t write(unsigned long number) = 0; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AbstractDataSource.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,101 @@ +/* + * AbstractDataSource.h + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @file AbstractDataSource.h + * An abstraction layer which provides means to read data from a + * connection. + * + * Example: + * @code + * AbstractDataSource source; + * char c; + * while (((c = source.read()) > 0) || (source.status() == DS_STATUS_OK)) { + * // read action + * } + * switch (source.status()) { + * case DS_STATUS_OK: + * // ok + * case DS_STATUS_CLOSED: + * // connection closed + * case DS_STATUS_TIMEOUT: + * // timeout + * default: + * // other error + * } + * @encode + * + */ + +#ifndef ABSTRACTDATASOURCE_H +#define ABSTRACTDATASOURCE_H + +#include "config.h" +#include <stdint.h> + +/** Return value indicating that no error has occurred. */ +#define DS_STATUS_OK 0 +/** Return value indicating that the connection has been closed by this + * or the foreign host. */ +#define DS_STATUS_CLOSED 1 +/** Return value indicating a transmission timeout. */ +#define DS_STATUS_TIMEOUT 2 +/** Return value indicating a state error. */ +#define DS_STATUS_ERROR 3 + +/* + * The AbstractDataSource class provides a way to read data from a + * connection. + */ +class AbstractDataSource +{ +public: + virtual ~AbstractDataSource() { }; + + /** + * Reads one character. When successful, the returned value + * represents the character. Otherwise, status() will return a + * non-zero value. This function is blocking. + * @return the caracter read or zero. If the return value is + * non-zero, status() is zero. Otherwise, check status() for a + * non-zero value. + */ + virtual char read() = 0; + + /** + * Returns the current read state. If a non-zero value is returned, + * there is an error. Otherwise, everything is ok. + * DS_STATUS_TIMEOUT means that there has been a read timeout. + * DS_STATUS_CLOSED means that the connection has been closed + * by either this or the foreign host. + * @return the status value + */ + virtual uint8_t status() = 0; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Aggregator.cpp Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,167 @@ +/* + * Aggregator.cpp + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "Aggregator.h" +#include <stdlib.h> + +#ifndef SMARTREST_AGGREGATOR_FIXED_SIZE +Aggregator::Aggregator(size_t capacity, bool growing, bool copy) +{ + _alloc = copy; + _growing = growing; + _capacity = 0; + _list = NULL; + _initial = capacity; + _length = 0; +} +#else +Aggregator::Aggregator(bool copy) +{ + _alloc = copy; + _length = 0; +} +#endif + +Aggregator::~Aggregator() +{ + if (_alloc) { + for (size_t n = 0; n < _length; n++) + delete _list[n]; + } + #ifndef SMARTREST_AGGREGATOR_FIXED_SIZE + if (_list != NULL) + free(_list); + #endif +} + +bool Aggregator::add(const DataGenerator& generator) +{ + if (this == &generator) + return false; + #ifndef SMARTREST_AGGREGATOR_FIXED_SIZE + if (_length == _capacity) { + size_t capacity; + + if ((!_growing) && (_capacity != 0)) + return false; + + if (_capacity == 0) + capacity = _initial; + else + capacity = _capacity + SMARTREST_AGGREGATOR_MEMORY_INCREMENT; + + const DataGenerator **list = (const DataGenerator**)realloc(_list, + capacity*sizeof(DataGenerator*)); + if (list == NULL) + return false; + _list = list; + _capacity = capacity; + } + #else + if (_length == SMARTREST_AGGREGATOR_FIXED_SIZE) + return false; + #endif + + if (_alloc) { + DataGenerator *copy = generator.copy(); + if (copy == NULL) + return false; + _list[_length++] = copy; + } else { + _list[_length++] = &generator; + } + return true; +} + +void Aggregator::clear() +{ + if (_alloc) { + for (size_t n = 0; n < _length; n++) + delete _list[n]; + } + _length = 0; + + #ifndef SMARTREST_AGGREGATOR_FIXED_SIZE + if (_list != NULL) + free(_list); + _list = NULL; + _capacity = 0; + #endif +} + +size_t Aggregator::length() +{ + return _length; +} + +bool Aggregator::full() +{ + #ifndef SMARTREST_AGGREGATOR_FIXED_SIZE + return (_growing) ? false : (_length == _capacity); + #else + return (_length == SMARTREST_AGGREGATOR_FIXED_SIZE); + #endif +} + +size_t Aggregator::capacity() +{ + #ifndef SMARTREST_AGGREGATOR_FIXED_SIZE + return (_growing) ? 0 : _capacity; + #else + return SMARTREST_AGGREGATOR_FIXED_SIZE; + #endif +} + +size_t Aggregator::writeTo(AbstractDataSink& sink) const +{ + size_t len = 0; + for (size_t n = 0; n < _length; n++) + len += _list[n]->writeTo(sink); + return len; +} + +size_t Aggregator::writtenLength() const +{ + size_t len = 0; + for (size_t n = 0; n < _length; n++) + len += _list[n]->writtenLength(); + return len; +} + +DataGenerator* Aggregator::copy() const +{ + #ifndef SMARTREST_AGGREGATOR_FIXED_SIZE + Aggregator *copy = new Aggregator(_length, _growing, true); + #else + Aggregator *copy = new Aggregator(true); + #endif + for (size_t n = 0; n < _length; n++) + copy->add(*_list[n]); + return copy; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Aggregator.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,155 @@ +/* + * Aggregator.h + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef AGGREGATOR_H +#define AGGREGATOR_H + +#include "config.h" +#include <stddef.h> +#include "DataGenerator.h" + +#ifndef SMARTREST_AGGREGATOR_INITIAL_CAPACITY +#define SMARTREST_AGGREGATOR_INITIAL_CAPACITY 50 +#endif +#ifndef SMARTREST_AGGREGATOR_MEMORY_INCREMENT +#define SMARTREST_AGGREGATOR_MEMORY_INCREMENT 25 +#endif +//#define SMARTREST_AGGREGATOR_FIXED_SIZE 100 + +/** + * An aggregator of data generators. This class can aggregate instances of + * itself. + * If the aggregator is set to copying all added data generators using + * the copy() method, all objects are being properly deallocated on + * destruction. + * + * Example: + * @code + * // Given: A concrete SmartRest implementation. + * SmartRest client; + * + * // sets up a growing aggregator which copies all added objects + * // to the heap + * Aggregator buffer(25, true, true); + * + * // random data collection + * for (uint8_t i = 0; i < 32; ++i) { + * // Note: ComposedRecord is not copying any values into the heap + * // because the availability of its values in guaranteed during the + * // instance's lifetime. + * ComposedRecord record(false); + * + * CharValue msgId(100); + * IntegerValue number(i); + * record.add(msgId).add(number); + * + * // Note: ComposedRecord is now cloned into the heap to extend its + * // lifetime beyond this code block. + * buffer.add(record); + * } + * + * // send the bulk request + * uint8_t ret = client.send(buffer); + * if (ret != SMARTREST_SUCCESS) { + * // error handling + * } + * @encode + */ +class Aggregator : public DataGenerator +{ +public: + #ifndef SMARTREST_AGGREGATOR_FIXED_SIZE + /** + * Creates a new Aggregator instance. + * @param capacity the initial capacity of the instance + * @param growing specifies the capability of this instance to grow + * @param copy specifies whether all added data generators shall be + * copied using the copy() method + */ + Aggregator(size_t=SMARTREST_AGGREGATOR_INITIAL_CAPACITY, bool=true, bool=false); + #else + /** + * Creates a new Aggregator instance. + * @param copy specifies whether all added data generators shall be + * copied using the copy() method + */ + Aggregator(bool=false); + #endif + ~Aggregator(); + + /** + * Adds a data generator to the aggregator. + * @param generator the data generator to add + * @return true if added, false otherwise. + */ + bool add(const DataGenerator&); + + /** + * Clears the aggregator. The capacity will shrink to it's initial + * size. + */ + void clear(); + + /** + * Returns the number of data generators aggregated by this instance. + * @return the number of data generators aggregated + */ + size_t length(); + + /** + * Returns whether the aggregator is full. If growing, this will + * always return false. + * @return whether the aggregator is full + */ + bool full(); + + /** + * Returns the capacity of the aggregator. This will always return zero + * if the aggregator is growing. + */ + size_t capacity(); + + size_t writeTo(AbstractDataSink&) const; + size_t writtenLength() const; + DataGenerator* copy() const; + +private: + #ifdef SMARTREST_AGGREGATOR_FIXED_SIZE + const DataGenerator *_list[SMARTREST_AGGREGATOR_FIXED_SIZE]; + #else + const DataGenerator **_list; + #endif + size_t _length; + bool _alloc; + #ifndef SMARTREST_AGGREGATOR_FIXED_SIZE + size_t _capacity, _initial; + bool _growing; + #endif +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CharValue.cpp Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,137 @@ +/* + * CharValue.cpp + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "CharValue.h" +#include "NullValue.h" +#include <stdlib.h> +#include <string.h> + +inline int8_t __charvalue_need_escape(const char *str); + +CharValue::CharValue(const char *str, bool copy) +{ + if ((str == NULL) || (*str == '\0')) { + _alloc = false; + _str = NULL; + } else { + _alloc = copy; + if (copy) { + _str = (const char*)malloc(strlen(str)*sizeof(char)); + strcpy((char*)_str, str); + } else { + _str = str; + } + } +} + +CharValue::~CharValue() +{ + if (_alloc) + free((void*)_str); +} + +uint8_t CharValue::valueType() const +{ + if (_str == NULL) + return VALUE_NULL; + return VALUE_CHARACTER; +} + +long CharValue::integerValue() const +{ + return 0; +} + +double CharValue::floatValue() const +{ + return 0.0; +} + +const char * CharValue::characterValue() const +{ + return _str; +} + +size_t CharValue::write(AbstractDataSink& sink) const +{ + if (_str == NULL) + return 0; + size_t n = 0; + int8_t esc = __charvalue_need_escape(_str) ? 1 : 0; + if (esc) n += sink.write('"'); + for (char *q = (char*)_str, c; (c = *q) != 0; q++) { + if ((esc) && (c == '"')) + n += sink.write('"'); + n += sink.write(c); + } + if (esc) n += sink.write('"'); + return n; +} + +size_t CharValue::length() const +{ + if (_str == NULL) + return 0; + size_t n = 0; + int8_t esc = __charvalue_need_escape(_str) ? 1 : 0; + if (esc) + n += 2; + for (char *q = (char*)_str, c; (c = *q) != 0; q++) { + if ((esc) && (c == '"')) + n++; + n++; + } + return n; +} + +int8_t __charvalue_need_escape(const char *str) +{ + int8_t w = 0; + for (char c; (c = *str) != 0; str++) { + if ((c == ' ') || (c == '\t')) { + if (w == 0) + return 1; + w = 2; + } else { + w = 1; + if ((c == '"') || (c == ',') || (c == '\r') || (c == '\n')) + return 1; + } + } + if (w == 2) + return 1; + return 0; +} + +Value* CharValue::copy() const +{ + if (_str == NULL) + return new NullValue(); + return new CharValue(_str, true); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CharValue.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,71 @@ +/* + * CharValue.h + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef CHARVALUE_H +#define CHARVALUE_H + +#include "config.h" +#include "Value.h" + +/** + * A basic character value. This value type behaves simmilar to a null + * value if the ommitted string is empty. + * + * Example: + * @code + * // A string + * CharValue str("Hello World!"); + * + * // a null value + * CharValue null(""); + * + * // another null value + * CharValue null2(NULL); + * @encode + */ +class CharValue : public Value +{ +public: + CharValue(const char*, bool=false); + ~CharValue(); + + uint8_t valueType() const; + long integerValue() const; + double floatValue() const; + const char * characterValue() const; + + size_t write(AbstractDataSink&) const; + size_t length() const; + Value* copy() const; + +private: + const char *_str; + bool _alloc; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ComposedRecord.cpp Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,124 @@ +/* + * ComposedRecord.cpp + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "ComposedRecord.h" +#include "NullValue.h" +#include <stdlib.h> +#include <string.h> + +ComposedRecord::ComposedRecord(bool copy) +{ + _alloc = copy; + #ifndef SMARTREST_COMPOSED_FIXED_SIZE + _capacity = 0; + _values = NULL; + #endif + _count = 0; +} + +ComposedRecord::~ComposedRecord() +{ + if (_alloc) { + for (size_t n = 0; n < _count; n++) + delete _values[n]; + } + #ifndef SMARTREST_COMPOSED_FIXED_SIZE + if (_values != NULL) + free(_values); + #endif +} + +bool ComposedRecord::add(const Value& value) +{ + #ifndef SMARTREST_COMPOSED_FIXED_SIZE + if (_capacity == _count) { + size_t capacity; + if (_capacity == 0) + capacity = SMARTREST_COMPOSED_INITIAL_CAPACITY; + else + capacity = _capacity + SMARTREST_COMPOSED_MEMORY_INCREMENT; + + const Value **values = (const Value**)realloc(_values, + capacity*sizeof(Value*)); + if (values == NULL) + return false; + _values = values; + _capacity = capacity; + } + #else + if (_count == SMARTREST_COMPOSED_FIXED_SIZE) + return false; + #endif + + if (_alloc) { + Value *copy = value.copy(); + if (copy == NULL) + return false; + _values[_count++] = copy; + } else { + _values[_count++] = &value; + } + return true; +} + +void ComposedRecord::clear() +{ + if (_alloc) { + for (size_t n = 0; n < _count; n++) + delete _values[n]; + } + _count = 0; + + #ifndef SMARTREST_COMPOSED_FIXED_SIZE + if (_values != NULL) + free(_values); + _values = NULL; + _capacity = 0; + #endif +} + +size_t ComposedRecord::values() const +{ + return _count; +} + +const Value& ComposedRecord::value(size_t index) const +{ + if (index >= _count) + return aNullValue; + return *_values[index]; +} + +DataGenerator* ComposedRecord::copy() const +{ + ComposedRecord *copy = new ComposedRecord(true); + for (size_t n = 0; n < _count; n++) + copy->add(*_values[n]); + return copy; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ComposedRecord.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,94 @@ +/* + * ComposedRecord.h + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef COMPOSEDRECORD_H +#define COMPOSEDRECORD_H + +#include "config.h" +#include "DataGenerator.h" +#include "Record.h" +#include "Value.h" + +#ifndef SMARTREST_COMPOSED_INITIAL_CAPACITY +#define SMARTREST_COMPOSED_INITIAL_CAPACITY 10 +#endif +#ifndef SMARTREST_COMPOSED_MEMORY_INCREMENT +#define SMARTREST_COMPOSED_MEMORY_INCREMENT 5 +#endif +//#define SMARTREST_COMPOSED_FIXED_SIZE 25 + +/** + * This value set collects values and serializes them into a SmartRequest. + * + * Example 1 (low memory usage): + * @code + * // this record does not copy added values into the heap because the + * // lifetime of the instance does not exceed the lifetime of its added + * // values. + * ComposedRecord record(false); + * IntegerValue msgId(100); + * CharValue str("Hello World!"); + * FloatValue num(3.1415, 2); + * record.add(msgId).add(str).add(num); + * @encode + * + * Example 2 (short form): + * @code + * // this record needs to copy added values due to the limited + * // lifetime of temporary objects. + * ComposedRecord record(true); + * record.add(IntegerValue(100)).add(CharValue("Hello World!"); + * record.add(FloatValue(3.1415, 2)); + * @encode + */ +class ComposedRecord : public Record +{ +public: + ComposedRecord(bool=false); + ~ComposedRecord(); + + bool add(const Value&); + void clear(); + + size_t values() const; + const Value& value(size_t index) const; + + DataGenerator* copy() const; + +private: + #ifndef SMARTREST_COMPOSED_FIXED_SIZE + const Value **_values; + size_t _capacity; + #else + const Value *_values[SMARTREST_COMPOSED_FIXED_SIZE]; + #endif + size_t _count; + bool _alloc; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DataGenerator.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,69 @@ +/* + * DataGenerator.h + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef DATAGENERATOR_H +#define DATAGENERATOR_H + +#include "config.h" +#include <stddef.h> +#include "AbstractDataSink.h" + +/* + * The DataGenerator class provides a way to stream data to a + * connection.. + */ +class DataGenerator +{ +public: + virtual ~DataGenerator() + { + } + + /** + * Writes the object to the specified destination. + * @param s the destination + * @return the number of bytes written + */ + virtual size_t writeTo(AbstractDataSink&) const = 0; + + /** + * Returns the estimated number of bytes which will be written. + * @return the estimated number of bytes printed + */ + virtual size_t writtenLength() const = 0; + + /** + * Creates a deep copy on the heap. The class type may be different. + * The only thing guaranteed is that the copy behaves exactly + * the same. + * @return cloned object with no memory dependencies + */ + virtual DataGenerator* copy() const = 0; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FloatValue.cpp Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,184 @@ +/* + * FloatValue.cpp + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "FloatValue.h" +#include <math.h> +#include <stdio.h> + +FloatValue::FloatValue(double number, uint8_t digits, bool zflag) +{ + _negative = (number < 0.0); + _zflag = zflag; + if (_negative) + _number = -number; + else + _number = number; + if (digits == SMARTREST_FLOATVALUE_DETECTPREC) + _digits = detectPrecision(_number); + else + _digits = digits; +} + +uint8_t FloatValue::valueType() const +{ + return VALUE_FLOAT; +} + +long FloatValue::integerValue() const +{ + return 0L; +} + +double FloatValue::floatValue() const +{ + return (_negative) ? -_number : _number; +} + +const char * FloatValue::characterValue() const +{ + return 0; +} + +size_t FloatValue::write(AbstractDataSink& sink) const +{ + size_t n = 0; + double number, rounding; + uint8_t i; + unsigned long int_part; + double remainder; + + if (isnan(_number)) + return sink.write("nan"); + + if (_negative) + n += sink.write('-'); + + if (isinf(_number)) { + n += sink.write("inf"); + return n; + } + + number = _number; + rounding = 0.5; + for (i = 0; i < _digits; ++i) + rounding /= 10.0; + number += rounding; + + int_part = (unsigned long)number; + remainder = number - (double)int_part; + + if ((_zflag) || (int_part)) + n += sink.write(int_part); + + if (_digits == 0) + return n; + n += sink.write("."); + + uint8_t digits = _digits; + while (digits-- > 0) { + remainder *= 10.0; + unsigned long l = (unsigned long)remainder; + n += sink.write(l); + remainder -= l; + } + + return n; +} + +size_t FloatValue::length() const +{ + size_t l = 0; + double number, rounding; + unsigned long n; + uint8_t i; + + if (isnan(_number)) + return 3; + + if (_negative) + l++; + + if (isinf(_number)) { + l += 3; + return l; + } + + number = _number; + rounding = 0.5; + for (i = 0; i < _digits; ++i) + rounding /= 10.0; + number += rounding; + + n = (unsigned long)number; + if ((_zflag) || (n)) { + do { + n /= 10; + l++; + } while(n); + } + + if (_digits > 0) + l += 1 + _digits; + + return l; +} + +Value* FloatValue::copy() const +{ + double number; + + number = (_negative) ? -_number : _number; + return new FloatValue(number, _digits, _zflag); +} + +uint8_t FloatValue::detectPrecision(double n) +{ + uint8_t prec = 0, count = 0; + int8_t d; + + if ((isinf(n)) || (isnan(n))) + return 0; + + n -= (long)n; + + while ((prec < 6) && (count < 3)) { + n *= 10; + d = (uint8_t)n; + + if (count == 0) { + if ((d <= 0) || (d >= 9)) + count++; + } else { + count++; + } + prec++; + n -= d; + } + + return --prec; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FloatValue.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,81 @@ +/* + * FloatValue.h + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef FLOATVALUE_H +#define FLOATVALUE_H + +#include "config.h" +#include <stdint.h> +#include "Value.h" + +#define SMARTREST_FLOATVALUE_DETECTPREC 255 + +/** + * A floating-point value. + * + * Example: + * @code + * // decleration // serialized form + * FloatValue val1(3.1415, 2); // 3.14 + * FloatValue val2(3.1234, 0); // 3 + * FloatValue val3(3.95, 0); // 4 + * FloatValue val4(0.55, 1, false); // .5 + * FloatValue val4(0.55, 2, true); // 0.55 + * @encode + */ +class FloatValue : public Value +{ +public: + /** + * Creates a new instance of a floating-point value. + * @param number the floating-point number + * @param digits precision in number of digits + * @param zflag whether to write a zero before the floating point + */ + FloatValue(double, uint8_t=SMARTREST_FLOATVALUE_DETECTPREC, bool=true); + + uint8_t valueType() const; + long integerValue() const; + double floatValue() const; + const char * characterValue() const; + + size_t write(AbstractDataSink&) const; + size_t length() const; + Value* copy() const; + +protected: + uint8_t detectPrecision(double); + +private: + double _number; + bool _negative; + uint8_t _digits; + bool _zflag; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTPResponseFilter.cpp Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,174 @@ +/* + * HTTPResponseFilter.cpp + * + * Created on: Feb 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "HTTPResponseFilter.h" +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <stdio.h> + +const char *cExpectedStatus = "HTTP/1.* "; +const char *cContentLength = "Content-Length: "; + +HTTPResponseFilter::HTTPResponseFilter(AbstractDataSource& source) : _source(source), _state(RESPF_STATE_INIT) +{ + _length = _read = 0; +} + +HTTPResponseFilter::~HTTPResponseFilter() +{ +} + +char HTTPResponseFilter::read() +{ + if (_state != RESPF_STATE_READ_HEADERS) + return 0; + if ((_length > 0) && (_length == _read)) + return 0; + _read++; + return _source.read(); +} + +uint8_t HTTPResponseFilter::status() +{ + if (_state != RESPF_STATE_READ_HEADERS) + return DS_STATUS_ERROR; + if ((_length > 0) && (_length == _read)) + return DS_STATUS_CLOSED; + return _source.status(); +} + +uint16_t HTTPResponseFilter::readStatus() +{ + uint16_t res = 0; + uint8_t state = 0; + char c; + size_t offset = 0; + uint8_t status = DS_STATUS_OK; + + if (_state != RESPF_STATE_INIT) + return 0; + + while ((state < 3) && (((c = _source.read()) > 0) || ((status = _source.status()) == DS_STATUS_OK))) { + switch (state) { + case 0: // read expected status line + if ((cExpectedStatus[offset] != c) && (cExpectedStatus[offset] != '*')) + state = 3; + offset++; + if (offset == strlen(cExpectedStatus)) { + state = 1; + } + break; + case 1: + if (isspace(c)) + state = 2; + if (isdigit(c)) + res = (res * 10) + (c - '0'); + break; + case 2: + if (c == '\n') + state = 3; + break; + } + } + + if ((status != DS_STATUS_OK) || (state != 3)) + return 0; + + _state = RESPF_STATE_READ_STATUS; + return res; +} + +bool HTTPResponseFilter::skipHeaders() +{ + uint16_t res = 0; + uint8_t state = 0; + char c; + size_t offset = 0; + uint8_t status = DS_STATUS_OK; + + if (_state != RESPF_STATE_READ_STATUS) + return false; + + while ((state < 5) && (((c = _source.read()) > 0) || ((status = _source.status()) == DS_STATUS_OK))) { + switch (state) { + case 0: // start of line + if (offset == 0) { + if (cContentLength[0] == c) + state = 1; + if (c == '\r') + state = 4; + } else { + if (c == '\r') + state = 3; + } + offset++; + break; + case 1: + if (c == '\r') + state = 3; + else if (cContentLength[offset] != c) + state = 0; + else if (offset == strlen(cContentLength)-1) + state = 2; + offset++; + break; + case 2: + if (isdigit(c)) + _length = (_length * 10) + (c - '0'); + else if (c == '\r') + state = 3; + else + state = 0; + offset++; + break; + case 3: + if (c == '\n') { + state = 0; + offset = 0; + } + break; + case 4: + if (c == '\n') + state = 5; + break; + } + } + + if ((status != DS_STATUS_OK) || (state != 5)) + return false; + + _state = RESPF_STATE_READ_HEADERS; + return true; +} + +void HTTPResponseFilter::reset() +{ + _state = RESPF_STATE_INIT; + _length = _read = 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTPResponseFilter.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,64 @@ +/* + * HTTPResponseFilter.h + * + * Created on: Feb 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef HTTPRESPONSEFILTER_H +#define HTTPRESPONSEFILTER_H + +#include <stddef.h> +#include "AbstractDataSource.h" + +#define RESPF_STATE_INIT 0 +#define RESPF_STATE_READ_STATUS 1 +#define RESPF_STATE_READ_HEADERS 2 + +/** + * Reads and evaluates a HTTP response. + * The read() and status() methods allow access to the response content + * without HTTP headers. + */ +class HTTPResponseFilter : public AbstractDataSource +{ +public: + HTTPResponseFilter(AbstractDataSource& source); + ~HTTPResponseFilter(); + + char read(); + uint8_t status(); + + uint16_t readStatus(); + bool skipHeaders(); + + void reset(); + +private: + AbstractDataSource& _source; + uint8_t _state; + size_t _length, _read; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IntegerValue.cpp Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,92 @@ +/* + * IntegerValue.cpp + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "IntegerValue.h" + +IntegerValue::IntegerValue(long number) +{ + _negative = (number < 0L); + if (_negative) + _number = -number; + else + _number = number; +} + +uint8_t IntegerValue::valueType() const +{ + return VALUE_INTEGER; +} + +long IntegerValue::integerValue() const +{ + return (_negative) ? -_number : _number; +} + +double IntegerValue::floatValue() const +{ + return 0.0; +} + +const char * IntegerValue::characterValue() const +{ + return 0; +} + +size_t IntegerValue::write(AbstractDataSink& sink) const +{ + size_t n = 0; + if (_negative) + n += sink.write('-'); + n += sink.write(_number); + return n; +} + +size_t IntegerValue::length() const +{ + size_t l = 0; + + if (_negative) + l++; + + unsigned long n = _number; + + do { + n /= 10; + l++; + } while(n); + return l; +} + +Value* IntegerValue::copy() const +{ + long number; + + number = (_negative) ? -_number : _number; + return new IntegerValue(number); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/IntegerValue.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,62 @@ +/* + * IntegerValue.h + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef NUMBERVALUE_H +#define NUMBERVALUE_H + +#include "config.h" +#include "Value.h" + +/** + * Represents an integer value. + * + * Example: + * @code + * IntegerValue val(100); + * @encode + */ +class IntegerValue : public Value +{ +public: + IntegerValue(long); + + uint8_t valueType() const; + long integerValue() const; + double floatValue() const; + const char * characterValue() const; + + size_t write(AbstractDataSink&) const; + size_t length() const; + Value* copy() const; + +private: + unsigned long _number; + bool _negative; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MbedClient.cpp Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,198 @@ +/* + * MbedClient.cpp + * + * Created on: Feb 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "MbedClient.h" +#include <stdlib.h> +#include <string.h> +#include "b64.h" +#include "mbed.h" + +MbedClient::MbedClient(const char* host, uint16_t port, const char* username, const char* password) + : _host(host), _port(port), _username(username), _password(password), _filter(_source), _source(_sock), _sink(_sock), _sock() +{ + _state = MBED_STATE_INIT; +} + +MbedClient::~MbedClient() +{ +} + +uint8_t MbedClient::beginRequest() +{ + if (_state != MBED_STATE_INIT) + return CLIENT_INTERNAL_ERROR; + + if (_sock.connect(_host, _port) < 0) { + stop(); + return CLIENT_CONNECTION_ERROR; + } + + if ((!send("POST /s HTTP/1.0\r\n")) || + (!send("Host: ")) || + (!send(_host)) || + (!send("\r\n"))) + return CLIENT_CONNECTION_ERROR; + + if ((strlen(_username) > 0) && (strlen(_password) > 0)) { + if (!sendBasicAuth()) + return CLIENT_CONNECTION_ERROR; + } + + _state = MBED_STATE_IN_REQUEST; + return CLIENT_OK; +} + +uint8_t MbedClient::sendIdentifier(const char* identifier) +{ + if (_state != MBED_STATE_IN_REQUEST) + return CLIENT_INTERNAL_ERROR; + + if ((identifier != NULL) && (strlen(identifier) != 0)) { + if ((!send("X-Id: ")) || + (!send(identifier)) || + (!send("\r\n"))) + return CLIENT_CONNECTION_ERROR; + } + + _state = MBED_STATE_SENT_ID; + return CLIENT_OK; +} + +uint8_t MbedClient::sendData(DataGenerator& generator) +{ + size_t len; char lenstr[8]; + + if ((_state != MBED_STATE_IN_REQUEST) && (_state != MBED_STATE_SENT_ID)) + return CLIENT_INTERNAL_ERROR; + + len = generator.writtenLength(); + snprintf(lenstr, 8, "%ld", len); + + if ((!send("Content-Length: ")) || + (!send(lenstr)) || + (!send("\r\n\r\n"))) + return CLIENT_CONNECTION_ERROR; + + if (generator.writeTo(_sink) != len) { + stop(); + return CLIENT_CONNECTION_ERROR; + } + + _state = MBED_STATE_SENT_DATA; + return CLIENT_OK; +} + +uint8_t MbedClient::endRequest() +{ + if ((_state != MBED_STATE_IN_REQUEST) && (_state != MBED_STATE_SENT_ID) && (_state != MBED_STATE_SENT_DATA)) + return CLIENT_INTERNAL_ERROR; + + if (_state != MBED_STATE_SENT_DATA) { + // send end of headers + if (!send("\r\n")) + return CLIENT_CONNECTION_ERROR; + } + + if (!_sink.flush()) { + stop(); + return CLIENT_CONNECTION_ERROR; + } + + _state = MBED_STATE_REQ_COMPLETE; + return CLIENT_OK; +} + +uint8_t MbedClient::awaitResponse() +{ + if (_state != MBED_STATE_REQ_COMPLETE) + return CLIENT_INTERNAL_ERROR; + + if ((_filter.readStatus() != 200) || (!_filter.skipHeaders())) { + stop(); + return CLIENT_CONNECTION_ERROR; + } + + _state = MBED_STATE_RECVD_RESPONSE; + return CLIENT_OK; +} + +AbstractDataSource& MbedClient::receiveData() +{ + return _filter; +} + +void MbedClient::stop() +{ + _sock.close(); + _source.reset(); + _sink.reset(); + _filter.reset(); + _state = MBED_STATE_INIT; +} + +bool MbedClient::send(const char *str) +{ + if (_sink.write(str) != strlen(str)) { + stop(); + return false; + } + return true; +} + +bool MbedClient::sendBasicAuth() +{ + size_t ul, pl; unsigned char input[3]; unsigned char output[5]; + int inputOffset = 0; + + if (!send("Authorization: Basic ")) + return false; + + ul = strlen(_username); + pl = strlen(_password); + + for (int i = 0; i < (ul+1+pl); i++) { + if (i < ul) + input[inputOffset++] = _username[i]; + else if (i == ul) + input[inputOffset++] = ':'; + else + input[inputOffset++] = _password[i-(ul+1)]; + + if ((inputOffset == 3) || (i == ul+pl)) { + b64_encode(input, inputOffset, output, 4); + output[4] = '\0'; + if (!send((char*)output)) + return false; + inputOffset = 0; + } + } + + if (!send("\r\n")) + return false; + return true; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MbedClient.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,73 @@ +/* + * MbedClient.h + * + * Created on: Feb 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MBEDCLIENT_H +#define MBEDCLIENT_H + +#include <stdint.h> +#include "AbstractClient.h" +#include "TCPSocketConnection.h" +#include "MbedDataSource.h" +#include "MbedDataSink.h" +#include "HTTPResponseFilter.h" + +#define MBED_STATE_INIT 0 +#define MBED_STATE_IN_REQUEST 1 +#define MBED_STATE_SENT_ID 2 +#define MBED_STATE_SENT_DATA 3 +#define MBED_STATE_REQ_COMPLETE 4 +#define MBED_STATE_RECVD_RESPONSE 5 +#define MBED_STATE_RECV_DATA 6 + +class MbedClient : public AbstractClient { +public: + MbedClient(const char*, uint16_t, const char*, const char*); + ~MbedClient(); + + uint8_t beginRequest(); + uint8_t sendIdentifier(const char*); + uint8_t sendData(DataGenerator& generator); + uint8_t endRequest(); + uint8_t awaitResponse(); + AbstractDataSource& receiveData(); + void stop(); + +protected: + bool send(const char *str); + bool sendBasicAuth(); + +private: + const char *_host, *_username, *_password; + uint16_t _port, _state; + TCPSocketConnection _sock; + MbedDataSource _source; + MbedDataSink _sink; + HTTPResponseFilter _filter; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MbedDataSink.cpp Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,130 @@ +/* + * MbedDataSink.cpp + * + * Created on: Feb 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "MbedDataSink.h" +#include "MbedClient.h" +#include <stdlib.h> +#include <string.h> + +#include "mbed.h" + +MbedDataSink::MbedDataSink(TCPSocketConnection& sock) : _len(0), _sock(sock) +{ +} + +MbedDataSink::~MbedDataSink() +{ +} + +size_t MbedDataSink::write(char c) +{ + while (MBED_SINK_BUFFER_SIZE - _len < 1) { + if (!send()) + return 0; + } + + _buf[_len++] = c; + return 1; +} + +size_t MbedDataSink::write(void *buf, size_t length) +{ + size_t sent = 0, len; + + while (sent < length) { + while (MBED_SINK_BUFFER_SIZE - _len < 1) { + if (!send()) + return 0; + } + + if (MBED_SINK_BUFFER_SIZE - _len >= length-sent) + len = length-sent; + else + len = MBED_SINK_BUFFER_SIZE - _len; + + memcpy(_buf+_len, (char*)buf+sent, len); + _len += len; + sent += len; + } + + return length; +} + +size_t MbedDataSink::write(const char *str) +{ + return write((void*)str, strlen(str)); +} + +size_t MbedDataSink::write(unsigned long number) +{ + char str[24]; + + snprintf(str, 24, "%lu", number); + return write(str); +} + +bool MbedDataSink::flush() +{ + while (_len > 0) { + if (!send()) + return false; + } + + return true; +} + +bool MbedDataSink::send() +{ + int ret; + + if (!_sock.is_connected()) + return false; + + _sock.set_blocking(true); + ret = _sock.send(_buf, _len); + + //TODO: fix bug in u-blox so no longer wait is needed + wait(0.5); + + if (ret < 0){ + puts("Send failed."); + return false; + } + + // move rest of buffer + if ((ret > 0) && (ret < _len)) + memmove(_buf, _buf+ret, _len-ret); + + _len -= ret; + return true; +} + +void MbedDataSink::reset() +{ + _len = 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MbedDataSink.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,65 @@ +/* + * MbedDataSink.h + * + * Created on: Feb 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MBEDDATASINK_H +#define MBEDDATASINK_H + +#include <stddef.h> +#include "AbstractDataSink.h" +#include "TCPSocketConnection.h" + +#define MBED_SINK_BUFFER_SIZE 60 + +class MbedClient; + +class MbedDataSink : public AbstractDataSink +{ +public: + MbedDataSink(TCPSocketConnection& sock); + ~MbedDataSink(); + + size_t write(char c); + size_t write(void *buf, size_t length); + size_t write(const char *str); + size_t write(unsigned long number); + + +protected: + bool flush(); + bool send(); + void reset(); + +private: + TCPSocketConnection& _sock; + char _buf[MBED_SINK_BUFFER_SIZE]; + size_t _len; + +friend class MbedClient; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MbedDataSource.cpp Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,88 @@ +/* + * MbedDataSource.cpp + * + * Created on: Feb 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "MbedDataSource.h" +#include "stdio.h" + +MbedDataSource::MbedDataSource(TCPSocketConnection& sock) : _sock(sock) +{ + _offset = _len = 0; + _timeout = false; +} + +MbedDataSource::~MbedDataSource() +{ +} + +char MbedDataSource::read() +{ + while (_offset == _len) { + if (!receive()) + return 0; + } + + return _buf[_offset++]; +} + +uint8_t MbedDataSource::status() +{ + if (!_sock.is_connected()) + return DS_STATUS_CLOSED; + + if (_timeout) + return DS_STATUS_TIMEOUT; + + return DS_STATUS_OK; +} + +bool MbedDataSource::receive() +{ + int ret; + + if (status() != DS_STATUS_OK) + return false; + + _sock.set_blocking(true, 60000); + ret = _sock.receive(_buf, MBED_SOURCE_BUFFER_SIZE); + + if (ret < 0) { + _timeout = true; + return false; + } + + _len = (size_t)ret; + _offset = 0; + + return true; +} + +void MbedDataSource::reset() +{ + _len = _offset = 0; + _timeout = false; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MbedDataSource.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,62 @@ +/* + * MbedDataSource.h + * + * Created on: Feb 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MBEDDATASOURCE_H +#define MBEDDATASOURCE_H + +#include <stddef.h> +#include "AbstractDataSource.h" +#include "TCPSocketConnection.h" + +#define MBED_SOURCE_BUFFER_SIZE 60 + +class MbedClient; + +class MbedDataSource : public AbstractDataSource +{ +public: + MbedDataSource(TCPSocketConnection& sock); + ~MbedDataSource(); + + char read(); + uint8_t status(); + +protected: + bool receive(); + void reset(); + +private: + TCPSocketConnection& _sock; + char _buf[MBED_SOURCE_BUFFER_SIZE]; + size_t _len, _offset; + bool _timeout; + +friend class MbedClient; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MbedSmartRest.cpp Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,33 @@ +/* + * MbedSmartRest.cpp + * + * Created on: Feb 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + #include "MbedSmartRest.h" + +MbedSmartRest::MbedSmartRest(const char* host, uint16_t port, const char* username, const char* password, const char* identifier) : SmartRest(_client, identifier), _client(host, port, username, password) +{ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MbedSmartRest.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,44 @@ +/* + * MbedSmartRest.h + * + * Created on: Feb 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MBEDSMARTREST_H +#define MBEDSMARTREST_H + +#include "SmartRest.h" +#include "MbedClient.h" + +class MbedSmartRest : public SmartRest +{ +public: + MbedSmartRest(const char*, uint16_t, const char*, const char*, const char*); + +private: + MbedClient _client; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NullValue.cpp Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,71 @@ +/* + * NullValue.cpp + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "NullValue.h" + +NullValue aNullValue; + +NullValue::NullValue() +{ +} + +uint8_t NullValue::valueType() const +{ + return VALUE_NULL; +} + +long NullValue::integerValue() const +{ + return 0; +} + +double NullValue::floatValue() const +{ + return 0.0; +} + +char * NullValue::characterValue() const +{ + return NULL; +} + +size_t NullValue::write(AbstractDataSink&) const +{ + return 0; +} + +size_t NullValue::length() const +{ + return 0; +} + +Value* NullValue::copy() const +{ + return new NullValue(); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NullValue.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,63 @@ +/* + * NullValue.h + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef NULLVALUE_H +#define NULLVALUE_H + +#include "config.h" +#include "Value.h" + +/** + * Represents a null value. + * + * Example: + * @code + * // You may use: + * NullValue nullv; + * // You should use whenever possible: + * aNullValue; + * @encode + */ +class NullValue : public Value +{ +public: + NullValue(); + + uint8_t valueType() const; + long integerValue() const; + double floatValue() const; + char * characterValue() const; + + size_t write(AbstractDataSink&) const; + size_t length() const; + Value* copy() const; +}; + +extern NullValue aNullValue; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ParsedRecord.cpp Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,115 @@ +/* + * ParsedRecord.cpp + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "ParsedRecord.h" +#include "ComposedRecord.h" +#include "ParsedValue.h" +#include "NullValue.h" +#include <stdlib.h> +#include <string.h> + +ParsedRecord::ParsedRecord() +{ + _count = 0; +#ifdef SMARTREST_PARSED_DYNAMIC_ALLOC + _values = NULL; +#endif +} + +ParsedRecord::~ParsedRecord() +{ + clear(); + +#ifdef SMARTREST_PARSED_DYNAMIC_ALLOC + if (_values != NULL) + free(_values); +#endif +} + +size_t ParsedRecord::values() const +{ + return _count; +} + +const Value& ParsedRecord::value(size_t index) const +{ + if (index >= _count) + return aNullValue; + return *_values[index]; +} + +DataGenerator* ParsedRecord::copy() const +{ + ComposedRecord *copy = new ComposedRecord(true); + for (size_t n = 0; n < _count; n++) + copy->add(*_values[n]); + return copy; +} + +const char * ParsedRecord::rawValue(size_t index) const +{ + if (index >= _count) + return NULL; + + const char *ptr = _buffer; + for (size_t n = 0; n < index; n++) { + ptr += strlen(ptr) + 1; + } + + return ptr; +} + +void ParsedRecord::set(const char *buffer, size_t count) +{ + clear(); + +#ifdef SMARTREST_PARSED_DYNAMIC_ALLOC + const Value **values = (const Value**)realloc(_values, count*sizeof(Value*)); + if (values == NULL) + return; + _values = values; +#else + if (count > SMARTREST_PARSED_FIXED_SIZE) + count = SMARTREST_PARSED_FIXED_SIZE; +#endif + + const char *ptr = buffer; + for (size_t n = 0; n < count; n++) { + _values[n] = new ParsedValue(ptr, false); + ptr += strlen(ptr) + 1; + } + + _count = count; + _buffer = buffer; +} + +void ParsedRecord::clear() +{ + for (size_t n = 0; n < _count; n++) + delete _values[n]; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ParsedRecord.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,110 @@ +/* + * ParsedRecord.h + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef PARSEDRECORD_H +#define PARSEDRECORD_H + +#include "config.h" +#include "DataGenerator.h" +#include "Record.h" +#include "Value.h" + +#ifndef SMARTREST_PARSED_DYNAMIC_ALLOC +#ifndef SMARTREST_PARSED_FIXED_SIZE +#define SMARTREST_PARSED_FIXED_SIZE 24 +#endif +#endif + +class Parser; + +/** + * This class provides accessors for values in a parsed record. + * + * Example: + * @code + * // given a concrete SmartRest client instance + * SmartRest client; + + * ParsedRecord record; + * if (client.receive(record) == SMARTREST_SUCCESS) { + * for (size_ i = 0; i < record.values(); i++) { + * const Value& val = record.value(i); + * switch (val.valueType()) { + * case VALUE_NULL: + * printf("Null value.\n"); + * break; + * case VALUE_CHARACTER: + * printf("Character value: %s\n", val.characterValue()); + * break; + * case VALUE_INTEGER: + * printf("Integer value: %d\n", val.integerValue()); + * break; + * case VALUE_FLOAT: + * printf("Float value: %lf\n", val.floatValue()); + * break; + * } + * } + * } + * @encode + */ +class ParsedRecord : public Record +{ +public: + ParsedRecord(); + ~ParsedRecord(); + + size_t values() const; + const Value& value(size_t index) const; + + DataGenerator* copy() const; + + /** + * Returns the raw value string by index + * @param index the index of the value + * @return a pointer to the raw value + */ + const char * rawValue(size_t index) const; + +protected: + void set(const char*, size_t); + void clear(); + +private: +#ifdef SMARTREST_PARSED_DYNAMIC_ALLOC + const Value **_values; +#else + const Value *_values[SMARTREST_PARSED_FIXED_SIZE]; +#endif + const char *_buffer; + size_t _count; + +friend class Parser; +}; + + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ParsedValue.cpp Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,160 @@ +/* + * ParsedValue.cpp + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "ParsedValue.h" +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <math.h> +#include "NullValue.h" +#include "IntegerValue.h" +#include "FloatValue.h" +#include "CharValue.h" + +ParsedValue::ParsedValue(const char *str, bool copy) : _value(str, copy), _float(0.0), _digits(0), _zflag(false), _integer(0l) +{ + if (_value.valueType() != VALUE_NULL) { + _type = VALUE_CHARACTER; + extractValue(); + } else { + _type = VALUE_NULL; + } +} + +uint8_t ParsedValue::valueType() const +{ + return _type; +} + +long ParsedValue::integerValue() const +{ + return _integer; +} + +double ParsedValue::floatValue() const +{ + return _float; +} + +const char * ParsedValue::characterValue() const +{ + if (_type != VALUE_CHARACTER) + return NULL; + return _value.characterValue(); +} + +size_t ParsedValue::write(AbstractDataSink& sink) const +{ + return _value.write(sink); +} + +size_t ParsedValue::length() const +{ + return _value.length(); +} + +Value* ParsedValue::copy() const +{ + if (_type == VALUE_NULL) + return new NullValue(); + if (_type == VALUE_INTEGER) + return new IntegerValue(_integer); + if (_type == VALUE_FLOAT) + return new FloatValue(_float, _digits, _zflag); + return new CharValue(_value.characterValue(), true); +} + +void ParsedValue::extractValue() +{ + const char *str; char *ptr, c; + bool floating = false, zflag = false, negative = false; + uint8_t digits = 0; + + str = _value.characterValue(); + + if (isspace(*str)) + return; + + // easy check for nan + if (strcmp(str, "nan") == 0) { + _float = NAN; + _type = VALUE_FLOAT; + return; + } + + if (*str == '-') { + negative = true; + str++; + } + + if (strcmp(str, "inf") == 0) { + _float = (negative) ? -INFINITY : INFINITY; + _type = VALUE_FLOAT; + return; + } + + for (ptr = (char*)str; (c = *ptr) != 0; ptr++) { + if (floating) { + if (!isdigit(c)) + return; + digits++; + } else { + if (c == '.') { + if (*(ptr+1) == '\0') + return; + floating = true; + } else if (isdigit(c)) { + _zflag = true; + } else { + return; + } + } + } + + if (floating) { + errno = 0; + if ((((_float = strtod(str, &ptr)) != 0.0) || (errno == 0)) && + (*ptr == '\0')) { + if (negative) + _float = -_float; + _zflag = zflag; + _digits = digits; + _type = VALUE_FLOAT; + } + } else { + errno = 0; + if ((((_integer = strtol(str, &ptr, 10)) != 0) || (errno == 0)) && + (*ptr == '\0')) { + if (negative) + _integer = -_integer; + _type = VALUE_INTEGER; + return; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ParsedValue.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,92 @@ +/* + * ParsedValue.h + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef PARSEDVALUE_H +#define PARSEDVALUE_H + +#include "config.h" +#include "Value.h" +#include "CharValue.h" + +#ifndef SMARTREST_PARSED_FIXED_SIZE +#define SMARTREST_PARSED_FIXED_SIZE 16 +#endif + +/** + * Provides access to a parsed value by implementing the value interface. + * + * Example: + * @code + * // given a filled parsed record + * ParsedRecord record; + * + * // get first value + * const Value& val = record.value(0); + * switch (val.valueType()) { + * case VALUE_NULL: + * printf("Null value.\n"); + * break; + * case VALUE_CHARACTER: + * printf("Character value: %s\n", val.characterValue()); + * break; + * case VALUE_INTEGER: + * printf("Integer value: %d\n", val.integerValue()); + * break; + * case VALUE_FLOAT: + * printf("Float value: %lf\n", val.floatValue()); + * break; + * } + * @encode + */ +class ParsedValue : public Value +{ +public: + ParsedValue(const char*, bool=false); + + uint8_t valueType() const; + long integerValue() const; + double floatValue() const; + const char * characterValue() const; + + size_t write(AbstractDataSink&) const; + size_t length() const; + Value* copy() const; + +private: + void extractValue(); + +private: + CharValue _value; + uint8_t _type; + double _float; + uint8_t _digits; + bool _zflag; + long _integer; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Parser.cpp Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,180 @@ +/* + * Parser.cpp + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "Parser.h" + +#define STATE_BLANK 0 +#define STATE_STRUCTURE 1 +#define STATE_VALUE 2 +#define STATE_INQUOTES 3 +#define STATE_AFTERQUOTE 4 +#define STATE_COMPLETE 5 +#define STATE_ERROR 6 + +Parser::Parser() +{ + reset(); +} + +uint8_t Parser::readFrom(AbstractDataSource& source, ParsedRecord& record) +{ + uint8_t status; char read; + + reset(); + record.set(NULL, 0); + + while ((_state < STATE_COMPLETE) && + (((read = source.read()) > 0 ) || + ((status = source.status()) == DS_STATUS_OK))) + parse(read); + + if (_state == STATE_COMPLETE) + record.set(_buffer, _count); + + if (_state == STATE_COMPLETE) + return PARSER_SUCCESS; + else if (_state == STATE_BLANK) + if (status == DS_STATUS_CLOSED) + return PARSER_END_OF_RESPONSE; + else + return PARSER_TIMEOUT_ERROR; + else + if (status == DS_STATUS_TIMEOUT) + return PARSER_TIMEOUT_ERROR; + else + return PARSER_PARSE_ERROR; +} + +void Parser::parse(char c) +{ + if (_ptr-_buffer >= SMARTREST_PARSER_BUFFER_SIZE) { + _state = STATE_ERROR; + return; + } + + switch (_state) { + case STATE_BLANK: + _state = STATE_STRUCTURE; + case STATE_STRUCTURE: + switch (c) { + case ' ': + case '\t': + case '\r': + break; + case '"': + _state = STATE_INQUOTES; + break; + case ',': + close(); + break; + case '\0': + case '\n': + if ((_count == 0) && (_length == 0)) { + _state = STATE_BLANK; + } else { + close(); + _state = STATE_COMPLETE; + } + break; + default: + if (_length > 0) { + _state = STATE_ERROR; + } else { + _state = STATE_VALUE; + parse(c); + } + break; + } + break; + case STATE_VALUE: + switch (c) { + case ',': + case '\n': + _state = STATE_STRUCTURE; + parse(c); + break; + case '"': + _state = STATE_ERROR; + break; + default: + if ((c == ' ') || (c == '\t') || (c == '\r')) + _trailing++; + else + _trailing = 0; + append(c); + break; + } + break; + case STATE_INQUOTES: + switch (c) { + case '"': + _state = STATE_AFTERQUOTE; + break; + default: + append(c); + break; + } + break; + case STATE_AFTERQUOTE: + switch (c) { + case '"': + append(c); + _state = STATE_INQUOTES; + break; + default: + _state = STATE_STRUCTURE; + parse(c); + break; + } + break; + } +} + +void Parser::append(char c) +{ + *_ptr++ = c; + _length++; +} + +void Parser::close() +{ + _ptr -= _trailing; + *_ptr++ = 0; + _trailing = 0; + _length = 0; + _count++; +} + +void Parser::reset() +{ + _state = STATE_BLANK; + _ptr = _buffer; + _count = 0; + _trailing = 0; + _length = 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Parser.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,117 @@ +/* + * Parser.h + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @file Parser.h + * A CSV parser utilizing an AbstractDataSource instance for reading from + * a connection. + */ + +#ifndef PARSER_H +#define PARSER_H + +#include "config.h" +#include <stddef.h> +#include <stdint.h> +#include "ParsedRecord.h" +#include "AbstractDataSource.h" + +#ifndef SMARTREST_PARSER_BUFFER_SIZE +#define SMARTREST_PARSER_BUFFER_SIZE 81 +#endif + +/** Return value indicating that no error occurred. */ +#define PARSER_SUCCESS 0 +/** Return value indicating that a transmission timeout occurred during + * the transmission of a record. */ +#define PARSER_TIMEOUT_ERROR 1 +/** Return value indicating the end of response. */ +#define PARSER_END_OF_RESPONSE 2 +/** Return value indicating a parse error. */ +#define PARSER_PARSE_ERROR 3 + +/* + * A record parser reading from a data source. + * + * Example: + * @code + * // given a concrete data sorce + * AbstractDataSource source; + * + * Parser parser; + * ParsedRecord record; + * uint8_t ret; + * + * while ((ret = parser.readFrom(source, record)) == PARSER_SUCCESS) { + * // read record + * } + + * // error handling + * switch (ret) { + * case PARSER_END_OF_RESPONSE: + * // no error; end of response + * break; + * case PARSER_TIMEOUT_ERROR: + * // timeout error + * break; + * default: + * // parse error + * break; + * } + * @encode + */ +class Parser +{ +public: + /* + * Creates a new Parser instance. + */ + Parser(); + + /* + * Parses a row from a stream. + * @param source the source to read from + * @param row the object written to + * @return a non-zero value if and only if an error occured. + */ + uint8_t readFrom(AbstractDataSource&,ParsedRecord&); + +private: + void parse(char); + void append(char); + void close(); + void reset(); + +private: + char _buffer[SMARTREST_PARSER_BUFFER_SIZE]; + uint8_t _state; + char *_ptr; + size_t _count, _length, _trailing; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Record.cpp Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,59 @@ +/* + * Record.cpp + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "Record.h" + +size_t Record::writeTo(AbstractDataSink& sink) const +{ + size_t written = 0; + for (size_t n = values(), i = 0; i < n; i++) { + written += value(i).write(sink); + if (i < n-1) + written += sink.write(','); + } + written += sink.write('\r'); + written += sink.write('\n'); + return written; +} + +size_t Record::writtenLength() const +{ + size_t written = 2; + for (size_t n = values(), i = 0; i < n; i++) { + written += value(i).length(); + if (i < n-1) + written++; + } + return written; +} + +Record::operator bool() const +{ + return values() > 0; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Record.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,63 @@ +/* + * Record.h + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef RECORD_H +#define RECORD_H + +#include "config.h" +#include "DataGenerator.h" +#include "Value.h" + +/** + * A record which can be read and serialized. + */ +class Record : public DataGenerator +{ +public: + virtual ~Record() { }; + + /** + * Returns the number of values in this record. + * @return number of values in this record + */ + virtual size_t values() const = 0; + + /** + * Returns the value object by index + * @param index the index of the value + * @return a copy of a value object + */ + virtual const Value& value(size_t index) const = 0; + + size_t writeTo(AbstractDataSink&) const; + size_t writtenLength() const; + + operator bool() const; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SmartRest.cpp Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,164 @@ +/* + * SmartRest.cpp + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "SmartRest.h" +#include <stdlib.h> +#include <string.h> + +SmartRest::SmartRest(AbstractClient& client, const char *identifier) : _client(client), _identifier(identifier) +{ + _source = NULL; + _mogid[0] = 0; +} + +int8_t SmartRest::send(DataGenerator& generator) +{ + uint8_t res; + + res = beginRequest(); + if (res != SMARTREST_SUCCESS) + return res; + + _client.sendData(generator); + return awaitResponse(); +} + +int8_t SmartRest::receive(ParsedRecord& record) +{ + uint8_t res; + + if (_source == NULL) + return SMARTREST_INTERNAL_ERROR; + + res = _parser.readFrom(*_source, record); + + switch (res) { + case PARSER_SUCCESS: + return SMARTREST_SUCCESS; + case PARSER_END_OF_RESPONSE: + return SMARTREST_END_OF_RESPONSE; + case PARSER_TIMEOUT_ERROR: + return SMARTREST_TIMEOUT_ERROR; + } + return SMARTREST_INTERNAL_ERROR; +} + +int8_t SmartRest::bootstrap(DataGenerator& generator) +{ + ParsedRecord record; + int8_t ret; + + ret = beginRequest(); + if (ret != SMARTREST_SUCCESS) + return ret; + ret = awaitResponse(); + if (ret != SMARTREST_SUCCESS) + return ret; + ret = receive(record); + if (ret != SMARTREST_SUCCESS) + return ret; + if (!record) { + return SMARTREST_INTERNAL_ERROR; + } + stop(); + + if (setMoGid(record)) + return SMARTREST_SUCCESS; + + if (record.value(0).integerValue() != 40) + return SMARTREST_INTERNAL_ERROR; + + ret = send(generator); + if (ret != SMARTREST_SUCCESS) + return ret; + ret = receive(record); + if (ret != SMARTREST_SUCCESS) + return ret; + stop(); + + if (!setMoGid(record)) + return SMARTREST_INTERNAL_ERROR; + + return SMARTREST_SUCCESS; +} + +void SmartRest::stop() +{ + _source = NULL; + _client.stop(); +} + +uint8_t SmartRest::beginRequest() +{ + int res; + + res = _client.beginRequest(); + if (res == CLIENT_CONNECTION_ERROR) { + return SMARTREST_CONNECTION_FAILED; + } else if (res != CLIENT_OK) { + return SMARTREST_INTERNAL_ERROR; + } + if (strlen(_mogid)) { + if (_client.sendIdentifier(_mogid) != CLIENT_OK) + return SMARTREST_INTERNAL_ERROR; + } else { + if (_client.sendIdentifier(_identifier) != CLIENT_OK) + return SMARTREST_INTERNAL_ERROR; + } + return SMARTREST_SUCCESS; +} + +uint8_t SmartRest::awaitResponse() +{ + if ((_client.endRequest() != CLIENT_OK) || + (_client.awaitResponse() != CLIENT_OK)) + return SMARTREST_INTERNAL_ERROR; + _source = &_client.receiveData(); + return SMARTREST_SUCCESS; +} + +bool SmartRest::setMoGid(ParsedRecord& record) +{ + const char *mogid; + + *_mogid = 0; + if ((record.values() < 2) || (record.value(0).integerValue() != 20)) + return false; + + if ((record.value(1).valueType() != VALUE_INTEGER) || + (record.value(1).integerValue() <= 0)) + return false; + + mogid = record.rawValue(1); + if (strlen(mogid)+1 > sizeof(_mogid)) + return false; + + strcpy(_mogid, mogid); + + return true; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SmartRest.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,150 @@ +/* + * SmartRest.h + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @file SmartRest.h + * The main SmartRest facade class. This class is abstract, because the + * actual implementation has to supply a client. + */ + +#ifndef SMARTREST_H +#define SMARTREST_H + +#include "config.h" +#include <stddef.h> +#include <stdint.h> +#include "AbstractClient.h" +#include "ParsedRecord.h" +#include "Parser.h" + +/** Return value indicating that no error occurred. */ +#define SMARTREST_SUCCESS 0 +/** Return value indicating that the connection has been closed during + * data transmission. */ +#define SMARTREST_CONNECTION_FAILED 1 +/** Return value indicating an internal state error. */ +#define SMARTREST_INTERNAL_ERROR 2 +/** Return value indicating a transmission timeout. */ +#define SMARTREST_TIMEOUT_ERROR 3 +/** Return value indicating an end of response indicated by the + * Content-Length header. */ +#define SMARTREST_END_OF_RESPONSE 4 +/** Return value indicating that the connection has been closed. */ +#define SMARTREST_CONNECTION_CLOSED 5 + +/** + * SmartRest client implementation. + * This class provides methods to send a request and receive a response + * from the server. + * + * Example: + * @code + * // given a concrete SmartRest implementation and a template + * SmartRest client; + * StaticData template; + * + * // bootstrap + * if (client.bootstrap(template) != SMARTREST_SUCCESS) { + * // error handling + * return; + * } + * + * if (client.send(StaticData("100,Hello")) != SMARTREST_SUCCESS) { + * // error handling + * } + * + * uint8_t ret; + * while ((ret = client.receive(record)) == SMARTREST_SUCCESS) { + * // work with data + * } + * + * // error handling + * + * // call after every request. + * client.stop(); + * @encode + */ +class SmartRest +{ +protected: + /** + * Creates a new GenericSmartRest object. + * @param client the abstract client to use + * @param identifier the device identifier + */ + SmartRest(AbstractClient&, const char*); + +public: + virtual ~SmartRest() { }; + + /** + * Sends a smart request. + * @param generator the generator which will generate the data to be + * sent. + * @return a non-zero value if and only if an error occured + */ + int8_t send(DataGenerator&); + + /** + * Tries to receive a parsed response row. + * When the function succeeds, but the row pointer is NULL, there are + * no more rows to be read. + * @param record an instance to where the parsed row is written + * @return a non-zero value if and only if an error occured + */ + int8_t receive(ParsedRecord&); + + /* + * Initiates the SmartRest bootstrap process. + * When successful, the template identifier will be replaced by the + * global managed object ID in future requests. + * @param generator the generator which will generate the data to be + * sent as a template. + * @return a non-zero value if and only if an error occured + */ + int8_t bootstrap(DataGenerator&); + + /* + * Closes the connection. + */ + void stop(); + +protected: + uint8_t beginRequest(); + uint8_t awaitResponse(); + bool setMoGid(ParsedRecord&); + +private: + AbstractClient& _client; + AbstractDataSource *_source; + Parser _parser; + const char *_identifier; + char _mogid[8 * sizeof(long) + 1]; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/StaticData.cpp Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,78 @@ +/* + * StaticData.cpp + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "StaticData.h" +#include <stdlib.h> +#include <string.h> + +StaticData::StaticData(void* buffer, size_t length, bool copy) +{ + _alloc = copy; + _len = length; + if (copy) { + _buf = malloc(length); + memcpy(_buf, buffer, length); + } else { + _buf = buffer; + } +} + +StaticData::StaticData(const char* string, bool copy) +{ + _alloc = copy; + if (copy) { + _len = strlen(string)*sizeof(char); + _buf = malloc(_len); + memcpy(_buf, string, _len); + } else { + _buf = (void*)string; + _len = strlen(string)*sizeof(char); + } +} + +StaticData::~StaticData() +{ + if (_alloc) + free(_buf); +} + +size_t StaticData::writeTo(AbstractDataSink& sink) const +{ + return sink.write((void*)_buf, _len*sizeof(char)); +} + +size_t StaticData::writtenLength() const +{ + return _len; +} + +DataGenerator* StaticData::copy() const +{ + return new StaticData(_buf, _len, true); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/StaticData.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,64 @@ +/* + * StaticData.h + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef STATICDATA_H +#define STATICDATA_H + +#include "config.h" +#include <stddef.h> +#include "DataGenerator.h" + +/* + * A static data store mechanism streaming data to a sink. + * + * Example: + * @code + * // given a concrete data sink + * AbstractDataSink sink; + + * StaticData data("Hello World!"); + * assert(data.writtenLength() == data.writeTo(sink)); + * @encode + */ +class StaticData : public DataGenerator +{ +public: + StaticData(void*, size_t, bool=false); + StaticData(const char*, bool=false); + ~StaticData(); + size_t writeTo(AbstractDataSink&) const; + size_t writtenLength() const; + DataGenerator* copy() const; + +private: + void *_buf; + size_t _len; + bool _alloc; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Value.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,107 @@ +/* + * Value.h + * + * Created on: Nov 1, 2013 + * * Authors: Vincent Wochnik <v.wochnik@gmail.com> + * + * Copyright (c) 2013 Cumulocity GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @file Value.h + * Represents a generic data value. + */ + +#ifndef VALUE_H +#define VALUE_H + +#include "config.h" +#include <stddef.h> +#include <stdint.h> +#include "AbstractDataSink.h" + +/** Return value indicating a null value. */ +#define VALUE_NULL 0 +/** Return value indicating an integer value. */ +#define VALUE_INTEGER 1 +/** Return value indicating a floating-point number. */ +#define VALUE_FLOAT 2 +/** Return value indicating a character string. */ +#define VALUE_CHARACTER 3 + +/** + * A generic value offering means to obtain the value type and contents + * as well as writing the value to a sink. + */ +class Value +{ +public: + virtual ~Value() { }; + + /** + * Returns the value type which can be VALUE_NULL, VALUE_INTEGER, + * VALUE_FLOAT or VALUE_CHARACTER. + * @return the value type + */ + virtual uint8_t valueType() const = 0; + + /** + * Returns the integer value if an integer type, otherwise zero. + * @return integer value + */ + virtual long integerValue() const = 0; + + /** + * Returns the float value if a float type, otherwise zero. + * @return float value + */ + virtual double floatValue() const = 0; + + /** + * Returns the character value if a character type, otherwise zero. + * @return character value + */ + virtual const char * characterValue() const = 0; + + /** + * Writes the value to a sink. + * If necessary, quotes and escape characters may be added. + * @param sink the sink to write the value to + * @return the number of bytes written + */ + virtual size_t write(AbstractDataSink&) const = 0; + + /** + * Returns the number of bytes required to write this value to a sink. + * @return number of bytes required to write this value + */ + virtual size_t length() const = 0; + + /** + * Copies this value to the heap. Referenced contents must also be + * copied. + * @return a new value instance allocated on the heap + */ + virtual Value* copy() const = 0; +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/b64.cpp Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,70 @@ +// Simple Base64 code +// (c) Copyright 2010 MCQN Ltd. +// Released under Apache License, version 2.0 + +#include "b64.h" + +/* Simple test program +#include <stdio.h> +void main() +{ + char* in = "amcewen"; + char out[22]; + + b64_encode(in, 15, out, 22); + out[21] = '\0'; + + printf(out); +} +*/ + +int b64_encode(const unsigned char* aInput, int aInputLen, unsigned char* aOutput, int aOutputLen) +{ + // Work out if we've got enough space to encode the input + // Every 6 bits of input becomes a byte of output + if (aOutputLen < (aInputLen*8)/6) + { + // FIXME Should we return an error here, or just the length + return (aInputLen*8)/6; + } + + // If we get here we've got enough space to do the encoding + + const char* b64_dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + if (aInputLen == 3) + { + aOutput[0] = b64_dictionary[aInput[0] >> 2]; + aOutput[1] = b64_dictionary[(aInput[0] & 0x3)<<4|(aInput[1]>>4)]; + aOutput[2] = b64_dictionary[(aInput[1]&0x0F)<<2|(aInput[2]>>6)]; + aOutput[3] = b64_dictionary[aInput[2]&0x3F]; + } + else if (aInputLen == 2) + { + aOutput[0] = b64_dictionary[aInput[0] >> 2]; + aOutput[1] = b64_dictionary[(aInput[0] & 0x3)<<4|(aInput[1]>>4)]; + aOutput[2] = b64_dictionary[(aInput[1]&0x0F)<<2]; + aOutput[3] = '='; + } + else if (aInputLen == 1) + { + aOutput[0] = b64_dictionary[aInput[0] >> 2]; + aOutput[1] = b64_dictionary[(aInput[0] & 0x3)<<4]; + aOutput[2] = '='; + aOutput[3] = '='; + } + else + { + // Break the input into 3-byte chunks and process each of them + int i; + for (i = 0; i < aInputLen/3; i++) + { + b64_encode(&aInput[i*3], 3, &aOutput[i*4], 4); + } + if (aInputLen % 3 > 0) + { + // It doesn't fit neatly into a 3-byte chunk, so process what's left + b64_encode(&aInput[i*3], aInputLen % 3, &aOutput[i*4], aOutputLen - (i*4)); + } + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/b64.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,6 @@ +#ifndef b64_h +#define b64_h + +int b64_encode(const unsigned char* aInput, int aInputLen, unsigned char* aOutput, int aOutputLen); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/config.h Thu Jul 03 20:38:04 2014 +0200 @@ -0,0 +1,33 @@ +#ifndef _SMARTREST_CONFIG_H +#define _SMARTREST_CONFIG_H 1 + +/* Define the fixed array size of the Aggregator module. This disables dynamic + memory management. */ +#define SMARTREST_AGGREGATOR_FIXED_SIZE 100 + +/* Define the initial capacity of the Aggregator module. */ +//#define SMARTREST_AGGREGATOR_INITIAL_CAPACITY 50 + +/* Define the memory increment of the Aggregator module. */ +//#define SMARTREST_AGGREGATOR_MEMORY_INCREMENT 25 + +/* Define the fixed array size of a ComposedRecord instance. This disables + dynamic memory management. */ +#define SMARTREST_COMPOSED_FIXED_SIZE 10 + +/* Define the initial capacity of a ComposedRecord instance. */ +//#define SMARTREST_COMPOSED_INITIAL_CAPACITY 10 + +/* Define the memory increment of a ComposedRecord instance. */ +//#define SMARTREST_COMPOSED_MEMORY_INCREMENT 5 + +/* Define, whether a ParsedRecord instance shall use dynamic allocation. */ +//#define SMARTREST_PARSED_DYNAMIC_ALLOC 1 + +/* Define the fixed array size of a ParsedRecord instance. */ +#define SMARTREST_PARSED_FIXED_SIZE 10 + +/* Define the buffer size of the Parser module. */ +#define SMARTREST_PARSER_BUFFER_SIZE 81 + +#endif