From 6bc6230eb6a44c20a27d735cab7d03fe6423ff19 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Thu, 27 Apr 2017 04:53:05 -0500 Subject: [PATCH] Add MetalClawWriter --- src/ox/CMakeLists.txt | 1 + src/ox/mc/CMakeLists.txt | 31 +++++++++ src/ox/mc/read.cpp | 15 ++++ src/ox/mc/read.hpp | 15 ++++ src/ox/mc/test/CMakeLists.txt | 8 +++ src/ox/mc/test/tests.cpp | 11 +++ src/ox/mc/write.cpp | 93 +++++++++++++++++++++++++ src/ox/mc/write.hpp | 127 ++++++++++++++++++++++++++++++++++ src/ox/std/byteswap.hpp | 63 +++++++++++++++++ 9 files changed, 364 insertions(+) create mode 100644 src/ox/mc/CMakeLists.txt create mode 100644 src/ox/mc/read.cpp create mode 100644 src/ox/mc/read.hpp create mode 100644 src/ox/mc/test/CMakeLists.txt create mode 100644 src/ox/mc/test/tests.cpp create mode 100644 src/ox/mc/write.cpp create mode 100644 src/ox/mc/write.hpp diff --git a/src/ox/CMakeLists.txt b/src/ox/CMakeLists.txt index e77392db5..a3968a6fc 100644 --- a/src/ox/CMakeLists.txt +++ b/src/ox/CMakeLists.txt @@ -4,4 +4,5 @@ if(OX_USE_STDLIB STREQUAL "ON") add_subdirectory(clargs) endif(OX_USE_STDLIB STREQUAL "ON") add_subdirectory(fs) +add_subdirectory(mc) add_subdirectory(std) diff --git a/src/ox/mc/CMakeLists.txt b/src/ox/mc/CMakeLists.txt new file mode 100644 index 000000000..99c58798b --- /dev/null +++ b/src/ox/mc/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 2.8) + +add_library( + OxMetalClaw + read.cpp + write.cpp +) + +set_property( + TARGET + OxMetalClaw + PROPERTY + POSITION_INDEPENDENT_CODE ON +) + +install( + FILES + read.hpp + write.hpp + DESTINATION + include/ox/mc +) + +install(TARGETS OxMetalClaw + LIBRARY DESTINATION lib/ox + ARCHIVE DESTINATION lib/ox +) + +if(OX_RUN_TESTS STREQUAL "ON") + add_subdirectory(test) +endif() diff --git a/src/ox/mc/read.cpp b/src/ox/mc/read.cpp new file mode 100644 index 000000000..f20a10142 --- /dev/null +++ b/src/ox/mc/read.cpp @@ -0,0 +1,15 @@ +/* + * Copyright 2015 - 2017 gtalent2@gmail.com + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "read.hpp" + +namespace ox { +namespace mc { + +} +} diff --git a/src/ox/mc/read.hpp b/src/ox/mc/read.hpp new file mode 100644 index 000000000..46fd1c8c1 --- /dev/null +++ b/src/ox/mc/read.hpp @@ -0,0 +1,15 @@ +/* + * Copyright 2015 - 2017 gtalent2@gmail.com + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +namespace ox { +namespace mc { + +} +} diff --git a/src/ox/mc/test/CMakeLists.txt b/src/ox/mc/test/CMakeLists.txt new file mode 100644 index 000000000..7789b0f58 --- /dev/null +++ b/src/ox/mc/test/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 2.8) + +add_executable( + McTest + tests.cpp +) + +target_link_libraries(McTest) diff --git a/src/ox/mc/test/tests.cpp b/src/ox/mc/test/tests.cpp new file mode 100644 index 000000000..92f5c5741 --- /dev/null +++ b/src/ox/mc/test/tests.cpp @@ -0,0 +1,11 @@ +/* + * Copyright 2015 - 2017 gtalent2@gmail.com + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +int main() { + return 0; +}; diff --git a/src/ox/mc/write.cpp b/src/ox/mc/write.cpp new file mode 100644 index 000000000..a5eaf6c5d --- /dev/null +++ b/src/ox/mc/write.cpp @@ -0,0 +1,93 @@ +/* + * Copyright 2015 - 2017 gtalent2@gmail.com + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include "write.hpp" + +namespace ox { +namespace mc { + +int FieldPresenseMask::set(int i, bool on) { + uint8_t val = on ? 1 : 0; // normalize to 0 or 1 + if (i / 8 < m_maxLen) { + m_mask[i / 8] |= ox::std::bigEndianAdapt((uint8_t) (val << (i % 8))); + return 0; + } else { + return MC_PRESENCEMASKOUTBOUNDS; + } +} + +void FieldPresenseMask::setMaxLen(int maxLen) { + m_maxLen = maxLen; +} + + + +MetalClawWriter::MetalClawWriter(uint8_t *buff, size_t buffLen): m_fieldPresence(buff, buffLen) { + m_buff = buff; + m_buffLen = buffLen; +} + +int MetalClawWriter::op(const char*, int16_t *val) { + return appendInteger(*val); +} + +int MetalClawWriter::op(const char*, int32_t *val) { + return appendInteger(*val); +} + +int MetalClawWriter::op(const char*, int64_t *val) { + return appendInteger(*val); +} + +int MetalClawWriter::op(const char*, uint16_t *val) { + return appendInteger(*val); +} + +int MetalClawWriter::op(const char*, uint32_t *val) { + return appendInteger(*val); +} + +int MetalClawWriter::op(const char*, uint64_t *val) { + return appendInteger(*val); +} + +int MetalClawWriter::op(const char*, bool *val) { + return m_fieldPresence.set(m_field++, *val); +} + +int MetalClawWriter::op(const char*, const char **val, size_t len) { + int err = 0; + if (val) { + // write the length + typedef uint32_t StringLength; + if (m_buffIt + sizeof(StringLength) + len < m_buffLen) { + *((StringLength*) &m_buff[m_buffIt]) = ox::std::bigEndianAdapt((StringLength) len); + m_field++; + m_buffIt += sizeof(StringLength); + + // write the string + ox_memcpy(&m_buff[m_buffIt], val, len); + m_buffIt += len + 1; + m_buff[m_buffIt - 1] = 0; + err |= m_fieldPresence.set(m_field, true); + m_field++; + } + } + return err; +} + +void MetalClawWriter::setFields(int fields) { + m_fields = fields; + m_field = fields / 8; + m_fieldPresence.setMaxLen(fields / 8); +} + +} +} diff --git a/src/ox/mc/write.hpp b/src/ox/mc/write.hpp new file mode 100644 index 000000000..a385948a9 --- /dev/null +++ b/src/ox/mc/write.hpp @@ -0,0 +1,127 @@ +/* + * Copyright 2015 - 2017 gtalent2@gmail.com + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include + +namespace ox { +namespace mc { + +enum { + MC_PRESENCEMASKOUTBOUNDS = 1, + MC_BUFFENDED = 2 +}; + +class FieldPresenseMask { + private: + uint8_t *m_mask; + int m_maxLen = 0; + + public: + FieldPresenseMask(uint8_t *mask, size_t maxLen); + + int set(int i, bool on); + + void setMaxLen(int); +}; + +class MetalClawWriter { + + private: + FieldPresenseMask m_fieldPresence; + int m_fields = 0; + int m_field = 0; + size_t m_buffIt = 0; + size_t m_buffLen = 0; + uint8_t *m_buff = nullptr; + + public: + MetalClawWriter(uint8_t *buff, size_t buffLen); + + int op(const char*, int16_t *val); + int op(const char*, int32_t *val); + int op(const char*, int64_t *val); + + int op(const char*, uint16_t *val); + int op(const char*, uint32_t *val); + int op(const char*, uint64_t *val); + + int op(const char*, bool *val); + + /** + * + * @param len the length of the string, not including the null terminator + */ + int op(const char*, const char **val, size_t len); + + template + int op(const char*, T **val, size_t len); + + template + int op(const char*, T *val); + + void setFields(int fields); + + private: + template + int appendInteger(I val); +}; + +template +int MetalClawWriter::op(const char*, T *val) { + MetalClawWriter reader(m_buff, m_buffLen - m_buffLen); + return ioOp(&reader, val); +}; + +template +int MetalClawWriter::appendInteger(I val) { + int err = 0; + if (val) { + if (m_buffIt + sizeof(I) < m_buffLen) { + *((I*) &m_buff[m_buffIt]) = ox::std::bigEndianAdapt(val); + err |= m_fieldPresence.set(m_field, true); + m_field++; + m_buffIt += sizeof(I); + } else { + err = MC_BUFFENDED; + } + } + return err; +}; + +template +int MetalClawWriter::op(const char *fieldName, T **val, size_t len) { + int err = 0; + if (val) { + // write the length + typedef uint32_t ArrayLength; + if (m_buffIt + sizeof(ArrayLength) < m_buffLen) { + *((ArrayLength*) &m_buff[m_buffIt]) = ox::std::bigEndianAdapt((ArrayLength) len); + m_field++; + m_buffIt += sizeof(ArrayLength); + } else { + err = MC_BUFFENDED; + } + + // write the string + for (size_t i = 0; i < len; i++) { + err |= op(val[i]); + } + } + return err; +}; + +template +int read(uint8_t *buff, size_t buffLen, T *val) { + MetalClawWriter writer(buff, buffLen); + return ioOp(&writer, val); +} + +} +} diff --git a/src/ox/std/byteswap.hpp b/src/ox/std/byteswap.hpp index cbe5e8068..22e405667 100644 --- a/src/ox/std/byteswap.hpp +++ b/src/ox/std/byteswap.hpp @@ -14,6 +14,28 @@ namespace ox { namespace std { +inline int16_t byteSwap(int16_t i) { + return (i << 8) | (i >> 8); +} + +inline int32_t byteSwap(int32_t i) { + return ((i >> 24) & 0x000000ff) | + ((i >> 8) & 0x0000ff00) | + ((i << 8) & 0x00ff0000) | + ((i << 24) & 0xff000000); +} + +inline int64_t byteSwap(int64_t i) { + return ((i >> 56) & 0x00000000000000ff) | + ((i >> 40) & 0x000000000000ff00) | + ((i >> 24) & 0x0000000000ff0000) | + ((i >> 8) & 0x00000000ff000000) | + ((i << 8) & 0x000000ff00000000) | + ((i << 24) & 0x0000ff0000000000) | + ((i << 40) & 0x00ff000000000000) | + ((i << 56) & 0xff00000000000000); +} + inline uint16_t byteSwap(uint16_t i) { return (i << 8) | (i >> 8); } @@ -37,6 +59,47 @@ inline uint64_t byteSwap(uint64_t i) { } +/** + * Takes an int and byte swaps if the platform is big endian. + */ +inline int8_t bigEndianAdapt(int8_t i) { + return i; +} + +/** + * Takes an int and byte swaps if the platform is big endian. + */ +inline int16_t bigEndianAdapt(int16_t i) { +#ifdef __BIG_ENDIAN__ + return byteSwap(i); +#else + return i; +#endif +} + +/** + * Takes an int and byte swaps if the platform is big endian. + */ +inline int32_t bigEndianAdapt(int32_t i) { +#ifdef __BIG_ENDIAN__ + return byteSwap(i); +#else + return i; +#endif +} + +/** + * Takes an int and byte swaps if the platform is big endian. + */ +inline int64_t bigEndianAdapt(int64_t i) { +#ifdef __BIG_ENDIAN__ + return byteSwap(i); +#else + return i; +#endif +} + + /** * Takes an int and byte swaps if the platform is big endian. */