From 04d50bb11e47b497f4e348cbb1abf134162e6c10 Mon Sep 17 00:00:00 2001 From: Todd Malsbary Date: Tue, 26 Apr 2016 13:41:55 -0700 Subject: [PATCH] Implement Binary String transit type in C++ stack The C stack got a Binary String component here: https://gerrit.iotivity.org/gerrit/#/c/2337/ This patch implements it in the C++ stack, and validates it in the unit test. Note that this patch does NOT do binary-string-array, but this patch should be able to demonstrate the effort involved. Change-Id: I2fd6341f3d84539c3ad5450279f1d755ba211fd6 Signed-off-by: Erich Keane Signed-off-by: Todd Malsbary Reviewed-on: https://gerrit.iotivity.org/gerrit/7937 Tested-by: jenkins-iotivity Reviewed-by: Tim Kourt Reviewed-by: Jon A. Cruz --- .../android_api/base/jni/JniOcRepresentation.cpp | 32 +++++++++++++++++++++ android/android_api/base/jni/JniOcRepresentation.h | 17 +++++++++++ .../org/iotivity/base/OcRepresentationTest.java | 12 ++++++++ .../java/org/iotivity/base/OcRepresentation.java | 6 ++++ resource/include/AttributeValue.h | 14 +++++++-- resource/include/OCRepresentation.h | 7 +++++ resource/src/OCRepresentation.cpp | 33 +++++++++++++++++++++- .../unittests/OCRepresentationEncodingTest.cpp | 4 +++ 8 files changed, 122 insertions(+), 3 deletions(-) diff --git a/android/android_api/base/jni/JniOcRepresentation.cpp b/android/android_api/base/jni/JniOcRepresentation.cpp index c3c37ad..c9cf0d3 100644 --- a/android/android_api/base/jni/JniOcRepresentation.cpp +++ b/android/android_api/base/jni/JniOcRepresentation.cpp @@ -729,6 +729,38 @@ JNIEXPORT void JNICALL Java_org_iotivity_base_OcRepresentation_setValueRepresent /* * Class: org_iotivity_base_OcRepresentation +* Method: setValueByteArray +* Signature: (Ljava/lang/String;[B)V +*/ +JNIEXPORT void JNICALL Java_org_iotivity_base_OcRepresentation_setValueByteArray +(JNIEnv *env, jobject thiz, jstring jKey, jbyteArray jValue) +{ + LOGD("OcRepresentation_setValueByteArray"); + if (!jKey) + { + ThrowOcException(OC_STACK_INVALID_PARAM, "key cannot be null"); + return; + } + + const jsize len = env->GetArrayLength(jValue); + jbyte* bytes = env->GetByteArrayElements(jValue, nullptr); + + std::vector value; + for (jsize i = 0; i < len; ++i) + { + value.push_back(static_cast(bytes[i])); + } + env->ReleaseByteArrayElements(jValue, bytes, JNI_ABORT); + + OCRepresentation *rep = JniOcRepresentation::getOCRepresentationPtr(env, thiz); + if (!rep) return; + + std::string key = env->GetStringUTFChars(jKey, nullptr); + rep->setValue(key, value); +} + +/* +* Class: org_iotivity_base_OcRepresentation * Method: addChild * Signature: (Lorg/iotivity/base/OcRepresentation;)V */ diff --git a/android/android_api/base/jni/JniOcRepresentation.h b/android/android_api/base/jni/JniOcRepresentation.h index ee8f222..e0a87b6 100644 --- a/android/android_api/base/jni/JniOcRepresentation.h +++ b/android/android_api/base/jni/JniOcRepresentation.h @@ -155,6 +155,15 @@ struct JObjectConverter : boost::static_visitor < jobject > } return repArr; } + jobject operator()(const std::vector& val) const + { + size_t len = val.size(); + jbyteArray jByteArray = env->NewByteArray(len); + if (!jByteArray) return nullptr; + const uint8_t* bytes = &val[0]; + env->SetByteArrayRegion(jByteArray, 0, len, reinterpret_cast(bytes)); + return jByteArray; + } // Nested sequences: jobject operator()(const std::vector>& val) const @@ -621,6 +630,14 @@ extern "C" { /* * Class: org_iotivity_base_OcRepresentation + * Method: setValueByteArray + * Signature: (Ljava/lang/String;[B)V + */ + JNIEXPORT void JNICALL Java_org_iotivity_base_OcRepresentation_setValueByteArray + (JNIEnv *, jobject, jstring, jbyteArray); + + /* + * Class: org_iotivity_base_OcRepresentation * Method: addChild * Signature: (Lorg/iotivity/base/OcRepresentation;)V */ diff --git a/android/android_api/base/src/androidTest/java/org/iotivity/base/OcRepresentationTest.java b/android/android_api/base/src/androidTest/java/org/iotivity/base/OcRepresentationTest.java index 8a7b93d..043eda0 100644 --- a/android/android_api/base/src/androidTest/java/org/iotivity/base/OcRepresentationTest.java +++ b/android/android_api/base/src/androidTest/java/org/iotivity/base/OcRepresentationTest.java @@ -309,6 +309,18 @@ public class OcRepresentationTest extends InstrumentationTestCase { rep.setValue(representationK, representationArrVEmpty); OcRepresentation[] representationArrVEmptyA = rep.getValue(representationK); assertEquals(representationArrVEmpty.length, representationArrVEmptyA.length); + + //byte + String byteK = "byteK"; + byte[] byteArrV = {1, 2, 3, 4, 0, 5, 6, 7}; + rep.setValue(byteK, byteArrV); + byte[] byteArrVa = rep.getValue(byteK); + assertTrue(Arrays.equals(byteArrV, byteArrVa)); + + byte[] byteArrVEmpty = {}; + rep.setValue(byteK, byteArrVEmpty); + byte[] byteArrVEmptyA = rep.getValue(byteK); + assertTrue(Arrays.equals(byteArrVEmpty, byteArrVEmptyA)); } public void testAttributeAccessBy2DType() throws OcException { diff --git a/android/android_api/base/src/main/java/org/iotivity/base/OcRepresentation.java b/android/android_api/base/src/main/java/org/iotivity/base/OcRepresentation.java index a752f09..0be617a 100644 --- a/android/android_api/base/src/main/java/org/iotivity/base/OcRepresentation.java +++ b/android/android_api/base/src/main/java/org/iotivity/base/OcRepresentation.java @@ -141,6 +141,10 @@ public class OcRepresentation { this.setValueRepresentation3DArray(key, value); } + public void setValue(String key, byte[] value) throws OcException { + this.setValueByteArray(key, value); + } + private native void setValueInteger(String key, int value) throws OcException; private native void setValueDouble(String key, double value) throws OcException; @@ -181,6 +185,8 @@ public class OcRepresentation { private native void setValueRepresentation3DArray(String key, OcRepresentation[][][] value) throws OcException; + private native void setValueByteArray(String key, byte[] value) throws OcException; + /** * @deprecated use {@link #getValue(String key)} instead. */ diff --git a/resource/include/AttributeValue.h b/resource/include/AttributeValue.h index 0506e0f..2bfb10b 100644 --- a/resource/include/AttributeValue.h +++ b/resource/include/AttributeValue.h @@ -76,7 +76,10 @@ namespace OC std::vector>>, std::vector>, - std::vector>> + std::vector>>, + + // used for binary data type + std::vector > AttributeValue; enum class AttributeType @@ -87,7 +90,8 @@ namespace OC Boolean, String, OCRepresentation, - Vector + Vector, + Binary }; template @@ -129,6 +133,12 @@ namespace OC constexpr static AttributeType type = AttributeType::OCRepresentation; }; + template<> + struct AttributeTypeConvert> + { + constexpr static AttributeType type = AttributeType::Binary; + }; + std::ostream& operator << (std::ostream& os, const AttributeType at); } #endif // OC_ATTRIBUTEVALUE_H_ diff --git a/resource/include/OCRepresentation.h b/resource/include/OCRepresentation.h index 4d1d24a..5f2071a 100644 --- a/resource/include/OCRepresentation.h +++ b/resource/include/OCRepresentation.h @@ -153,6 +153,13 @@ namespace OC m_values[str] = val; } + // using R-value(or universal ref depending) to move string and vector + template + void setValue(const std::string& str, T&& val) + { + m_values[str] = std::forward(val); + } + /** * Retrieve the attribute value associated with the supplied name * diff --git a/resource/src/OCRepresentation.cpp b/resource/src/OCRepresentation.cpp index 47dce71..8b0015b 100644 --- a/resource/src/OCRepresentation.cpp +++ b/resource/src/OCRepresentation.cpp @@ -431,6 +431,11 @@ namespace OC case AttributeType::Vector: getPayloadArray(root, val); break; + case AttributeType::Binary: + OCRepPayloadSetPropByteString(root, val.attrname().c_str(), + OCByteString{const_cast(val.getValue>().data()), + val.getValue>().size()}); + break; default: throw std::logic_error(std::string("Getpayload: Not Implemented") + std::to_string((int)val.type())); @@ -635,6 +640,12 @@ namespace OC case OCREP_PROP_ARRAY: setPayloadArray(val); break; + case OCREP_PROP_BYTE_STRING: + setValue(val->name, + std::vector + (val->ocByteStr.bytes, val->ocByteStr.bytes + val->ocByteStr.len) + ); + break; default: throw std::logic_error(std::string("Not Implemented!") + std::to_string((int)val->type)); @@ -841,6 +852,8 @@ namespace OC case AttributeType::Vector: os << "Vector"; break; + case AttributeType::Binary: + os<< "Binary"; } return os; } @@ -888,7 +901,13 @@ namespace OC }; template - struct type_info::value>::type> + struct type_info< + T, + typename std::enable_if< + is_vector::value && + !std::is_same::value + >::type + > { typedef T type; typedef typename type_info::base_type base_type; @@ -899,6 +918,18 @@ namespace OC type_info::depth; }; + // special case for binary data, which is a std::vector + template<> + struct type_info, void> + { + typedef std::vector type; + typedef std::vector base_type; + constexpr static AttributeType enum_type = AttributeType::Binary; + constexpr static AttributeType enum_base_type = AttributeType::Binary; + constexpr static size_t depth = 0; + }; + + struct type_introspection_visitor : boost::static_visitor<> { AttributeType type; diff --git a/resource/unittests/OCRepresentationEncodingTest.cpp b/resource/unittests/OCRepresentationEncodingTest.cpp index a1ca196..8c827c1 100644 --- a/resource/unittests/OCRepresentationEncodingTest.cpp +++ b/resource/unittests/OCRepresentationEncodingTest.cpp @@ -286,6 +286,8 @@ namespace OCRepresentationEncodingTest subRep.setValue("DoubleAttr", 3.333); subRep.setValue("BoolAttr", true); subRep.setValue("StringAttr", std::string("String attr")); + std::vector bin_data {5,3,4,5,6,0,34,2,4,5,6,3}; + subRep.setValue("BinaryAttr", bin_data); startRep.setValue("Sub", subRep); OC::MessageContainer mc1; @@ -315,6 +317,8 @@ namespace OCRepresentationEncodingTest EXPECT_EQ(3.333, newSubRep.getValue("DoubleAttr")); EXPECT_EQ(true, newSubRep.getValue("BoolAttr")); EXPECT_STREQ("String attr", newSubRep.getValue("StringAttr").c_str()); + EXPECT_EQ(bin_data, + newSubRep.getValue>("BinaryAttr")); OCPayloadDestroy(cparsed); } -- 2.7.4