Add ByteString support in CBOR wrapper in OIC stack
authorSachin Agrawal <sachin.agrawal@intel.com>
Thu, 8 Oct 2015 16:20:54 +0000 (09:20 -0700)
committerSachin Agrawal <sachin.agrawal@intel.com>
Tue, 27 Oct 2015 20:10:06 +0000 (20:10 +0000)
Currently byte strings in CBOR wrapper are achieved by using
int arrays. Drawbacks with this approach is in-efficient memory
consumption and 3rd Party tools cannot properly decode the CBOR
generated in this fashion.

Updated code in CBOR wrapper and also added unit tests.

Change-Id: I4ed1adc891be84e800c833df404914a335150ded
Signed-off-by: Sachin Agrawal <sachin.agrawal@intel.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/2337
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
resource/csdk/stack/include/ocpayload.h
resource/csdk/stack/include/octypes.h
resource/csdk/stack/include/payload_logging.h
resource/csdk/stack/src/ocpayload.c
resource/csdk/stack/src/ocpayloadconvert.c
resource/csdk/stack/src/ocpayloadparse.c
resource/csdk/stack/test/SConscript
resource/csdk/stack/test/cbortests.cpp [new file with mode: 0644]

index d645d2b..66c086e 100755 (executable)
@@ -62,6 +62,43 @@ bool OCRepPayloadGetPropInt(const OCRepPayload* payload, const char* name, int64
 bool OCRepPayloadSetPropDouble(OCRepPayload* payload, const char* name, double value);
 bool OCRepPayloadGetPropDouble(const OCRepPayload* payload, const char* name, double* value);
 
+/**
+ * This function allocates memory for the byte string and sets it in the payload.
+ *
+ * @param payload      Pointer to the payload to which byte string needs to be added.
+ * @param name         Name of the byte string.
+ * @param value        Byte string and it's length.
+ *
+ * @return true on success, false upon failure.
+ */
+bool OCRepPayloadSetPropByteString(OCRepPayload* payload, const char* name, OCByteString value);
+
+/**
+ * This function sets the byte string in the payload.
+ *
+ * @param payload      Pointer to the payload to which byte string needs to be added.
+ * @param name         Name of the byte string.
+ * @param value        Byte string and it's length.
+ *
+ * @return true on success, false upon failure.
+ */
+bool OCRepPayloadSetPropByteStringAsOwner(OCRepPayload* payload, const char* name,
+        OCByteString* value);
+
+/**
+ * This function gets the byte string from the payload.
+ *
+ * @param payload      Pointer to the payload from which byte string needs to be retrieved.
+ * @param name         Name of the byte string.
+ * @param value        Byte string and it's length.
+ *
+ * @note: Caller needs to invoke OCFree on value.bytes after it is finished using the byte string.
+ *
+ * @return true on success, false upon failure.
+ */
+bool OCRepPayloadGetPropByteString(const OCRepPayload* payload, const char* name,
+        OCByteString* value);
+
 bool OCRepPayloadSetPropString(OCRepPayload* payload, const char* name, const char* value);
 bool OCRepPayloadSetPropStringAsOwner(OCRepPayload* payload, const char* name, char* value);
 bool OCRepPayloadGetPropString(const OCRepPayload* payload, const char* name, char** value);
@@ -74,6 +111,48 @@ bool OCRepPayloadSetPropObjectAsOwner(OCRepPayload* payload, const char* name,
         OCRepPayload* value);
 bool OCRepPayloadGetPropObject(const OCRepPayload* payload, const char* name, OCRepPayload** value);
 
+/**
+ * This function allocates memory for the byte string array and sets it in the payload.
+ *
+ * @param payload      Pointer to the payload to which byte string array needs to be added.
+ * @param name         Name of the byte string.
+ * @param array        Byte string array.
+ * @param dimensions   Number of byte strings in above array.
+ *
+ * @return true on success, false upon failure.
+ */
+bool OCRepPayloadSetByteStringArrayAsOwner(OCRepPayload* payload, const char* name,
+        OCByteString* array, size_t dimensions[MAX_REP_ARRAY_DEPTH]);
+
+/**
+ * This function sets the byte string array in the payload.
+ *
+ * @param payload      Pointer to the payload to which byte string array needs to be added.
+ * @param name         Name of the byte string.
+ * @param array        Byte string array.
+ * @param dimensions   Number of byte strings in above array.
+ *
+ * @return true on success, false upon failure.
+ */
+bool OCRepPayloadSetByteStringArray(OCRepPayload* payload, const char* name,
+        const OCByteString* array, size_t dimensions[MAX_REP_ARRAY_DEPTH]);
+
+/**
+ * This function gets the byte string array from the payload.
+ *
+ * @param payload      Pointer to the payload from which byte string array needs to be retrieved.
+ * @param name         Name of the byte string array.
+ * @param value        Byte string array.
+ * @param dimensions   Number of byte strings in above array.
+ *
+ * @note: Caller needs to invoke OICFree on 'bytes' field of all array elements after it is
+ *        finished using the byte string array.
+ *
+ * @return true on success, false upon failure.
+ */
+bool OCRepPayloadGetByteStringArray(const OCRepPayload* payload, const char* name,
+        OCByteString** array, size_t dimensions[MAX_REP_ARRAY_DEPTH]);
+
 bool OCRepPayloadSetIntArrayAsOwner(OCRepPayload* payload, const char* name,
         int64_t* array, size_t dimensions[MAX_REP_ARRAY_DEPTH]);
 bool OCRepPayloadSetIntArray(OCRepPayload* payload, const char* name,
index 63c9c23..9c15e35 100644 (file)
@@ -943,10 +943,21 @@ typedef enum
     OCREP_PROP_DOUBLE,
     OCREP_PROP_BOOL,
     OCREP_PROP_STRING,
+    OCREP_PROP_BYTE_STRING,
     OCREP_PROP_OBJECT,
     OCREP_PROP_ARRAY
 }OCRepPayloadPropType;
 
+/** This structure will be used to represent a binary string for CBOR payloads.*/
+typedef struct
+{
+    /** pointer to data bytes.*/
+    uint8_t* bytes;
+
+    /** number of data bytes.*/
+    size_t   len;
+} OCByteString;
+
 #define MAX_REP_ARRAY_DEPTH 3
 typedef struct
 {
@@ -959,6 +970,10 @@ typedef struct
         double* dArray;
         bool* bArray;
         char** strArray;
+
+        /** pointer to ByteString array.*/
+        OCByteString* ocByteStrArray;
+
         struct OCRepPayload** objArray;
     };
 } OCRepPayloadValueArray;
