eefc4122f98cbf367ab32037c0d321f82da5bc17
2 ** NetXMS - Network Management System
3 ** NetXMS Foundation Library
4 ** Copyright (C) 2003-2016 Victor Kirhenshtein
6 ** This program is free software; you can redistribute it and/or modify
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
9 ** (at your option) any later version.
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.
16 ** You should have received a copy of the GNU Lesser General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "libnetxms.h"
27 * Calculate field size
29 static size_t CalculateFieldSize(NXCP_MESSAGE_FIELD
*field
, bool networkByteOrder
)
45 case NXCP_DT_INETADDR
:
51 nSize
= ntohl(field
->df_string
.length
) + 12;
53 nSize
= field
->df_string
.length
+ 12;
63 * Field hash map entry
70 NXCP_MESSAGE_FIELD data
;
74 * Create new hash entry wth given field size
76 inline MessageField
*CreateMessageField(size_t fieldSize
)
78 size_t entrySize
= sizeof(MessageField
) - sizeof(NXCP_MESSAGE_FIELD
) + fieldSize
;
79 MessageField
*entry
= (MessageField
*)calloc(1, entrySize
);
80 entry
->size
= entrySize
;
85 * Default constructor for NXCPMessage class
87 NXCPMessage::NXCPMessage(int version
)
99 * Create a copy of prepared CSCP message
101 NXCPMessage::NXCPMessage(NXCPMessage
*msg
)
103 m_code
= msg
->m_code
;
105 m_flags
= msg
->m_flags
;
106 m_version
= msg
->m_version
;
109 if (m_flags
& MF_BINARY
)
111 m_dataSize
= msg
->m_dataSize
;
112 m_data
= (BYTE
*)nx_memdup(msg
->m_data
, m_dataSize
);
119 MessageField
*entry
, *tmp
;
120 HASH_ITER(hh
, msg
->m_fields
, entry
, tmp
)
122 MessageField
*f
= (MessageField
*)nx_memdup(entry
, entry
->size
);
123 HASH_ADD_INT(m_fields
, id
, f
);
129 * Create NXCPMessage object from received message
131 NXCPMessage::NXCPMessage(NXCP_MESSAGE
*msg
, int version
)
135 m_flags
= ntohs(msg
->flags
);
136 m_code
= ntohs(msg
->code
);
137 m_id
= ntohl(msg
->id
);
142 if (m_flags
& MF_BINARY
)
144 m_dataSize
= (size_t)ntohl(msg
->numFields
);
145 m_data
= (BYTE
*)nx_memdup(msg
->fields
, m_dataSize
);
152 int fieldCount
= (int)ntohl(msg
->numFields
);
153 size_t size
= (size_t)ntohl(msg
->size
);
154 size_t pos
= NXCP_HEADER_SIZE
;
155 for(int f
= 0; f
< fieldCount
; f
++)
157 NXCP_MESSAGE_FIELD
*field
= (NXCP_MESSAGE_FIELD
*)(((BYTE
*)msg
) + pos
);
159 // Validate position inside message
162 if ((pos
> size
- 12) &&
163 ((field
->type
== NXCP_DT_STRING
) || (field
->type
== NXCP_DT_BINARY
)))
166 // Calculate and validate variable size
167 size_t fieldSize
= CalculateFieldSize(field
, true);
168 if (pos
+ fieldSize
> size
)
172 MessageField
*entry
= CreateMessageField(fieldSize
);
173 entry
->id
= ntohl(field
->fieldId
);
174 memcpy(&entry
->data
, field
, fieldSize
);
176 // Convert values to host format
177 entry
->data
.fieldId
= ntohl(entry
->data
.fieldId
);
181 entry
->data
.df_int32
= ntohl(entry
->data
.df_int32
);
184 entry
->data
.df_int64
= ntohq(entry
->data
.df_int64
);
187 entry
->data
.df_int16
= ntohs(entry
->data
.df_int16
);
190 entry
->data
.df_real
= ntohd(entry
->data
.df_real
);
193 #if !(WORDS_BIGENDIAN)
194 entry
->data
.df_string
.length
= ntohl(entry
->data
.df_string
.length
);
195 for(i
= 0; i
< entry
->data
.df_string
.length
/ 2; i
++)
196 entry
->data
.df_string
.value
[i
] = ntohs(entry
->data
.df_string
.value
[i
]);
200 entry
->data
.df_string
.length
= ntohl(entry
->data
.df_string
.length
);
202 case NXCP_DT_INETADDR
:
203 if (entry
->data
.df_inetaddr
.family
== NXCP_AF_INET
)
205 entry
->data
.df_inetaddr
.addr
.v4
= ntohl(entry
->data
.df_inetaddr
.addr
.v4
);
210 HASH_ADD_INT(m_fields
, id
, entry
);
212 // Starting from version 2, all variables should be 8-byte aligned
214 pos
+= fieldSize
+ ((8 - (fieldSize
% 8)) & 7);
223 * Destructor for NXCPMessage
225 NXCPMessage::~NXCPMessage()
234 NXCP_MESSAGE_FIELD
*NXCPMessage::find(UINT32 fieldId
) const
237 HASH_FIND_INT(m_fields
, &fieldId
, entry
);
238 return (entry
!= NULL
) ? &entry
->data
: NULL
;
243 * Argument size (data size) contains data length in bytes for DT_BINARY type
244 * and maximum number of characters for DT_STRING type (0 means no limit)
246 void *NXCPMessage::set(UINT32 fieldId
, BYTE type
, const void *value
, bool isSigned
, size_t size
)
248 if (m_flags
& MF_BINARY
)
252 #if defined(UNICODE_UCS2) && defined(UNICODE)
253 #define __buffer value
263 entry
= CreateMessageField(12);
264 entry
->data
.df_int32
= *((const UINT32
*)value
);
267 entry
= CreateMessageField(8);
268 entry
->data
.df_int16
= *((const WORD
*)value
);
271 entry
= CreateMessageField(16);
272 entry
->data
.df_int64
= *((const UINT64
*)value
);
275 entry
= CreateMessageField(16);
276 entry
->data
.df_real
= *((const double *)value
);
280 length
= _tcslen((const TCHAR
*)value
);
281 if ((size
> 0) && (length
> size
))
283 #ifndef UNICODE_UCS2 /* assume UNICODE_UCS4 */
284 __buffer
= (UCS2CHAR
*)malloc(length
* 2 + 2);
285 ucs4_to_ucs2((WCHAR
*)value
, length
, __buffer
, length
+ 1);
287 #else /* not UNICODE */
288 __buffer
= UCS2StringFromMBString((const char *)value
);
289 length
= (UINT32
)ucs2_strlen(__buffer
);
290 if ((size
> 0) && (length
> size
))
293 entry
= CreateMessageField(12 + length
* 2);
294 entry
->data
.df_string
.length
= (UINT32
)(length
* 2);
295 memcpy(entry
->data
.df_string
.value
, __buffer
, entry
->data
.df_string
.length
);
296 #if !defined(UNICODE_UCS2) || !defined(UNICODE)
301 entry
= CreateMessageField(12 + size
);
302 entry
->data
.df_binary
.length
= (UINT32
)size
;
303 if ((entry
->data
.df_binary
.length
> 0) && (value
!= NULL
))
304 memcpy(entry
->data
.df_binary
.value
, value
, entry
->data
.df_binary
.length
);
306 case NXCP_DT_INETADDR
:
307 entry
= CreateMessageField(32);
308 entry
->data
.df_inetaddr
.family
= (((InetAddress
*)value
)->getFamily() == AF_INET
) ? NXCP_AF_INET
: NXCP_AF_INET6
;
309 entry
->data
.df_inetaddr
.maskBits
= (BYTE
)((InetAddress
*)value
)->getMaskBits();
310 if (((InetAddress
*)value
)->getFamily() == AF_INET
)
312 entry
->data
.df_inetaddr
.addr
.v4
= ((InetAddress
*)value
)->getAddressV4();
316 memcpy(entry
->data
.df_inetaddr
.addr
.v6
, ((InetAddress
*)value
)->getAddressV6(), 16);
320 return NULL
; // Invalid data type, unable to handle
323 entry
->data
.fieldId
= fieldId
;
324 entry
->data
.type
= type
;
326 entry
->data
.flags
|= NXCP_MFF_SIGNED
;
328 // add or replace field
330 HASH_FIND_INT(m_fields
, &fieldId
, curr
);
333 HASH_DEL(m_fields
, curr
);
336 HASH_ADD_INT(m_fields
, id
, entry
);
338 return (type
== NXCP_DT_INT16
) ? ((void *)((BYTE
*)&entry
->data
+ 6)) : ((void *)((BYTE
*)&entry
->data
+ 8));
345 void *NXCPMessage::get(UINT32 fieldId
, BYTE requiredType
, BYTE
*fieldType
) const
347 NXCP_MESSAGE_FIELD
*field
= find(fieldId
);
349 return NULL
; // No such field
351 // Data type check exception - return IPv4 address as INT32 if requested
352 if ((requiredType
== NXCP_DT_INT32
) && (field
->type
== NXCP_DT_INETADDR
) && (field
->df_inetaddr
.family
== NXCP_AF_INET
))
353 return &field
->df_inetaddr
.addr
.v4
;
356 if ((requiredType
!= 0xFF) && (field
->type
!= requiredType
))
359 if (fieldType
!= NULL
)
360 *fieldType
= field
->type
;
361 return (field
->type
== NXCP_DT_INT16
) ?
362 ((void *)((BYTE
*)field
+ 6)) :
363 ((void *)((BYTE
*)field
+ 8));
367 * Get 16 bit field as boolean
369 bool NXCPMessage::getFieldAsBoolean(UINT32 fieldId
) const
372 void *value
= (void *)get(fieldId
, 0xFF, &type
);
379 return *((UINT16
*)value
) ? true : false;
381 return *((UINT32
*)value
) ? true : false;
383 return *((UINT64
*)value
) ? true : false;
390 * Get data type of message field.
392 * @return field type or -1 if field with given ID does not exist
394 int NXCPMessage::getFieldType(UINT32 fieldId
) const
396 NXCP_MESSAGE_FIELD
*field
= find(fieldId
);
397 return (field
!= NULL
) ? (int)field
->type
: -1;
401 * get signed integer field
403 INT32
NXCPMessage::getFieldAsInt32(UINT32 fieldId
) const
405 char *value
= (char *)get(fieldId
, NXCP_DT_INT32
);
406 return (value
!= NULL
) ? *((INT32
*)value
) : 0;
410 * get unsigned integer field
412 UINT32
NXCPMessage::getFieldAsUInt32(UINT32 fieldId
) const
414 void *value
= get(fieldId
, NXCP_DT_INT32
);
415 return (value
!= NULL
) ? *((UINT32
*)value
) : 0;
419 * get signed 16-bit integer field
421 INT16
NXCPMessage::getFieldAsInt16(UINT32 fieldId
) const
423 void *value
= get(fieldId
, NXCP_DT_INT16
);
424 return (value
!= NULL
) ? *((INT16
*)value
) : 0;
428 * get unsigned 16-bit integer variable
430 UINT16
NXCPMessage::getFieldAsUInt16(UINT32 fieldId
) const
432 void *value
= get(fieldId
, NXCP_DT_INT16
);
433 return value
? *((WORD
*)value
) : 0;
437 * get signed 64-bit integer field
439 INT64
NXCPMessage::getFieldAsInt64(UINT32 fieldId
) const
441 void *value
= get(fieldId
, NXCP_DT_INT64
);
442 return (value
!= NULL
) ? *((INT64
*)value
) : 0;
446 * get unsigned 64-bit integer field
448 UINT64
NXCPMessage::getFieldAsUInt64(UINT32 fieldId
) const
450 void *value
= get(fieldId
, NXCP_DT_INT64
);
451 return value
? *((UINT64
*)value
) : 0;
455 * get 64-bit floating point variable
457 double NXCPMessage::getFieldAsDouble(UINT32 fieldId
) const
459 void *value
= get(fieldId
, NXCP_DT_FLOAT
);
460 return (value
!= NULL
) ? *((double *)value
) : 0;
466 time_t NXCPMessage::getFieldAsTime(UINT32 fieldId
) const
469 void *value
= (void *)get(fieldId
, 0xFF, &type
);
476 return (time_t)(*((UINT32
*)value
));
478 return (time_t)(*((UINT64
*)value
));
485 * Get field as inet address
487 InetAddress
NXCPMessage::getFieldAsInetAddress(UINT32 fieldId
) const
489 NXCP_MESSAGE_FIELD
*f
= find(fieldId
);
491 return InetAddress();
493 if (f
->type
== NXCP_DT_INETADDR
)
496 (f
->df_inetaddr
.family
== NXCP_AF_INET
) ?
497 InetAddress(f
->df_inetaddr
.addr
.v4
) :
498 InetAddress(f
->df_inetaddr
.addr
.v6
);
499 a
.setMaskBits(f
->df_inetaddr
.maskBits
);
502 else if (f
->type
== NXCP_DT_INT32
)
504 return InetAddress(f
->df_uint32
);
506 return InetAddress();
511 * If buffer is NULL, memory block of required size will be allocated
512 * for result; if buffer is not NULL, entire result or part of it will
513 * be placed to buffer and pointer to buffer will be returned.
514 * Note: bufferSize is buffer size in characters, not bytes!
516 TCHAR
*NXCPMessage::getFieldAsString(UINT32 fieldId
, TCHAR
*buffer
, size_t bufferSize
) const
518 if ((buffer
!= NULL
) && (bufferSize
== 0))
519 return NULL
; // non-sense combination
522 void *value
= get(fieldId
, NXCP_DT_STRING
);
527 #if defined(UNICODE) && defined(UNICODE_UCS4)
528 str
= (TCHAR
*)malloc(*((UINT32
*)value
) * 2 + 4);
529 #elif defined(UNICODE) && defined(UNICODE_UCS2)
530 str
= (TCHAR
*)malloc(*((UINT32
*)value
) + 2);
532 str
= (TCHAR
*)malloc(*((UINT32
*)value
) / 2 + 1);
540 size_t length
= (buffer
== NULL
) ? (*((UINT32
*)value
) / 2) : min(*((UINT32
*)value
) / 2, bufferSize
- 1);
541 #if defined(UNICODE) && defined(UNICODE_UCS4)
542 ucs2_to_ucs4((UCS2CHAR
*)((BYTE
*)value
+ 4), length
, str
, length
+ 1);
543 #elif defined(UNICODE) && defined(UNICODE_UCS2)
544 memcpy(str
, (BYTE
*)value
+ 4, length
* 2);
546 ucs2_to_mb((UCS2CHAR
*)((BYTE
*)value
+ 4), length
, str
, length
+ 1);
564 * get variable as multibyte string
566 char *NXCPMessage::getFieldAsMBString(UINT32 fieldId
, char *buffer
, size_t bufferSize
) const
568 if ((buffer
!= NULL
) && (bufferSize
== 0))
569 return NULL
; // non-sense combination
572 void *value
= get(fieldId
, NXCP_DT_STRING
);
577 str
= (char *)malloc(*((UINT32
*)value
) / 2 + 1);
584 size_t length
= (buffer
== NULL
) ? (*((UINT32
*)value
) / 2) : min(*((UINT32
*)value
) / 2, bufferSize
- 1);
585 ucs2_to_mb((UCS2CHAR
*)((BYTE
*)value
+ 4), (int)length
, str
, (int)length
+ 1);
602 * get field as multibyte string
604 char *NXCPMessage::getFieldAsMBString(UINT32 fieldId
, char *buffer
, size_t bufferSize
) const
606 return getFieldAsString(fieldId
, buffer
, bufferSize
);
612 * get field as UTF-8 string
614 char *NXCPMessage::getFieldAsUtf8String(UINT32 fieldId
, char *buffer
, size_t bufferSize
) const
616 if ((buffer
!= NULL
) && (bufferSize
== 0))
617 return NULL
; // non-sense combination
620 void *value
= get(fieldId
, NXCP_DT_STRING
);
626 // Assume worst case scenario - 3 bytes per character
627 outSize
= (int)(*((UINT32
*)value
) + *((UINT32
*)value
) / 2 + 1);
628 str
= (char *)malloc(outSize
);
632 outSize
= (int)bufferSize
;
636 size_t length
= *((UINT32
*)value
) / 2;
638 int cc
= WideCharToMultiByte(CP_UTF8
, 0, (WCHAR
*)((BYTE
*)value
+ 4), (int)length
, str
, outSize
- 1, NULL
, NULL
);
640 int cc
= ucs2_to_utf8((UCS2CHAR
*)((BYTE
*)value
+ 4), (int)length
, str
, outSize
- 1);
656 * get binary (byte array) field
657 * Result will be placed to the buffer provided (no more than bufferSize bytes,
658 * and actual size of data will be returned
659 * If pBuffer is NULL, just actual data length is returned
661 UINT32
NXCPMessage::getFieldAsBinary(UINT32 fieldId
, BYTE
*pBuffer
, size_t bufferSize
) const
664 void *value
= get(fieldId
, NXCP_DT_BINARY
);
667 size
= *((UINT32
*)value
);
669 memcpy(pBuffer
, (BYTE
*)value
+ 4, min(bufferSize
, size
));
679 * get binary (byte array) field
680 * Returns pointer to internal buffer or NULL if field not found
681 * Data length set in size parameter.
683 const BYTE
*NXCPMessage::getBinaryFieldPtr(UINT32 fieldId
, size_t *size
) const
686 void *value
= get(fieldId
, NXCP_DT_BINARY
);
689 *size
= (size_t)(*((UINT32
*)value
));
690 data
= (BYTE
*)value
+ 4;
702 * Returns NULL GUID on error
704 uuid
NXCPMessage::getFieldAsGUID(UINT32 fieldId
) const
706 NXCP_MESSAGE_FIELD
*f
= find(fieldId
);
708 return uuid::NULL_UUID
;
710 if ((f
->type
== NXCP_DT_BINARY
) && (f
->df_binary
.length
== UUID_LENGTH
))
712 return uuid(f
->df_binary
.value
);
714 else if (f
->type
== NXCP_DT_STRING
)
716 TCHAR buffer
[64] = _T("");
717 getFieldAsString(fieldId
, buffer
, 64);
718 return uuid::parse(buffer
);
720 return uuid::NULL_UUID
;
724 * Build protocol message ready to be send over the wire
726 NXCP_MESSAGE
*NXCPMessage::createMessage()
728 // Calculate message size
729 size_t size
= NXCP_HEADER_SIZE
;
730 UINT32 fieldCount
= 0;
731 if (m_flags
& MF_BINARY
)
734 fieldCount
= (UINT32
)m_dataSize
;
735 size
+= (8 - (size
% 8)) & 7;
739 MessageField
*entry
, *tmp
;
740 HASH_ITER(hh
, m_fields
, entry
, tmp
)
742 size_t fieldSize
= CalculateFieldSize(&entry
->data
, false);
744 size
+= fieldSize
+ ((8 - (fieldSize
% 8)) & 7);
750 // Message should be aligned to 8 bytes boundary
751 // This is always the case starting from version 2 because
752 // all fields are padded to 8 bytes boundary
754 size
+= (8 - (size
% 8)) & 7;
758 NXCP_MESSAGE
*msg
= (NXCP_MESSAGE
*)malloc(size
);
759 memset(msg
, 0, size
);
760 msg
->code
= htons(m_code
);
761 msg
->flags
= htons(m_flags
);
762 msg
->size
= htonl((UINT32
)size
);
763 msg
->id
= htonl(m_id
);
764 msg
->numFields
= htonl(fieldCount
);
767 if (m_flags
& MF_BINARY
)
769 memcpy(msg
->fields
, m_data
, m_dataSize
);
773 NXCP_MESSAGE_FIELD
*field
= (NXCP_MESSAGE_FIELD
*)((char *)msg
+ NXCP_HEADER_SIZE
);
774 MessageField
*entry
, *tmp
;
775 HASH_ITER(hh
, m_fields
, entry
, tmp
)
777 size_t fieldSize
= CalculateFieldSize(&entry
->data
, false);
778 memcpy(field
, &entry
->data
, fieldSize
);
780 // Convert numeric values to network format
781 field
->fieldId
= htonl(field
->fieldId
);
785 field
->df_int32
= htonl(field
->df_int32
);
788 field
->df_int64
= htonq(field
->df_int64
);
791 field
->df_int16
= htons(field
->df_int16
);
794 field
->df_real
= htond(field
->df_real
);
797 #if !(WORDS_BIGENDIAN)
799 for(UINT32 i
= 0; i
< field
->df_string
.length
/ 2; i
++)
800 field
->df_string
.value
[i
] = htons(field
->df_string
.value
[i
]);
801 field
->df_string
.length
= htonl(field
->df_string
.length
);
806 field
->df_string
.length
= htonl(field
->df_string
.length
);
808 case NXCP_DT_INETADDR
:
809 if (field
->df_inetaddr
.family
== NXCP_AF_INET
)
811 field
->df_inetaddr
.addr
.v4
= htonl(field
->df_inetaddr
.addr
.v4
);
817 field
= (NXCP_MESSAGE_FIELD
*)((char *)field
+ fieldSize
+ ((8 - (fieldSize
% 8)) & 7));
819 field
= (NXCP_MESSAGE_FIELD
*)((char *)field
+ fieldSize
);
826 * Delete all variables
828 void NXCPMessage::deleteAllFields()
830 MessageField
*entry
, *tmp
;
831 HASH_ITER(hh
, m_fields
, entry
, tmp
)
833 HASH_DEL(m_fields
, entry
);
841 * set variable from multibyte string
843 void NXCPMessage::setFieldFromMBString(UINT32 fieldId
, const char *value
)
845 WCHAR
*wcValue
= WideStringFromMBString(value
);
846 set(fieldId
, NXCP_DT_STRING
, wcValue
);
853 * set binary field to an array of UINT32s
855 void NXCPMessage::setFieldFromInt32Array(UINT32 fieldId
, size_t numElements
, const UINT32
*elements
)
857 UINT32
*pdwBuffer
= (UINT32
*)set(fieldId
, NXCP_DT_BINARY
, elements
, false, numElements
* sizeof(UINT32
));
858 if (pdwBuffer
!= NULL
)
860 pdwBuffer
++; // First UINT32 is a length field
861 for(size_t i
= 0; i
< numElements
; i
++) // Convert UINT32s to network byte order
862 pdwBuffer
[i
] = htonl(pdwBuffer
[i
]);
867 * set binary field to an array of UINT32s
869 void NXCPMessage::setFieldFromInt32Array(UINT32 fieldId
, IntegerArray
<UINT32
> *data
)
871 UINT32
*pdwBuffer
= (UINT32
*)set(fieldId
, NXCP_DT_BINARY
, data
->getBuffer(), false, data
->size() * sizeof(UINT32
));
872 if (pdwBuffer
!= NULL
)
874 pdwBuffer
++; // First UINT32 is a length field
875 for(int i
= 0; i
< data
->size(); i
++) // Convert UINT32s to network byte order
876 pdwBuffer
[i
] = htonl(pdwBuffer
[i
]);
881 * get binary field as an array of 32 bit unsigned integers
883 UINT32
NXCPMessage::getFieldAsInt32Array(UINT32 fieldId
, UINT32 numElements
, UINT32
*buffer
) const
885 UINT32 size
= getFieldAsBinary(fieldId
, (BYTE
*)buffer
, numElements
* sizeof(UINT32
));
886 size
/= sizeof(UINT32
); // Convert bytes to elements
887 for(UINT32 i
= 0; i
< size
; i
++)
888 buffer
[i
] = ntohl(buffer
[i
]);
893 * get binary field as an array of 32 bit unsigned integers
895 UINT32
NXCPMessage::getFieldAsInt32Array(UINT32 fieldId
, IntegerArray
<UINT32
> *data
) const
899 UINT32
*value
= (UINT32
*)get(fieldId
, NXCP_DT_BINARY
);
902 UINT32 size
= *value
/ sizeof(UINT32
);
904 for(UINT32 i
= 0; i
< size
; i
++)
906 data
->add(ntohl(*value
));
910 return (UINT32
)data
->size();
914 * set binary field from file
916 bool NXCPMessage::setFieldFromFile(UINT32 fieldId
, const TCHAR
*pszFileName
)
921 bool bResult
= false;
923 size
= (UINT32
)FileSize(pszFileName
);
924 pFile
= _tfopen(pszFileName
, _T("rb"));
927 pBuffer
= (BYTE
*)set(fieldId
, NXCP_DT_BINARY
, NULL
, false, size
);
930 if (fread(pBuffer
+ sizeof(UINT32
), 1, size
, pFile
) == size
)
939 * Get string from field
941 static TCHAR
*GetStringFromField(void *df
)
943 #if defined(UNICODE) && defined(UNICODE_UCS4)
944 TCHAR
*str
= (TCHAR
*)malloc(*((UINT32
*)df
) * 2 + 4);
945 #elif defined(UNICODE) && defined(UNICODE_UCS2)
946 TCHAR
*str
= (TCHAR
*)malloc(*((UINT32
*)df
) + 2);
948 TCHAR
*str
= (TCHAR
*)malloc(*((UINT32
*)df
) / 2 + 1);
950 int len
= (int)(*((UINT32
*)df
) / 2);
951 #if defined(UNICODE) && defined(UNICODE_UCS4)
952 ucs2_to_ucs4((UCS2CHAR
*)((BYTE
*)df
+ 4), len
, str
, len
+ 1);
953 #elif defined(UNICODE) && defined(UNICODE_UCS2)
954 memcpy(str
, (BYTE
*)df
+ 4, len
* 2);
956 ucs2_to_mb((UCS2CHAR
*)((BYTE
*)df
+ 4), len
, str
, len
+ 1);
965 String
NXCPMessage::dump(const NXCP_MESSAGE
*msg
, int version
)
969 TCHAR
*str
, buffer
[128];
971 WORD flags
= ntohs(msg
->flags
);
972 WORD code
= ntohs(msg
->code
);
973 UINT32 id
= ntohl(msg
->id
);
974 UINT32 size
= ntohl(msg
->size
);
975 int numFields
= (int)ntohl(msg
->numFields
);
978 for(i
= 0; i
< (int)size
; i
+= 16)
980 BinToStr(((BYTE
*)msg
) + i
, min(16, size
- i
), buffer
);
981 out
.appendFormattedString(_T(" ** %s\n"), buffer
);
985 out
.appendFormattedString(_T(" ** code=0x%04X (%s) flags=0x%04X id=%d size=%d numFields=%d\n"),
986 code
, NXCPMessageCodeName(code
, buffer
), flags
, id
, size
, numFields
);
987 if (flags
& MF_BINARY
)
989 out
+= _T(" ** binary message\n");
994 size_t pos
= NXCP_HEADER_SIZE
;
995 for(int f
= 0; f
< numFields
; f
++)
997 NXCP_MESSAGE_FIELD
*field
= (NXCP_MESSAGE_FIELD
*)(((BYTE
*)msg
) + pos
);
999 // Validate position inside message
1002 out
+= _T(" ** message format error (pos > size - 8)\n");
1005 if ((pos
> size
- 12) &&
1006 ((field
->type
== NXCP_DT_STRING
) || (field
->type
== NXCP_DT_BINARY
)))
1008 out
.appendFormattedString(_T(" ** message format error (pos > size - 8 and field type %d)\n"), (int)field
->type
);
1012 // Calculate and validate field size
1013 size_t fieldSize
= CalculateFieldSize(field
, TRUE
);
1014 if (pos
+ fieldSize
> size
)
1016 out
+= _T(" ** message format error (invalid field size)\n");
1021 NXCP_MESSAGE_FIELD
*convertedField
= (NXCP_MESSAGE_FIELD
*)malloc(fieldSize
);
1022 memcpy(convertedField
, field
, fieldSize
);
1024 // Convert numeric values to host format
1025 convertedField
->fieldId
= ntohl(convertedField
->fieldId
);
1029 convertedField
->df_int32
= ntohl(convertedField
->df_int32
);
1030 out
.appendFormattedString(_T(" ** [%6d] INT32 %d\n"), (int)convertedField
->fieldId
, convertedField
->df_int32
);
1033 convertedField
->df_int64
= ntohq(convertedField
->df_int64
);
1034 out
.appendFormattedString(_T(" ** [%6d] INT64 ") INT64_FMT
_T("\n"), (int)convertedField
->fieldId
, convertedField
->df_int64
);
1037 convertedField
->df_int16
= ntohs(convertedField
->df_int16
);
1038 out
.appendFormattedString(_T(" ** [%6d] INT16 %d\n"), (int)convertedField
->fieldId
, (int)convertedField
->df_int16
);
1041 convertedField
->df_real
= ntohd(convertedField
->df_real
);
1042 out
.appendFormattedString(_T(" ** [%6d] FLOAT %f\n"), (int)convertedField
->fieldId
, convertedField
->df_real
);
1044 case NXCP_DT_STRING
:
1045 #if !(WORDS_BIGENDIAN)
1046 convertedField
->df_string
.length
= ntohl(convertedField
->df_string
.length
);
1047 for(i
= 0; i
< (int)convertedField
->df_string
.length
/ 2; i
++)
1048 convertedField
->df_string
.value
[i
] = ntohs(convertedField
->df_string
.value
[i
]);
1050 str
= GetStringFromField((BYTE
*)convertedField
+ 8);
1051 out
.appendFormattedString(_T(" ** [%6d] STRING \"%s\"\n"), (int)convertedField
->fieldId
, str
);
1054 case NXCP_DT_BINARY
:
1055 convertedField
->df_string
.length
= ntohl(convertedField
->df_string
.length
);
1056 out
.appendFormattedString(_T(" ** [%6d] BINARY len=%d\n"), (int)convertedField
->fieldId
, (int)convertedField
->df_string
.length
);
1058 case NXCP_DT_INETADDR
:
1061 (convertedField
->df_inetaddr
.family
== NXCP_AF_INET
) ?
1062 InetAddress(ntohl(convertedField
->df_inetaddr
.addr
.v4
)) :
1063 InetAddress(convertedField
->df_inetaddr
.addr
.v6
);
1064 a
.setMaskBits(convertedField
->df_inetaddr
.maskBits
);
1065 out
.appendFormattedString(_T(" ** [%6d] INETADDR %s\n"), (int)convertedField
->fieldId
, (const TCHAR
*)a
.toString());
1069 out
.appendFormattedString(_T(" ** [%6d] unknown type %d\n"), (int)convertedField
->fieldId
, (int)field
->type
);
1072 free(convertedField
);
1074 // Starting from version 2, all fields should be 8-byte aligned
1076 pos
+= fieldSize
+ ((8 - (fieldSize
% 8)) & 7);