Adding premature C++ side; supporting only primitive types (including string) for now
[iot2.git] / iotjava / iotrmi / C++ / IoTRMIUtil.hpp
1 /** Class IoTRMIUtil provides methods that the upper
2  *  layers can use to transport and invoke methods
3  *  when using IoTSocket, IoTSocketClient and IoTSocketServer.
4  *
5  * @author      Rahmadi Trimananda <rtrimana @ uci.edu>
6  * @version     1.0
7  * @since       2016-10-18
8  */
9 #ifndef _IOTRMIUTIL_HPP__
10 #define _IOTRMIUTIL_HPP__
11
12 #include <stdio.h>
13 #include <stdint.h>
14 #include <endian.h>
15 #include <cxxabi.h>
16 #include <cstdlib>
17 #include <memory>
18 #include <typeinfo>
19
20 #include <iostream>
21 #include <string>
22 #include <string.h>
23
24 #include "IoTRMITypes.hpp"
25
26 using namespace std;
27
28 class IoTRMIUtil {
29
30         public:
31                 IoTRMIUtil();
32                 //~IoTRMIUtil();
33                 
34                 // Helper functions
35                 static void             printBytes(char* bytes, const int len, const bool hex);
36                 static int              hashCode(string str);
37                 static char*    getHashCodeBytes(string methodSign, char* bytes);
38                 int                     getTypeSize(string type);
39                 
40                 // Primitives to byte array
41                 static char*    shortToByteArray(short i, char* bytes);
42                 static char*    intToByteArray(int i, char* bytes);
43                 static char*    longToByteArray(int64_t i, char* bytes);
44                 static char*    floatToByteArray(float f, char* bytes);
45                 static char*    doubleToByteArray(double d, char* bytes);
46                 static char*    charToByteArray(char c, char* bytes);
47                 static char*    booleanToByteArray(bool c, char* bytes);
48                 static char*    stringToByteArray(string c, char* bytes);
49
50                 // Byte array to primitives
51                 static short*   byteArrayToShort(short* result, char* bytes);
52                 static int*     byteArrayToInt(int* result, char* bytes);
53                 static int64_t* byteArrayToLong(int64_t* result, char* bytes);
54                 static float*   byteArrayToFloat(float* result, char* bytes);
55                 static double*  byteArrayToDouble(double* result, char* bytes);
56                 static char*    byteArrayToChar(char* result, char* bytes);
57                 static bool*    byteArrayToBoolean(bool* result, char* bytes);
58                 static string*  byteArrayToString(string* result, char* bytes);
59
60                 // Get parameter object from byte array
61                 static void*    getParamObject(void* retObj, const char* type, char* paramBytes);
62                 static char*    getObjectBytes(char* retObjBytes, void* obj, const char* type);
63
64                 // Constants
65                 const static int        METHOD_ID_LEN = 4;      // 4 bytes = 32 bits
66                 const static int        PARAM_LEN = 4;          // 4 bytes = 32 bits (4-byte field that stores the length of the param)
67                 
68         private:
69                 map<string,string>      mapPrimitives;
70                 map<string,int>         mapPrimitiveSizesJava;
71                 map<string,int>         mapPrimitiveSizesCplus;
72                 map<string,string>      mapNonPrimitives;
73 };
74
75
76 // Constructor
77 IoTRMIUtil::IoTRMIUtil() {
78
79         // Prepare vectors for inputs
80         std::vector<string> primJava (IoTRMITypes::primitivesJava, 
81                 IoTRMITypes::primitivesJava + sizeof(IoTRMITypes::primitivesJava)/sizeof(string));
82         std::vector<string> primCplus (IoTRMITypes::primitivesCplus, 
83                 IoTRMITypes::primitivesCplus + sizeof(IoTRMITypes::primitivesCplus)/sizeof(string));
84         std::vector<int> primJavaSizes (IoTRMITypes::primitivesJavaSizes, 
85                 IoTRMITypes::primitivesJavaSizes + sizeof(IoTRMITypes::primitivesJavaSizes)/sizeof(int));
86         std::vector<int> primCplusSizes (IoTRMITypes::primitivesCplusSizes, 
87                 IoTRMITypes::primitivesCplusSizes + sizeof(IoTRMITypes::primitivesCplusSizes)/sizeof(int));
88         std::vector<string> nonPrimJava (IoTRMITypes::nonPrimitivesJava, 
89                 IoTRMITypes::nonPrimitivesJava + sizeof(IoTRMITypes::nonPrimitivesJava)/sizeof(string));
90         std::vector<string> nonPrimCplus (IoTRMITypes::nonPrimitivesCplus, 
91                 IoTRMITypes::nonPrimitivesCplus + sizeof(IoTRMITypes::nonPrimitivesCplus)/sizeof(string));
92
93
94         // Write into maps
95         IoTRMITypes::arraysToMap(mapPrimitives, primJava, primCplus);
96         IoTRMITypes::arraysToMap(mapPrimitiveSizesJava, primJava, primJavaSizes); 
97         IoTRMITypes::arraysToMap(mapPrimitiveSizesCplus, primJava, primCplusSizes); 
98         IoTRMITypes::arraysToMap(mapNonPrimitives, nonPrimJava, nonPrimCplus);
99 }
100
101 // *************
102 //    Helpers
103 // *************
104 void IoTRMIUtil::printBytes(char* bytes, const int len, const bool hex) {
105
106         printf("[ ");
107         for (int i = 0; i < len; i++) {
108                 if (hex)        // print in hexadecimal
109                         printf("%x", bytes[i]);
110                 else
111                         printf("%d", bytes[i]);
112                 if (i < len - 1)
113                         printf(", ");
114         }
115         printf(" ]\n");
116 }
117
118
119 // Return hashCode value 
120 // This mimics the method Object.hashCode() in Java
121 int IoTRMIUtil::hashCode(string str)  
122 {
123         int hash = 0;
124         int len = str.length();
125         char c;
126         if (len == 0) 
127                 return hash;
128         
129         for (int i = 0; i < len; i++) {
130                 c = str.at(i);
131                 hash = (31*hash) + (int) c;
132         }
133
134         return hash;
135 }
136
137
138 char* IoTRMIUtil::getHashCodeBytes(string methodSign, char* bytes) {
139
140         int hash = hashCode(methodSign);
141         return intToByteArray(hash, bytes);
142 }
143
144
145 int IoTRMIUtil::getTypeSize(string type) {
146
147         // Handle the types and find the sizes
148         if (mapPrimitiveSizesCplus.find(type) != mapPrimitiveSizesCplus.end())
149                 return mapPrimitiveSizesCplus.find(type)->second;
150         else
151                 return -1; // Size is unknown
152 }
153
154
155 // Getting parameter object based on received byte array
156 void* IoTRMIUtil::getParamObject(void* retObj, const char* type, char* paramBytes) {
157
158         if (strcmp(type, "b") == 0 ||
159                 strcmp(type, "byte") == 0) {
160                 retObj = (void*) &paramBytes[0];
161         } else if ( strcmp(type, "s") == 0 ||
162                                 strcmp(type, "short") == 0) {
163                 retObj = (void*) byteArrayToShort((short*) retObj, paramBytes);
164         } else if ( strcmp(type, "i") == 0 ||
165                                 strcmp(type, "int") == 0) {
166                 retObj = (void*) byteArrayToInt((int*) retObj, paramBytes);
167         } else if ( strcmp(type, "l") == 0 ||
168                                 strcmp(type, "long") == 0) {
169                 retObj = (void*) byteArrayToLong((int64_t*) retObj, paramBytes);
170         } else if ( strcmp(type, "f") == 0 ||
171                                 strcmp(type, "float") == 0) {
172                 retObj = (void*) byteArrayToFloat((float*) retObj, paramBytes);
173         } else if ( strcmp(type, "d") == 0 ||
174                                 strcmp(type, "double") == 0) {
175                 retObj = (void*) byteArrayToDouble((double*) retObj, paramBytes);
176         } else if ( strcmp(type, "b") == 0 ||
177                                 strcmp(type, "bool") == 0) {
178                 retObj = (void*) byteArrayToBoolean((bool*) retObj, paramBytes);
179         } else if ( strcmp(type, "c") == 0 ||
180                                 strcmp(type, "char") == 0) {
181                 retObj = (void*) byteArrayToChar((char*) retObj, paramBytes);
182         } else if ( strcmp(type, "Ss") == 0 ||
183                                 strcmp(type, "string") == 0) {
184                 retObj = (void*) byteArrayToString((string*) retObj, paramBytes);
185         } else {
186                 string error = "IoTRMIUtil: Unrecognizable type: " + string(type);
187                 throw error;
188         }
189
190         return retObj;
191 }
192
193
194 // Getting byte array based on parameter and its type
195 char* IoTRMIUtil::getObjectBytes(char* retObjBytes, void* obj, const char* type) {
196
197         if (strcmp(type, "b") == 0 ||
198                 strcmp(type, "byte") == 0) {
199                 retObjBytes = (char*) obj;
200         } else if ( strcmp(type, "s") == 0 ||
201                                 strcmp(type, "short") == 0) {
202                 retObjBytes = shortToByteArray(*((short*) obj), retObjBytes);
203         } else if ( strcmp(type, "i") == 0 ||
204                                 strcmp(type, "int") == 0) {
205                 retObjBytes = intToByteArray(*((int*) obj), retObjBytes);
206         } else if ( strcmp(type, "l") == 0 ||
207                                 strcmp(type, "long") == 0) {
208                 retObjBytes = longToByteArray(*((int64_t*) obj), retObjBytes);
209         } else if ( strcmp(type, "f") == 0 ||
210                                 strcmp(type, "float") == 0) {
211                 retObjBytes = floatToByteArray(*((float*) obj), retObjBytes);
212         } else if ( strcmp(type, "d") == 0 ||
213                                 strcmp(type, "double") == 0) {
214                 retObjBytes = doubleToByteArray(*((double*) obj), retObjBytes);
215         } else if ( strcmp(type, "b") == 0 ||
216                                 strcmp(type, "bool") == 0) {
217                 retObjBytes = booleanToByteArray(*((bool*) obj), retObjBytes);
218         } else if ( strcmp(type, "c") == 0 ||
219                                 strcmp(type, "char") == 0) {
220                 retObjBytes = charToByteArray(*((char*) obj), retObjBytes);
221         } else if ( strcmp(type, "Ss") == 0 ||
222                                 strcmp(type, "string") == 0) {
223                 retObjBytes = stringToByteArray(*((string*) obj), retObjBytes);
224         } else {
225                 string error = "IoTRMIUtil: Unrecognizable type: " + string(type);
226                 throw error;
227         }
228
229         return retObjBytes;
230 }
231
232
233 // Conversions
234 // Primitives to byte array
235 char* IoTRMIUtil::shortToByteArray(short s, char* bytes) {
236
237         short sInvert = htobe16(s);
238         //short sInvert = htons(s);
239         memcpy(bytes, &sInvert, sizeof(short));
240
241         return bytes;
242 }
243
244
245 char* IoTRMIUtil::intToByteArray(int i, char* bytes) {
246
247         int iInvert = htobe32(i);
248         //int iInvert = htonl(i);
249         memcpy(bytes, &iInvert, sizeof(int));
250
251         return bytes;
252 }
253
254
255 char* IoTRMIUtil::longToByteArray(int64_t l, char* bytes) {
256
257         int64_t lInvert = htobe64(l);
258         memcpy(bytes, &lInvert, sizeof(int64_t));
259
260         return bytes;
261 }
262
263
264 char* IoTRMIUtil::floatToByteArray(float f, char* bytes) {
265
266         // Copy to int to allow the usage of htobeXX() functions
267         int i = 0;
268         memcpy(&i, &f, sizeof(float));
269         int iInvert = htobe32(i);
270         memcpy(bytes, &iInvert, sizeof(int));
271         
272         return bytes;
273 }
274
275
276 char* IoTRMIUtil::doubleToByteArray(double d, char* bytes) {
277
278         // Copy to int to allow the usage of htobeXX() functions
279         int64_t i = 0;
280         memcpy(&i, &d, sizeof(double));
281         int64_t iInvert = htobe64(i);
282         memcpy(bytes, &iInvert, sizeof(int64_t));
283         
284         return bytes;
285 }
286
287
288 char* IoTRMIUtil::charToByteArray(char c, char* bytes) {
289
290         // We need 2 bytes to accommodate Java char type, whose size is 2
291         bytes[0] = 0;
292         bytes[1] = c;
293
294         return bytes;
295 }
296
297
298 char* IoTRMIUtil::booleanToByteArray(bool b, char* bytes) {
299
300         bytes[0] = (b) ? 1 : 0;
301         return bytes;
302 }
303
304
305 char* IoTRMIUtil::stringToByteArray(string str, char* bytes) {
306
307         strcpy(bytes, str.c_str());
308         return bytes;
309 }
310
311
312 // Conversions
313 // Byte array to primitives
314 short* IoTRMIUtil::byteArrayToShort(short* result, char* bytes) {
315
316         short s = 0;
317         memcpy(&s, bytes, sizeof(short));
318         //short result = be16toh(s);
319         *result = be16toh(s);
320
321         return result;
322 }
323
324
325 int* IoTRMIUtil::byteArrayToInt(int* result, char* bytes) {
326
327         int i = 0;
328         memcpy(&i, bytes, sizeof(int));
329         *result = be32toh(i);
330
331         return result;
332 }
333
334
335 int64_t* IoTRMIUtil::byteArrayToLong(int64_t* result, char* bytes) {
336
337         int64_t l = 0;
338         memcpy(&l, bytes, sizeof(int64_t));
339         *result = be64toh(l);
340
341         return result;
342 }
343
344
345 float* IoTRMIUtil::byteArrayToFloat(float* result, char* bytes) {
346
347         // Copy to int to allow the usage of beXXtoh() functions
348         int i = 0;
349         memcpy(&i, bytes, sizeof(int));
350         int iInvert = be32toh(i);
351         memcpy(result, &iInvert, sizeof(float));
352
353         return result;
354 }
355
356
357 double* IoTRMIUtil::byteArrayToDouble(double* result, char* bytes) {
358
359         // Copy to int to allow the usage of beXXtoh() functions
360         int64_t i = 0;
361         memcpy(&i, bytes, sizeof(int64_t));
362         int64_t iInvert = be64toh(i);
363         memcpy(result, &iInvert, sizeof(double));
364
365         return result;
366 }
367
368
369 char* IoTRMIUtil::byteArrayToChar(char* result, char* bytes) {
370
371         *result = bytes[1];
372         return result;
373 }
374
375
376 bool* IoTRMIUtil::byteArrayToBoolean(bool* result, char* bytes) {
377
378         *result = (bytes[0]) ? true : false;
379         return result;
380 }
381
382
383 string* IoTRMIUtil::byteArrayToString(string* result, char* bytes) {
384
385         *result= string(bytes);
386         return result;
387 }
388
389 #endif