@@ -973,6 +988,10 @@ typedef struct OCRepPayloadValue
         double d;
         bool b;
         char* str;
+
+        /** ByteString object.*/
+        OCByteString ocByteStr;
+
         struct OCRepPayload* obj;
         OCRepPayloadValueArray arr;
     };
index 3938c17..2c181cd 100644 (file)
@@ -94,6 +94,10 @@ static inline void OCPayloadLogRep(LogLevel level, OCRepPayload* payload)
                 case OCREP_PROP_STRING:
                     OC_LOG_V(level, PL_TAG, "\t\t%s(string):%s", val->name, val->str);
                     break;
+                case OCREP_PROP_BYTE_STRING:
+                    OC_LOG_V(level, PL_TAG, "\t\t%s(binary):", val->name);
+                    OC_LOG_BUFFER(level, PL_TAG, val->ocByteStr.bytes, val->ocByteStr.len);
+                    break;
                 case OCREP_PROP_OBJECT:
                     // Note: Only prints the URI (if available), to print further, you'll
                     // need to dig into the object better!
@@ -126,6 +130,12 @@ static inline void OCPayloadLogRep(LogLevel level, OCRepPayload* payload)
                                     val->arr.dimensions[0], val->arr.dimensions[1],
                                     val->arr.dimensions[2]);
                             break;
