Prechádzať zdrojové kódy

JSON: support nanoseconds when encosing/decoding DateTime

The OPC UA specification 1.04 part 6 at paragraph 5.4.2.6 does not
define any restrictions of the fraction part of ISO 8601. To support
the whole precison of DateTime we need to support at least 100ns.
Patrick Gansterer 6 rokov pred
rodič
commit
932b9e1a09

+ 31 - 35
src/ua_types_encoding_json.c

@@ -52,7 +52,7 @@
 #define UA_EXPANDEDNODEID_SERVERINDEX_FLAG 0x40
 #define UA_EXPANDEDNODEID_NAMESPACEURI_FLAG 0x80
 
-#define UA_JSON_DATETIME_LENGTH 24
+#define UA_JSON_DATETIME_LENGTH 30
 
 /* Max length of numbers for the allocation of temp buffers. Don't forget that
  * printf adds an additional \0 at the end!
@@ -747,41 +747,37 @@ printNumber(u16 n, u8 *pos, size_t digits) {
     }
 }
 
-UA_String
-UA_DateTime_toJSON(UA_DateTime t) {
-    UA_DateTimeStruct tSt = UA_DateTime_toStruct(t);
-
-    /* Format: yyyy-MM-dd'T'HH:mm:ss.SSS'Z' is used. 24 bytes.*/
-    UA_String str = {UA_JSON_DATETIME_LENGTH, 
-        (u8*) UA_malloc(UA_JSON_DATETIME_LENGTH)};
-    if(!str.data)
-        return UA_STRING_NULL;
-    
-    printNumber(tSt.year, str.data, 4);
-    str.data[4] = '-';
-    printNumber(tSt.month, &str.data[5], 2);
-    str.data[7] = '-';
-    printNumber(tSt.day, &str.data[8], 2);
-    str.data[10] = 'T';
-    printNumber(tSt.hour, &str.data[11], 2);
-    str.data[13] = ':';
-    printNumber(tSt.min, &str.data[14], 2);
-    str.data[16] = ':';
-    printNumber(tSt.sec, &str.data[17], 2);
-    str.data[19] = '.';
-    printNumber(tSt.milliSec, &str.data[20], 3);
-    str.data[23] = 'Z';
-    return str;
-}
-
 ENCODE_JSON(DateTime) {
-    if(ctx->pos + UA_JSON_DATETIME_LENGTH > ctx->end)
-        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
-    
-    UA_String str = UA_DateTime_toJSON(*src);
-    UA_StatusCode ret = ENCODE_DIRECT_JSON(&str, String);
-    UA_String_deleteMembers(&str);
-    return ret;
+    UA_DateTimeStruct tSt = UA_DateTime_toStruct(*src);
+
+    /* Format: yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS'Z' is used. max 30 bytes.*/
+    UA_Byte buffer[UA_JSON_DATETIME_LENGTH];
+
+    printNumber(tSt.year, &buffer[0], 4);
+    buffer[4] = '-';
+    printNumber(tSt.month, &buffer[5], 2);
+    buffer[7] = '-';
+    printNumber(tSt.day, &buffer[8], 2);
+    buffer[10] = 'T';
+    printNumber(tSt.hour, &buffer[11], 2);
+    buffer[13] = ':';
+    printNumber(tSt.min, &buffer[14], 2);
+    buffer[16] = ':';
+    printNumber(tSt.sec, &buffer[17], 2);
+    buffer[19] = '.';
+    printNumber(tSt.milliSec, &buffer[20], 3);
+    printNumber(tSt.microSec, &buffer[23], 3);
+    printNumber(tSt.nanoSec, &buffer[26], 3);
+
+    size_t length = 28;
+    while (buffer[length] == '0')
+        length--;
+    if (length != 19)
+         length++;
+
+    buffer[length] = 'Z';
+    UA_String str = {length + 1, buffer};
+    return ENCODE_DIRECT_JSON(&str, String);
 }
 
 /* NodeId */

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 32 - 8
tests/check_types_builtin_json.c


+ 2 - 2
tests/pubsub/check_pubsub_encoding_json.c

@@ -79,7 +79,7 @@ START_TEST(UA_PubSub_EncodeAllOptionalFields) {
     m.payload.dataSetPayload.dataSetMessages[0].data.keyFrameData.dataSetFields[0].hasValue = true;
 
     size_t size = UA_NetworkMessage_calcSizeJson(&m, NULL, 0, NULL, 0, true);
-    ck_assert(size == 338);
+    ck_assert_int_eq(size, 342);
 
     UA_ByteString buffer;
     UA_StatusCode rv = UA_ByteString_allocBuffer(&buffer, size+1);
@@ -95,7 +95,7 @@ START_TEST(UA_PubSub_EncodeAllOptionalFields) {
     // then
     ck_assert_int_eq(rv, UA_STATUSCODE_GOOD);
 
-    char* result = "{\"MessageId\":\"ABCDEFGH\",\"MessageType\":\"ua-data\",\"PublisherId\":65535,\"DataSetClassId\":\"00000001-0002-0003-0000-000000000000\",\"Messages\":[{\"DataSetWriterId\":12345,\"SequenceNumber\":4711,\"MetaDataVersion\":{\"MajorVersion\":42,\"MinorVersion\":7},\"Timestamp\":\"1601-01-13T20:38:32.111Z\",\"Status\":2764857,\"Payload\":{\"Field1\":{\"Type\":7,\"Body\":27}}}]}";
+    char* result = "{\"MessageId\":\"ABCDEFGH\",\"MessageType\":\"ua-data\",\"PublisherId\":65535,\"DataSetClassId\":\"00000001-0002-0003-0000-000000000000\",\"Messages\":[{\"DataSetWriterId\":12345,\"SequenceNumber\":4711,\"MetaDataVersion\":{\"MajorVersion\":42,\"MinorVersion\":7},\"Timestamp\":\"1601-01-13T20:38:32.1111111Z\",\"Status\":2764857,\"Payload\":{\"Field1\":{\"Type\":7,\"Body\":27}}}]}";
     ck_assert_str_eq(result, (char*)buffer.data);
 
     UA_ByteString_deleteMembers(&buffer);