+/** Class IoTRMIUtil provides methods that the upper
+ * layers can use to transport and invoke methods
+ * when using IoTSocket, IoTSocketClient and IoTSocketServer.
+ *
+ * @author Rahmadi Trimananda <rtrimana @ uci.edu>
+ * @version 1.0
+ * @since 2016-10-18
+ */
+#ifndef _IOTRMIUTIL_HPP__
+#define _IOTRMIUTIL_HPP__
+
+#include <stdio.h>
+#include <stdint.h>
+#include <endian.h>
+#include <cxxabi.h>
+#include <cstdlib>
+#include <memory>
+#include <typeinfo>
+
+#include <iostream>
+#include <string>
+#include <string.h>
+
+#include "IoTRMITypes.hpp"
+
+using namespace std;
+
+class IoTRMIUtil {
+
+ public:
+ IoTRMIUtil();
+ //~IoTRMIUtil();
+
+ // Helper functions
+ static void printBytes(char* bytes, const int len, const bool hex);
+ static int hashCode(string str);
+ static char* getHashCodeBytes(string methodSign, char* bytes);
+ int getTypeSize(string type);
+
+ // Primitives to byte array
+ static char* shortToByteArray(short i, char* bytes);
+ static char* intToByteArray(int i, char* bytes);
+ static char* longToByteArray(int64_t i, char* bytes);
+ static char* floatToByteArray(float f, char* bytes);
+ static char* doubleToByteArray(double d, char* bytes);
+ static char* charToByteArray(char c, char* bytes);
+ static char* booleanToByteArray(bool c, char* bytes);
+ static char* stringToByteArray(string c, char* bytes);
+
+ // Byte array to primitives
+ static short* byteArrayToShort(short* result, char* bytes);
+ static int* byteArrayToInt(int* result, char* bytes);
+ static int64_t* byteArrayToLong(int64_t* result, char* bytes);
+ static float* byteArrayToFloat(float* result, char* bytes);
+ static double* byteArrayToDouble(double* result, char* bytes);
+ static char* byteArrayToChar(char* result, char* bytes);
+ static bool* byteArrayToBoolean(bool* result, char* bytes);
+ static string* byteArrayToString(string* result, char* bytes);
+
+ // Get parameter object from byte array
+ static void* getParamObject(void* retObj, const char* type, char* paramBytes);
+ static char* getObjectBytes(char* retObjBytes, void* obj, const char* type);
+
+ // Constants
+ const static int METHOD_ID_LEN = 4; // 4 bytes = 32 bits
+ const static int PARAM_LEN = 4; // 4 bytes = 32 bits (4-byte field that stores the length of the param)
+
+ private:
+ map<string,string> mapPrimitives;
+ map<string,int> mapPrimitiveSizesJava;
+ map<string,int> mapPrimitiveSizesCplus;
+ map<string,string> mapNonPrimitives;
+};
+
+
+// Constructor
+IoTRMIUtil::IoTRMIUtil() {
+
+ // Prepare vectors for inputs
+ std::vector<string> primJava (IoTRMITypes::primitivesJava,
+ IoTRMITypes::primitivesJava + sizeof(IoTRMITypes::primitivesJava)/sizeof(string));
+ std::vector<string> primCplus (IoTRMITypes::primitivesCplus,
+ IoTRMITypes::primitivesCplus + sizeof(IoTRMITypes::primitivesCplus)/sizeof(string));
+ std::vector<int> primJavaSizes (IoTRMITypes::primitivesJavaSizes,
+ IoTRMITypes::primitivesJavaSizes + sizeof(IoTRMITypes::primitivesJavaSizes)/sizeof(int));
+ std::vector<int> primCplusSizes (IoTRMITypes::primitivesCplusSizes,
+ IoTRMITypes::primitivesCplusSizes + sizeof(IoTRMITypes::primitivesCplusSizes)/sizeof(int));
+ std::vector<string> nonPrimJava (IoTRMITypes::nonPrimitivesJava,
+ IoTRMITypes::nonPrimitivesJava + sizeof(IoTRMITypes::nonPrimitivesJava)/sizeof(string));
+ std::vector<string> nonPrimCplus (IoTRMITypes::nonPrimitivesCplus,
+ IoTRMITypes::nonPrimitivesCplus + sizeof(IoTRMITypes::nonPrimitivesCplus)/sizeof(string));
+
+
+ // Write into maps
+ IoTRMITypes::arraysToMap(mapPrimitives, primJava, primCplus);
+ IoTRMITypes::arraysToMap(mapPrimitiveSizesJava, primJava, primJavaSizes);
+ IoTRMITypes::arraysToMap(mapPrimitiveSizesCplus, primJava, primCplusSizes);
+ IoTRMITypes::arraysToMap(mapNonPrimitives, nonPrimJava, nonPrimCplus);
+}
+
+// *************
+// Helpers
+// *************
+void IoTRMIUtil::printBytes(char* bytes, const int len, const bool hex) {
+
+ printf("[ ");
+ for (int i = 0; i < len; i++) {
+ if (hex) // print in hexadecimal
+ printf("%x", bytes[i]);
+ else
+ printf("%d", bytes[i]);
+ if (i < len - 1)
+ printf(", ");
+ }
+ printf(" ]\n");
+}
+
+
+// Return hashCode value
+// This mimics the method Object.hashCode() in Java
+int IoTRMIUtil::hashCode(string str)
+{
+ int hash = 0;
+ int len = str.length();
+ char c;
+ if (len == 0)
+ return hash;
+
+ for (int i = 0; i < len; i++) {
+ c = str.at(i);
+ hash = (31*hash) + (int) c;
+ }
+
+ return hash;
+}
+
+
+char* IoTRMIUtil::getHashCodeBytes(string methodSign, char* bytes) {
+
+ int hash = hashCode(methodSign);
+ return intToByteArray(hash, bytes);
+}
+
+
+int IoTRMIUtil::getTypeSize(string type) {
+
+ // Handle the types and find the sizes
+ if (mapPrimitiveSizesCplus.find(type) != mapPrimitiveSizesCplus.end())
+ return mapPrimitiveSizesCplus.find(type)->second;
+ else
+ return -1; // Size is unknown
+}
+
+
+// Getting parameter object based on received byte array
+void* IoTRMIUtil::getParamObject(void* retObj, const char* type, char* paramBytes) {
+
+ if (strcmp(type, "b") == 0 ||
+ strcmp(type, "byte") == 0) {
+ retObj = (void*) ¶mBytes[0];
+ } else if ( strcmp(type, "s") == 0 ||
+ strcmp(type, "short") == 0) {
+ retObj = (void*) byteArrayToShort((short*) retObj, paramBytes);
+ } else if ( strcmp(type, "i") == 0 ||
+ strcmp(type, "int") == 0) {
+ retObj = (void*) byteArrayToInt((int*) retObj, paramBytes);
+ } else if ( strcmp(type, "l") == 0 ||
+ strcmp(type, "long") == 0) {
+ retObj = (void*) byteArrayToLong((int64_t*) retObj, paramBytes);
+ } else if ( strcmp(type, "f") == 0 ||
+ strcmp(type, "float") == 0) {
+ retObj = (void*) byteArrayToFloat((float*) retObj, paramBytes);
+ } else if ( strcmp(type, "d") == 0 ||
+ strcmp(type, "double") == 0) {
+ retObj = (void*) byteArrayToDouble((double*) retObj, paramBytes);
+ } else if ( strcmp(type, "b") == 0 ||
+ strcmp(type, "bool") == 0) {
+ retObj = (void*) byteArrayToBoolean((bool*) retObj, paramBytes);
+ } else if ( strcmp(type, "c") == 0 ||
+ strcmp(type, "char") == 0) {
+ retObj = (void*) byteArrayToChar((char*) retObj, paramBytes);
+ } else if ( strcmp(type, "Ss") == 0 ||
+ strcmp(type, "string") == 0) {
+ retObj = (void*) byteArrayToString((string*) retObj, paramBytes);
+ } else {
+ string error = "IoTRMIUtil: Unrecognizable type: " + string(type);
+ throw error;
+ }
+
+ return retObj;
+}
+
+
+// Getting byte array based on parameter and its type
+char* IoTRMIUtil::getObjectBytes(char* retObjBytes, void* obj, const char* type) {
+
+ if (strcmp(type, "b") == 0 ||
+ strcmp(type, "byte") == 0) {
+ retObjBytes = (char*) obj;
+ } else if ( strcmp(type, "s") == 0 ||
+ strcmp(type, "short") == 0) {
+ retObjBytes = shortToByteArray(*((short*) obj), retObjBytes);
+ } else if ( strcmp(type, "i") == 0 ||
+ strcmp(type, "int") == 0) {
+ retObjBytes = intToByteArray(*((int*) obj), retObjBytes);
+ } else if ( strcmp(type, "l") == 0 ||
+ strcmp(type, "long") == 0) {
+ retObjBytes = longToByteArray(*((int64_t*) obj), retObjBytes);
+ } else if ( strcmp(type, "f") == 0 ||
+ strcmp(type, "float") == 0) {
+ retObjBytes = floatToByteArray(*((float*) obj), retObjBytes);
+ } else if ( strcmp(type, "d") == 0 ||
+ strcmp(type, "double") == 0) {
+ retObjBytes = doubleToByteArray(*((double*) obj), retObjBytes);
+ } else if ( strcmp(type, "b") == 0 ||
+ strcmp(type, "bool") == 0) {
+ retObjBytes = booleanToByteArray(*((bool*) obj), retObjBytes);
+ } else if ( strcmp(type, "c") == 0 ||
+ strcmp(type, "char") == 0) {
+ retObjBytes = charToByteArray(*((char*) obj), retObjBytes);
+ } else if ( strcmp(type, "Ss") == 0 ||
+ strcmp(type, "string") == 0) {
+ retObjBytes = stringToByteArray(*((string*) obj), retObjBytes);
+ } else {
+ string error = "IoTRMIUtil: Unrecognizable type: " + string(type);
+ throw error;
+ }
+
+ return retObjBytes;
+}
+
+
+// Conversions
+// Primitives to byte array
+char* IoTRMIUtil::shortToByteArray(short s, char* bytes) {
+
+ short sInvert = htobe16(s);
+ //short sInvert = htons(s);
+ memcpy(bytes, &sInvert, sizeof(short));
+
+ return bytes;
+}
+
+
+char* IoTRMIUtil::intToByteArray(int i, char* bytes) {
+
+ int iInvert = htobe32(i);
+ //int iInvert = htonl(i);
+ memcpy(bytes, &iInvert, sizeof(int));
+
+ return bytes;
+}
+
+
+char* IoTRMIUtil::longToByteArray(int64_t l, char* bytes) {
+
+ int64_t lInvert = htobe64(l);
+ memcpy(bytes, &lInvert, sizeof(int64_t));
+
+ return bytes;
+}
+
+
+char* IoTRMIUtil::floatToByteArray(float f, char* bytes) {
+
+ // Copy to int to allow the usage of htobeXX() functions
+ int i = 0;
+ memcpy(&i, &f, sizeof(float));
+ int iInvert = htobe32(i);
+ memcpy(bytes, &iInvert, sizeof(int));
+
+ return bytes;
+}
+
+
+char* IoTRMIUtil::doubleToByteArray(double d, char* bytes) {
+
+ // Copy to int to allow the usage of htobeXX() functions
+ int64_t i = 0;
+ memcpy(&i, &d, sizeof(double));
+ int64_t iInvert = htobe64(i);
+ memcpy(bytes, &iInvert, sizeof(int64_t));
+
+ return bytes;
+}
+
+
+char* IoTRMIUtil::charToByteArray(char c, char* bytes) {
+
+ // We need 2 bytes to accommodate Java char type, whose size is 2
+ bytes[0] = 0;
+ bytes[1] = c;
+
+ return bytes;
+}
+
+
+char* IoTRMIUtil::booleanToByteArray(bool b, char* bytes) {
+
+ bytes[0] = (b) ? 1 : 0;
+ return bytes;
+}
+
+
+char* IoTRMIUtil::stringToByteArray(string str, char* bytes) {
+
+ strcpy(bytes, str.c_str());
+ return bytes;
+}
+
+
+// Conversions
+// Byte array to primitives
+short* IoTRMIUtil::byteArrayToShort(short* result, char* bytes) {
+
+ short s = 0;
+ memcpy(&s, bytes, sizeof(short));
+ //short result = be16toh(s);
+ *result = be16toh(s);
+
+ return result;
+}
+
+
+int* IoTRMIUtil::byteArrayToInt(int* result, char* bytes) {
+
+ int i = 0;
+ memcpy(&i, bytes, sizeof(int));
+ *result = be32toh(i);
+
+ return result;
+}
+
+
+int64_t* IoTRMIUtil::byteArrayToLong(int64_t* result, char* bytes) {
+
+ int64_t l = 0;
+ memcpy(&l, bytes, sizeof(int64_t));
+ *result = be64toh(l);
+
+ return result;
+}
+
+
+float* IoTRMIUtil::byteArrayToFloat(float* result, char* bytes) {
+
+ // Copy to int to allow the usage of beXXtoh() functions
+ int i = 0;
+ memcpy(&i, bytes, sizeof(int));
+ int iInvert = be32toh(i);
+ memcpy(result, &iInvert, sizeof(float));
+
+ return result;
+}
+
+
+double* IoTRMIUtil::byteArrayToDouble(double* result, char* bytes) {
+
+ // Copy to int to allow the usage of beXXtoh() functions
+ int64_t i = 0;
+ memcpy(&i, bytes, sizeof(int64_t));
+ int64_t iInvert = be64toh(i);
+ memcpy(result, &iInvert, sizeof(double));
+
+ return result;
+}
+
+
+char* IoTRMIUtil::byteArrayToChar(char* result, char* bytes) {
+
+ *result = bytes[1];
+ return result;
+}
+
+
+bool* IoTRMIUtil::byteArrayToBoolean(bool* result, char* bytes) {
+
+ *result = (bytes[0]) ? true : false;
+ return result;
+}
+
+
+string* IoTRMIUtil::byteArrayToString(string* result, char* bytes) {
+
+ *result= string(bytes);
+ return result;
+}
+
+#endif