+                        case OCREP_PROP_BYTE_STRING:
+                            OC_LOG_V(level, PL_TAG, "\t\t%s(byte array):%lld x %lld x %lld",
+                                    val->name,
+                                    val->arr.dimensions[0], val->arr.dimensions[1],
+                                    val->arr.dimensions[2]);
+                            break;
                         case OCREP_PROP_OBJECT:
                             OC_LOG_V(level, PL_TAG, "\t\t%s(OCRep array):%zu x %zu x %zu",
                                     val->name,
index cf7d754..43694bb 100755 (executable)
@@ -197,6 +197,10 @@ static void OCFreeRepPayloadValueContents(OCRepPayloadValue* val)
     {
         OICFree(val->str);
     }
+    else if(val->type == OCREP_PROP_BYTE_STRING)
+    {
+        OICFree(val->ocByteStr.bytes);
+    }
     else if (val->type == OCREP_PROP_OBJECT)
     {
         OCRepPayloadDestroy(val->obj);
@@ -220,6 +224,13 @@ static void OCFreeRepPayloadValueContents(OCRepPayloadValue* val)
                 }
                 OICFree(val->arr.strArray);
                 break;
+            case OCREP_PROP_BYTE_STRING:
+                for (size_t i = 0; i< dimTotal; ++i)
+                {
+                    OICFree(val->arr.ocByteStrArray[i].bytes);
+                }
+                OICFree(val->arr.ocByteStrArray);
+                break;
             case OCREP_PROP_OBJECT:
                 for(size_t i = 0; i< dimTotal;++i)
                 {
@@ -479,6 +490,9 @@ static bool OCRepPayloadSetProp(OCRepPayload* payload, const char* name,
         case OCREP_PROP_STRING:
                val->str = (char*)value;
                return val->str != NULL;
+        case OCREP_PROP_BYTE_STRING:
+               val->ocByteStr = *(OCByteString*)value;
+               break;
         case OCREP_PROP_NULL:
                return val != NULL;
         case OCREP_PROP_ARRAY:
@@ -562,6 +576,62 @@ bool OCRepPayloadGetPropString(const OCRepPayload* payload, const char* name, ch
     return *value != NULL;
 }
 
+bool OCRepPayloadSetPropByteString(OCRepPayload* payload, const char* name, OCByteString value)
+{
+    if (!value.bytes || !value.len)
+    {
+        return false;
+    }
+
+    OCByteString ocByteStr = {
+                    .bytes = (uint8_t*)OICMalloc(value.len * sizeof(uint8_t)),
+                    .len = value.len };
+
+    if(!ocByteStr.bytes)
+    {
+        return false;
+    }
+    memcpy(ocByteStr.bytes, value.bytes, ocByteStr.len);
+
+    bool b = OCRepPayloadSetPropByteStringAsOwner(payload, name, &ocByteStr);
+
+    if(!b)
+    {
+        OICFree(ocByteStr.bytes);
+    }
+    return b;
+}
+
+bool OCRepPayloadSetPropByteStringAsOwner(OCRepPayload* payload, const char* name, OCByteString* value)
+{
+    return OCRepPayloadSetProp(payload, name, value, OCREP_PROP_BYTE_STRING);
+}
+
+bool OCRepPayloadGetPropByteString(const OCRepPayload* payload, const char* name, OCByteString* value)
+{
+    OCRepPayloadValue* val = OCRepPayloadFindValue(payload, name);
+
+    if (!val || val->type != OCREP_PROP_BYTE_STRING)
+    {
+        return false;
+    }
+
+    if (!value)
+    {
+        return false;
+    }
+
+    value->bytes = (uint8_t*)OICMalloc(val->ocByteStr.len * sizeof(uint8_t));
+    if (!value->bytes)
+    {
+        return false;
+    }
+    value->len = val->ocByteStr.len;
+    memcpy(value->bytes, val->ocByteStr.bytes, value->len);
+
+    return true;
+}
+
 bool OCRepPayloadSetPropBool(OCRepPayload* payload,
         const char* name, bool value)
 {
@@ -626,6 +696,123 @@ size_t calcDimTotal(const size_t dimensions[MAX_REP_ARRAY_DEPTH])
     return total;
 }
 
+
+bool OCRepPayloadSetByteStringArrayAsOwner(OCRepPayload* payload, const char* name,
+        OCByteString* array, size_t dimensions[MAX_REP_ARRAY_DEPTH])
+{
+    OCRepPayloadValue* val = OCRepPayloadFindAndSetValue(payload, name, OCREP_PROP_ARRAY);
+
+    if (!val)
+    {
+        return false;
+    }
+
+    val->arr.type = OCREP_PROP_BYTE_STRING;
+    memcpy(val->arr.dimensions, dimensions, MAX_REP_ARRAY_DEPTH * sizeof(size_t));
+    val->arr.ocByteStrArray = array;
+
+    return true;
+}
+
+bool OCRepPayloadSetByteStringArray(OCRepPayload* payload, const char* name,
+        const OCByteString* array, size_t dimensions[MAX_REP_ARRAY_DEPTH])
+{
+    if (!array)
+    {
+        return NULL;
+    }
+
+    size_t dimTotal = calcDimTotal(dimensions);
+    if (dimTotal == 0)
+    {
+        return false;
+    }
+
+    OCByteString* newArray = (OCByteString*)OICCalloc(dimTotal, sizeof(OCByteString));
+
+    if (!newArray)
+    {
+        return false;
+    }
+
+    for (size_t i = 0; i < dimTotal; ++i)
+    {
+        newArray[i].bytes = (uint8_t*)OICMalloc(array[i].len * sizeof(uint8_t));
+        if (NULL == newArray[i].bytes)
+        {
+            for (size_t j = 0; j < i; ++j)
+            {
+                OICFree(newArray[j].bytes);
+            }
+
+            OICFree(newArray);
+            return false;
+        }
+        newArray[i].len = array[i].len;
+        memcpy(newArray[i].bytes, array[i].bytes, newArray[i].len);
+    }
+
+    bool b = OCRepPayloadSetByteStringArrayAsOwner(payload, name, newArray, dimensions);
+    if (!b)
+    {
+        for (size_t i = 0; i < dimTotal; ++i)
+        {
+            OICFree(newArray[i].bytes);
+        }
+
+        OICFree(newArray);
+    }
+    return b;
+}
+
+bool OCRepPayloadGetByteStringArray(const OCRepPayload* payload, const char* name,
+        OCByteString** array, size_t dimensions[MAX_REP_ARRAY_DEPTH])
+{
+    OCRepPayloadValue* val = OCRepPayloadFindValue(payload, name);
+
+    if (!val || val->type != OCREP_PROP_ARRAY || val->arr.type != OCREP_PROP_BYTE_STRING
+            || !val->arr.ocByteStrArray)
+    {
+        return false;
+    }
+
+    size_t dimTotal = calcDimTotal(val->arr.dimensions);
+    if (dimTotal == 0)
+    {
+        return false;
+    }
+
+    *array = (OCByteString*)OICCalloc(dimTotal, sizeof(OCByteString));
+    if (!*array)
+    {
+        return false;
+    }
+
+    for (size_t i = 0; i < dimTotal; ++i)
+    {
+        OCByteString* tmp = &(*array)[i];
+        tmp->bytes = (uint8_t*)OICMalloc(val->arr.ocByteStrArray[i].len * sizeof(uint8_t));
+        if (NULL == tmp->bytes)
+        {
+            for (size_t j = 0; j < i; ++j)
+            {
+                OCByteString* tmp = &(*array)[j];
+                OICFree(tmp->bytes);
+            }
+            OICFree(*array);
+            *array = NULL;
+
+            return false;
+        }
+        tmp->len = val->arr.ocByteStrArray[i].len;
+        memcpy(tmp->bytes, val->arr.ocByteStrArray[i].bytes, tmp->len);
+    }
+
+    memcpy(dimensions, val->arr.dimensions, MAX_REP_ARRAY_DEPTH * sizeof(size_t));
+    return true;
+}
+
+
 bool OCRepPayloadSetIntArrayAsOwner(OCRepPayload* payload, const char* name,
         int64_t* array, size_t dimensions[MAX_REP_ARRAY_DEPTH])
 {
index 062df00..4e80fc0 100644 (file)
@@ -578,6 +578,17 @@ static int64_t OCConvertArrayItem(CborEncoder* array, const OCRepPayloadValueArr
                         strlen(valArray->strArray[index]));
             }
             break;
+        case OCREP_PROP_BYTE_STRING:
+            if (!valArray->strArray[index])
+            {
+                err = err | cbor_encode_null(array);
+            }
+            else
+            {
+                err = err | cbor_encode_byte_string(array, valArray->ocByteStrArray[index].bytes,
+                        valArray->ocByteStrArray[index].len);
+            }
+            break;
         case OCREP_PROP_OBJECT:
             if (!valArray->objArray[index])
             {
@@ -735,6 +746,10 @@ static int64_t OCConvertSingleRepPayload(CborEncoder* parent, const OCRepPayload
                     err = err | cbor_encode_text_string(&repMap,
                             value->str, strlen(value->str));
                     break;
+                case OCREP_PROP_BYTE_STRING:
+                    err = err | cbor_encode_byte_string(&repMap,
+                            value->ocByteStr.bytes, value->ocByteStr.len);
+                    break;
                 case OCREP_PROP_OBJECT:
                     err = err | OCConvertSingleRepPayload(&repMap, value->obj);
                     break;
index 94dece9..e33dda4 100644 (file)
@@ -723,6 +723,8 @@ static OCRepPayloadPropType DecodeCborType(CborType type)
                 return OCREP_PROP_BOOL;
             case CborTextStringType:
                 return OCREP_PROP_STRING;
+            case CborByteStringType:
+                return OCREP_PROP_BYTE_STRING;
             case CborMapType:
                 return OCREP_PROP_OBJECT;
             case CborArrayType:
@@ -803,6 +805,8 @@ static size_t getAllocSize(OCRepPayloadPropType type)
             return sizeof (bool);
         case OCREP_PROP_STRING:
             return sizeof (char*);
+        case OCREP_PROP_BYTE_STRING:
+            return sizeof (OCByteString);
         case OCREP_PROP_OBJECT:
             return sizeof (OCRepPayload*);
         default:
@@ -828,6 +832,7 @@ static bool OCParseArrayFillArray(const CborValue* parent, size_t dimensions[MAX
 
     size_t i = 0;
     char* tempStr = NULL;
+    OCByteString ocByteStr = { .bytes = NULL, .len = 0};
     size_t tempLen = 0;
     OCRepPayload* tempPl = NULL;
 
@@ -900,6 +905,21 @@ static bool OCParseArrayFillArray(const CborValue* parent, size_t dimensions[MAX
                             );
                     }
                     break;
+                case OCREP_PROP_BYTE_STRING:
+                    if (dimensions[1] == 0)
+                    {
+                        err = err || cbor_value_dup_byte_string(&insideArray,
+                                &(ocByteStr.bytes), &(ocByteStr.len), NULL);
+                        ((OCByteString*)targetArray)[i] = ocByteStr;
+                    }
+                    else
+                    {
+                        err = err || OCParseArrayFillArray(&insideArray, newdim,
+                                type,
+                                &(((OCByteString*)targetArray)[arrayStep(dimensions, i)])
+                                );
+                    }
+                    break;
                 case OCREP_PROP_OBJECT:
                     if (dimensions[1] == 0)
                     {
@@ -993,6 +1013,17 @@ static bool OCParseArray(OCRepPayload* out, const char* name, CborValue* contain
                 err = true;
             }
             break;
+        case OCREP_PROP_BYTE_STRING:
+            if (err || !OCRepPayloadSetByteStringArrayAsOwner(out, name, (OCByteString*)arr, dimensions))
+            {
+                for (size_t i = 0; i < dimTotal; ++i)
+                {
+                    OICFree(((OCByteString*)arr)[i].bytes);
+                }
+                OICFree(arr);
+                err = true;
+            }
+            break;
         case OCREP_PROP_OBJECT:
             if (err || !OCRepPayloadSetPropObjectArrayAsOwner(out, name, (OCRepPayload**)arr, dimensions))
             {
@@ -1111,6 +1142,7 @@ static bool OCParseSingleRepPayload(OCRepPayload** outPayload, CborValue* repPar
             int64_t intval = 0;
             bool boolval = false;
             char* strval = NULL;
+            uint8_t* bytestrval = NULL;
             double doubleval = 0;
             OCRepPayload* pl;
 
@@ -1147,6 +1179,14 @@ static bool OCParseSingleRepPayload(OCRepPayload** outPayload, CborValue* repPar
                         err = !OCRepPayloadSetPropStringAsOwner(curPayload, name, strval);
                     }
                     break;
+                case CborByteStringType:
+                    err = err || cbor_value_dup_byte_string(&repMap, &bytestrval, &len, NULL);
+                    if (!err)
+                    {
+                        OCByteString tmp = {.bytes = bytestrval, .len = len};
+                        err = !OCRepPayloadSetPropByteStringAsOwner(curPayload, name, &tmp);
+                    }
+                    break;
                 case CborMapType:
                     err = err || OCParseSingleRepPayload(&pl, &repMap);
                     if (!err)
index ade8f3f..6654610 100644 (file)
@@ -69,8 +69,9 @@ if env.get('LOGGING'):
 # Source files and Targets
 ######################################################################
 stacktests = stacktest_env.Program('stacktests', ['stacktests.cpp'])
+cbortests = stacktest_env.Program('cbortests', ['cbortests.cpp'])
 
-Alias("test", [stacktests])
+Alias("test", [stacktests, cbortests])
 
 env.AppendTarget('test')
 if env.get('TEST') == '1':
diff --git a/resource/csdk/stack/test/cbortests.cpp b/resource/csdk/stack/test/cbortests.cpp
new file mode 100644 (file)
index 0000000..2e4a202
--- /dev/null
@@ -0,0 +1,222 @@
+//******************************************************************
+//
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+
+extern "C"
+{
+    #include "ocstack.h"
+    #include "ocpayload.h"
+    #include "ocpayloadcbor.h"
+    #include "logger.h"
+    #include "oic_malloc.h"
+}
+
+#include "gtest/gtest.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+//-----------------------------------------------------------------------------
+// Includes
+//-----------------------------------------------------------------------------
+#include <stdio.h>
+#include <string.h>
+
+#include <iostream>
+#include <stdint.h>
+
+#include "gtest_helper.h"
+
+class CborByteStringTest : public ::testing::Test {
+    protected:
+        virtual void SetUp() {
+            // Create Payload
+            payload_in = OCRepPayloadCreate();
+            ASSERT_TRUE(payload_in != NULL);
+        }
+
+        virtual void TearDown() {
+            OCPayloadDestroy((OCPayload*)payload_in);
+        }
+
+        OCRepPayload* payload_in;
+};
+
+TEST_F(CborByteStringTest, ByteStringSetGetTest)
+{
+    OCRepPayloadSetUri(payload_in, "/a/quake_sensor");
+    OCRepPayloadSetPropInt(payload_in, "scale", 4);
+
+    uint8_t binval[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x0, 0xA, 0xB, 0xC,
+                        0xD, 0xE, 0xF};
+    OCByteString quakedata_in = { binval, sizeof(binval)};
+
+    EXPECT_EQ(true, OCRepPayloadSetPropByteString(payload_in, "quakedata", quakedata_in));
+
+    OCByteString quakedata_out = { NULL, 0};
+    ASSERT_EQ(true, OCRepPayloadGetPropByteString(payload_in, "quakedata", &quakedata_out));
+
+    EXPECT_EQ(quakedata_in.len, quakedata_out.len);
+    EXPECT_EQ(0, memcmp(quakedata_in.bytes, quakedata_out.bytes, quakedata_in.len));
+
+    // Cleanup
+    OICFree(quakedata_out.bytes);
+}
+
+TEST_F(CborByteStringTest, ByteStringConvertParseTest)
+{
+    OCRepPayloadSetUri(payload_in, "/a/quake_sensor");
+    OCRepPayloadSetPropInt(payload_in, "scale", 4);
+
+    uint8_t binval[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x0, 0xA, 0xB, 0xC,
+                        0xD, 0xE, 0xF};
+    OCByteString quakedata_in = { binval, sizeof(binval)};
+
+    // Set ByteString in Payload
+    EXPECT_EQ(true, OCRepPayloadSetPropByteString(payload_in, "quakedata", quakedata_in));
+
+    // Convert OCPayload to CBOR
+    uint8_t *payload_cbor = NULL;
+    size_t payload_cbor_size = 0;
+    EXPECT_EQ(OC_STACK_OK, OCConvertPayload((OCPayload*) payload_in, &payload_cbor, &payload_cbor_size));
+
+#ifdef CBOR_BIN_STRING_DEBUG
+    FILE *fp = fopen("binstring.cbor", "wb+");
+    if (fp)
+    {
+        fwrite(payload_cbor, 1, payload_cbor_size, fp);
+        fclose(fp);
+    }
+#endif //CBOR_BIN_STRING_DEBUG
+
+    // Parse CBOR back to OCPayload
+    OCPayload* payload_out = NULL;
+    EXPECT_EQ(OC_STACK_OK, OCParsePayload(&payload_out, PAYLOAD_TYPE_REPRESENTATION,
+                 payload_cbor, payload_cbor_size));
+
+    OCByteString quakedata_out = {NULL, 0};
+    ASSERT_EQ(true, OCRepPayloadGetPropByteString((OCRepPayload*)payload_out, "quakedata", &quakedata_out));
+
+    // Compare input and output data
+    EXPECT_EQ(quakedata_in.len, quakedata_out.len);
+    EXPECT_EQ(0, memcmp(quakedata_in.bytes, quakedata_out.bytes, quakedata_in.len));
+
+    // Cleanup
+    OICFree(payload_cbor);
+    OICFree(quakedata_out.bytes);
+    OCPayloadDestroy((OCPayload*)payload_out);
+}
+
+TEST_F(CborByteStringTest, ByteStringArraySetGetTest )
+{
+    OCRepPayloadSetUri(payload_in, "/a/quake_sensor");
+    OCRepPayloadSetPropInt(payload_in, "scale", 4);
+
+    size_t dimensions_in[MAX_REP_ARRAY_DEPTH] = { 3, 0, 0};
+    uint8_t binval1[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19};
+    uint8_t binval2[] = {0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29};
+    uint8_t binval3[] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39};
+
+    OCByteString quakedata_in[3] = {{binval1, sizeof(binval1)},
+                                    {binval2, sizeof(binval2)},
+                                    {binval3, sizeof(binval3)}};
+
+    EXPECT_EQ(true, OCRepPayloadSetByteStringArray(payload_in, "quakedata",
+                quakedata_in, dimensions_in));
+
+    OCByteString* quakedata_out = NULL;
+    size_t dimensions_out[MAX_REP_ARRAY_DEPTH] = {0};
+    ASSERT_EQ(true, OCRepPayloadGetByteStringArray(payload_in, "quakedata",
+                &quakedata_out, dimensions_out));
+
+    for(size_t i = 0; i < dimensions_in[0]; i++)
+    {
+        EXPECT_EQ(quakedata_in[i].len, quakedata_out[i].len);
+        EXPECT_EQ(0, memcmp(quakedata_in[i].bytes, quakedata_out[i].bytes, quakedata_in[i].len));
+    }
+
+    // Cleanup
+    for(size_t i = 0; i < dimensions_out[0]; i++)
+    {
+        OICFree(quakedata_out[i].bytes);
+    }
+    OICFree(quakedata_out);
+}
+
+
+TEST_F(CborByteStringTest, ByteStringArrayConvertParseTest )
+{
+    OCRepPayloadSetUri(payload_in, "/a/quake_sensor");
+    OCRepPayloadSetPropInt(payload_in, "scale", 4);
+
+    size_t dimensions_in[MAX_REP_ARRAY_DEPTH] = { 3, 0, 0};
+    uint8_t binval1[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19};
+    uint8_t binval2[] = {0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29};
+    uint8_t binval3[] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39};
+
+    OCByteString quakedata_in[3] = {{binval1, sizeof(binval1)},
+                                    {binval2, sizeof(binval2)},
+                                    {binval3, sizeof(binval3)}};
+
+    EXPECT_EQ(true, OCRepPayloadSetByteStringArray(payload_in, "quakedata",
+                quakedata_in, dimensions_in));
+
+    // Convert OCPayload to CBOR
+    uint8_t *payload_cbor = NULL;
+    size_t payload_cbor_size = 0;
+    EXPECT_EQ(OC_STACK_OK, OCConvertPayload((OCPayload*) payload_in, &payload_cbor, &payload_cbor_size));
+#ifdef CBOR_BIN_STRING_DEBUG
+    FILE *fp = fopen("binstringarr.cbor", "wb+");
+    if (fp)
+    {
+        fwrite(payload_cbor, 1, payload_cbor_size, fp);
+        fclose(fp);
+    }
+#endif //CBOR_BIN_STRING_DEBUG
+
+    // Parse CBOR back to OCPayload
+    OCPayload* payload_out = NULL;
+    EXPECT_EQ(OC_STACK_OK, OCParsePayload(&payload_out, PAYLOAD_TYPE_REPRESENTATION,
+                payload_cbor, payload_cbor_size));
+
+    OCByteString* quakedata_out = NULL;
+    size_t dimensions_out[MAX_REP_ARRAY_DEPTH] = {0};
+    ASSERT_EQ(true, OCRepPayloadGetByteStringArray((OCRepPayload*)payload_out, "quakedata",
+                &quakedata_out, dimensions_out));
+
+    for(size_t i = 0; i < dimensions_in[0]; i++)
+    {
+        EXPECT_EQ(quakedata_in[i].len, quakedata_out[i].len);
+        EXPECT_EQ(0, memcmp(quakedata_in[i].bytes, quakedata_out[i].bytes, quakedata_in[i].len));
+    }
+
+    // Cleanup
+    OICFree(payload_cbor);
+    for(size_t i = 0; i < dimensions_out[0]; i++)
+    {
+        OICFree(quakedata_out[i].bytes);
+    }
+    OICFree(quakedata_out);
+
+    OCPayloadDestroy((OCPayload*)payload_out);
+}