Austin Hsieh | fb46917 | 2022-02-15 19:11:22 -0800 | [diff] [blame] | 1 | #include <jni.h> |
joonhaengHeo | 155917e | 2023-11-08 10:29:50 +0900 | [diff] [blame] | 2 | #include <lib/core/CHIPError.h> |
| 3 | #include <lib/core/TLV.h> |
Andrei Litvin | 377ac09 | 2022-09-14 16:16:41 -0400 | [diff] [blame] | 4 | #include <lib/support/JniReferences.h> |
joonhaengHeo | 155917e | 2023-11-08 10:29:50 +0900 | [diff] [blame] | 5 | #include <lib/support/JniTypeWrappers.h> |
Austin Hsieh | fb46917 | 2022-02-15 19:11:22 -0800 | [diff] [blame] | 6 | |
| 7 | #define JNI_METHOD(RETURN, CLASS_NAME, METHOD_NAME) \ |
| 8 | extern "C" JNIEXPORT RETURN JNICALL Java_chip_devicecontroller_ChipClusters_00024##CLASS_NAME##_##METHOD_NAME |
| 9 | |
joonhaengHeo | 155917e | 2023-11-08 10:29:50 +0900 | [diff] [blame] | 10 | #define CHIP_TLV_WRITER_BUFFER_SIZE 1024 |
| 11 | |
| 12 | jobject decodeValueFromTLV(JNIEnv * env, chip::TLV::TLVReader * data); |
| 13 | static CHIP_ERROR encodeTLVFromValue(JNIEnv * env, jobject jObject, chip::TLV::TLVWriter & writer, chip::TLV::Tag tag); |
| 14 | |
| 15 | jobject decodeValueFromTLV(JNIEnv * env, chip::TLV::TLVReader * data) |
Austin Hsieh | fb46917 | 2022-02-15 19:11:22 -0800 | [diff] [blame] | 16 | { |
joonhaengHeo | 155917e | 2023-11-08 10:29:50 +0900 | [diff] [blame] | 17 | chip::TLV::TLVType dataTLVType = data->GetType(); |
| 18 | switch (dataTLVType) |
Austin Hsieh | fb46917 | 2022-02-15 19:11:22 -0800 | [diff] [blame] | 19 | { |
joonhaengHeo | 155917e | 2023-11-08 10:29:50 +0900 | [diff] [blame] | 20 | case chip::TLV::kTLVType_SignedInteger: { |
| 21 | int64_t val; |
| 22 | CHIP_ERROR err = data->Get(val); |
| 23 | VerifyOrReturnValue( |
| 24 | err == CHIP_NO_ERROR, nullptr, |
| 25 | ChipLogError(Controller, "Error: TLV signed integer decoding failed : %" CHIP_ERROR_FORMAT, err.Format())); |
| 26 | jclass intTypeCls = env->FindClass("chip/devicecontroller/ChipTLVType$IntType"); |
| 27 | jmethodID constructor = env->GetMethodID(intTypeCls, "<init>", "(J)V"); |
| 28 | return env->NewObject(intTypeCls, constructor, static_cast<jlong>(val)); |
| 29 | } |
| 30 | case chip::TLV::kTLVType_UnsignedInteger: { |
| 31 | uint64_t val; |
| 32 | CHIP_ERROR err = data->Get(val); |
| 33 | VerifyOrReturnValue( |
| 34 | err == CHIP_NO_ERROR, nullptr, |
| 35 | ChipLogError(Controller, "Error: TLV unsigned integer decoding failed : %" CHIP_ERROR_FORMAT, err.Format())); |
| 36 | jclass uintTypeCls = env->FindClass("chip/devicecontroller/ChipTLVType$UIntType"); |
| 37 | jmethodID constructor = env->GetMethodID(uintTypeCls, "<init>", "(J)V"); |
| 38 | return env->NewObject(uintTypeCls, constructor, static_cast<jlong>(val)); |
| 39 | } |
| 40 | case chip::TLV::kTLVType_Boolean: { |
| 41 | bool val; |
| 42 | CHIP_ERROR err = data->Get(val); |
| 43 | VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, |
| 44 | ChipLogError(Controller, "Error: TLV boolean decoding failed : %" CHIP_ERROR_FORMAT, err.Format())); |
| 45 | jclass booleanTypeCls = env->FindClass("chip/devicecontroller/ChipTLVType$BooleanType"); |
| 46 | jmethodID constructor = env->GetMethodID(booleanTypeCls, "<init>", "(Z)V"); |
| 47 | return env->NewObject(booleanTypeCls, constructor, static_cast<jboolean>(val)); |
| 48 | } |
| 49 | case chip::TLV::kTLVType_FloatingPointNumber: { |
| 50 | // Try float first |
| 51 | float floatValue; |
| 52 | CHIP_ERROR err = data->Get(floatValue); |
| 53 | if (err == CHIP_NO_ERROR) |
| 54 | { |
| 55 | jclass floatTypeCls = env->FindClass("chip/devicecontroller/ChipTLVType$FloatType"); |
| 56 | jmethodID constructor = env->GetMethodID(floatTypeCls, "<init>", "(F)V"); |
| 57 | return env->NewObject(floatTypeCls, constructor, static_cast<jfloat>(floatValue)); |
| 58 | } |
| 59 | double val; |
| 60 | err = data->Get(val); |
| 61 | VerifyOrReturnValue( |
| 62 | err == CHIP_NO_ERROR, nullptr, |
| 63 | ChipLogError(Controller, "Error: TLV floating point decoding failed : %" CHIP_ERROR_FORMAT, err.Format())); |
| 64 | jclass doubleTypeCls = env->FindClass("chip/devicecontroller/ChipTLVType$DoubleType"); |
| 65 | jmethodID doubleConstructor = env->GetMethodID(doubleTypeCls, "<init>", "(D)V"); |
| 66 | return env->NewObject(doubleTypeCls, doubleConstructor, static_cast<jdouble>(val)); |
| 67 | } |
| 68 | case chip::TLV::kTLVType_UTF8String: { |
| 69 | chip::CharSpan stringValue; |
| 70 | CHIP_ERROR err = data->Get(stringValue); |
| 71 | VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, |
| 72 | ChipLogError(Controller, "Error: TLV UTF8String decoding failed : %" CHIP_ERROR_FORMAT, err.Format())); |
| 73 | chip::UtfString stringObj(env, stringValue); |
| 74 | jclass stringTypeCls = env->FindClass("chip/devicecontroller/ChipTLVType$StringType"); |
| 75 | jmethodID constructor = env->GetMethodID(stringTypeCls, "<init>", "(Ljava/lang/String;)V"); |
| 76 | return env->NewObject(stringTypeCls, constructor, stringObj.jniValue()); |
| 77 | } |
| 78 | case chip::TLV::kTLVType_ByteString: { |
| 79 | chip::ByteSpan bytesValue; |
| 80 | CHIP_ERROR err = data->Get(bytesValue); |
| 81 | VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, |
| 82 | ChipLogError(Controller, "Error: TLV ByteString decoding failed : %" CHIP_ERROR_FORMAT, err.Format())); |
| 83 | chip::ByteArray byteArrayObj(env, bytesValue); |
| 84 | jclass stringTypeCls = env->FindClass("chip/devicecontroller/ChipTLVType$ByteArrayType"); |
| 85 | jmethodID constructor = env->GetMethodID(stringTypeCls, "<init>", "([B)V"); |
| 86 | return env->NewObject(stringTypeCls, constructor, byteArrayObj.jniValue()); |
| 87 | } |
| 88 | case chip::TLV::kTLVType_Null: { |
| 89 | jclass nullTypeCls = env->FindClass("chip/devicecontroller/ChipTLVType$NullType"); |
| 90 | jmethodID constructor = env->GetMethodID(nullTypeCls, "<init>", "()V"); |
| 91 | return env->NewObject(nullTypeCls, constructor); |
| 92 | } |
| 93 | case chip::TLV::kTLVType_Structure: |
| 94 | case chip::TLV::kTLVType_Array: { |
| 95 | chip::TLV::TLVType tlvType; |
| 96 | CHIP_ERROR err = data->EnterContainer(tlvType); |
| 97 | VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, |
| 98 | ChipLogError(Controller, "Error: TLV container entering failed : %" CHIP_ERROR_FORMAT, err.Format())); |
| 99 | |
| 100 | jobject arrayLists; |
| 101 | err = chip::JniReferences::GetInstance().CreateArrayList(arrayLists); |
| 102 | VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, |
| 103 | ChipLogError(Controller, "Error: Create ArrayList object failed : %" CHIP_ERROR_FORMAT, err.Format())); |
| 104 | |
| 105 | while ((err = data->Next()) == CHIP_NO_ERROR) |
| 106 | { |
| 107 | chip::TLV::Tag tag = data->GetTag(); |
| 108 | jobject value = decodeValueFromTLV(env, data); |
| 109 | VerifyOrReturnValue( |
| 110 | value != nullptr, nullptr, |
| 111 | ChipLogError(Controller, "Error when decoding TLV container of type : %" CHIP_ERROR_FORMAT, err.Format())); |
| 112 | |
| 113 | jobject jValue = nullptr; |
| 114 | if (dataTLVType == chip::TLV::kTLVType_Structure) |
| 115 | { |
| 116 | uint64_t tagNum = TagNumFromTag(tag); |
| 117 | |
| 118 | jclass structElementCls = env->FindClass("chip/devicecontroller/ChipTLVType$StructElement"); |
| 119 | jmethodID constructor = |
| 120 | env->GetMethodID(structElementCls, "<init>", "(JLchip/devicecontroller/ChipTLVType$BaseTLVType;)V"); |
| 121 | |
| 122 | jValue = env->NewObject(structElementCls, constructor, static_cast<jlong>(tagNum), value); |
| 123 | } |
| 124 | else |
| 125 | { |
| 126 | jValue = value; |
| 127 | } |
| 128 | err = chip::JniReferences::GetInstance().AddToList(arrayLists, jValue); |
| 129 | VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, |
| 130 | ChipLogError(Controller, "Error: Add ArrayList object failed : %" CHIP_ERROR_FORMAT, err.Format())); |
| 131 | } |
| 132 | if (err != CHIP_END_OF_TLV) |
| 133 | { |
| 134 | ChipLogError(Controller, "Error: TLV container decoding failed: %" CHIP_ERROR_FORMAT, err.Format()); |
| 135 | return nullptr; |
| 136 | } |
| 137 | |
| 138 | err = data->ExitContainer(tlvType); |
| 139 | VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, |
| 140 | ChipLogError(Controller, "Error: TLV container exiting failed: %" CHIP_ERROR_FORMAT, err.Format())); |
| 141 | |
| 142 | jclass typeCls = nullptr; |
| 143 | if (dataTLVType == chip::TLV::kTLVType_Structure) |
| 144 | { |
| 145 | typeCls = env->FindClass("chip/devicecontroller/ChipTLVType$StructType"); |
| 146 | } |
| 147 | else |
| 148 | { |
| 149 | typeCls = env->FindClass("chip/devicecontroller/ChipTLVType$ArrayType"); |
| 150 | } |
| 151 | jmethodID constructor = env->GetMethodID(typeCls, "<init>", "(Ljava/util/ArrayList;)V"); |
| 152 | return env->NewObject(typeCls, constructor, arrayLists); |
| 153 | } |
| 154 | default: |
| 155 | ChipLogError(Controller, "Error: Unsupported TLV type for conversion : %u", data->GetType()); |
| 156 | return nullptr; |
Austin Hsieh | fb46917 | 2022-02-15 19:11:22 -0800 | [diff] [blame] | 157 | } |
| 158 | } |
Andrei Litvin | 377ac09 | 2022-09-14 16:16:41 -0400 | [diff] [blame] | 159 | |
joonhaengHeo | 155917e | 2023-11-08 10:29:50 +0900 | [diff] [blame] | 160 | static bool isEqualTLVType(JNIEnv * env, const char * typeName, jobject tlvType) |
Andrei Litvin | 377ac09 | 2022-09-14 16:16:41 -0400 | [diff] [blame] | 161 | { |
joonhaengHeo | 155917e | 2023-11-08 10:29:50 +0900 | [diff] [blame] | 162 | jclass tlvEnum = env->FindClass("chip/devicecontroller/ChipTLVType$TLVType"); |
Andrei Litvin | 377ac09 | 2022-09-14 16:16:41 -0400 | [diff] [blame] | 163 | |
joonhaengHeo | 155917e | 2023-11-08 10:29:50 +0900 | [diff] [blame] | 164 | jfieldID enumFieldID = env->GetStaticFieldID(tlvEnum, typeName, "Lchip/devicecontroller/ChipTLVType$TLVType;"); |
| 165 | jobject enumObj = env->GetStaticObjectField(tlvEnum, enumFieldID); |
Andrei Litvin | 377ac09 | 2022-09-14 16:16:41 -0400 | [diff] [blame] | 166 | |
joonhaengHeo | 155917e | 2023-11-08 10:29:50 +0900 | [diff] [blame] | 167 | jmethodID equalsMethodID = env->GetMethodID(tlvEnum, "equals", "(Ljava/lang/Object;)Z"); |
| 168 | |
| 169 | return (env->CallBooleanMethod(enumObj, equalsMethodID, tlvType) == JNI_TRUE); |
Andrei Litvin | 377ac09 | 2022-09-14 16:16:41 -0400 | [diff] [blame] | 170 | } |
| 171 | |
joonhaengHeo | 155917e | 2023-11-08 10:29:50 +0900 | [diff] [blame] | 172 | static CHIP_ERROR encodeTLVFromValue(JNIEnv * env, jobject jValue, chip::TLV::TLVWriter & writer, chip::TLV::Tag tag) |
Andrei Litvin | 377ac09 | 2022-09-14 16:16:41 -0400 | [diff] [blame] | 173 | { |
joonhaengHeo | 155917e | 2023-11-08 10:29:50 +0900 | [diff] [blame] | 174 | jmethodID getTypeMethod = nullptr; |
| 175 | jmethodID getValueMethod = nullptr; |
| 176 | ReturnLogErrorOnFailure(chip::JniReferences::GetInstance().FindMethod( |
| 177 | env, jValue, "type", "()Lchip/devicecontroller/ChipTLVType$TLVType;", &getTypeMethod)); |
Andrei Litvin | 377ac09 | 2022-09-14 16:16:41 -0400 | [diff] [blame] | 178 | |
joonhaengHeo | 155917e | 2023-11-08 10:29:50 +0900 | [diff] [blame] | 179 | jobject jType = env->CallObjectMethod(jValue, getTypeMethod); |
| 180 | if (jType == nullptr) |
| 181 | { |
| 182 | ChipLogError(Controller, "Error: Object to encode is corrupt"); |
| 183 | return CHIP_ERROR_INVALID_ARGUMENT; |
| 184 | } |
| 185 | if (isEqualTLVType(env, "UInt", jType)) |
| 186 | { |
| 187 | jclass typeClass = env->FindClass("chip/devicecontroller/ChipTLVType$UIntType"); |
| 188 | VerifyOrReturnError(typeClass != nullptr, CHIP_JNI_ERROR_TYPE_NOT_FOUND); |
| 189 | getValueMethod = env->GetMethodID(typeClass, "value", "()J"); |
| 190 | VerifyOrReturnError(getValueMethod != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); |
Andrei Litvin | 377ac09 | 2022-09-14 16:16:41 -0400 | [diff] [blame] | 191 | |
joonhaengHeo | 155917e | 2023-11-08 10:29:50 +0900 | [diff] [blame] | 192 | jlong value = env->CallLongMethod(jValue, getValueMethod); |
| 193 | VerifyOrReturnLogError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); |
| 194 | |
| 195 | return writer.Put(tag, static_cast<uint64_t>(value)); |
Andrei Litvin | 377ac09 | 2022-09-14 16:16:41 -0400 | [diff] [blame] | 196 | } |
joonhaengHeo | 155917e | 2023-11-08 10:29:50 +0900 | [diff] [blame] | 197 | if (isEqualTLVType(env, "Int", jType)) |
Andrei Litvin | 377ac09 | 2022-09-14 16:16:41 -0400 | [diff] [blame] | 198 | { |
joonhaengHeo | 155917e | 2023-11-08 10:29:50 +0900 | [diff] [blame] | 199 | jclass typeClass = env->FindClass("chip/devicecontroller/ChipTLVType$IntType"); |
| 200 | VerifyOrReturnError(typeClass != nullptr, CHIP_JNI_ERROR_TYPE_NOT_FOUND); |
| 201 | getValueMethod = env->GetMethodID(typeClass, "value", "()J"); |
| 202 | VerifyOrReturnError(getValueMethod != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); |
| 203 | |
| 204 | jlong value = env->CallLongMethod(jValue, getValueMethod); |
| 205 | VerifyOrReturnLogError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); |
| 206 | |
| 207 | return writer.Put(tag, static_cast<int64_t>(value)); |
Andrei Litvin | 377ac09 | 2022-09-14 16:16:41 -0400 | [diff] [blame] | 208 | } |
joonhaengHeo | 155917e | 2023-11-08 10:29:50 +0900 | [diff] [blame] | 209 | if (isEqualTLVType(env, "Boolean", jType)) |
| 210 | { |
| 211 | jclass typeClass = env->FindClass("chip/devicecontroller/ChipTLVType$BooleanType"); |
| 212 | VerifyOrReturnError(typeClass != nullptr, CHIP_JNI_ERROR_TYPE_NOT_FOUND); |
| 213 | getValueMethod = env->GetMethodID(typeClass, "value", "()Z"); |
| 214 | VerifyOrReturnError(getValueMethod != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); |
| 215 | |
| 216 | jboolean value = env->CallBooleanMethod(jValue, getValueMethod); |
| 217 | VerifyOrReturnLogError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); |
| 218 | |
| 219 | return writer.Put(tag, static_cast<bool>(value)); |
| 220 | } |
| 221 | if (isEqualTLVType(env, "Float", jType)) |
| 222 | { |
| 223 | jclass typeClass = env->FindClass("chip/devicecontroller/ChipTLVType$FloatType"); |
| 224 | VerifyOrReturnError(typeClass != nullptr, CHIP_JNI_ERROR_TYPE_NOT_FOUND); |
| 225 | getValueMethod = env->GetMethodID(typeClass, "value", "()F"); |
| 226 | VerifyOrReturnError(getValueMethod != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); |
| 227 | |
| 228 | jfloat value = env->CallFloatMethod(jValue, getValueMethod); |
| 229 | VerifyOrReturnLogError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); |
| 230 | |
| 231 | return writer.Put(tag, static_cast<float>(value)); |
| 232 | } |
| 233 | if (isEqualTLVType(env, "Double", jType)) |
| 234 | { |
| 235 | jclass typeClass = env->FindClass("chip/devicecontroller/ChipTLVType$DoubleType"); |
| 236 | VerifyOrReturnError(typeClass != nullptr, CHIP_JNI_ERROR_TYPE_NOT_FOUND); |
| 237 | getValueMethod = env->GetMethodID(typeClass, "value", "()D"); |
| 238 | VerifyOrReturnError(getValueMethod != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); |
| 239 | |
| 240 | jdouble value = env->CallDoubleMethod(jValue, getValueMethod); |
| 241 | VerifyOrReturnLogError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); |
| 242 | |
| 243 | return writer.Put(tag, static_cast<double>(value)); |
| 244 | } |
| 245 | if (isEqualTLVType(env, "Null", jType)) |
| 246 | { |
| 247 | return writer.PutNull(tag); |
| 248 | } |
| 249 | if (isEqualTLVType(env, "String", jType)) |
| 250 | { |
| 251 | jclass typeClass = env->FindClass("chip/devicecontroller/ChipTLVType$StringType"); |
| 252 | VerifyOrReturnError(typeClass != nullptr, CHIP_JNI_ERROR_TYPE_NOT_FOUND); |
| 253 | getValueMethod = env->GetMethodID(typeClass, "value", "()Ljava/lang/String;"); |
| 254 | VerifyOrReturnError(getValueMethod != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); |
| 255 | |
| 256 | jstring value = (jstring) env->CallObjectMethod(jValue, getValueMethod); |
| 257 | VerifyOrReturnLogError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); |
| 258 | |
| 259 | chip::JniUtfString jniString(env, value); |
| 260 | |
| 261 | return writer.PutString(tag, jniString.c_str()); |
| 262 | } |
| 263 | if (isEqualTLVType(env, "ByteArray", jType)) |
| 264 | { |
| 265 | jclass typeClass = env->FindClass("chip/devicecontroller/ChipTLVType$ByteArrayType"); |
| 266 | VerifyOrReturnError(typeClass != nullptr, CHIP_JNI_ERROR_TYPE_NOT_FOUND); |
| 267 | getValueMethod = env->GetMethodID(typeClass, "value", "()[B"); |
| 268 | VerifyOrReturnError(getValueMethod != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); |
| 269 | |
| 270 | jbyteArray value = (jbyteArray) env->CallObjectMethod(jValue, getValueMethod); |
| 271 | VerifyOrReturnLogError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); |
| 272 | |
| 273 | chip::JniByteArray jniByteArray(env, value); |
| 274 | |
| 275 | return writer.Put(tag, jniByteArray.byteSpan()); |
| 276 | } |
| 277 | if (isEqualTLVType(env, "Struct", jType)) |
| 278 | { |
| 279 | jmethodID getSizeMethod = nullptr; |
| 280 | |
| 281 | jclass typeClass = env->FindClass("chip/devicecontroller/ChipTLVType$StructType"); |
| 282 | VerifyOrReturnError(typeClass != nullptr, CHIP_JNI_ERROR_TYPE_NOT_FOUND); |
| 283 | getSizeMethod = env->GetMethodID(typeClass, "size", "()I"); |
| 284 | VerifyOrReturnError(getSizeMethod != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); |
| 285 | getValueMethod = env->GetMethodID(typeClass, "value", "(I)Lchip/devicecontroller/ChipTLVType$StructElement;"); |
| 286 | VerifyOrReturnError(getValueMethod != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); |
| 287 | |
| 288 | jclass elementClass = env->FindClass("chip/devicecontroller/ChipTLVType$StructElement"); |
| 289 | VerifyOrReturnError(elementClass != nullptr, CHIP_JNI_ERROR_TYPE_NOT_FOUND); |
| 290 | jmethodID getcontextTagNumMethod = env->GetMethodID(elementClass, "contextTagNum", "()J"); |
| 291 | VerifyOrReturnError(getcontextTagNumMethod != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); |
| 292 | jmethodID getElementValueMethod = |
| 293 | env->GetMethodID(elementClass, "value", "()Lchip/devicecontroller/ChipTLVType$BaseTLVType;"); |
| 294 | VerifyOrReturnError(getElementValueMethod != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); |
| 295 | |
| 296 | jint size = env->CallIntMethod(jValue, getSizeMethod); |
| 297 | VerifyOrReturnLogError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); |
| 298 | |
| 299 | chip::TLV::TLVType outer; |
| 300 | ReturnErrorOnFailure(writer.StartContainer(tag, chip::TLV::kTLVType_Structure, outer)); |
| 301 | for (int i = 0; i < static_cast<int>(size); i++) |
| 302 | { |
| 303 | jobject eachElement = env->CallObjectMethod(jValue, getValueMethod, static_cast<jint>(i)); |
| 304 | VerifyOrReturnLogError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); |
| 305 | |
| 306 | jlong jEachTag = env->CallLongMethod(eachElement, getcontextTagNumMethod); |
| 307 | VerifyOrReturnLogError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); |
| 308 | |
| 309 | jobject jEachValue = env->CallObjectMethod(eachElement, getElementValueMethod); |
| 310 | VerifyOrReturnLogError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); |
| 311 | |
| 312 | uint64_t tagValue = static_cast<uint64_t>(jEachTag); |
| 313 | chip::TLV::Tag innerTag = chip::TLV::ContextTag(static_cast<uint8_t>(tagValue)); |
| 314 | ReturnErrorOnFailure(encodeTLVFromValue(env, jEachValue, writer, innerTag)); |
| 315 | } |
| 316 | ReturnErrorOnFailure(writer.EndContainer(outer)); |
| 317 | return CHIP_NO_ERROR; |
| 318 | } |
| 319 | if (isEqualTLVType(env, "Array", jType)) |
| 320 | { |
| 321 | jmethodID getSizeMethod = nullptr; |
| 322 | |
| 323 | jclass typeClass = env->FindClass("chip/devicecontroller/ChipTLVType$ArrayType"); |
| 324 | VerifyOrReturnError(typeClass != nullptr, CHIP_JNI_ERROR_TYPE_NOT_FOUND); |
| 325 | |
| 326 | getSizeMethod = env->GetMethodID(typeClass, "size", "()I"); |
| 327 | VerifyOrReturnError(getSizeMethod != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); |
| 328 | getValueMethod = env->GetMethodID(typeClass, "value", "(I)Lchip/devicecontroller/ChipTLVType$BaseTLVType;"); |
| 329 | VerifyOrReturnError(getValueMethod != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND); |
| 330 | |
| 331 | jint size = env->CallIntMethod(jValue, getSizeMethod); |
| 332 | VerifyOrReturnLogError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); |
| 333 | |
| 334 | chip::TLV::TLVType outer; |
| 335 | ReturnErrorOnFailure(writer.StartContainer(tag, chip::TLV::kTLVType_Array, outer)); |
| 336 | for (int i = 0; i < static_cast<int>(size); i++) |
| 337 | { |
| 338 | jobject eachValue = env->CallObjectMethod(jValue, getValueMethod, static_cast<jint>(i)); |
| 339 | VerifyOrReturnLogError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN); |
| 340 | |
| 341 | ReturnErrorOnFailure(encodeTLVFromValue(env, eachValue, writer, chip::TLV::AnonymousTag())); |
| 342 | } |
| 343 | ReturnErrorOnFailure(writer.EndContainer(outer)); |
| 344 | return CHIP_NO_ERROR; |
| 345 | } |
| 346 | if (isEqualTLVType(env, "Empty", jType)) |
| 347 | { |
| 348 | // For optional Value |
| 349 | return CHIP_NO_ERROR; |
| 350 | } |
| 351 | |
| 352 | ChipLogError(Controller, "Error: Unsupported type to encode"); |
| 353 | return CHIP_ERROR_INVALID_ARGUMENT; |
| 354 | } |
| 355 | |
| 356 | JNI_METHOD(jbyteArray, BaseChipCluster, encodeToTlv)(JNIEnv * env, jclass clazz, jobject value) |
| 357 | { |
| 358 | VerifyOrReturnValue(value != nullptr, nullptr, ChipLogError(Controller, "invalid parameter: value is null")); |
| 359 | chip::TLV::TLVWriter writer; |
| 360 | uint8_t buffer[CHIP_TLV_WRITER_BUFFER_SIZE]; |
| 361 | jbyteArray tlv = nullptr; |
| 362 | writer.Init(buffer, sizeof(buffer)); |
| 363 | |
| 364 | CHIP_ERROR err = encodeTLVFromValue(env, value, writer, chip::TLV::AnonymousTag()); |
| 365 | VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, ChipLogError(Controller, "Encode Error: %" CHIP_ERROR_FORMAT, err.Format())); |
| 366 | |
joonhaengHeo | f3b7808 | 2024-01-05 00:02:18 +0900 | [diff] [blame] | 367 | err = chip::JniReferences::GetInstance().N2J_ByteArray(env, buffer, static_cast<jint>(writer.GetLengthWritten()), tlv); |
joonhaengHeo | 155917e | 2023-11-08 10:29:50 +0900 | [diff] [blame] | 368 | VerifyOrReturnValue(err == CHIP_NO_ERROR, nullptr, ChipLogError(Controller, "JNI Error: %" CHIP_ERROR_FORMAT, err.Format())); |
| 369 | |
| 370 | return tlv; |
| 371 | } |
| 372 | |
| 373 | JNI_METHOD(jobject, BaseChipCluster, decodeFromTlv)(JNIEnv * env, jclass clazz, jbyteArray tlvBytesObj) |
| 374 | { |
| 375 | VerifyOrReturnValue(tlvBytesObj != nullptr, nullptr, ChipLogError(Controller, "invalid parameter: tlvBytesObj is null")); |
| 376 | chip::JniByteArray tlvBytesObjBytes(env, tlvBytesObj); |
| 377 | |
| 378 | chip::TLV::TLVReader reader; |
| 379 | reader.Init(tlvBytesObjBytes.byteSpan()); |
| 380 | VerifyOrReturnValue(reader.Next() == CHIP_NO_ERROR, nullptr, ChipLogError(Controller, "TLV Parsing is wrong")); |
| 381 | |
| 382 | return decodeValueFromTLV(env, &reader); |
Andrei Litvin | 377ac09 | 2022-09-14 16:16:41 -0400 | [diff] [blame] | 383 | } |