From 263dfe154b215f527bea979aaa5fca941483b67a Mon Sep 17 00:00:00 2001 From: Habib Virji Date: Tue, 23 Feb 2016 00:45:29 +0000 Subject: [PATCH] Add collection payload to include each resource information separately Change-Id: I0692018c13d295d6a28d289819835c525dc08cf5 - Each resource information is stored separately. [{"href":"", "rt": "", "if":"", }, .. ] - Compared to previous approach where all resource where stored together. - It fixes issue related to checking map before finding value, duplicated information in the payload of rt and if. - Adds unit test when empty array is passed as a parameter. - Adds unit test for checking values not containing rt and itf. Jira-Issue: 923, 950, 962 Change-Id: I0692018c13d295d6a28d289819835c525dc08cf5 Signed-off-by: Habib Virji Reviewed-on: https://gerrit.iotivity.org/gerrit/5121 Tested-by: jenkins-iotivity Reviewed-by: Jihun Ha Reviewed-by: Jon A. Cruz Reviewed-by: Mushfiqul Islam Signed-off-by: youngman --- resource/csdk/stack/src/ocpayloadconvert.c | 91 +++++++----- resource/csdk/stack/src/ocpayloadparse.c | 156 ++++++++++++--------- .../unittests/OCRepresentationEncodingTest.cpp | 99 +++++++++++++ 3 files changed, 249 insertions(+), 97 deletions(-) diff --git a/resource/csdk/stack/src/ocpayloadconvert.c b/resource/csdk/stack/src/ocpayloadconvert.c index 85a36ce..a2035cf 100644 --- a/resource/csdk/stack/src/ocpayloadconvert.c +++ b/resource/csdk/stack/src/ocpayloadconvert.c @@ -704,51 +704,76 @@ static int64_t OCConvertRepPayload(OCRepPayload* payload, uint8_t* outPayload, s int64_t err = 0; cbor_encoder_init(&encoder, outPayload, *size, 0); - CborEncoder rootMap; - err = err | cbor_encoder_create_map(&encoder, &rootMap, CborIndefiniteLength); + CborEncoder rootMap ; - if (payload->types) + size_t arrayCount = 0; + for (OCRepPayload *temp = payload; temp; temp = temp->next) { - OC_LOG(INFO, TAG, "Payload has types or interfaces"); - char* joinedTypes = OCStringLLJoin(payload->types); - if (joinedTypes) - { - err = err | cbor_encode_text_string(&rootMap, OC_RSRVD_RESOURCE_TYPE, - sizeof(OC_RSRVD_RESOURCE_TYPE) - 1); - err = err | cbor_encode_text_string(&rootMap, joinedTypes, - strlen(joinedTypes)); - OICFree(joinedTypes); - } - else - { - return OC_STACK_NO_MEMORY; - } + arrayCount++; + } + CborEncoder rootArray; + if (arrayCount > 1) + { + err = err | cbor_encoder_create_array(&encoder, &rootArray, arrayCount); } - if (payload->interfaces) + + while (payload != NULL && (err == CborNoError)) { - char* joinedInterfaces = OCStringLLJoin(payload->interfaces); - if (joinedInterfaces) + err = err | cbor_encoder_create_map(((arrayCount == 1)? &encoder: &rootArray), + &rootMap, CborIndefiniteLength); + // Only in case of collection href is included. + if (arrayCount > 1 && payload->uri && strlen(payload->uri) > 0) { - err = err | cbor_encode_text_string(&rootMap, OC_RSRVD_INTERFACE, - sizeof(OC_RSRVD_INTERFACE) - 1); - err = err | cbor_encode_text_string(&rootMap, joinedInterfaces, - strlen(joinedInterfaces)); - OICFree(joinedInterfaces); + OC_LOG(INFO, TAG, "Payload has uri"); + err = err | cbor_encode_text_string(&rootMap, OC_RSRVD_HREF, + strlen(OC_RSRVD_HREF)); + err = err | cbor_encode_text_string(&rootMap, payload->uri, + strlen(payload->uri)); } - else + if (payload->types) { - return OC_STACK_NO_MEMORY; + OC_LOG(INFO, TAG, "Payload has types"); + char* joinedTypes = OCStringLLJoin(payload->types); + if (joinedTypes) + { + err = err | cbor_encode_text_string(&rootMap, OC_RSRVD_RESOURCE_TYPE, + strlen(OC_RSRVD_RESOURCE_TYPE)); + err = err | cbor_encode_text_string(&rootMap, joinedTypes, + strlen(joinedTypes)); + OICFree(joinedTypes); + } + else + { + return OC_STACK_NO_MEMORY; + } + } + if (payload->interfaces) + { + OC_LOG(INFO, TAG, "Payload has interfaces"); + char* joinedInterfaces = OCStringLLJoin(payload->interfaces); + if (joinedInterfaces) + { + err = err | cbor_encode_text_string(&rootMap, OC_RSRVD_INTERFACE, + strlen(OC_RSRVD_INTERFACE)); + err = err | cbor_encode_text_string(&rootMap, joinedInterfaces, + strlen(joinedInterfaces)); + OICFree(joinedInterfaces); + } + else + { + return OC_STACK_NO_MEMORY; + } } - } - while(payload != NULL && (err == 0 || err == CborErrorOutOfMemory)) - { err = err | OCConvertSingleRepPayload(&rootMap, payload); + err = err | cbor_encoder_close_container(((arrayCount == 1) ? &encoder: &rootArray), + &rootMap); payload = payload->next; } - - // Close main array - err = err | cbor_encoder_close_container(&encoder, &rootMap); + if (arrayCount > 1) + { + err = err | cbor_encoder_close_container(&encoder, &rootArray); + } return checkError(err, &encoder, outPayload, size); } diff --git a/resource/csdk/stack/src/ocpayloadparse.c b/resource/csdk/stack/src/ocpayloadparse.c index c045e14..1851d45 100644 --- a/resource/csdk/stack/src/ocpayloadparse.c +++ b/resource/csdk/stack/src/ocpayloadparse.c @@ -961,18 +961,29 @@ static bool OCParseSingleRepPayload(OCRepPayload** outPayload, CborValue *objMap } OCRepPayload* curPayload = *outPayload; - - size_t len; - CborValue repMap; + size_t len = 0; + CborValue repMap = *objMap; err = err || cbor_value_enter_container(objMap, &repMap); - - while(!err && cbor_value_is_valid(&repMap)) + while (!err && cbor_value_is_valid(&repMap)) { - char* name; - err = err || cbor_value_dup_text_string(&repMap, &name, &len, NULL); - err = err || cbor_value_advance(&repMap); + char *name = NULL; + if (cbor_value_is_text_string(&repMap)) + { + err = err || cbor_value_dup_text_string(&repMap, &name, &len, NULL); + err = err || cbor_value_advance(&repMap); + if (name && + ((0 == strcmp(OC_RSRVD_HREF, name)) || + (0 == strcmp(OC_RSRVD_RESOURCE_TYPE, name)) || + (0 == strcmp(OC_RSRVD_INTERFACE, name)))) + { + err = err || cbor_value_advance(&repMap); + OICFree(name); + continue; + } + } CborType type = cbor_value_get_type(&repMap); + switch(type) { case CborNullType: @@ -1053,10 +1064,11 @@ static bool OCParseSingleRepPayload(OCRepPayload** outPayload, CborValue *objMap } OICFree(name); } - - err = err || cbor_value_leave_container(objMap, &repMap); - - if(err) + if (cbor_value_is_container(objMap)) + { + err = err || cbor_value_leave_container(objMap, &repMap); + } + if (err) { OCRepPayloadDestroy(*outPayload); *outPayload = NULL; @@ -1066,7 +1078,7 @@ static bool OCParseSingleRepPayload(OCRepPayload** outPayload, CborValue *objMap return err; } -static OCStackResult OCParseRepPayload(OCPayload** outPayload, CborValue* rootMap) +static OCStackResult OCParseRepPayload(OCPayload** outPayload, CborValue* root) { if (!outPayload) { @@ -1075,64 +1087,83 @@ static OCStackResult OCParseRepPayload(OCPayload** outPayload, CborValue* rootMa OCRepPayload *rootPayload = NULL; OCRepPayload *curPayload = NULL; - OCRepPayload *temp = OCRepPayloadCreate(); - if (!temp) - { - return OC_STACK_NO_MEMORY; - } CborValue curVal; bool err = false; - size_t len; - err = err || cbor_value_map_find_value(rootMap, OC_RSRVD_RESOURCE_TYPE, &curVal); - if(cbor_value_is_text_string(&curVal)) + size_t len = 0; + CborValue rootMap = *root; + if (cbor_value_is_array(root)) + { + cbor_value_enter_container(root, &rootMap); + } + while (!err && cbor_value_is_valid(&rootMap)) { - char* allRt = NULL; - err = err || cbor_value_dup_text_string(&curVal, &allRt, &len, NULL); - if (allRt) + OCRepPayload *temp = OCRepPayloadCreate(); + if (!temp) { - char* savePtr; - char* curPtr = strtok_r(allRt, " ", &savePtr); - while (curPtr) + return OC_STACK_NO_MEMORY; + } + if (!err && cbor_value_is_map(&rootMap)) + { + err = err || cbor_value_map_find_value(&rootMap, OC_RSRVD_HREF, &curVal); + if (cbor_value_is_valid(&curVal)) { - char* trimmed = InPlaceStringTrim(curPtr); - if (trimmed[0] != '\0') + err = err || cbor_value_dup_text_string(&curVal, &temp->uri, &len, NULL); + } + } + if (!err && cbor_value_is_map(&rootMap)) + { + err = err || cbor_value_map_find_value(&rootMap, OC_RSRVD_RESOURCE_TYPE, &curVal); + if(cbor_value_is_text_string(&curVal)) + { + char* allRt = NULL; + err = err || cbor_value_dup_text_string(&curVal, &allRt, &len, NULL); + if (allRt) { - OCRepPayloadAddResourceType(temp, curPtr); + char* savePtr; + char* curPtr = strtok_r(allRt, " ", &savePtr); + while (curPtr) + { + char* trimmed = InPlaceStringTrim(curPtr); + if (trimmed[0] != '\0') + { + OCRepPayloadAddResourceType(temp, curPtr); + } + curPtr = strtok_r(NULL, " ", &savePtr); + } } - curPtr = strtok_r(NULL, " ", &savePtr); + OICFree(allRt); } } - OICFree(allRt); - } - - err = err || cbor_value_map_find_value(rootMap, OC_RSRVD_INTERFACE, &curVal); - if(cbor_value_is_text_string(&curVal)) - { - char* allIf = NULL; - err = err || cbor_value_dup_text_string(&curVal, &allIf, &len, NULL); - if (allIf) + if (!err && cbor_value_is_map(&rootMap)) { - char* savePtr; - char* curPtr = strtok_r(allIf, " ", &savePtr); - while (curPtr) + err = err || cbor_value_map_find_value(&rootMap, OC_RSRVD_INTERFACE, &curVal); + if(cbor_value_is_text_string(&curVal)) { - char* trimmed = InPlaceStringTrim(curPtr); - if (trimmed[0] != '\0') + char* allIf = NULL; + err = err || cbor_value_dup_text_string(&curVal, &allIf, &len, NULL); + if (allIf) { - OCRepPayloadAddInterface(temp, curPtr); + char* savePtr; + char* curPtr = strtok_r(allIf, " ", &savePtr); + while (curPtr) + { + char* trimmed = InPlaceStringTrim(curPtr); + if (trimmed[0] != '\0') + { + OCRepPayloadAddInterface(temp, curPtr); + } + curPtr = strtok_r(NULL, " ", &savePtr); + } } - curPtr = strtok_r(NULL, " ", &savePtr); + OICFree(allIf); } } - OICFree(allIf); - } - - while (!err && cbor_value_is_map(rootMap)) - { - err = err || OCParseSingleRepPayload(&temp, rootMap); - - if(rootPayload == NULL) + if (!err && cbor_value_is_map(&rootMap)) + { + err = err || OCParseSingleRepPayload(&temp, &rootMap); + } + if (rootPayload == NULL) { rootPayload = temp; curPayload = temp; @@ -1142,21 +1173,18 @@ static OCStackResult OCParseRepPayload(OCPayload** outPayload, CborValue* rootMa curPayload->next = temp; curPayload = curPayload->next; } - - if (cbor_value_is_valid(rootMap)) - { - err = err || cbor_value_advance(rootMap); - } - - if(err) + if (err) { OCRepPayloadDestroy(rootPayload); OC_LOG(ERROR, TAG, "CBOR error in ParseRepPayload"); return OC_STACK_MALFORMED_RESPONSE; } + if (cbor_value_is_array(&rootMap)) + { + err = err || cbor_value_advance(&rootMap); + } } - - *outPayload = (OCPayload*)rootPayload; + *outPayload = (OCPayload *)rootPayload; return OC_STACK_OK; } diff --git a/resource/unittests/OCRepresentationEncodingTest.cpp b/resource/unittests/OCRepresentationEncodingTest.cpp index e1b0807..edf695f 100644 --- a/resource/unittests/OCRepresentationEncodingTest.cpp +++ b/resource/unittests/OCRepresentationEncodingTest.cpp @@ -232,6 +232,38 @@ namespace OCRepresentationEncodingTest OCPayloadDestroy(cparsed); } + TEST(RepresentationEncoding, RepAttributeEmpty) + { + OC::OCRepresentation startRep; + std::vector iarr {}; + startRep["iarr"] = {}; + + OC::MessageContainer mc1; + mc1.addRepresentation(startRep); + + OCRepPayload* cstart = mc1.getPayload(); + EXPECT_EQ(PAYLOAD_TYPE_REPRESENTATION, cstart->base.type); + + uint8_t *cborData = NULL; + size_t cborSize = 0; + OCPayload *cparsed = NULL; + EXPECT_EQ(OC_STACK_OK, OCConvertPayload((OCPayload*)cstart, &cborData, &cborSize)); + EXPECT_EQ(OC_STACK_OK, OCParsePayload(&cparsed, PAYLOAD_TYPE_REPRESENTATION, + cborData, cborSize)); + OCPayloadDestroy((OCPayload*)cstart); + OICFree(cborData); + + OC::MessageContainer mc2; + mc2.setPayload(cparsed); + EXPECT_EQ(1u, mc2.representations().size()); + const OC::OCRepresentation& r = mc2.representations()[0]; + + std::vector iarr2 = r["iarr"]; + + EXPECT_EQ(iarr, iarr2); + OCPayloadDestroy(cparsed); + } + TEST(RepresentationEncoding, RepAttribute) { OC::OCRepresentation startRep; @@ -1148,4 +1180,71 @@ namespace OCRepresentationEncodingTest OCRepPayloadDestroy(payload); OCPayloadDestroy(cparsed); } + TEST(RepresentationEncodingRTandIF, TestPayloadContents) + { + OC::OCRepresentation subRep1; + std::vector types; + types.push_back("rt.firstitem"); + std::vector interfaces; + interfaces.push_back("if.firstitem"); + subRep1.setResourceTypes(types); + subRep1.setResourceInterfaces(interfaces); + subRep1.setNULL("NullAttr"); + subRep1.setValue("IntAttr", 77); + subRep1.setValue("DoubleAttr", 3.333); + subRep1.setValue("BoolAttr", true); + subRep1.setValue("StringAttr", std::string("String attr")); + + OC::MessageContainer mc1; + mc1.addRepresentation(subRep1); + + OCRepPayload *repPayload = mc1.getPayload(); + EXPECT_EQ(PAYLOAD_TYPE_REPRESENTATION, repPayload->base.type); + + uint8_t *cborData = NULL; + size_t cborSize = 0; + OCPayload *cparsed = NULL; + + EXPECT_EQ(OC_STACK_OK, OCConvertPayload((OCPayload*)repPayload, &cborData, &cborSize)); + EXPECT_EQ(OC_STACK_OK, OCParsePayload(&cparsed, PAYLOAD_TYPE_REPRESENTATION, + cborData, cborSize)); + + OCRepPayload *parsedPayload = (OCRepPayload *)cparsed; + EXPECT_EQ(NULL, parsedPayload->uri); + EXPECT_STREQ("rt.firstitem", parsedPayload->types->value); + EXPECT_EQ(NULL, parsedPayload->types->next); + EXPECT_STREQ("if.firstitem", parsedPayload->interfaces->value); + EXPECT_EQ(NULL, parsedPayload->interfaces->next); + + // To make sure rt and if are not duplicated. + EXPECT_STREQ("BoolAttr", parsedPayload->values->name); + EXPECT_EQ(true, parsedPayload->values->b); + EXPECT_EQ(OCREP_PROP_BOOL, parsedPayload->values->type); + parsedPayload->values = parsedPayload->values->next; + + EXPECT_STREQ("DoubleAttr", parsedPayload->values->name); + EXPECT_EQ(OCREP_PROP_DOUBLE, parsedPayload->values->type); + EXPECT_EQ(3.3330000000000002, parsedPayload->values->d); + parsedPayload->values = parsedPayload->values->next; + + EXPECT_STREQ("IntAttr", parsedPayload->values->name); + EXPECT_EQ(77, parsedPayload->values->i); + EXPECT_EQ(OCREP_PROP_INT, parsedPayload->values->type); + parsedPayload->values = parsedPayload->values->next; + + EXPECT_STREQ("NullAttr", parsedPayload->values->name); + EXPECT_EQ(OCREP_PROP_NULL, parsedPayload->values->type); + parsedPayload->values = parsedPayload->values->next; + + EXPECT_STREQ("StringAttr", parsedPayload->values->name); + EXPECT_STREQ("String attr", parsedPayload->values->str); + EXPECT_EQ(OCREP_PROP_STRING, parsedPayload->values->type); + parsedPayload->values = parsedPayload->values->next; + + EXPECT_EQ(NULL, parsedPayload->values); + + OICFree(cborData); + OCRepPayloadDestroy(repPayload); + OCPayloadDestroy(cparsed); + } } -- 2.7.4