min/max calls replaced with std::min/std::max
[public/netxms.git] / src / libnetxms / message.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
3** NetXMS Foundation Library
9674aefa 4** Copyright (C) 2003-2017 Victor Kirhenshtein
5039dede
AK
5**
6** This program is free software; you can redistribute it and/or modify
68f384ea
VK
7** it under the terms of the GNU Lesser General Public License as published
8** by the Free Software Foundation; either version 3 of the License, or
5039dede
AK
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
68f384ea 16** You should have received a copy of the GNU Lesser General Public License
5039dede
AK
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19**
20** File: message.cpp
21**
22**/
5039dede 23#include "libnetxms.h"
c7c23e6d 24#include <nxcpapi.h>
5c44534b 25#include <uthash.h>
9674aefa 26#include <zlib.h>
5039dede 27
5c44534b 28/**
934f53da
VK
29 * Calculate field size
30 */
b368969c 31static size_t CalculateFieldSize(NXCP_MESSAGE_FIELD *field, bool networkByteOrder)
5039dede 32{
818ebb6a 33 size_t nSize;
5039dede 34
b368969c 35 switch(field->type)
5039dede 36 {
b368969c 37 case NXCP_DT_INT32:
5039dede
AK
38 nSize = 12;
39 break;
b368969c
VK
40 case NXCP_DT_INT64:
41 case NXCP_DT_FLOAT:
5039dede
AK
42 nSize = 16;
43 break;
b368969c 44 case NXCP_DT_INT16:
5039dede
AK
45 nSize = 8;
46 break;
712b2760
VK
47 case NXCP_DT_INETADDR:
48 nSize = 32;
49 break;
b368969c
VK
50 case NXCP_DT_STRING:
51 case NXCP_DT_BINARY:
5c44534b 52 if (networkByteOrder)
b368969c 53 nSize = ntohl(field->df_string.length) + 12;
5039dede 54 else
b368969c 55 nSize = field->df_string.length + 12;
5039dede
AK
56 break;
57 default:
58 nSize = 8;
59 break;
60 }
61 return nSize;
62}
63
934f53da 64/**
5c44534b
VK
65 * Field hash map entry
66 */
67struct MessageField
68{
69 UT_hash_handle hh;
70 UINT32 id;
818ebb6a 71 size_t size;
b368969c 72 NXCP_MESSAGE_FIELD data;
5c44534b
VK
73};
74
75/**
76 * Create new hash entry wth given field size
77 */
818ebb6a 78inline MessageField *CreateMessageField(size_t fieldSize)
5c44534b 79{
b368969c 80 size_t entrySize = sizeof(MessageField) - sizeof(NXCP_MESSAGE_FIELD) + fieldSize;
818ebb6a 81 MessageField *entry = (MessageField *)calloc(1, entrySize);
5c44534b
VK
82 entry->size = entrySize;
83 return entry;
84}
85
86/**
b368969c 87 * Default constructor for NXCPMessage class
934f53da 88 */
b368969c 89NXCPMessage::NXCPMessage(int version)
5039dede 90{
5c44534b
VK
91 m_code = 0;
92 m_id = 0;
93 m_fields = NULL;
94 m_flags = 0;
95 m_version = version;
6be0a20b
VK
96 m_data = NULL;
97 m_dataSize = 0;
5039dede
AK
98}
99
56dd6325 100/**
3b89a4c1
VK
101 * Create message with given code and ID
102 */
103NXCPMessage::NXCPMessage(UINT16 code, UINT32 id, int version)
104{
105 m_code = code;
106 m_id = id;
107 m_fields = NULL;
108 m_flags = 0;
109 m_version = version;
110 m_data = NULL;
111 m_dataSize = 0;
112}
113
114/**
56dd6325
VK
115 * Create a copy of prepared CSCP message
116 */
b368969c 117NXCPMessage::NXCPMessage(NXCPMessage *msg)
5039dede 118{
b368969c
VK
119 m_code = msg->m_code;
120 m_id = msg->m_id;
121 m_flags = msg->m_flags;
122 m_version = msg->m_version;
5c44534b 123 m_fields = NULL;
5039dede 124
6be0a20b 125 if (m_flags & MF_BINARY)
5039dede 126 {
279d8695 127 m_dataSize = msg->m_dataSize;
b368969c 128 m_data = (BYTE *)nx_memdup(msg->m_data, m_dataSize);
6be0a20b
VK
129 }
130 else
131 {
279d8695
VK
132 m_data = NULL;
133 m_dataSize = 0;
134
6be0a20b 135 MessageField *entry, *tmp;
b368969c 136 HASH_ITER(hh, msg->m_fields, entry, tmp)
6be0a20b
VK
137 {
138 MessageField *f = (MessageField *)nx_memdup(entry, entry->size);
139 HASH_ADD_INT(m_fields, id, f);
140 }
5039dede
AK
141 }
142}
143
56dd6325 144/**
b368969c 145 * Create NXCPMessage object from received message
56dd6325 146 */
b368969c 147NXCPMessage::NXCPMessage(NXCP_MESSAGE *msg, int version)
5039dede 148{
b368969c
VK
149 m_flags = ntohs(msg->flags);
150 m_code = ntohs(msg->code);
151 m_id = ntohl(msg->id);
5c44534b
VK
152 m_version = version;
153 m_fields = NULL;
154
5039dede 155 // Parse data fields
6be0a20b 156 if (m_flags & MF_BINARY)
5039dede 157 {
b368969c 158 m_dataSize = (size_t)ntohl(msg->numFields);
3a1356ab 159 if ((m_flags & MF_COMPRESSED) && !(m_flags & MF_STREAM) && (m_version >= 4))
d3a20572
VK
160 {
161 m_flags &= ~MF_COMPRESSED; // clear "compressed" flag so it will not be mistakenly re-sent
162
163 z_stream stream;
164 stream.zalloc = Z_NULL;
165 stream.zfree = Z_NULL;
166 stream.opaque = Z_NULL;
d55f77c8 167 stream.avail_in = (UINT32)ntohl(msg->size) - NXCP_HEADER_SIZE - 4;
d3a20572
VK
168 stream.next_in = (BYTE *)msg + NXCP_HEADER_SIZE + 4;
169 if (inflateInit(&stream) != Z_OK)
170 {
171 nxlog_debug(6, _T("NXCPMessage: inflateInit() failed"));
172 return;
173 }
174
175 m_data = (BYTE *)malloc(m_dataSize);
176 stream.next_out = m_data;
d55f77c8 177 stream.avail_out = (UINT32)m_dataSize;
d3a20572
VK
178
179 if (inflate(&stream, Z_FINISH) != Z_STREAM_END)
180 {
181 inflateEnd(&stream);
182 TCHAR buffer[256];
183 nxlog_debug(6, _T("NXCPMessage: failed to decompress binary message %s with ID %d"), NXCPMessageCodeName(m_code, buffer), m_id);
184 return;
185 }
186 inflateEnd(&stream);
187 }
188 else
189 {
190 m_data = (BYTE *)nx_memdup(msg->fields, m_dataSize);
191 }
6be0a20b
VK
192 }
193 else
194 {
195 m_data = NULL;
196 m_dataSize = 0;
5039dede 197
9674aefa
VK
198 BYTE *msgData;
199 size_t msgDataSize;
200 if ((m_flags & MF_COMPRESSED) && (m_version >= 4))
201 {
202 m_flags &= ~MF_COMPRESSED; // clear "compressed" flag so it will not be mistakenly re-sent
203 msgDataSize = (size_t)ntohl(*((UINT32 *)((BYTE *)msg + NXCP_HEADER_SIZE))) - NXCP_HEADER_SIZE;
204
205 z_stream stream;
206 stream.zalloc = Z_NULL;
207 stream.zfree = Z_NULL;
208 stream.opaque = Z_NULL;
d55f77c8 209 stream.avail_in = (UINT32)ntohl(msg->size) - NXCP_HEADER_SIZE - 4;
9674aefa
VK
210 stream.next_in = (BYTE *)msg + NXCP_HEADER_SIZE + 4;
211 if (inflateInit(&stream) != Z_OK)
212 {
213 nxlog_debug(6, _T("NXCPMessage: inflateInit() failed"));
214 return;
215 }
216
217 msgData = (BYTE *)malloc(msgDataSize);
218 stream.next_out = msgData;
d55f77c8 219 stream.avail_out = (UINT32)msgDataSize;
9674aefa
VK
220
221 if (inflate(&stream, Z_FINISH) != Z_STREAM_END)
222 {
223 inflateEnd(&stream);
224 TCHAR buffer[256];
225 nxlog_debug(6, _T("NXCPMessage: failed to decompress message %s with ID %d"), NXCPMessageCodeName(m_code, buffer), m_id);
226 return;
227 }
228 inflateEnd(&stream);
229 }
230 else
231 {
232 msgData = (BYTE *)msg + NXCP_HEADER_SIZE;
233 msgDataSize = (size_t)ntohl(msg->size) - NXCP_HEADER_SIZE;
234 }
235
b368969c 236 int fieldCount = (int)ntohl(msg->numFields);
9674aefa 237 size_t pos = 0;
6be0a20b 238 for(int f = 0; f < fieldCount; f++)
5039dede 239 {
9674aefa 240 NXCP_MESSAGE_FIELD *field = (NXCP_MESSAGE_FIELD *)(msgData + pos);
6be0a20b
VK
241
242 // Validate position inside message
9674aefa 243 if (pos > msgDataSize - 8)
5039dede 244 break;
9674aefa 245 if ((pos > msgDataSize - 12) &&
b368969c 246 ((field->type == NXCP_DT_STRING) || (field->type == NXCP_DT_BINARY)))
5039dede 247 break;
6be0a20b 248
9674aefa 249 // Calculate and validate field size
6be0a20b 250 size_t fieldSize = CalculateFieldSize(field, true);
9674aefa 251 if (pos + fieldSize > msgDataSize)
5039dede 252 break;
6be0a20b
VK
253
254 // Create new entry
255 MessageField *entry = CreateMessageField(fieldSize);
256 entry->id = ntohl(field->fieldId);
257 memcpy(&entry->data, field, fieldSize);
258
259 // Convert values to host format
260 entry->data.fieldId = ntohl(entry->data.fieldId);
b368969c 261 switch(field->type)
6be0a20b 262 {
b368969c 263 case NXCP_DT_INT32:
6be0a20b
VK
264 entry->data.df_int32 = ntohl(entry->data.df_int32);
265 break;
b368969c 266 case NXCP_DT_INT64:
6be0a20b
VK
267 entry->data.df_int64 = ntohq(entry->data.df_int64);
268 break;
b368969c 269 case NXCP_DT_INT16:
6be0a20b
VK
270 entry->data.df_int16 = ntohs(entry->data.df_int16);
271 break;
b368969c 272 case NXCP_DT_FLOAT:
6be0a20b
VK
273 entry->data.df_real = ntohd(entry->data.df_real);
274 break;
b368969c 275 case NXCP_DT_STRING:
5039dede 276#if !(WORDS_BIGENDIAN)
b368969c 277 entry->data.df_string.length = ntohl(entry->data.df_string.length);
c62d158b 278 bswap_array_16(entry->data.df_string.value, entry->data.df_string.length / 2);
5039dede 279#endif
6be0a20b 280 break;
b368969c
VK
281 case NXCP_DT_BINARY:
282 entry->data.df_string.length = ntohl(entry->data.df_string.length);
6be0a20b 283 break;
712b2760
VK
284 case NXCP_DT_INETADDR:
285 if (entry->data.df_inetaddr.family == NXCP_AF_INET)
286 {
287 entry->data.df_inetaddr.addr.v4 = ntohl(entry->data.df_inetaddr.addr.v4);
288 }
289 break;
6be0a20b 290 }
5039dede 291
6be0a20b
VK
292 HASH_ADD_INT(m_fields, id, entry);
293
294 // Starting from version 2, all variables should be 8-byte aligned
295 if (m_version >= 2)
296 pos += fieldSize + ((8 - (fieldSize % 8)) & 7);
297 else
298 pos += fieldSize;
299 }
5c44534b 300
9674aefa
VK
301 if (msgData != (BYTE *)msg + NXCP_HEADER_SIZE)
302 free(msgData);
5039dede 303 }
5039dede
AK
304}
305
56dd6325 306/**
b368969c 307 * Destructor for NXCPMessage
56dd6325 308 */
b368969c 309NXCPMessage::~NXCPMessage()
5039dede 310{
b368969c 311 deleteAllFields();
9af93576 312 free(m_data);
5039dede
AK
313}
314
56dd6325 315/**
5c44534b 316 * Find field by ID
56dd6325 317 */
ca0a165b 318NXCP_MESSAGE_FIELD *NXCPMessage::find(UINT32 fieldId) const
5039dede 319{
5c44534b
VK
320 MessageField *entry;
321 HASH_FIND_INT(m_fields, &fieldId, entry);
322 return (entry != NULL) ? &entry->data : NULL;
5039dede
AK
323}
324
fb9441ee 325/**
4af351c7 326 * set variable
b368969c 327 * Argument size (data size) contains data length in bytes for DT_BINARY type
fb9441ee
VK
328 * and maximum number of characters for DT_STRING type (0 means no limit)
329 */
712b2760 330void *NXCPMessage::set(UINT32 fieldId, BYTE type, const void *value, bool isSigned, size_t size)
5039dede 331{
6be0a20b
VK
332 if (m_flags & MF_BINARY)
333 return NULL;
334
b368969c 335 size_t length;
8756ff63 336#if defined(UNICODE_UCS2) && defined(UNICODE)
b368969c 337#define __buffer value
8756ff63
VK
338#else
339 UCS2CHAR *__buffer;
5039dede
AK
340#endif
341
5c44534b
VK
342 // Create entry
343 MessageField *entry;
b368969c 344 switch(type)
5039dede 345 {
b368969c 346 case NXCP_DT_INT32:
5c44534b 347 entry = CreateMessageField(12);
b368969c 348 entry->data.df_int32 = *((const UINT32 *)value);
5039dede 349 break;
b368969c 350 case NXCP_DT_INT16:
5c44534b 351 entry = CreateMessageField(8);
b368969c 352 entry->data.df_int16 = *((const WORD *)value);
5039dede 353 break;
b368969c 354 case NXCP_DT_INT64:
5c44534b 355 entry = CreateMessageField(16);
b368969c 356 entry->data.df_int64 = *((const UINT64 *)value);
5039dede 357 break;
b368969c 358 case NXCP_DT_FLOAT:
5c44534b 359 entry = CreateMessageField(16);
b368969c 360 entry->data.df_real = *((const double *)value);
5039dede 361 break;
b368969c 362 case NXCP_DT_STRING:
5039dede 363#ifdef UNICODE
b368969c
VK
364 length = _tcslen((const TCHAR *)value);
365 if ((size > 0) && (length > size))
366 length = size;
8756ff63 367#ifndef UNICODE_UCS2 /* assume UNICODE_UCS4 */
b368969c
VK
368 __buffer = (UCS2CHAR *)malloc(length * 2 + 2);
369 ucs4_to_ucs2((WCHAR *)value, length, __buffer, length + 1);
5039dede
AK
370#endif
371#else /* not UNICODE */
b368969c
VK
372 __buffer = UCS2StringFromMBString((const char *)value);
373 length = (UINT32)ucs2_strlen(__buffer);
374 if ((size > 0) && (length > size))
375 length = size;
8756ff63 376#endif
b368969c
VK
377 entry = CreateMessageField(12 + length * 2);
378 entry->data.df_string.length = (UINT32)(length * 2);
379 memcpy(entry->data.df_string.value, __buffer, entry->data.df_string.length);
8756ff63
VK
380#if !defined(UNICODE_UCS2) || !defined(UNICODE)
381 free(__buffer);
5039dede
AK
382#endif
383 break;
b368969c
VK
384 case NXCP_DT_BINARY:
385 entry = CreateMessageField(12 + size);
de4af576
VK
386 entry->data.df_binary.length = (UINT32)size;
387 if ((entry->data.df_binary.length > 0) && (value != NULL))
388 memcpy(entry->data.df_binary.value, value, entry->data.df_binary.length);
5039dede 389 break;
712b2760
VK
390 case NXCP_DT_INETADDR:
391 entry = CreateMessageField(32);
d44496e3
VK
392 entry->data.df_inetaddr.family =
393 (((InetAddress *)value)->getFamily() == AF_INET) ? NXCP_AF_INET :
394 ((((InetAddress *)value)->getFamily() == AF_INET6) ? NXCP_AF_INET6 : NXCP_AF_UNSPEC);
712b2760
VK
395 entry->data.df_inetaddr.maskBits = (BYTE)((InetAddress *)value)->getMaskBits();
396 if (((InetAddress *)value)->getFamily() == AF_INET)
397 {
398 entry->data.df_inetaddr.addr.v4 = ((InetAddress *)value)->getAddressV4();
399 }
d44496e3 400 else if (((InetAddress *)value)->getFamily() == AF_INET6)
712b2760
VK
401 {
402 memcpy(entry->data.df_inetaddr.addr.v6, ((InetAddress *)value)->getAddressV6(), 16);
403 }
404 break;
5039dede
AK
405 default:
406 return NULL; // Invalid data type, unable to handle
407 }
8f238fd7
VK
408 entry->id = fieldId;
409 entry->data.fieldId = fieldId;
b368969c 410 entry->data.type = type;
712b2760
VK
411 if (isSigned)
412 entry->data.flags |= NXCP_MFF_SIGNED;
5c44534b
VK
413
414 // add or replace field
415 MessageField *curr;
8f238fd7 416 HASH_FIND_INT(m_fields, &fieldId, curr);
5c44534b 417 if (curr != NULL)
5039dede 418 {
5c44534b
VK
419 HASH_DEL(m_fields, curr);
420 free(curr);
5039dede 421 }
5c44534b 422 HASH_ADD_INT(m_fields, id, entry);
5039dede 423
b368969c 424 return (type == NXCP_DT_INT16) ? ((void *)((BYTE *)&entry->data + 6)) : ((void *)((BYTE *)&entry->data + 8));
8756ff63 425#undef __buffer
5039dede
AK
426}
427
56dd6325 428/**
712b2760 429 * Get field value
56dd6325 430 */
ca0a165b 431void *NXCPMessage::get(UINT32 fieldId, BYTE requiredType, BYTE *fieldType) const
5039dede 432{
b368969c 433 NXCP_MESSAGE_FIELD *field = find(fieldId);
5c44534b
VK
434 if (field == NULL)
435 return NULL; // No such field
5039dede 436
712b2760
VK
437 // Data type check exception - return IPv4 address as INT32 if requested
438 if ((requiredType == NXCP_DT_INT32) && (field->type == NXCP_DT_INETADDR) && (field->df_inetaddr.family == NXCP_AF_INET))
439 return &field->df_inetaddr.addr.v4;
440
5039dede 441 // Check data type
b368969c 442 if ((requiredType != 0xFF) && (field->type != requiredType))
5039dede
AK
443 return NULL;
444
8f238fd7 445 if (fieldType != NULL)
b368969c
VK
446 *fieldType = field->type;
447 return (field->type == NXCP_DT_INT16) ?
5c44534b
VK
448 ((void *)((BYTE *)field + 6)) :
449 ((void *)((BYTE *)field + 8));
5039dede
AK
450}
451
56dd6325 452/**
712b2760 453 * Get 16 bit field as boolean
d6bbfa4e 454 */
ca0a165b 455bool NXCPMessage::getFieldAsBoolean(UINT32 fieldId) const
d6bbfa4e 456{
8f238fd7
VK
457 BYTE type;
458 void *value = (void *)get(fieldId, 0xFF, &type);
459 if (value == NULL)
460 return false;
461
462 switch(type)
463 {
b368969c 464 case NXCP_DT_INT16:
8f238fd7 465 return *((UINT16 *)value) ? true : false;
b368969c 466 case NXCP_DT_INT32:
8f238fd7 467 return *((UINT32 *)value) ? true : false;
b368969c 468 case NXCP_DT_INT64:
8f238fd7
VK
469 return *((UINT64 *)value) ? true : false;
470 default:
471 return false;
472 }
d6bbfa4e
VK
473}
474
475/**
4101571e
VK
476 * Get data type of message field.
477 *
478 * @return field type or -1 if field with given ID does not exist
479 */
ca0a165b 480int NXCPMessage::getFieldType(UINT32 fieldId) const
4101571e 481{
b368969c
VK
482 NXCP_MESSAGE_FIELD *field = find(fieldId);
483 return (field != NULL) ? (int)field->type : -1;
4101571e
VK
484}
485
486/**
487 * get signed integer field
488 */
ca0a165b 489INT32 NXCPMessage::getFieldAsInt32(UINT32 fieldId) const
4101571e 490{
b368969c 491 char *value = (char *)get(fieldId, NXCP_DT_INT32);
4101571e
VK
492 return (value != NULL) ? *((INT32 *)value) : 0;
493}
494
495/**
496 * get unsigned integer field
56dd6325 497 */
ca0a165b 498UINT32 NXCPMessage::getFieldAsUInt32(UINT32 fieldId) const
5039dede 499{
b368969c 500 void *value = get(fieldId, NXCP_DT_INT32);
8f238fd7 501 return (value != NULL) ? *((UINT32 *)value) : 0;
5039dede
AK
502}
503
967893bb 504/**
4101571e
VK
505 * get signed 16-bit integer field
506 */
ca0a165b 507INT16 NXCPMessage::getFieldAsInt16(UINT32 fieldId) const
4101571e 508{
b368969c 509 void *value = get(fieldId, NXCP_DT_INT16);
4101571e
VK
510 return (value != NULL) ? *((INT16 *)value) : 0;
511}
512
513/**
514 * get unsigned 16-bit integer variable
967893bb 515 */
ca0a165b 516UINT16 NXCPMessage::getFieldAsUInt16(UINT32 fieldId) const
5039dede 517{
b368969c
VK
518 void *value = get(fieldId, NXCP_DT_INT16);
519 return value ? *((WORD *)value) : 0;
5039dede
AK
520}
521
967893bb 522/**
4101571e 523 * get signed 64-bit integer field
967893bb 524 */
ca0a165b 525INT64 NXCPMessage::getFieldAsInt64(UINT32 fieldId) const
5039dede 526{
b368969c 527 void *value = get(fieldId, NXCP_DT_INT64);
4101571e 528 return (value != NULL) ? *((INT64 *)value) : 0;
5039dede
AK
529}
530
967893bb 531/**
4101571e 532 * get unsigned 64-bit integer field
967893bb 533 */
ca0a165b 534UINT64 NXCPMessage::getFieldAsUInt64(UINT32 fieldId) const
5039dede 535{
b368969c
VK
536 void *value = get(fieldId, NXCP_DT_INT64);
537 return value ? *((UINT64 *)value) : 0;
5039dede
AK
538}
539
56dd6325 540/**
4af351c7 541 * get 64-bit floating point variable
56dd6325 542 */
ca0a165b 543double NXCPMessage::getFieldAsDouble(UINT32 fieldId) const
5039dede 544{
b368969c 545 void *value = get(fieldId, NXCP_DT_FLOAT);
4101571e 546 return (value != NULL) ? *((double *)value) : 0;
5039dede
AK
547}
548
56dd6325 549/**
8f238fd7
VK
550 * get time_t field
551 */
ca0a165b 552time_t NXCPMessage::getFieldAsTime(UINT32 fieldId) const
8f238fd7
VK
553{
554 BYTE type;
555 void *value = (void *)get(fieldId, 0xFF, &type);
556 if (value == NULL)
557 return 0;
558
559 switch(type)
560 {
b368969c 561 case NXCP_DT_INT32:
8f238fd7 562 return (time_t)(*((UINT32 *)value));
b368969c 563 case NXCP_DT_INT64:
8f238fd7
VK
564 return (time_t)(*((UINT64 *)value));
565 default:
566 return false;
567 }
568}
569
570/**
712b2760
VK
571 * Get field as inet address
572 */
ca0a165b 573InetAddress NXCPMessage::getFieldAsInetAddress(UINT32 fieldId) const
712b2760
VK
574{
575 NXCP_MESSAGE_FIELD *f = find(fieldId);
576 if (f == NULL)
577 return InetAddress();
578
579 if (f->type == NXCP_DT_INETADDR)
580 {
581 InetAddress a =
582 (f->df_inetaddr.family == NXCP_AF_INET) ?
583 InetAddress(f->df_inetaddr.addr.v4) :
d44496e3 584 ((f->df_inetaddr.family == NXCP_AF_INET6) ? InetAddress(f->df_inetaddr.addr.v6) : InetAddress());
712b2760
VK
585 a.setMaskBits(f->df_inetaddr.maskBits);
586 return a;
587 }
588 else if (f->type == NXCP_DT_INT32)
589 {
590 return InetAddress(f->df_uint32);
591 }
592 return InetAddress();
593}
594
ce9e00cc
VK
595/*
596 * Get field as MAC address
597 */
598MacAddress NXCPMessage::getFieldAsMacAddress(UINT32 fieldId) const
599{
600 NXCP_MESSAGE_FIELD *f = find(fieldId);
601
602 if (f == NULL || !((f->type == NXCP_DT_BINARY) && (f->df_binary.length <= 8)))
603 return MacAddress();
604
605 return MacAddress(f->df_binary.value, f->df_binary.length);
606}
607
712b2760
VK
608/**
609 * Get string field
610 * If buffer is NULL, memory block of required size will be allocated
611 * for result; if buffer is not NULL, entire result or part of it will
612 * be placed to buffer and pointer to buffer will be returned.
b368969c 613 * Note: bufferSize is buffer size in characters, not bytes!
56dd6325 614 */
ca0a165b 615TCHAR *NXCPMessage::getFieldAsString(UINT32 fieldId, TCHAR *buffer, size_t bufferSize) const
5039dede 616{
b368969c 617 if ((buffer != NULL) && (bufferSize == 0))
5039dede
AK
618 return NULL; // non-sense combination
619
b368969c
VK
620 TCHAR *str = NULL;
621 void *value = get(fieldId, NXCP_DT_STRING);
622 if (value != NULL)
5039dede 623 {
b368969c 624 if (buffer == NULL)
5039dede
AK
625 {
626#if defined(UNICODE) && defined(UNICODE_UCS4)
b368969c 627 str = (TCHAR *)malloc(*((UINT32 *)value) * 2 + 4);
5039dede 628#elif defined(UNICODE) && defined(UNICODE_UCS2)
b368969c 629 str = (TCHAR *)malloc(*((UINT32 *)value) + 2);
5039dede 630#else
b368969c 631 str = (TCHAR *)malloc(*((UINT32 *)value) / 2 + 1);
5039dede
AK
632#endif
633 }
634 else
635 {
b368969c 636 str = buffer;
5039dede
AK
637 }
638
b9792835
VK
639 size_t length = (buffer == NULL) ?
640 static_cast<size_t>(*((UINT32 *)value) / 2) :
641 std::min(static_cast<size_t>(*((UINT32 *)value) / 2), bufferSize - 1);
5039dede 642#if defined(UNICODE) && defined(UNICODE_UCS4)
b368969c 643 ucs2_to_ucs4((UCS2CHAR *)((BYTE *)value + 4), length, str, length + 1);
5039dede 644#elif defined(UNICODE) && defined(UNICODE_UCS2)
b368969c 645 memcpy(str, (BYTE *)value + 4, length * 2);
5039dede 646#else
b368969c 647 ucs2_to_mb((UCS2CHAR *)((BYTE *)value + 4), length, str, length + 1);
5039dede 648#endif
b368969c 649 str[length] = 0;
5039dede
AK
650 }
651 else
652 {
b368969c 653 if (buffer != NULL)
5039dede 654 {
b368969c 655 str = buffer;
934f53da 656 str[0] = 0;
5039dede
AK
657 }
658 }
934f53da 659 return str;
5039dede
AK
660}
661
35f836fe
VK
662#ifdef UNICODE
663
56dd6325 664/**
4af351c7 665 * get variable as multibyte string
56dd6325 666 */
ca0a165b 667char *NXCPMessage::getFieldAsMBString(UINT32 fieldId, char *buffer, size_t bufferSize) const
35f836fe 668{
b368969c 669 if ((buffer != NULL) && (bufferSize == 0))
35f836fe
VK
670 return NULL; // non-sense combination
671
b368969c
VK
672 char *str = NULL;
673 void *value = get(fieldId, NXCP_DT_STRING);
674 if (value != NULL)
35f836fe 675 {
b368969c 676 if (buffer == NULL)
35f836fe 677 {
b368969c 678 str = (char *)malloc(*((UINT32 *)value) / 2 + 1);
35f836fe
VK
679 }
680 else
681 {
b368969c 682 str = buffer;
35f836fe
VK
683 }
684
b9792835
VK
685 size_t length = (buffer == NULL) ?
686 static_cast<size_t>(*((UINT32 *)value) / 2) :
687 std::min(static_cast<size_t>(*((UINT32 *)value) / 2), bufferSize - 1);
688 ucs2_to_mb((UCS2CHAR *)((BYTE *)value + 4), (int)length, str, (int)length + 1);
b368969c 689 str[length] = 0;
35f836fe
VK
690 }
691 else
692 {
b368969c 693 if (buffer != NULL)
35f836fe 694 {
b368969c 695 str = buffer;
934f53da 696 str[0] = 0;
35f836fe
VK
697 }
698 }
934f53da 699 return str;
35f836fe
VK
700}
701
702#else
703
56dd6325 704/**
5c44534b 705 * get field as multibyte string
56dd6325 706 */
ca0a165b 707char *NXCPMessage::getFieldAsMBString(UINT32 fieldId, char *buffer, size_t bufferSize) const
35f836fe 708{
b368969c 709 return getFieldAsString(fieldId, buffer, bufferSize);
35f836fe
VK
710}
711
712#endif
713
56dd6325 714/**
5c44534b 715 * get field as UTF-8 string
56dd6325 716 */
ca0a165b 717char *NXCPMessage::getFieldAsUtf8String(UINT32 fieldId, char *buffer, size_t bufferSize) const
35f836fe 718{
b368969c 719 if ((buffer != NULL) && (bufferSize == 0))
35f836fe
VK
720 return NULL; // non-sense combination
721
b368969c
VK
722 char *str = NULL;
723 void *value = get(fieldId, NXCP_DT_STRING);
724 if (value != NULL)
35f836fe 725 {
b368969c
VK
726 int outSize;
727 if (buffer == NULL)
35f836fe
VK
728 {
729 // Assume worst case scenario - 3 bytes per character
b368969c
VK
730 outSize = (int)(*((UINT32 *)value) + *((UINT32 *)value) / 2 + 1);
731 str = (char *)malloc(outSize);
35f836fe
VK
732 }
733 else
734 {
b368969c
VK
735 outSize = (int)bufferSize;
736 str = buffer;
35f836fe
VK
737 }
738
b368969c 739 size_t length = *((UINT32 *)value) / 2;
35f836fe 740#ifdef UNICODE_UCS2
b368969c 741 int cc = WideCharToMultiByte(CP_UTF8, 0, (WCHAR *)((BYTE *)value + 4), (int)length, str, outSize - 1, NULL, NULL);
35f836fe 742#else
b368969c 743 int cc = ucs2_to_utf8((UCS2CHAR *)((BYTE *)value + 4), (int)length, str, outSize - 1);
35f836fe 744#endif
934f53da 745 str[cc] = 0;
35f836fe
VK
746 }
747 else
748 {
b368969c 749 if (buffer != NULL)
35f836fe 750 {
b368969c 751 str = buffer;
934f53da 752 str[0] = 0;
35f836fe
VK
753 }
754 }
934f53da 755 return str;
35f836fe
VK
756}
757
5c44534b
VK
758/**
759 * get binary (byte array) field
b368969c 760 * Result will be placed to the buffer provided (no more than bufferSize bytes,
5c44534b
VK
761 * and actual size of data will be returned
762 * If pBuffer is NULL, just actual data length is returned
763 */
78032263 764size_t NXCPMessage::getFieldAsBinary(UINT32 fieldId, BYTE *pBuffer, size_t bufferSize) const
5039dede 765{
78032263 766 size_t size;
b368969c 767 void *value = get(fieldId, NXCP_DT_BINARY);
9a68ca24 768 if (value != NULL)
5039dede 769 {
9a68ca24 770 size = *((UINT32 *)value);
5039dede 771 if (pBuffer != NULL)
78032263 772 memcpy(pBuffer, (BYTE *)value + 4, std::min(bufferSize, size));
5039dede
AK
773 }
774 else
775 {
9a68ca24 776 size = 0;
5039dede 777 }
9a68ca24 778 return size;
5039dede
AK
779}
780
5c44534b 781/**
ac14e3e6
VK
782 * get binary (byte array) field
783 * Returns pointer to internal buffer or NULL if field not found
784 * Data length set in size parameter.
785 */
ca0a165b 786const BYTE *NXCPMessage::getBinaryFieldPtr(UINT32 fieldId, size_t *size) const
ac14e3e6
VK
787{
788 BYTE *data;
b368969c 789 void *value = get(fieldId, NXCP_DT_BINARY);
ac14e3e6
VK
790 if (value != NULL)
791 {
792 *size = (size_t)(*((UINT32 *)value));
793 data = (BYTE *)value + 4;
794 }
795 else
796 {
797 *size = 0;
798 data = NULL;
799 }
800 return data;
801}
802
803/**
de4af576
VK
804 * Get field as GUID
805 * Returns NULL GUID on error
806 */
ca0a165b 807uuid NXCPMessage::getFieldAsGUID(UINT32 fieldId) const
de4af576
VK
808{
809 NXCP_MESSAGE_FIELD *f = find(fieldId);
810 if (f == NULL)
811 return uuid::NULL_UUID;
812
813 if ((f->type == NXCP_DT_BINARY) && (f->df_binary.length == UUID_LENGTH))
814 {
815 return uuid(f->df_binary.value);
816 }
817 else if (f->type == NXCP_DT_STRING)
818 {
819 TCHAR buffer[64] = _T("");
820 getFieldAsString(fieldId, buffer, 64);
821 return uuid::parse(buffer);
822 }
823 return uuid::NULL_UUID;
824}
825
826/**
5c44534b
VK
827 * Build protocol message ready to be send over the wire
828 */
9674aefa 829NXCP_MESSAGE *NXCPMessage::createMessage(bool allowCompression) const
5039dede 830{
5039dede 831 // Calculate message size
6be0a20b 832 size_t size = NXCP_HEADER_SIZE;
5c44534b 833 UINT32 fieldCount = 0;
d3a20572
VK
834 BYTE *compressedData = NULL;
835 size_t compressedDataSize = 0;
6be0a20b 836 if (m_flags & MF_BINARY)
5039dede 837 {
6be0a20b
VK
838 size += m_dataSize;
839 fieldCount = (UINT32)m_dataSize;
840 size += (8 - (size % 8)) & 7;
5039dede 841 }
6be0a20b
VK
842 else
843 {
844 MessageField *entry, *tmp;
845 HASH_ITER(hh, m_fields, entry, tmp)
846 {
847 size_t fieldSize = CalculateFieldSize(&entry->data, false);
848 if (m_version >= 2)
849 size += fieldSize + ((8 - (fieldSize % 8)) & 7);
850 else
851 size += fieldSize;
852 fieldCount++;
853 }
5039dede 854
6be0a20b
VK
855 // Message should be aligned to 8 bytes boundary
856 // This is always the case starting from version 2 because
857 // all fields are padded to 8 bytes boundary
858 if (m_version < 2)
859 size += (8 - (size % 8)) & 7;
860 }
5039dede
AK
861
862 // Create message
b368969c
VK
863 NXCP_MESSAGE *msg = (NXCP_MESSAGE *)malloc(size);
864 memset(msg, 0, size);
865 msg->code = htons(m_code);
866 msg->flags = htons(m_flags);
867 msg->size = htonl((UINT32)size);
868 msg->id = htonl(m_id);
869 msg->numFields = htonl(fieldCount);
5039dede
AK
870
871 // Fill data fields
6be0a20b 872 if (m_flags & MF_BINARY)
5039dede 873 {
b368969c 874 memcpy(msg->fields, m_data, m_dataSize);
6be0a20b
VK
875 }
876 else
877 {
b368969c 878 NXCP_MESSAGE_FIELD *field = (NXCP_MESSAGE_FIELD *)((char *)msg + NXCP_HEADER_SIZE);
6be0a20b
VK
879 MessageField *entry, *tmp;
880 HASH_ITER(hh, m_fields, entry, tmp)
5039dede 881 {
6be0a20b
VK
882 size_t fieldSize = CalculateFieldSize(&entry->data, false);
883 memcpy(field, &entry->data, fieldSize);
884
885 // Convert numeric values to network format
886 field->fieldId = htonl(field->fieldId);
b368969c 887 switch(field->type)
6be0a20b 888 {
b368969c 889 case NXCP_DT_INT32:
6be0a20b
VK
890 field->df_int32 = htonl(field->df_int32);
891 break;
b368969c 892 case NXCP_DT_INT64:
6be0a20b
VK
893 field->df_int64 = htonq(field->df_int64);
894 break;
b368969c 895 case NXCP_DT_INT16:
6be0a20b
VK
896 field->df_int16 = htons(field->df_int16);
897 break;
b368969c 898 case NXCP_DT_FLOAT:
6be0a20b
VK
899 field->df_real = htond(field->df_real);
900 break;
b368969c 901 case NXCP_DT_STRING:
5039dede 902#if !(WORDS_BIGENDIAN)
6be0a20b 903 {
c62d158b 904 bswap_array_16(field->df_string.value, field->df_string.length / 2);
b368969c 905 field->df_string.length = htonl(field->df_string.length);
6be0a20b 906 }
5039dede 907#endif
6be0a20b 908 break;
b368969c
VK
909 case NXCP_DT_BINARY:
910 field->df_string.length = htonl(field->df_string.length);
6be0a20b 911 break;
712b2760
VK
912 case NXCP_DT_INETADDR:
913 if (field->df_inetaddr.family == NXCP_AF_INET)
914 {
915 field->df_inetaddr.addr.v4 = htonl(field->df_inetaddr.addr.v4);
916 }
917 break;
6be0a20b 918 }
5039dede 919
6be0a20b 920 if (m_version >= 2)
b368969c 921 field = (NXCP_MESSAGE_FIELD *)((char *)field + fieldSize + ((8 - (fieldSize % 8)) & 7));
6be0a20b 922 else
b368969c 923 field = (NXCP_MESSAGE_FIELD *)((char *)field + fieldSize);
6be0a20b 924 }
5039dede 925 }
9674aefa
VK
926
927 // Compress message payload if requested. Compression supported starting with NXCP version 4.
3a1356ab 928 if ((m_version >= 4) && allowCompression && (size > 128) && !(m_flags & MF_STREAM))
9674aefa
VK
929 {
930 z_stream stream;
931 stream.zalloc = Z_NULL;
932 stream.zfree = Z_NULL;
933 stream.opaque = Z_NULL;
934 stream.avail_in = 0;
935 stream.next_in = Z_NULL;
936 if (deflateInit(&stream, 9) == Z_OK)
937 {
d55f77c8 938 size_t compBufferSize = deflateBound(&stream, (unsigned long)(size - NXCP_HEADER_SIZE));
9674aefa
VK
939 BYTE *compressedMsg = (BYTE *)malloc(compBufferSize + NXCP_HEADER_SIZE + 4);
940 stream.next_in = (BYTE *)msg->fields;
d55f77c8 941 stream.avail_in = (UINT32)(size - NXCP_HEADER_SIZE);
9674aefa 942 stream.next_out = compressedMsg + NXCP_HEADER_SIZE + 4;
d55f77c8 943 stream.avail_out = (UINT32)compBufferSize;
9674aefa
VK
944 if (deflate(&stream, Z_FINISH) == Z_STREAM_END)
945 {
946 size_t compMsgSize = compBufferSize - stream.avail_out + NXCP_HEADER_SIZE + 4;
947 // Message should be aligned to 8 bytes boundary
948 compMsgSize += (8 - (compMsgSize % 8)) & 7;
949 if (compMsgSize < size - 4)
950 {
951 memcpy(compressedMsg, msg, NXCP_HEADER_SIZE);
952 free(msg);
953 msg = (NXCP_MESSAGE *)compressedMsg;
954 msg->flags |= htons(MF_COMPRESSED);
955 memcpy((BYTE *)msg + NXCP_HEADER_SIZE, &msg->size, 4); // Save size of uncompressed message
956 msg->size = htonl((UINT32)compMsgSize);
957 }
a6e1cb15
VK
958 else
959 {
960 free(compressedMsg);
961 }
962 }
963 else
964 {
965 free(compressedMsg);
9674aefa
VK
966 }
967 deflateEnd(&stream);
968 }
969 }
b368969c 970 return msg;
5039dede
AK
971}
972
4af351c7
VK
973/**
974 * Delete all variables
975 */
b368969c 976void NXCPMessage::deleteAllFields()
5039dede 977{
5c44534b
VK
978 MessageField *entry, *tmp;
979 HASH_ITER(hh, m_fields, entry, tmp)
5039dede 980 {
5c44534b
VK
981 HASH_DEL(m_fields, entry);
982 free(entry);
5039dede
AK
983 }
984}
985
35f836fe
VK
986#ifdef UNICODE
987
4af351c7
VK
988/**
989 * set variable from multibyte string
990 */
b368969c 991void NXCPMessage::setFieldFromMBString(UINT32 fieldId, const char *value)
35f836fe 992{
b368969c
VK
993 WCHAR *wcValue = WideStringFromMBString(value);
994 set(fieldId, NXCP_DT_STRING, wcValue);
35f836fe
VK
995 free(wcValue);
996}
997
998#endif
999
fb9441ee 1000/**
9a68ca24 1001 * set binary field to an array of UINT32s
fb9441ee 1002 */
14149881 1003void NXCPMessage::setFieldFromInt32Array(UINT32 fieldId, size_t numElements, const UINT32 *elements)
5039dede 1004{
14149881 1005 UINT32 *pdwBuffer = (UINT32 *)set(fieldId, NXCP_DT_BINARY, elements, false, numElements * sizeof(UINT32));
9a68ca24
VK
1006 if (pdwBuffer != NULL)
1007 {
1008 pdwBuffer++; // First UINT32 is a length field
14149881 1009 for(size_t i = 0; i < numElements; i++) // Convert UINT32s to network byte order
9a68ca24
VK
1010 pdwBuffer[i] = htonl(pdwBuffer[i]);
1011 }
1012}
5039dede 1013
9a68ca24
VK
1014/**
1015 * set binary field to an array of UINT32s
1016 */
e30c2442 1017void NXCPMessage::setFieldFromInt32Array(UINT32 fieldId, const IntegerArray<UINT32> *data)
9a68ca24 1018{
712b2760 1019 UINT32 *pdwBuffer = (UINT32 *)set(fieldId, NXCP_DT_BINARY, data->getBuffer(), false, data->size() * sizeof(UINT32));
5039dede
AK
1020 if (pdwBuffer != NULL)
1021 {
967893bb 1022 pdwBuffer++; // First UINT32 is a length field
9a68ca24 1023 for(int i = 0; i < data->size(); i++) // Convert UINT32s to network byte order
5039dede
AK
1024 pdwBuffer[i] = htonl(pdwBuffer[i]);
1025 }
1026}
1027
fb9441ee 1028/**
9a68ca24 1029 * get binary field as an array of 32 bit unsigned integers
fb9441ee 1030 */
ca0a165b 1031UINT32 NXCPMessage::getFieldAsInt32Array(UINT32 fieldId, UINT32 numElements, UINT32 *buffer) const
5039dede 1032{
b368969c 1033 UINT32 size = getFieldAsBinary(fieldId, (BYTE *)buffer, numElements * sizeof(UINT32));
9a68ca24
VK
1034 size /= sizeof(UINT32); // Convert bytes to elements
1035 for(UINT32 i = 0; i < size; i++)
1036 buffer[i] = ntohl(buffer[i]);
1037 return size;
1038}
5039dede 1039
9a68ca24
VK
1040/**
1041 * get binary field as an array of 32 bit unsigned integers
1042 */
ca0a165b 1043UINT32 NXCPMessage::getFieldAsInt32Array(UINT32 fieldId, IntegerArray<UINT32> *data) const
9a68ca24
VK
1044{
1045 data->clear();
1046
b368969c 1047 UINT32 *value = (UINT32 *)get(fieldId, NXCP_DT_BINARY);
9a68ca24
VK
1048 if (value != NULL)
1049 {
ed83fef5 1050 UINT32 size = *value / sizeof(UINT32);
9a68ca24
VK
1051 value++;
1052 for(UINT32 i = 0; i < size; i++)
1053 {
1054 data->add(ntohl(*value));
1055 value++;
1056 }
1057 }
1058 return (UINT32)data->size();
5039dede
AK
1059}
1060
5c44534b
VK
1061/**
1062 * set binary field from file
1063 */
b368969c 1064bool NXCPMessage::setFieldFromFile(UINT32 fieldId, const TCHAR *pszFileName)
5039dede
AK
1065{
1066 FILE *pFile;
1067 BYTE *pBuffer;
b368969c 1068 UINT32 size;
5944946e 1069 bool bResult = false;
5039dede 1070
b368969c 1071 size = (UINT32)FileSize(pszFileName);
5039dede
AK
1072 pFile = _tfopen(pszFileName, _T("rb"));
1073 if (pFile != NULL)
1074 {
712b2760 1075 pBuffer = (BYTE *)set(fieldId, NXCP_DT_BINARY, NULL, false, size);
5039dede
AK
1076 if (pBuffer != NULL)
1077 {
b368969c 1078 if (fread(pBuffer + sizeof(UINT32), 1, size, pFile) == size)
5944946e 1079 bResult = true;
5039dede
AK
1080 }
1081 fclose(pFile);
1082 }
1083 return bResult;
1084}
1085
4af351c7 1086/**
934f53da
VK
1087 * Get string from field
1088 */
1089static TCHAR *GetStringFromField(void *df)
1090{
1091#if defined(UNICODE) && defined(UNICODE_UCS4)
1092 TCHAR *str = (TCHAR *)malloc(*((UINT32 *)df) * 2 + 4);
1093#elif defined(UNICODE) && defined(UNICODE_UCS2)
1094 TCHAR *str = (TCHAR *)malloc(*((UINT32 *)df) + 2);
1095#else
1096 TCHAR *str = (TCHAR *)malloc(*((UINT32 *)df) / 2 + 1);
1097#endif
1098 int len = (int)(*((UINT32 *)df) / 2);
1099#if defined(UNICODE) && defined(UNICODE_UCS4)
1100 ucs2_to_ucs4((UCS2CHAR *)((BYTE *)df + 4), len, str, len + 1);
1101#elif defined(UNICODE) && defined(UNICODE_UCS2)
1102 memcpy(str, (BYTE *)df + 4, len * 2);
1103#else
1104 ucs2_to_mb((UCS2CHAR *)((BYTE *)df + 4), len, str, len + 1);
1105#endif
1106 str[len] = 0;
1107 return str;
1108}
1109
1110/**
1111 * Dump NXCP message
1112 */
ca0a165b 1113String NXCPMessage::dump(const NXCP_MESSAGE *msg, int version)
934f53da
VK
1114{
1115 String out;
1116 int i;
1117 TCHAR *str, buffer[128];
1118
b368969c
VK
1119 WORD flags = ntohs(msg->flags);
1120 WORD code = ntohs(msg->code);
1121 UINT32 id = ntohl(msg->id);
1122 UINT32 size = ntohl(msg->size);
1123 int numFields = (int)ntohl(msg->numFields);
934f53da
VK
1124
1125 // Dump raw message
1126 for(i = 0; i < (int)size; i += 16)
1127 {
78032263 1128 BinToStr(((BYTE *)msg) + i, MIN(16, size - i), buffer);
4e0e77e6 1129 out.appendFormattedString(_T(" ** %s\n"), buffer);
934f53da
VK
1130 }
1131
1132 // header
4e0e77e6 1133 out.appendFormattedString(_T(" ** code=0x%04X (%s) flags=0x%04X id=%d size=%d numFields=%d\n"),
934f53da
VK
1134 code, NXCPMessageCodeName(code, buffer), flags, id, size, numFields);
1135 if (flags & MF_BINARY)
1136 {
1137 out += _T(" ** binary message\n");
1138 return out;
1139 }
1140
1141 // Parse data fields
6be0a20b 1142 size_t pos = NXCP_HEADER_SIZE;
934f53da
VK
1143 for(int f = 0; f < numFields; f++)
1144 {
b368969c 1145 NXCP_MESSAGE_FIELD *field = (NXCP_MESSAGE_FIELD *)(((BYTE *)msg) + pos);
934f53da
VK
1146
1147 // Validate position inside message
1148 if (pos > size - 8)
1149 {
1150 out += _T(" ** message format error (pos > size - 8)\n");
1151 break;
1152 }
1153 if ((pos > size - 12) &&
b368969c 1154 ((field->type == NXCP_DT_STRING) || (field->type == NXCP_DT_BINARY)))
934f53da 1155 {
4e0e77e6 1156 out.appendFormattedString(_T(" ** message format error (pos > size - 8 and field type %d)\n"), (int)field->type);
934f53da
VK
1157 break;
1158 }
1159
1160 // Calculate and validate field size
818ebb6a 1161 size_t fieldSize = CalculateFieldSize(field, TRUE);
934f53da
VK
1162 if (pos + fieldSize > size)
1163 {
1164 out += _T(" ** message format error (invalid field size)\n");
1165 break;
1166 }
1167
1168 // Create new entry
b368969c 1169 NXCP_MESSAGE_FIELD *convertedField = (NXCP_MESSAGE_FIELD *)malloc(fieldSize);
934f53da
VK
1170 memcpy(convertedField, field, fieldSize);
1171
1172 // Convert numeric values to host format
8f238fd7 1173 convertedField->fieldId = ntohl(convertedField->fieldId);
b368969c 1174 switch(field->type)
934f53da 1175 {
b368969c 1176 case NXCP_DT_INT32:
934f53da 1177 convertedField->df_int32 = ntohl(convertedField->df_int32);
845303de 1178 out.appendFormattedString(_T(" ** [%6d] INT32 %d\n"), (int)convertedField->fieldId, convertedField->df_int32);
934f53da 1179 break;
b368969c 1180 case NXCP_DT_INT64:
934f53da 1181 convertedField->df_int64 = ntohq(convertedField->df_int64);
845303de 1182 out.appendFormattedString(_T(" ** [%6d] INT64 ") INT64_FMT _T("\n"), (int)convertedField->fieldId, convertedField->df_int64);
934f53da 1183 break;
b368969c 1184 case NXCP_DT_INT16:
934f53da 1185 convertedField->df_int16 = ntohs(convertedField->df_int16);
845303de 1186 out.appendFormattedString(_T(" ** [%6d] INT16 %d\n"), (int)convertedField->fieldId, (int)convertedField->df_int16);
934f53da 1187 break;
b368969c 1188 case NXCP_DT_FLOAT:
934f53da 1189 convertedField->df_real = ntohd(convertedField->df_real);
845303de 1190 out.appendFormattedString(_T(" ** [%6d] FLOAT %f\n"), (int)convertedField->fieldId, convertedField->df_real);
934f53da 1191 break;
b368969c 1192 case NXCP_DT_STRING:
934f53da 1193#if !(WORDS_BIGENDIAN)
b368969c 1194 convertedField->df_string.length = ntohl(convertedField->df_string.length);
c62d158b 1195 bswap_array_16(convertedField->df_string.value, (int)convertedField->df_string.length / 2);
934f53da
VK
1196#endif
1197 str = GetStringFromField((BYTE *)convertedField + 8);
845303de 1198 out.appendFormattedString(_T(" ** [%6d] STRING \"%s\"\n"), (int)convertedField->fieldId, str);
934f53da
VK
1199 free(str);
1200 break;
b368969c
VK
1201 case NXCP_DT_BINARY:
1202 convertedField->df_string.length = ntohl(convertedField->df_string.length);
845303de 1203 out.appendFormattedString(_T(" ** [%6d] BINARY len=%d\n"), (int)convertedField->fieldId, (int)convertedField->df_string.length);
934f53da 1204 break;
cb33b0e2
VK
1205 case NXCP_DT_INETADDR:
1206 {
1207 InetAddress a =
1208 (convertedField->df_inetaddr.family == NXCP_AF_INET) ?
1209 InetAddress(ntohl(convertedField->df_inetaddr.addr.v4)) :
1210 InetAddress(convertedField->df_inetaddr.addr.v6);
1211 a.setMaskBits(convertedField->df_inetaddr.maskBits);
1212 out.appendFormattedString(_T(" ** [%6d] INETADDR %s\n"), (int)convertedField->fieldId, (const TCHAR *)a.toString());
1213 }
1214 break;
934f53da 1215 default:
4e0e77e6 1216 out.appendFormattedString(_T(" ** [%6d] unknown type %d\n"), (int)convertedField->fieldId, (int)field->type);
934f53da
VK
1217 break;
1218 }
1219 free(convertedField);
1220
6be0a20b 1221 // Starting from version 2, all fields should be 8-byte aligned
934f53da
VK
1222 if (version >= 2)
1223 pos += fieldSize + ((8 - (fieldSize % 8)) & 7);
1224 else
1225 pos += fieldSize;
1226 }
1227
1228 return out;
1229}