CMSDK 2.0.1
Cross-platform C++ base library and SDK for the Psyclone AIOS platform
Loading...
Searching...
No Matches
DataMessage.cpp
Go to the documentation of this file.
1
6#include "DataMessage.h"
7#include "PsyTime.h"
8#include "UnitTestFramework.h"
9
10namespace cmlabs {
11
12/*
13 IMPLEMENTATION NOTES - binary layout
14 ------------------------------------
15 A DataMessage is ONE contiguous heap block (malloc/realloc, never new[])
16 pointed to by 'data':
17
18 [DataMessageHeader][entry][entry][entry]... total bytes = data->size
19
20 The header starts with { uint32 size; uint32 cid; ... }, so the first
21 4 bytes of any serialised message are its total size and the next 4 the
22 class id (DATAMESSAGEID). Because the block is already flat, "serialise"
23 is simply "send data->size bytes starting at data" - there is no separate
24 marshalling step and no per-field byte swapping: all integers are stored
25 in HOST byte order. All supported platforms (x86/x64, ARM/ARM64 in the
26 default configs) are little-endian, so blocks are wire-compatible between
27 nodes; only the transport-level frame length (see NetworkProtocols.cpp)
28 uses network byte order.
29
30 Each user entry is a PAIR of tagged records laid out back to back:
31
32 [DataMessageEntryHeader{size,cid=CONSTCHARID}][key chars + NUL]
33 [DataMessageEntryHeader{size,cid=<value type>}][value bytes]
34
35 where entry.size is the full record size INCLUDING its own header, so a
36 walker advances with 'src += ((DataMessageEntryHeader*)src)->size'. Value
37 cids are INTID (int64), DOUBLEID (float64), TIMEID (uint64 ms),
38 CONSTCHARID (NUL-terminated text), CHARDATAID (raw bytes), DATAMESSAGEID
39 (a nested, fully serialised message) and the *INFOID variants which hold
40 only an int64 byte count as a placeholder for content that was stripped
41 (see the "draft" constructors below).
42
43 Arrays and maps are NOT separate structures: they are encoded purely in
44 the key string. Element i of array "foo" is stored under the mangled key
45 "foo_-|i|-_" and map entry "bar" of map "m" under "m_-[bar]-_". All the
46 array/map getters below therefore do a linear scan matching the key
47 prefix/suffix; there is no index. Lookup of single keys is a linear scan
48 too (findEntry() in the header), assisted by a one-slot find cache that
49 must be invalidated (invalidateFindKeyCache()) whenever the block is
50 modified or reallocated.
51*/
52
53std::string DataMessageHeader::toJSON(std::map<uint16, std::string>* subtypes, std::map<uint16, std::string>* subcontexts, std::map<uint32, std::string>* compNames) {
54 if (cid != DATAMESSAGEID) return 0;
55 if (!subtypes && !subcontexts && !compNames)
56 return utils::StringFormat("{ \"size\": %u, \"memid\": \"%llu\", \"time\": \"%llu\", \"time__desc\": \"%s\", \"sendtime\": \"%llu\", \"sendtime__desc\": \"%s\", \"recvtime\": \"%llu\", \"recvtime__desc\": \"%s\", "
57 "\"modulecputime\": %u, \"modulewalltime\": %u, \"chaincputime\": %u, \"chainwalltime\": %u, \"chaincount\": %u, "
58 "\"origin\": %u, \"destination\": %u, \"ttl\": \"%llu\", \"eol__desc\": \"%s\", \"priority\": %u, \"policy\": %u, \"from\": %u, \"to\": %u, \"type\": \"%s\", \"tag\": \"%u\", \"status\": %u, \"reference\": \"%llu\", \"serial\": \"%llu\", \"contextchange\": \"%s\", \"userdatacount\": %u, \"userdatasize\": %u }",
59 size, memid,
60 time, time ? PrintTimeString(time).c_str() : "",
64 origin, destination, ttl, ttl ? PrintTimeString(time + ttl).c_str() : "",
65 priority, policy, from, to, type.toString().c_str(), tag, status, reference, serial,
66 contextchange.isValid() ? contextchange.toString().c_str() : "",
68
69 std::string typeStr, contextStr, fromStr, toStr;
70 typeStr = type.toString(subtypes);
71 contextStr = contextchange.toString(subcontexts);
72 if (compNames) {
73 fromStr = (*compNames)[from];
74 toStr = (*compNames)[to];
75 }
76 if (!fromStr.length()) {
77 if (from)
78 fromStr = utils::StringFormat("Component %u", from);
79 }
80 if (!toStr.length()) {
81 if (to)
82 toStr = utils::StringFormat("Component %u", to);
83 }
84 return utils::StringFormat("{ \"size\": %u, \"memid\": \"%llu\", \"time\": \"%llu\", \"time__desc\": \"%s\", \"sendtime\": \"%llu\", \"sendtime__desc\": \"%s\", \"recvtime\": \"%llu\", \"recvtime__desc\": \"%s\", "
85 "\"modulecputime\": %u, \"modulewalltime\": %u, \"chaincputime\": %u, \"chainwalltime\": %u, \"chaincount\": %u, "
86 "\"origin\": %u, \"destination\": %u, \"ttl\": \"%llu\", \"eol__desc\": \"%s\", \"priority\": %u, \"policy\": %u, \"from\": \"%s\", \"to\": \"%s\", \"type\": \"%s\", \"tag\": \"%u\", \"status\": %u, \"reference\": \"%llu\", \"serial\": \"%llu\", \"contextchange\": \"%s\", \"userdatacount\": %u, \"userdatasize\": %u }",
87 size, memid,
88 time, time ? PrintTimeString(time).c_str() : "",
92 origin, destination, ttl, ttl ? PrintTimeString(time + ttl).c_str() : "",
94 fromStr.c_str(),
95 toStr.c_str(),
96 typeStr.c_str(), tag, status, reference, serial,
97 contextStr.c_str(), userCount, userSize);
98
99}
100
101std::string DataMessageHeader::toXML(std::map<uint16, std::string>* subtypes, std::map<uint16, std::string>* subcontexts, std::map<uint32, std::string>* compNames) {
102 if (cid != DATAMESSAGEID) return 0;
103
104 if (!subtypes && !subcontexts && !compNames)
105 return utils::StringFormat("<datamessage size=\"%u\" memid=\"%llu\" time=\"%llu\" timetext=\"%s\" sendtime=\"%llu\" sendtimetext=\"%s\" recvtime=\"%llu\" recvtimetext=\"%s\" "
106 "modulecputime=\"%u\" modulewalltime=\"%u\" chaincputime=\"%u\" chainwalltime=\"%u\" chaincount=\"%u\" "
107 "origin=\"%u\" destination=\"%u\" ttl=\"%llu\" eoltext=\"%s\" priority=\"%u\" policy=\"%u\" from=\"%u\" to=\"%u\" type=\"%s\" tag=\"%u\" status=\"%u\" reference=\"%llu\" serial=\"%llu\" contextchange=\"%s\" userdatacount=\"%u\" userdatasize=\"%u\" />\n",
108 size, memid,
109 time, time ? PrintTimeString(time).c_str() : "",
110 sendtime, sendtime ? PrintTimeString(sendtime).c_str() : "",
111 recvtime, recvtime ? PrintTimeString(recvtime).c_str() : "",
113 origin, destination, ttl, ttl ? PrintTimeString(time + ttl).c_str() : "", priority, policy, from, to, type.toString().c_str(), tag, status, reference, serial, contextchange.isValid() ? contextchange.toString().c_str() : "", userCount, userSize);
114
115 std::string typeStr, contextStr, fromStr, toStr;
116 typeStr = type.toString(subtypes);
117 contextStr = contextchange.toString(subcontexts);
118 if (compNames) {
119 fromStr = (*compNames)[from];
120 toStr = (*compNames)[to];
121 }
122 if (!fromStr.length()) {
123 if (from)
124 fromStr = utils::StringFormat("Component %u", from);
125 }
126 if (!toStr.length()) {
127 if (to)
128 toStr = utils::StringFormat("Component %u", to);
129 }
130
131 return utils::StringFormat("<datamessage size=\"%u\" memid=\"%llu\" time=\"%llu\" timetext=\"%s\" sendtime=\"%llu\" sendtimetext=\"%s\" recvtime=\"%llu\" recvtimetext=\"%s\" "
132 "modulecputime=\"%u\" modulewalltime=\"%u\" chaincputime=\"%u\" chainwalltime=\"%u\" chaincount=\"%u\" "
133 "origin=\"%u\" destination=\"%u\" ttl=\"%llu\" eoltext=\"%s\" priority=\"%u\" policy=\"%u\" from=\"%s\" to=\"%s\" type=\"%s\" tag=\"%u\" status=\"%u\" reference=\"%llu\" serial=\"%llu\" contextchange=\"%s\" userdatacount=\"%u\" userdatasize=\"%u\" />\n",
134 size, memid,
135 time, time ? PrintTimeString(time).c_str() : "",
136 sendtime, sendtime ? PrintTimeString(sendtime).c_str() : "",
137 recvtime, recvtime ? PrintTimeString(recvtime).c_str() : "",
140 fromStr.c_str(),
141 toStr.c_str(),
142 typeStr.c_str(), tag, status, reference, serial, contextStr.c_str(), userCount, userSize);
143}
144
145
146// Bulk-import every user entry from another message by walking its flat
147// block directly: each key record (CONSTCHARID) is followed by its value
148// record, which is re-inserted here via setRawData() (deep copy, preserving
149// the original value cid). Returns the number of entries copied.
151 if ((data->cid != DATAMESSAGEID) || !msg || (msg->data->cid != DATAMESSAGEID))
152 return 0;
153
154 if (!msg->data->userCount)
155 return 0;
156
157 uint32 count = 0;
158 const char* key;
159 // Walk [header][entry][entry]... of the source block; srcEnd guards the walk.
160 char* src = (char*)(msg->data) + sizeof(DataMessageHeader);
161 char* srcEnd = (char*)(msg->data) + msg->data->size;
162 while (src < srcEnd) {
163 // A CONSTCHARID record here is a key; the value record follows it directly.
164 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
165 key = src + sizeof(DataMessageEntryHeader);
166 src += sizeof(DataMessageEntryHeader) + strlen(key) + 1;
167 if (setRawData(key, src + sizeof(DataMessageEntryHeader), ((DataMessageEntryHeader*)src)->size - sizeof(DataMessageEntryHeader), ((DataMessageEntryHeader*)src)->cid))
168 count++;
169 }
170 src += ((DataMessageEntryHeader*)src)->size;
171 }
172 return count;
173}
174
175namespace {
176 // Scratch records used while grouping mangled array/map keys during the
177 // text/JSON/XML dumps: they remember where each element's value record
178 // lives inside the flat block so it can be printed under its parent key.
179 struct ArrayElem { int64 index; char* entryPtr; uint32 cid; };
180 struct MapElem { std::string index; char* entryPtr; uint32 cid; };
181}
182
183// Human-readable dump of all user entries. Single pass over the flat block:
184// plain keys are printed immediately; keys carrying the array ("_-|i|-_")
185// or map ("_-[k]-_") mangling are collected into userArrays/userMaps first
186// and printed grouped (indented) after the scan. Nested DATAMESSAGEID
187// entries recurse via a temporary DataMessage wrapper.
189 if (data->cid != DATAMESSAGEID) return 0;
190
191 if (!data->userCount)
192 return "";
193
194 std::map< std::string, std::list<ArrayElem> > userArrays;
195 std::map< std::string, std::list<MapElem> > userMaps;
196
197 DataMessage* msg;
198 bool ok;
199 const char* key;
200 const char* mapStart, *mapEnd;
201 std::string userData;
202 userData.reserve(data->userSize + data->userCount * 64);
203 char* src = (char*)data + sizeof(DataMessageHeader);
204 char* srcEnd = (char*)data + data->size;
205 while (src < srcEnd) {
206 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
207 key = src + sizeof(DataMessageEntryHeader);
208 src += sizeof(DataMessageEntryHeader) + strlen(key) + 1;
209 if ((mapStart = strstr(key, "_-|")) && (mapEnd = strstr(key, "|-_"))) {
210 ArrayElem e;
211 e.index = utils::Ascii2Int64(std::string(mapStart + 3, mapEnd - mapStart - 3).c_str());
212 e.entryPtr = src;
213 e.cid = ((DataMessageEntryHeader*)src)->cid;
214 userArrays[std::string(key, mapStart - key)].push_back(e);
215 src += ((DataMessageEntryHeader*)src)->size;
216 continue;
217 }
218 else if ((mapStart = strstr(key, "_-[")) && (mapEnd = strstr(key, "]-_"))) {
219 MapElem e;
220 e.index = std::string(mapStart + 3, mapEnd - mapStart - 3);
221 e.entryPtr = src;
222 e.cid = ((DataMessageEntryHeader*)src)->cid;
223 userMaps[std::string(key, mapStart - key)].push_back(e);
224 src += ((DataMessageEntryHeader*)src)->size;
225 continue;
226 }
227 switch (((DataMessageEntryHeader*)src)->cid) {
228 case CONSTCHARID:
229 userData += utils::StringFormat("'%s' : '%s' (string)\n", key, src + sizeof(DataMessageEntryHeader));
230 break;
231 case TIMEID:
232 userData += utils::StringFormat("'%s' : %s (time)\n",
233 key,
234 *(uint64*)(src + sizeof(DataMessageEntryHeader)) ? PrintTimeString(*(uint64*)(src + sizeof(DataMessageEntryHeader))).c_str() : ""
235 );
236 break;
237 case CHARDATAID:
238 userData += utils::StringFormat("'%s' : size %u (binary)\n", key, ((DataMessageEntryHeader*)src)->size - sizeof(DataMessageEntryHeader));
239 break;
240 case CONSTCHARINFOID:
241 userData += utils::StringFormat("'%s' : (string of size %lld)\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
242 break;
243 case CHARDATAINFOID:
244 userData += utils::StringFormat("'%s' : (binary of size %lld)\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
245 break;
247 userData += utils::StringFormat("'%s' : (message of size %lld)\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
248 break;
249 case INTID:
250 userData += utils::StringFormat("'%s' : %lld (integer)\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
251 break;
252 case DOUBLEID:
253 userData += utils::StringFormat("'%s' : %f (float)\n", key, *(float64*)(src + sizeof(DataMessageEntryHeader)));
254 break;
255 case DATAMESSAGEID:
256 msg = new DataMessage(src + sizeof(DataMessageEntryHeader));
257 if (msg) {
258 if (userData.length()) userData += ", ";
259 userData += utils::StringFormat("'%s' : (message)\n%s\n", key, utils::TextIndent(msg->getUserEntriesAsString().c_str(), " -").c_str());
260 }
261 delete(msg);
262 break;
264 // ignore
265 default:
266 break;
267 }
268 }
269 // else cannot generate JSON for this entry
270 src += ((DataMessageEntryHeader*)src)->size;
271 }
272
273 std::string subUserData;
274
275 std::list<ArrayElem>::iterator entryII, entryEE;
276 std::map< std::string, std::list<ArrayElem> >::iterator keyII = userArrays.begin(), keyEE = userArrays.end();
277 while (keyII != keyEE) {
278 subUserData.clear();
279 entryII = keyII->second.begin();
280 entryEE = keyII->second.end();
281 while (entryII != entryEE) {
282 char* ep = entryII->entryPtr;
283 char* val = ep + sizeof(DataMessageEntryHeader);
284 uint32 cid = entryII->cid;
285 switch (cid) {
286 case CONSTCHARID:
287 subUserData += utils::StringFormat("%lld : '%s' (string)\n", entryII->index, val);
288 break;
289 case TIMEID:
290 subUserData += utils::StringFormat("%lld : %s (time)\n",
291 entryII->index,
292 *(uint64*)val ? PrintTimeString(*(uint64*)val).c_str() : ""
293 );
294 break;
295 case CHARDATAID:
296 subUserData += utils::StringFormat("%lld : size %u (binary)\n", entryII->index, ((DataMessageEntryHeader*)ep)->size - sizeof(DataMessageEntryHeader));
297 break;
298 case DATAMESSAGEID:
299 msg = new DataMessage(val);
300 if (msg) {
301 if (subUserData.length()) subUserData += ", ";
302 subUserData += utils::StringFormat("%lld : (message)\n%s\n", entryII->index, utils::TextIndent(msg->getUserEntriesAsString().c_str(), " -").c_str());
303 }
304 delete(msg);
305 break;
306 case INTID:
307 subUserData += utils::StringFormat("%lld : %lld (integer)\n", entryII->index, *(int64*)val);
308 break;
309 case DOUBLEID:
310 subUserData += utils::StringFormat("%lld : %f (float)\n", entryII->index, *(float64*)val);
311 break;
312 case CONSTCHARINFOID:
313 subUserData += utils::StringFormat("%lld : (string of size %lld)\n", entryII->index, *(int64*)val);
314 break;
315 case CHARDATAINFOID:
316 subUserData += utils::StringFormat("%lld : (binary of size %lld)\n", entryII->index, *(int64*)val);
317 break;
319 subUserData += utils::StringFormat("%lld : (message of size %lld)\n", entryII->index, *(int64*)val);
320 break;
321 default:
322 break;
323 }
324 entryII++;
325 }
326 userData += utils::StringFormat("'%s' : (array)\n%s", keyII->first.c_str(), utils::TextIndent(subUserData.c_str(), " -").c_str());
327 keyII++;
328 }
329
330 std::list<MapElem>::iterator entryI, entryE;
331 std::map< std::string, std::list<MapElem> >::iterator keyI = userMaps.begin(), keyE = userMaps.end();
332 while (keyI != keyE) {
333 subUserData.clear();
334 entryI = keyI->second.begin();
335 entryE = keyI->second.end();
336 while (entryI != entryE) {
337 char* ep = entryI->entryPtr;
338 char* val = ep + sizeof(DataMessageEntryHeader);
339 uint32 cid = entryI->cid;
340 switch (cid) {
341 case CONSTCHARID:
342 subUserData += utils::StringFormat("'%s' : '%s' (string)\n", entryI->index.c_str(), val);
343 break;
344 case TIMEID:
345 subUserData += utils::StringFormat("'%s' : %s (time)\n",
346 entryI->index.c_str(),
347 *(uint64*)val ? PrintTimeString(*(uint64*)val).c_str() : ""
348 );
349 break;
350 case CHARDATAID:
351 subUserData += utils::StringFormat("'%s' : size %u (binary)\n", entryI->index.c_str(), ((DataMessageEntryHeader*)ep)->size - sizeof(DataMessageEntryHeader));
352 break;
353 case DATAMESSAGEID:
354 msg = new DataMessage(val);
355 if (msg) {
356 if (subUserData.length()) subUserData += ", ";
357 subUserData += utils::StringFormat("'%s' : (message)\n%s\n", entryI->index.c_str(), utils::TextIndent(msg->getUserEntriesAsString().c_str(), " -").c_str());
358 }
359 delete(msg);
360 break;
361 case INTID:
362 subUserData += utils::StringFormat("'%s' : %lld (integer)\n", entryI->index.c_str(), *(int64*)val);
363 break;
364 case DOUBLEID:
365 subUserData += utils::StringFormat("'%s' : %f (float)\n", entryI->index.c_str(), *(float64*)val);
366 break;
367 case CONSTCHARINFOID:
368 subUserData += utils::StringFormat("'%s' : (string of size %lld)\n", entryI->index.c_str(), *(int64*)val);
369 break;
370 case CHARDATAINFOID:
371 subUserData += utils::StringFormat("'%s' : (binary of size %lld)\n", entryI->index.c_str(), *(int64*)val);
372 break;
374 subUserData += utils::StringFormat("'%s' : (message of size %lld)\n", entryI->index.c_str(), *(int64*)val);
375 break;
376 default:
377 break;
378 }
379 entryI++;
380 }
381 userData += utils::StringFormat("'%s' : (map)\n%s", keyI->first.c_str(), utils::TextIndent(subUserData.c_str(), " -").c_str());
382 keyI++;
383 }
384
385 return userData;
386}
387
388// JSON dump of all user entries; same two-phase walk as
389// getUserEntriesAsString() (plain keys inline, mangled array/map keys
390// grouped afterwards). With asText=true values are emitted as bare JSON
391// scalars; otherwise each value becomes a {"type", "value"} object so the
392// receiver can distinguish text/time/binary/etc.
393std::string DataMessage::getUserEntriesAsJSON(bool asText) {
394 if (data->cid != DATAMESSAGEID) return "{}";
395
396 if (!data->userCount)
397 return "{}";
398
399 std::map< std::string, std::list<ArrayElem> > userArrays;
400 std::map< std::string, std::list<MapElem> > userMaps;
401
402 const char* oldData = NULL;
403 DataMessage* msg = new DataMessage();
404 bool ok;
405 const char* key;
406 const char* mapStart, *mapEnd;
407 std::string userData;
408 userData.reserve(data->userSize + data->userCount * 64);
409 char* src = (char*)data + sizeof(DataMessageHeader);
410 char* srcEnd = (char*)data + data->size;
411 while (src < srcEnd) {
412 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
413 key = src + sizeof(DataMessageEntryHeader);
414 src += sizeof(DataMessageEntryHeader) + strlen(key) + 1;
415 if ((mapStart = strstr(key, "_-|")) && (mapEnd = strstr(key, "|-_"))) {
416 ArrayElem e;
417 e.index = utils::Ascii2Int64(std::string(mapStart + 3, mapEnd - mapStart - 3).c_str());
418 e.entryPtr = src;
419 e.cid = ((DataMessageEntryHeader*)src)->cid;
420 userArrays[std::string(key, mapStart - key)].push_back(e);
421 src += ((DataMessageEntryHeader*)src)->size;
422 continue;
423 }
424 else if ((mapStart = strstr(key, "_-[")) && (mapEnd = strstr(key, "]-_"))) {
425 MapElem e;
426 e.index = std::string(mapStart + 3, mapEnd - mapStart - 3);
427 e.entryPtr = src;
428 e.cid = ((DataMessageEntryHeader*)src)->cid;
429 userMaps[std::string(key, mapStart - key)].push_back(e);
430 src += ((DataMessageEntryHeader*)src)->size;
431 continue;
432 }
433 switch (((DataMessageEntryHeader*)src)->cid) {
434 case CONSTCHARID:
435 if (userData.length()) userData += ", ";
436 if (!asText)
437 userData += utils::StringFormat("\"%s\": {\"type\": \"text\", \"value\": \"%s\" }\n", key, src + sizeof(DataMessageEntryHeader));
438 else
439 userData += utils::StringFormat("\"%s\": \"%s\"\n", key, src + sizeof(DataMessageEntryHeader));
440 break;
441 case TIMEID:
442 if (userData.length()) userData += ", ";
443 if (!asText)
444 userData += utils::StringFormat("\"%s\": {\"type\": \"time\", \"value\": %llu, \"text\": \"%s\" }\n",
445 key, *(uint64*)(src + sizeof(DataMessageEntryHeader)),
446 *(uint64*)(src + sizeof(DataMessageEntryHeader)) ? PrintTimeString(*(uint64*)(src + sizeof(DataMessageEntryHeader))).c_str() : ""
447 );
448 else
449 userData += utils::StringFormat("\"%s\": \"%s\"\n",
450 key,
451 *(uint64*)(src + sizeof(DataMessageEntryHeader)) ? PrintTimeString(*(uint64*)(src + sizeof(DataMessageEntryHeader))).c_str() : ""
452 );
453 break;
454 case CHARDATAID:
455 if (userData.length()) userData += ", ";
456 if (!asText)
457 userData += utils::StringFormat("\"%s\": {\"type\": \"binary\", \"size\": %u }\n", key, ((DataMessageEntryHeader*)src)->size - sizeof(DataMessageEntryHeader));
458 break;
459 case INTID:
460 if (userData.length()) userData += ", ";
461 if (!asText)
462 userData += utils::StringFormat("\"%s\": {\"type\": \"integer\", \"value\": %lld }\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
463 else
464 userData += utils::StringFormat("\"%s\": \"%lld\"\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
465 break;
466 case DOUBLEID:
467 if (userData.length()) userData += ", ";
468 if (!asText)
469 userData += utils::StringFormat("\"%s\": {\"type\": \"double\", \"value\": %f }\n", key, *(float64*)(src + sizeof(DataMessageEntryHeader)));
470 else
471 userData += utils::StringFormat("\"%s\": \"%f\"\n", key, *(float64*)(src + sizeof(DataMessageEntryHeader)));
472 break;
473 case DATAMESSAGEID:
474 if (((DataMessageHeader*)(src + sizeof(DataMessageEntryHeader)))->cid == DATAMESSAGEID) {
475 if (!oldData)
476 oldData = msg->swapMessageData(src + sizeof(DataMessageEntryHeader));
477 else
478 msg->swapMessageData(src + sizeof(DataMessageEntryHeader));
479 //msg = new DataMessage(src + sizeof(DataMessageEntryHeader));
480 //if (msg) {
481 if (userData.length()) userData += ", ";
482 if (!asText)
483 userData += utils::StringFormat("\"%s\": {\"type\": \"message\", \"value\": %s }\n", key, msg->toJSON().c_str());
484 else
485 userData += utils::StringFormat("\"%s\": %s\n", key, msg->getUserEntriesAsJSON(true).c_str());
486 //}
487 //delete(msg);
488 }
489 break;
490 case CONSTCHARINFOID:
491 if (!asText) {
492 if (userData.length()) userData += ", ";
493 userData += utils::StringFormat("\"%s\": {\"type\": \"textinfo\", \"size\": %u }\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
494 }
495 break;
496 case CHARDATAINFOID:
497 if (!asText) {
498 if (userData.length()) userData += ", ";
499 userData += utils::StringFormat("\"%s\": {\"type\": \"binary\", \"size\": %u }\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
500 }
501 break;
503 if (!asText) {
504 if (userData.length()) userData += ", ";
505 userData += utils::StringFormat("\"%s\": {\"type\": \"messageinfo\", \"size\": %u }\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
506 }
507 break;
509 default:
510 break;
511 }
512 }
513 // else cannot generate JSON for this entry
514 src += ((DataMessageEntryHeader*)src)->size;
515 }
516
517 if (oldData)
518 msg->swapMessageData(oldData);
519 delete(msg);
520
521 std::string subUserData;
522
523 std::list<ArrayElem>::iterator entryII, entryEE;
524 std::map< std::string, std::list<ArrayElem> >::iterator keyII = userArrays.begin(), keyEE = userArrays.end();
525 while (keyII != keyEE) {
526 subUserData.clear();
527 entryII = keyII->second.begin();
528 entryEE = keyII->second.end();
529 while (entryII != entryEE) {
530 char* ep = entryII->entryPtr;
531 char* val = ep + sizeof(DataMessageEntryHeader);
532 uint32 cid = entryII->cid;
533 if (subUserData.length()) subUserData += ", ";
534 switch (cid) {
535 case CONSTCHARID:
536 if (!asText)
537 subUserData += utils::StringFormat("%lld: {\"type\": \"text\", \"value\": \"%s\" }\n", entryII->index, val);
538 else
539 subUserData += utils::StringFormat("%lld: \"%s\"\n", entryII->index, val);
540 break;
541 case TIMEID:
542 if (!asText)
543 subUserData += utils::StringFormat("%lld: {\"type\": \"time\", \"value\": %llu, \"text\": \"%s\" }\n",
544 entryII->index, *(uint64*)val,
545 *(uint64*)val ? PrintTimeString(*(uint64*)val).c_str() : ""
546 );
547 else
548 subUserData += utils::StringFormat("%lld: \"%s\"\n", entryII->index, *(uint64*)val ? PrintTimeString(*(uint64*)val).c_str() : "");
549 break;
550 case CHARDATAID:
551 if (!asText)
552 subUserData += utils::StringFormat("%lld: {\"type\": \"binary\", \"size\": %u }\n", entryII->index, ((DataMessageEntryHeader*)ep)->size - sizeof(DataMessageEntryHeader));
553 break;
554 case DATAMESSAGEID:
555 msg = new DataMessage(val);
556 if (msg) {
557 if (subUserData.length()) subUserData += ", ";
558 if (!asText)
559 subUserData += utils::StringFormat("%lld: {\"type\": \"message\", \"value\": %s }\n", entryII->index, msg->toJSON().c_str());
560 else
561 subUserData += utils::StringFormat("%lld: %s }\n", entryII->index, msg->getUserEntriesAsJSON(true).c_str());
562 }
563 delete(msg);
564 break;
565 case INTID:
566 if (!asText)
567 subUserData += utils::StringFormat("%lld: {\"type\": \"integer\", \"value\": %lld }\n", entryII->index, *(int64*)val);
568 else
569 subUserData += utils::StringFormat("%lld: %lld\n", entryII->index, *(int64*)val);
570 break;
571 case DOUBLEID:
572 if (!asText)
573 subUserData += utils::StringFormat("%lld: {\"type\": \"double\", \"value\": %f }\n", entryII->index, *(float64*)val);
574 else
575 subUserData += utils::StringFormat("%lld: \"%f\" }\n", entryII->index, *(float64*)val);
576 break;
577 case CONSTCHARINFOID:
578 if (!asText)
579 subUserData += utils::StringFormat("%lld: {\"type\": \"textinfo\", \"size\": %lld }", entryII->index, *(int64*)val);
580 break;
581 case CHARDATAINFOID:
582 if (!asText)
583 subUserData += utils::StringFormat("%lld: {\"type\": \"binary\", \"size\": %lld }", entryII->index, *(int64*)val);
584 break;
586 if (!asText)
587 subUserData += utils::StringFormat("%lld: {\"type\": \"messageinfo\", \"size\": %lld }", entryII->index, *(int64*)val);
588 break;
589 default:
590 break;
591 }
592 entryII++;
593 }
594 if (userData.length()) userData += ", ";
595 if (!asText)
596 userData += utils::StringFormat("\"%s\": {\"type\": \"array\", \"value\":\n{%s} }\n", keyII->first.c_str(), subUserData.c_str());
597 else
598 userData += utils::StringFormat("\"%s\": {%s}\n", keyII->first.c_str(), subUserData.c_str());
599 keyII++;
600 }
601
602
603 std::list<MapElem>::iterator entryI, entryE;
604 std::map< std::string, std::list<MapElem> >::iterator keyI = userMaps.begin(), keyE = userMaps.end();
605 while (keyI != keyE) {
606 subUserData.clear();
607 entryI = keyI->second.begin();
608 entryE = keyI->second.end();
609 while (entryI != entryE) {
610 char* ep = entryI->entryPtr;
611 char* val = ep + sizeof(DataMessageEntryHeader);
612 uint32 cid = entryI->cid;
613 if (subUserData.length()) subUserData += ", ";
614 switch (cid) {
615 case CONSTCHARID:
616 if (!asText)
617 subUserData += utils::StringFormat("\"%s\": {\"type\": \"text\", \"value\": \"%s\" }\n", entryI->index.c_str(), val);
618 else
619 subUserData += utils::StringFormat("\"%s\": \"%s\"\n", entryI->index.c_str(), val);
620 break;
621 case TIMEID:
622 if (!asText)
623 subUserData += utils::StringFormat("\"%s\": {\"type\": \"time\", \"value\": %llu, \"text\": \"%s\" }\n",
624 entryI->index.c_str(), *(uint64*)val,
625 *(uint64*)val ? PrintTimeString(*(uint64*)val).c_str() : ""
626 );
627 else
628 subUserData += utils::StringFormat("\"%s\": \"%s\"\n", entryI->index.c_str(), *(uint64*)val ? PrintTimeString(*(uint64*)val).c_str() : "");
629 break;
630 case CHARDATAID:
631 if (!asText)
632 subUserData += utils::StringFormat("\"%s\": {\"type\": \"binary\", \"size\": %u }\n", entryI->index.c_str(), ((DataMessageEntryHeader*)ep)->size - sizeof(DataMessageEntryHeader));
633 break;
634 case DATAMESSAGEID:
635 msg = new DataMessage(val);
636 if (msg) {
637 if (subUserData.length()) subUserData += ", ";
638 if (!asText)
639 subUserData += utils::StringFormat("\"%s\": {\"type\": \"message\", \"value\": %s }\n", entryI->index.c_str(), msg->toJSON().c_str());
640 else
641 subUserData += utils::StringFormat("\"%s\": %s\n", entryI->index.c_str(), msg->getUserEntriesAsJSON(true).c_str());
642 }
643 delete(msg);
644 break;
645 case INTID:
646 if (!asText)
647 subUserData += utils::StringFormat("\"%s\": {\"type\": \"integer\", \"value\": %lld }\n", entryI->index.c_str(), *(int64*)val);
648 else
649 subUserData += utils::StringFormat("\"%s\": \"%lld\"\n", entryI->index.c_str(), *(int64*)val);
650 break;
651 case DOUBLEID:
652 if (!asText)
653 subUserData += utils::StringFormat("\"%s\": {\"type\": \"double\", \"value\": %f }\n", entryI->index.c_str(), *(float64*)val);
654 else
655 subUserData += utils::StringFormat("\"%s\": \"%f\" }\n", entryI->index.c_str(), *(float64*)val);
656 break;
657 case CONSTCHARINFOID:
658 if (!asText)
659 subUserData += utils::StringFormat("\"%s\": {\"type\": \"textinfo\", \"size\": %lld }", entryI->index.c_str(), *(int64*)val);
660 break;
661 case CHARDATAINFOID:
662 if (!asText)
663 subUserData += utils::StringFormat("\"%s\": {\"type\": \"binary\", \"size\": %lld }", entryI->index.c_str(), *(int64*)val);
664 break;
666 if (!asText)
667 subUserData += utils::StringFormat("\"%s\": {\"type\": \"messageinfo\", \"size\": %lld }", entryI->index.c_str(), *(int64*)val);
668 break;
669 default:
670 break;
671 }
672 entryI++;
673 }
674 if (userData.length()) userData += ", ";
675 if (!asText)
676 userData += utils::StringFormat("\"%s\": {\"type\": \"map\", \"value\":\n{%s} }\n", keyI->first.c_str(), subUserData.c_str());
677 else
678 userData += utils::StringFormat("\"%s\": {%s}\n", keyI->first.c_str(), subUserData.c_str());
679 keyI++;
680 }
681
682 return utils::StringFormat("{\n%s}\n", userData.c_str());
683}
684
685
686std::string DataMessage::toJSON(std::map<uint16, std::string>* subtypes, std::map<uint16, std::string>* subcontexts, std::map<uint32, std::string>* compNames) {
687 if (data->cid != DATAMESSAGEID) return "";
688
689 if (!data->userCount)
690 return data->toJSON(subtypes, subcontexts, compNames);
691
692 std::string userData = getUserEntriesAsJSON(false);
693
694 std::map< std::string, std::list<std::string> > userMaps;
695 std::map< std::string, std::list<int64> > userArrays;
696
697 uint32 draftSize = 0;
698 uint32 draftUserSize = 0;
699 uint32 draftUserCount = 0;
700
701 const char* key;
702 char* src = (char*)data + sizeof(DataMessageHeader);
703 char* srcEnd = (char*)data + data->size;
704 while (src < srcEnd) {
705 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
706 key = src + sizeof(DataMessageEntryHeader);
707 src += sizeof(DataMessageEntryHeader) + strlen(key) + 1;
708 switch (((DataMessageEntryHeader*)src)->cid) {
710 if (strcmp(key, "OS") == 0)
711 draftSize = (uint32)(*(int64*)(src + sizeof(DataMessageEntryHeader)));
712 else if (strcmp(key, "US") == 0)
713 draftUserSize = (uint32)(*(int64*)(src + sizeof(DataMessageEntryHeader)));
714 else if (strcmp(key, "UC") == 0)
715 draftUserCount = (uint32)(*(int64*)(src + sizeof(DataMessageEntryHeader)));
716 default:
717 break;
718 }
719 }
720 src += ((DataMessageEntryHeader*)src)->size;
721 }
722
723 if (draftSize) {
724 return utils::StringFormat("{ \"draft\":\"yes\", \"size\": %u, \"memid\": \"%llu\", \"time\": \"%llu\", \"time__text\": \"%s\", \"sendtime\": \"%llu\", \"sendtime__text\": \"%s\", \"recvtime\": \"%llu\", \"recvtime__text\": \"%s\", \"origin\": %u, \"destination\": %u, \"ttl\": \"%llu\", \"eol__text\": \"%s\", \"priority\": %u, \"policy\": %u, \"from\": %u, \"to\": %u, \"type\": \"%s\", \"tag\": \"%u\", \"status\": %u, \"reference\": \"%llu\", \"serial\": \"%llu\", \"contextchange\": \"%s\", \"userdatacount\": %u, \"userdatasize\": %u, \"userdata\":\n%s }\n",
725 draftSize, data->memid,
726 data->time, data->time ? PrintTimeString(data->time).c_str() : "",
727 data->sendtime, data->sendtime ? PrintTimeString(data->sendtime).c_str() : "",
728 data->recvtime, data->recvtime ? PrintTimeString(data->recvtime).c_str() : "",
729 data->origin, data->destination, data->ttl, data->ttl ? PrintTimeString(data->time + data->ttl).c_str() : "",
730 data->priority, data->policy, data->from, data->to, data->type.toString().c_str(), data->tag, data->status, data->reference, data->serial,
731 data->contextchange.isValid() ? data->contextchange.toString().c_str() : "",
732 draftUserCount, draftUserSize, userData.c_str());
733 }
734 else {
735 return utils::StringFormat("{ \"size\": %u, \"memid\": \"%llu\", \"time\": \"%llu\", \"time__text\": \"%s\", \"sendtime\": \"%llu\", \"sendtime__text\": \"%s\", \"recvtime\": \"%llu\", \"recvtime__text\": \"%s\", \"origin\": %u, \"destination\": %u, \"ttl\": \"%llu\", \"eol__text\": \"%s\", \"priority\": %u, \"policy\": %u, \"from\": %u, \"to\": %u, \"type\": \"%s\", \"tag\": \"%u\", \"status\": %u, \"reference\": \"%llu\", \"serial\": \"%llu\", \"contextchange\": \"%s\", \"userdatacount\": %u, \"userdatasize\": %u, \"userdata\":\n%s }\n",
736 data->size, data->memid,
737 data->time, data->time ? PrintTimeString(data->time).c_str() : "",
738 data->sendtime, data->sendtime ? PrintTimeString(data->sendtime).c_str() : "",
739 data->recvtime, data->recvtime ? PrintTimeString(data->recvtime).c_str() : "",
740 data->origin, data->destination, data->ttl, data->ttl ? PrintTimeString(data->time + data->ttl).c_str() : "",
741 data->priority, data->policy, data->from, data->to, data->type.toString().c_str(), data->tag, data->status, data->reference, data->serial,
742 data->contextchange.isValid() ? data->contextchange.toString().c_str() : "",
743 data->userCount, data->userSize, userData.c_str());
744 }
745}
746
747std::string DataMessage::toCSV(const char* separator, const char* preample, std::map<uint16, std::string>* subtypes, std::map<uint16, std::string>* subcontexts, std::map<uint32, std::string>* compNames) {
748 // triggername,type,created,sent,received,modulecputime,modulewalltime,chaincputime,chainwalltime,chaincount,size,priority,ttl,from,to,tag,serial,contextchange,userdatacount,userdatasize,userdata
749
750 char sep[64];
751 uint32 len;
752 if (separator && (len = (uint32)strlen(separator)))
753 memcpy(sep, separator, len+1);
754 else
755 memcpy(sep, ",", 2);
756
757 std::string userData;
758 if (data->userCount) {
759 userData = this->getUserEntriesAsString();
760 utils::StringSingleReplace(userData, sep, "*", false);
761 utils::StringSingleReplace(userData, "\n", "||", false);
762 }
763
764 std::string typeStr, contextStr, fromStr, toStr;
765 typeStr = data->type.toString(subtypes);
766 contextStr = data->contextchange.toString(subcontexts);
767 if (compNames) {
768 fromStr = (*compNames)[data->from];
769 toStr = (*compNames)[data->to];
770 }
771 if (!fromStr.length()) {
772 if (data->from)
773 fromStr = utils::StringFormat("Component %u", data->from);
774 }
775 if (!toStr.length()) {
776 if (data->to)
777 toStr = utils::StringFormat("Component %u", data->to);
778 }
779
780 if (preample && strlen(preample)) {
781 return utils::StringFormat("%s%s%s%s%s%s%s%s%s%s%u%s%u%s%u%s%u%s%u%s%u%s%u%s%llu%s%s%s%s%s%u%s%llu%s%s%s%u%s%u%s%s\n",
782 preample, sep,
783 typeStr.c_str(), sep,
784 data->time ? PrintTimeString(data->time).c_str() : "", sep,
785 data->sendtime ? PrintTimeString(data->sendtime).c_str() : "", sep,
786 data->recvtime ? PrintTimeString(data->recvtime).c_str() : "", sep,
787 data->cyclecputime, sep,
788 data->cyclewalltime, sep,
789 data->chaincputime, sep,
790 data->chainwalltime, sep,
791 data->chaincount, sep,
792 data->size, sep,
793 data->priority, sep,
794 data->ttl, sep,
795 fromStr.c_str(), sep,
796 toStr.c_str(), sep,
797 data->tag, sep,
798 data->serial, sep,
799 contextStr.c_str(), sep,
800 data->userCount, sep,
801 data->userSize, sep,
802 userData.c_str());
803 }
804 else {
805 return utils::StringFormat("%s%s%s%s%s%s%s%s%u%s%u%s%u%s%u%s%u%s%u%s%u%s%llu%s%s%s%s%s%u%s%llu%s%s%s%u%s%u%s%s\n",
806 typeStr.c_str(), sep,
807 data->time ? PrintTimeString(data->time).c_str() : "", sep,
808 data->sendtime ? PrintTimeString(data->sendtime).c_str() : "", sep,
809 data->recvtime ? PrintTimeString(data->recvtime).c_str() : "", sep,
810 data->cyclecputime, sep,
811 data->cyclewalltime, sep,
812 data->chaincputime, sep,
813 data->chainwalltime, sep,
814 data->chaincount, sep,
815 data->size, sep,
816 data->priority, sep,
817 data->ttl, sep,
818 fromStr.c_str(), sep,
819 toStr.c_str(), sep,
820 data->tag, sep,
821 data->serial, sep,
822 contextStr.c_str(), sep,
823 data->userCount, sep,
824 data->userSize, sep,
825 userData.c_str());
826 }
827}
828
829std::string DataMessage::GetCSVHeader(const char* separator, const char* preample) {
830 // triggername,type,created,sent,received,modulecputime,modulewalltime,chaincputime,chainwalltime,chaincount,size,priority,ttl,from,to,tag,serial,contextchange,userdatacount,userdatasize,userdata
831
832 char sep[64];
833 uint32 len;
834 if (separator && (len = (uint32)strlen(separator)))
835 memcpy(sep, separator, len + 1);
836 else
837 memcpy(sep, ",", 2);
838
839 std::string header;
840 if (preample && strlen(preample))
841 header = utils::StringFormat("%s,type,created,sent,received,modulecputime,modulewalltime,chaincputime,chainwalltime,chaincount,size,priority,ttl,from,to,tag,serial,contextchange,userdatacount,userdatasize,userdata\n", preample);
842 else
843 header = "type,created,sent,received,modulecputime,modulewalltime,chaincputime,chainwalltime,chaincount,size,priority,ttl,from,to,tag,serial,contextchange,userdatacount,userdatasize,userdata\n";
844
845 if (stricmp(sep, ",") != 0)
846 utils::StringSingleReplace(header, ",", sep, false);
847
848 return header;
849}
850
851
852std::string DataMessage::toXML(std::map<uint16, std::string>* subtypes, std::map<uint16, std::string>* subcontexts, std::map<uint32, std::string>* compNames) {
853 if (data->cid != DATAMESSAGEID) return "";
854
855 if (!data->userCount)
856 return data->toXML(subtypes, subcontexts, compNames);
857
858 std::map< std::string, std::list<ArrayElem> > userArrays;
859 std::map< std::string, std::list<MapElem> > userMaps;
860 uint32 draftSize = 0;
861 uint32 draftUserSize = 0;
862 uint32 draftUserCount = 0;
863
864 const char* oldData = NULL;
865 DataMessage* msg = new DataMessage();
866 const char* key;
867 const char* mapStart, *mapEnd;
868 std::string userData;
869 userData.reserve(data->userSize + data->userCount * 64);
870 char* src = (char*)data + sizeof(DataMessageHeader);
871 char* srcEnd = (char*)data + data->size;
872 while (src < srcEnd) {
873 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
874 key = src + sizeof(DataMessageEntryHeader);
875 src += sizeof(DataMessageEntryHeader) + strlen(key) + 1;
876 if ((mapStart = strstr(key, "_-|")) && (mapEnd = strstr(key, "|-_"))) {
877 ArrayElem e;
878 e.index = utils::Ascii2Int64(std::string(mapStart + 3, mapEnd - mapStart - 3).c_str());
879 e.entryPtr = src;
880 e.cid = ((DataMessageEntryHeader*)src)->cid;
881 userArrays[std::string(key, mapStart - key)].push_back(e);
882 src += ((DataMessageEntryHeader*)src)->size;
883 continue;
884 }
885 else if ((mapStart = strstr(key, "_-[")) && (mapEnd = strstr(key, "]-_"))) {
886 MapElem e;
887 e.index = std::string(mapStart + 3, mapEnd - mapStart - 3);
888 e.entryPtr = src;
889 e.cid = ((DataMessageEntryHeader*)src)->cid;
890 userMaps[std::string(key, mapStart - key)].push_back(e);
891 src += ((DataMessageEntryHeader*)src)->size;
892 continue;
893 }
894 switch (((DataMessageEntryHeader*)src)->cid) {
895 case CONSTCHARID:
896 userData += utils::StringFormat("<data name=\"%s\" type=\"text\" value=\"%s\" />\n", key, src + sizeof(DataMessageEntryHeader));
897 break;
898 case TIMEID:
899 userData += utils::StringFormat("<data name=\"%s\" type=\"time\" value=\"%llu\" text=\"%s\" />\n",
900 key,
901 *(uint64*)(src + sizeof(DataMessageEntryHeader)),
902 *(uint64*)(src + sizeof(DataMessageEntryHeader)) ?
903 PrintTimeString(*(uint64*)(src + sizeof(DataMessageEntryHeader))).c_str() : ""
904 );
905 break;
906 case CHARDATAID:
907 userData += utils::StringFormat("<data name=\"%s\" type=\"binary\" size=\"%u\" />\n", key, ((DataMessageEntryHeader*)src)->size - sizeof(DataMessageEntryHeader));
908 break;
909 case INTID:
910 userData += utils::StringFormat("<data name=\"%s\" type=\"integer\" value=\"%lld\" />\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
911 break;
912 case DOUBLEID:
913 userData += utils::StringFormat("<data name=\"%s\" type=\"float\" value=\"%f\" />\n", key, *(float64*)(src + sizeof(DataMessageEntryHeader)));
914 break;
915 case DATAMESSAGEID:
916 if (((DataMessageHeader*)(src + sizeof(DataMessageEntryHeader)))->cid == DATAMESSAGEID) {
917 if (!oldData)
918 oldData = msg->swapMessageData(src + sizeof(DataMessageEntryHeader));
919 else
920 msg->swapMessageData(src + sizeof(DataMessageEntryHeader));
921 //msg = new DataMessage(src + sizeof(DataMessageEntryHeader));
922 //if (msg)
923 userData += utils::StringFormat("<data name=\"%s\" type=\"datamessage\">\n%s</data>", key, msg->toXML().c_str());
924 //delete(msg);
925 }
926 break;
927 case CONSTCHARINFOID:
928 userData += utils::StringFormat("<data name=\"%s\" type=\"textinfo\" size=\"%u\" />\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
929 break;
930 case CHARDATAINFOID:
931 userData += utils::StringFormat("<data name=\"%s\" type=\"binary\" size=\"%u\" />\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
932 break;
934 userData += utils::StringFormat("<data name=\"%s\" type=\"messageinfo\" size=\"%u\" />\n", key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
935 break;
937 if (strcmp(key, "OS") == 0)
938 draftSize = (uint32)(*(int64*)(src + sizeof(DataMessageEntryHeader)));
939 else if (strcmp(key, "US") == 0)
940 draftUserSize = (uint32)(*(int64*)(src + sizeof(DataMessageEntryHeader)));
941 else if (strcmp(key, "UC") == 0)
942 draftUserCount = (uint32)(*(int64*)(src + sizeof(DataMessageEntryHeader)));
943 default:
944 break;
945 }
946 }
947 // else cannot generate JSON for this entry
948 src += ((DataMessageEntryHeader*)src)->size;
949 }
950
951 if (oldData)
952 msg->swapMessageData(oldData);
953 delete(msg);
954
955 std::string subUserData;
956
957 std::list<ArrayElem>::iterator entryII, entryEE;
958 std::map< std::string, std::list<ArrayElem> >::iterator keyII = userArrays.begin(), keyEE = userArrays.end();
959 while (keyII != keyEE) {
960 subUserData.clear();
961 entryII = keyII->second.begin();
962 entryEE = keyII->second.end();
963 while (entryII != entryEE) {
964 char* ep = entryII->entryPtr;
965 char* val = ep + sizeof(DataMessageEntryHeader);
966 uint32 cid = entryII->cid;
967 switch (cid) {
968 case CONSTCHARID:
969 subUserData += utils::StringFormat("<data name=\"%lld\" type=\"text\" value=\"%s\" />\n", entryII->index, val);
970 break;
971 case TIMEID:
972 subUserData += utils::StringFormat("<data name=\"%lld\" type=\"time\" value=\"%llu\" text=\"%s\" />\n",
973 entryII->index, *(uint64*)val,
974 *(uint64*)val ? PrintTimeString(*(uint64*)val).c_str() : ""
975 );
976 break;
977 case CHARDATAID:
978 subUserData += utils::StringFormat("<data name=\"%lld\" type=\"binary\" size=\"%u\" />\n", entryII->index, ((DataMessageEntryHeader*)ep)->size - sizeof(DataMessageEntryHeader));
979 break;
980 case INTID:
981 subUserData += utils::StringFormat("<data name=\"%lld\" type=\"integer\" value=\"%lld\" />\n", entryII->index, *(int64*)val);
982 break;
983 case DOUBLEID:
984 subUserData += utils::StringFormat("<data name=\"%lld\" type=\"float\" value=\"%f\" />\n", entryII->index, *(float64*)val);
985 break;
986 case DATAMESSAGEID:
987 msg = new DataMessage(val);
988 if (msg) {
989 subUserData += utils::StringFormat("<data name=\"%lld\" type=\"datamessage\">\n%s</data>", entryII->index, msg->toXML().c_str());
990 delete(msg);
991 }
992 break;
993 case CONSTCHARINFOID:
994 subUserData += utils::StringFormat("<data name=\"%lld\" type=\"textinfo\" size=\"%lld\" />\n", entryII->index, *(int64*)val);
995 break;
996 case CHARDATAINFOID:
997 subUserData += utils::StringFormat("<data name=\"%lld\" type=\"binary\" size=\"%lld\" />\n", entryII->index, *(int64*)val);
998 break;
1000 subUserData += utils::StringFormat("<data name=\"%lld\" type=\"messageinfo\" size=\"%lld\" />\n", entryII->index, *(int64*)val);
1001 break;
1002 default:
1003 break;
1004 }
1005 entryII++;
1006 }
1007 userData += utils::StringFormat("<array name=\"%s\">\n%s</array>\n", keyII->first.c_str(), subUserData.c_str());
1008 keyII++;
1009 }
1010
1011 std::list<MapElem>::iterator entryI, entryE;
1012 std::map< std::string, std::list<MapElem> >::iterator keyI = userMaps.begin(), keyE = userMaps.end();
1013 while (keyI != keyE) {
1014 subUserData.clear();
1015 entryI = keyI->second.begin();
1016 entryE = keyI->second.end();
1017 while (entryI != entryE) {
1018 char* ep = entryI->entryPtr;
1019 char* val = ep + sizeof(DataMessageEntryHeader);
1020 uint32 cid = entryI->cid;
1021 switch (cid) {
1022 case CONSTCHARID:
1023 subUserData += utils::StringFormat("<data name=\"%s\" type=\"text\" value=\"%s\" />\n", entryI->index.c_str(), val);
1024 break;
1025 case TIMEID:
1026 subUserData += utils::StringFormat("<data name=\"%s\" type=\"time\" value=\"%llu\" text=\"%s\" />\n",
1027 entryI->index.c_str(), *(uint64*)val,
1028 *(uint64*)val ? PrintTimeString(*(uint64*)val).c_str() : ""
1029 );
1030 break;
1031 case CHARDATAID:
1032 subUserData += utils::StringFormat("<data name=\"%s\" type=\"binary\" size=\"%u\" />\n", entryI->index.c_str(), ((DataMessageEntryHeader*)ep)->size - sizeof(DataMessageEntryHeader));
1033 break;
1034 case INTID:
1035 subUserData += utils::StringFormat("<data name=\"%s\" type=\"integer\" value=\"%lld\" />\n", entryI->index.c_str(), *(int64*)val);
1036 break;
1037 case DOUBLEID:
1038 subUserData += utils::StringFormat("<data name=\"%s\" type=\"float\" value=\"%f\" />\n", entryI->index.c_str(), *(float64*)val);
1039 break;
1040 case DATAMESSAGEID:
1041 msg = new DataMessage(val);
1042 if (msg) {
1043 subUserData += utils::StringFormat("<data name=\"%s\" type=\"datamessage\">\n%s</data>", entryI->index.c_str(), msg->toXML().c_str());
1044 delete(msg);
1045 }
1046 break;
1047 case CONSTCHARINFOID:
1048 subUserData += utils::StringFormat("<data name=\"%s\" type=\"textinfo\" size=\"%lld\" />\n", entryI->index.c_str(), *(int64*)val);
1049 break;
1050 case CHARDATAINFOID:
1051 subUserData += utils::StringFormat("<data name=\"%s\" type=\"binary\" size=\"%lld\" />\n", entryI->index.c_str(), *(int64*)val);
1052 break;
1053 case DATAMESSAGEINFOID:
1054 subUserData += utils::StringFormat("<data name=\"%s\" type=\"messageinfo\" size=\"%lld\" />\n", entryI->index.c_str(), *(int64*)val);
1055 break;
1056 default:
1057 break;
1058 }
1059 entryI++;
1060 }
1061 userData += utils::StringFormat("<map name=\"%s\">\n%s</map>\n", keyI->first.c_str(), subUserData.c_str());
1062 keyI++;
1063 }
1064
1065 if (draftSize) {
1066 return utils::StringFormat("<datamessage draft=\"yes\" size=\"%u\" memid=\"%llu\" time=\"%llu\" timetext=\"%s\" sendtime=\"%llu\" sendtimetext=\"%s\" recvtime=\"%llu\" recvtimetext=\"%s\" origin=\"%u\" destination=\"%u\" ttl=\"%llu\" eoltext=\"%s\" priority=\"%u\" policy=\"%u\" from=\"%u\" to=\"%u\" type=\"%s\" tag=\"%u\" status=\"%u\" reference=\"%llu\" serial=\"%llu\" contextchange=\"%s\" userdatacount=\"%u\" userdatasize=\"%u\">\n%s</datamessage>\n",
1067 draftSize, data->memid,
1068 data->time, data->time ? PrintTimeString(data->time).c_str() : "",
1069 data->sendtime, data->sendtime ? PrintTimeString(data->sendtime).c_str() : "",
1070 data->recvtime, data->recvtime ? PrintTimeString(data->recvtime).c_str() : "",
1071 data->origin, data->destination, data->ttl, data->ttl ? PrintTimeString(data->time + data->ttl).c_str() : "",
1072 data->priority, data->policy, data->from, data->to, data->type.toString().c_str(), data->tag, data->status, data->reference, data->serial, data->contextchange.isValid() ? data->contextchange.toString().c_str() : "", draftUserCount, draftUserSize, userData.c_str());
1073 }
1074 else {
1075 return utils::StringFormat("<datamessage size=\"%u\" memid=\"%llu\" time=\"%llu\" timetext=\"%s\" sendtime=\"%llu\" sendtimetext=\"%s\" recvtime=\"%llu\" recvtimetext=\"%s\" origin=\"%u\" destination=\"%u\" ttl=\"%llu\" eoltext=\"%s\" priority=\"%u\" policy=\"%u\" from=\"%u\" to=\"%u\" type=\"%s\" tag=\"%u\" status=\"%u\" reference=\"%llu\" serial=\"%llu\" contextchange=\"%s\" userdatacount=\"%u\" userdatasize=\"%u\">\n%s</datamessage>\n",
1076 data->size, data->memid,
1077 data->time, data->time ? PrintTimeString(data->time).c_str() : "",
1078 data->sendtime, data->sendtime ? PrintTimeString(data->sendtime).c_str() : "",
1079 data->recvtime, data->recvtime ? PrintTimeString(data->recvtime).c_str() : "",
1080 data->origin, data->destination, data->ttl, data->ttl ? PrintTimeString(data->time + data->ttl).c_str() : "",
1081 data->priority, data->policy, data->from, data->to, data->type.toString().c_str(), data->tag, data->status, data->reference, data->serial, data->contextchange.isValid() ? data->contextchange.toString().c_str() : "", data->userCount, data->userSize, userData.c_str());
1082 }
1083}
1084
1085
1086
1087
1088// ################# Constructors #################
1089
1090// ---------------------------------------------------------------------------
1091// Constructors. All of them establish the invariant described at the top of
1092// this file: 'data' is a single malloc'ed block whose header fields size,
1093// cid (DATAMESSAGEID) and cver (CURRENTDATAMESSAGEVERSION) are always valid.
1094// Header-only construction is a plain malloc+memset; entries are appended
1095// later by setRawData() growing the block with realloc.
1096// ---------------------------------------------------------------------------
1098 this->data = (DataMessageHeader*) malloc(sizeof(DataMessageHeader));
1099 memset((char*)this->data, 0, sizeof(DataMessageHeader));
1100 data->size = sizeof(DataMessageHeader);
1101 data->cid = DATAMESSAGEID;
1103 data->time = GetTimeNow();
1105}
1106
1108 this->data = (DataMessageHeader*) malloc(sizeof(DataMessageHeader));
1109 memset((char*)this->data, 0, sizeof(DataMessageHeader));
1110 data->size = sizeof(DataMessageHeader);
1111 data->cid = DATAMESSAGEID;
1113 data->type = type;
1114 data->time = GetTimeNow();
1115 data->from = from;
1117}
1118
1119DataMessage::DataMessage(PsyType type, uint32 from, uint32 to, uint64 ttl, uint16 priority) {
1120 this->data = (DataMessageHeader*) malloc(sizeof(DataMessageHeader));
1121 memset((char*)this->data, 0, sizeof(DataMessageHeader));
1122 data->size = sizeof(DataMessageHeader);
1123 data->cid = DATAMESSAGEID;
1125 data->type = type;
1126 data->time = GetTimeNow();
1127 data->from = from;
1128 data->to = to;
1129 data->ttl = ttl;
1130 data->priority = priority;
1132}
1133
1134DataMessage::DataMessage(PsyType type, uint32 from, uint32 to, uint32 tag, uint64 time, uint64 ttl, uint16 priority) {
1135 this->data = (DataMessageHeader*) malloc(sizeof(DataMessageHeader));
1136 memset((char*)this->data, 0, sizeof(DataMessageHeader));
1137 data->size = sizeof(DataMessageHeader);
1138 data->cid = DATAMESSAGEID;
1140 data->type = type;
1141 data->time = GetTimeNow();
1142 data->from = from;
1143 data->to = to;
1144 data->tag = tag;
1145 data->time = time;
1146 data->ttl = ttl;
1147 data->priority = priority;
1149}
1150
1151// Adopting/copying constructor for raw serialised bytes (e.g. straight off a
1152// socket). Handles three cases:
1153// - old-format block (DATAMESSAGEOLDID): converted into a fresh block via
1154// ConvertDataFromOlderMessageFormat(); the input is delete[]'d when
1155// copy==false because ownership was transferred to us.
1156// - current-format block: adopted in place (copy==false, zero-copy - the
1157// caller must NOT free it afterwards) or duplicated (copy==true; the
1158// total size is read from the leading uint32).
1159// - anything else / failed conversion: falls through to an empty message so
1160// the object is always usable.
1161// The "check cpu numbers" fixup repairs cycle/chain CPU counters that were
1162// written as wrapped-around (MAXVALUINT32 - x) values by older senders.
1164 char* newData = NULL;
1165 if (GetObjID(data) == DATAMESSAGEOLDID) {
1166 if (ConvertDataFromOlderMessageFormat(data, &newData) && newData) {
1167 this->data = (DataMessageHeader*)newData;
1168 if (!copy)
1169 delete[] data;
1171 return;
1172 }
1173 else
1174 delete[] newData;
1175 }
1176 else if (GetObjID(data) == DATAMESSAGEID) {
1177 // check cpu numbers
1178 if (((DataMessageHeader*)data)->cyclecputime > 10000 * (((DataMessageHeader*)data)->cyclewalltime)) {
1179 ((DataMessageHeader*)data)->cyclecputime = MAXVALUINT32 - (((DataMessageHeader*)data)->cyclecputime);
1180 ((DataMessageHeader*)data)->chaincputime = MAXVALUINT32 - (((DataMessageHeader*)data)->chaincputime);
1181 }
1183 if (!copy)
1184 this->data = (DataMessageHeader*)data;
1185 else {
1186 uint32 size = *(uint32*)data;
1187 this->data = (DataMessageHeader*)malloc(size);
1188 memcpy(this->data, data, size);
1189 }
1191 return;
1192 }
1193 else {
1194 if (ConvertDataFromOlderMessageFormat(data, &newData) && newData) {
1195 this->data = (DataMessageHeader*)newData;
1196 if (!copy)
1197 delete[] data;
1199 return;
1200 }
1201 else
1202 delete[] newData;
1203 }
1204 }
1205
1206 // If we get here, everything else failed, just create empty message
1207 this->data = (DataMessageHeader*) malloc(sizeof(DataMessageHeader));
1208 memset((char*)this->data, 0, sizeof(DataMessageHeader));
1209 this->data->size = sizeof(DataMessageHeader);
1210 this->data->cid = DATAMESSAGEID;
1211 this->data->cver = CURRENTDATAMESSAGEVERSION;
1213 return;
1214}
1215
1216// Const-input variant of the above: never adopts, always converts or copies
1217// (the source bytes are left untouched apart from the CPU-counter fixup).
1219 char* newData = NULL;
1220 if (GetObjID(data) == DATAMESSAGEOLDID) {
1221 if (ConvertDataFromOlderMessageFormat(data, &newData) && newData) {
1222 this->data = (DataMessageHeader*)newData;
1224 return;
1225 }
1226 else
1227 delete[] newData;
1228 }
1229 else if (GetObjID(data) == DATAMESSAGEID) {
1230 // check cpu numbers
1231 if (((DataMessageHeader*)data)->cyclecputime > 10 * (((DataMessageHeader*)data)->cyclewalltime)) {
1232 ((DataMessageHeader*)data)->cyclecputime = MAXVALUINT32 - (((DataMessageHeader*)data)->cyclecputime);
1233 ((DataMessageHeader*)data)->chaincputime = MAXVALUINT32 - (((DataMessageHeader*)data)->chaincputime);
1234 }
1236 uint32 size = *(uint32*)data;
1237 this->data = (DataMessageHeader*)malloc(size);
1238 memcpy(this->data, data, size);
1240 return;
1241 }
1242 else {
1243 if (ConvertDataFromOlderMessageFormat(data, &newData) && newData) {
1244 this->data = (DataMessageHeader*)newData;
1246 return;
1247 }
1248 else
1249 delete[] newData;
1250 }
1251 }
1252
1253 // If we get here, everything else failed, just create empty message
1254 this->data = (DataMessageHeader*)malloc(sizeof(DataMessageHeader));
1255 memset((char*)this->data, 0, sizeof(DataMessageHeader));
1256 this->data->size = sizeof(DataMessageHeader);
1257 this->data->cid = DATAMESSAGEID;
1258 this->data->cver = CURRENTDATAMESSAGEVERSION;
1260 return;
1261}
1262
1263// Deep-copy constructor: one malloc + one memcpy of the whole flat block.
1265 if (GetObjID(msg.data) != DATAMESSAGEID) {
1266 this->data = (DataMessageHeader*) malloc(sizeof(DataMessageHeader));
1267 memset((char*)this->data, 0, sizeof(DataMessageHeader));
1268 this->data->size = sizeof(DataMessageHeader);
1269 this->data->cid = DATAMESSAGEID;
1270 this->data->cver = CURRENTDATAMESSAGEVERSION;
1272 return;
1273 }
1274 this->data = (DataMessageHeader*)malloc(msg.data->size);
1275 memcpy(this->data, msg.data, msg.data->size);
1277}
1278
1279// "Draft" constructor: build a size-capped preview of a (possibly huge)
1280// message. If the source fits within maxDraftSize it is copied verbatim;
1281// otherwise only the header is copied and fillInDraftUserDataFrom() adds as
1282// many entries as the budget allows, replacing oversized content with
1283// *INFOID size placeholders. Old-format input is first converted via a
1284// temporary full message.
1285DataMessage::DataMessage(const char* data, uint32 maxDraftSize) {
1286 if ((GetObjID(data) == DATAMESSAGEOLDID) ||
1288 DataMessage* correctMsg = new DataMessage(data, true);
1289 const char* newData = (const char*)correctMsg->data;
1290 uint32 size = *(uint32*)newData;
1291 if (size <= maxDraftSize) {
1292 this->data = (DataMessageHeader*)malloc(size);
1293 memcpy(this->data, newData, size);
1294 }
1295 else {
1296 this->data = (DataMessageHeader*)malloc(maxDraftSize);
1297 memcpy(this->data, newData, sizeof(DataMessageHeader));
1298 fillInDraftUserDataFrom(newData, maxDraftSize);
1299 }
1300 delete(correctMsg);
1302 return;
1303 }
1304 else if (GetObjID(data) != DATAMESSAGEID) {
1305 this->data = (DataMessageHeader*)malloc(sizeof(DataMessageHeader));
1306 memset((char*)this->data, 0, sizeof(DataMessageHeader));
1307 this->data->size = sizeof(DataMessageHeader);
1308 this->data->cid = DATAMESSAGEID;
1309 this->data->cver = CURRENTDATAMESSAGEVERSION;
1311 return;
1312 }
1313
1314 uint32 size = *(uint32*)data;
1315 if (size <= maxDraftSize) {
1316 this->data = (DataMessageHeader*)malloc(size);
1317 memcpy(this->data, data, size);
1318 }
1319 else {
1320 this->data = (DataMessageHeader*)malloc(maxDraftSize);
1321 memcpy(this->data, data, sizeof(DataMessageHeader));
1322 fillInDraftUserDataFrom(data, maxDraftSize);
1323 }
1325}
1326
1327// Draft copy of an existing message; same budget logic as above.
1328DataMessage::DataMessage(const DataMessage& msg, uint32 maxDraftSize) {
1329 if (GetObjID(msg.data) != DATAMESSAGEID) {
1330 this->data = (DataMessageHeader*)malloc(sizeof(DataMessageHeader));
1331 memset((char*)this->data, 0, sizeof(DataMessageHeader));
1332 this->data->size = sizeof(DataMessageHeader);
1333 this->data->cid = DATAMESSAGEID;
1334 this->data->cver = CURRENTDATAMESSAGEVERSION;
1336 return;
1337 }
1338 uint32 size = *(uint32*)msg.data;
1339 if (size <= maxDraftSize) {
1340 this->data = (DataMessageHeader*)malloc(size);
1341 memcpy(this->data, msg.data, size);
1342 }
1343 else {
1344 this->data = (DataMessageHeader*)malloc(maxDraftSize);
1345 memcpy(this->data, msg.data, sizeof(DataMessageHeader));
1346 fillInDraftUserDataFrom((char*)msg.data, maxDraftSize);
1347 }
1349}
1350
1351// Populate a draft message from a full serialised block without exceeding
1352// maxDraftSize. Strategy:
1353// 0. record the original totals as DATAMESSAGEDRAFTID entries "OS"
1354// (original size), "US" (user bytes) and "UC" (user count) so a reader
1355// can tell what was elided;
1356// 1. first pass copies all SMALL values (time/int/double) verbatim and
1357// replaces binary blobs and nested messages by int64 size placeholders
1358// (*INFOID cids);
1359// 2. second pass adds full strings while room remains, then falls back to
1360// CONSTCHARINFOID size placeholders.
1361// Entries that do not even fit as placeholders are merely counted into
1362// userCount/userSize so the header still reflects the full message.
1363bool DataMessage::fillInDraftUserDataFrom(const char* rawdata, uint32 maxDraftSize) {
1365 if (data->cid != DATAMESSAGEID) return false;
1366
1367 if (!data->userCount)
1368 return true;
1369
1370 this->data->size = sizeof(DataMessageHeader);
1371 uint32 draftInfoSize = (uint32)((2 * sizeof(DataMessageEntryHeader)) + 3 + sizeof(int64));
1372 if (this->data->size + (3 * draftInfoSize) > maxDraftSize)
1373 return false;
1374
1375 this->data->userCount = 0;
1376 this->data->userSize = 0;
1377
1378 int64 size;
1379 uint32 itemSize;
1380
1381 size = data->size;
1382 setRawData("OS", (char*)&size, sizeof(int64), DATAMESSAGEDRAFTID);
1383 size = data->userSize;
1384 setRawData("US", (char*)&size, sizeof(int64), DATAMESSAGEDRAFTID);
1385 size = data->userCount;
1386 setRawData("UC", (char*)&size, sizeof(int64), DATAMESSAGEDRAFTID);
1387
1388 std::map< std::string, std::list<std::string> > userMaps;
1389
1390 const char* key;
1391 std::string userData;
1392
1393 // First try to add all the small data info (int, float, time and info about binary, messages)
1394 char* src = (char*)data + sizeof(DataMessageHeader);
1395 char* srcEnd = (char*)data + data->size;
1396 while (src < srcEnd) {
1397 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
1398 key = src + sizeof(DataMessageEntryHeader);
1399 itemSize = (uint32)(sizeof(DataMessageEntryHeader) + strlen(key) + 1);
1400 src += itemSize;
1401 switch (((DataMessageEntryHeader*)src)->cid) {
1402 case TIMEID:
1403 itemSize += sizeof(DataMessageEntryHeader) + sizeof(uint64);
1404 if (this->data->size + itemSize < maxDraftSize) {
1405 setTime(key, *(uint64*)(src + sizeof(DataMessageEntryHeader)));
1406 }
1407 else {
1408 this->data->userCount++;
1409 this->data->userSize += itemSize;
1410 }
1411 break;
1412 case INTID:
1413 itemSize += sizeof(DataMessageEntryHeader) + sizeof(int64);
1414 if (this->data->size + itemSize < maxDraftSize) {
1415 setInt(key, *(int64*)(src + sizeof(DataMessageEntryHeader)));
1416 }
1417 else {
1418 this->data->userCount++;
1419 this->data->userSize += itemSize;
1420 }
1421 break;
1422 case DOUBLEID:
1423 itemSize += sizeof(DataMessageEntryHeader) + sizeof(float64);
1424 if (this->data->size + itemSize < maxDraftSize) {
1425 setDouble(key, (double)*(float64*)(src + sizeof(DataMessageEntryHeader)));
1426 }
1427 else {
1428 this->data->userCount++;
1429 this->data->userSize += itemSize;
1430 }
1431 break;
1432 case CHARDATAID:
1433 size = ((DataMessageEntryHeader*)src)->size - sizeof(DataMessageEntryHeader);
1434 itemSize += sizeof(DataMessageEntryHeader) + sizeof(int64);
1435 if (this->data->size + itemSize < maxDraftSize) {
1436 setRawData(key, (char*)&size, sizeof(int64), CHARDATAINFOID);
1437 }
1438 else {
1439 this->data->userCount++;
1440 this->data->userSize += itemSize - sizeof(int64) + (uint32)size;
1441 }
1442 break;
1443 case DATAMESSAGEID:
1444 size = ((DataMessageEntryHeader*)src)->size - sizeof(DataMessageEntryHeader);
1445 itemSize += sizeof(DataMessageEntryHeader) + sizeof(int64);
1446 if (this->data->size + itemSize < maxDraftSize) {
1447 setRawData(key, (char*)&size, sizeof(int64), DATAMESSAGEID);
1448 }
1449 else {
1450 this->data->userCount++;
1451 this->data->userSize += itemSize - sizeof(int64) + (uint32)size;
1452 }
1453 break;
1454
1455 case CONSTCHARINFOID:
1456 size = (*(int64*)(src + sizeof(DataMessageEntryHeader)));
1457 itemSize += sizeof(DataMessageEntryHeader) + sizeof(int64);
1458 if (this->data->size + itemSize < maxDraftSize) {
1459 setRawData(key, (char*)&size, sizeof(int64), CONSTCHARINFOID);
1460 }
1461 else {
1462 this->data->userCount++;
1463 this->data->userSize += itemSize - sizeof(int64) + (uint32)size;
1464 }
1465 break;
1466 case CHARDATAINFOID:
1467 size = (*(int64*)(src + sizeof(DataMessageEntryHeader)));
1468 itemSize += sizeof(DataMessageEntryHeader) + sizeof(int64);
1469 if (this->data->size + itemSize < maxDraftSize) {
1470 setRawData(key, (char*)&size, sizeof(int64), CHARDATAINFOID);
1471 }
1472 else {
1473 this->data->userCount++;
1474 this->data->userSize += itemSize - sizeof(int64) + (uint32)size;
1475 }
1476 break;
1477 case DATAMESSAGEINFOID:
1478 size = (*(int64*)(src + sizeof(DataMessageEntryHeader)));
1479 itemSize += sizeof(DataMessageEntryHeader) + sizeof(int64);
1480 if (this->data->size + itemSize < maxDraftSize) {
1481 setRawData(key, (char*)&size, sizeof(int64), DATAMESSAGEINFOID);
1482 }
1483 else {
1484 this->data->userCount++;
1485 this->data->userSize += itemSize - sizeof(int64) + (uint32)size;
1486 }
1487 break;
1488 // Ignore these for now
1489 case CONSTCHARID:
1490 default:
1491 break;
1492 }
1493 }
1494 src += ((DataMessageEntryHeader*)src)->size;
1495 }
1496
1497 // Now try to see how many strings we have room for
1498 src = (char*)data + sizeof(DataMessageHeader);
1499 srcEnd = (char*)data + data->size;
1500 while (src < srcEnd) {
1501 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
1502 key = src + sizeof(DataMessageEntryHeader);
1503 itemSize = (uint32)(sizeof(DataMessageEntryHeader) + strlen(key) + 1);
1504 src += itemSize;
1505 switch (((DataMessageEntryHeader*)src)->cid) {
1506 case CONSTCHARID:
1507 size = ((DataMessageEntryHeader*)src)->size - sizeof(DataMessageEntryHeader);
1508 itemSize += sizeof(DataMessageEntryHeader);
1509 if (this->data->size + itemSize + size < maxDraftSize) {
1510 // add the whole thing
1511 setString(key, (src + sizeof(DataMessageEntryHeader)));
1512 }
1513 else if (this->data->size + itemSize + sizeof(int64) < maxDraftSize) {
1514 setRawData(key, (char*)&size, sizeof(int64), CONSTCHARINFOID);
1515 }
1516 else {
1517 this->data->userCount++;
1518 this->data->userSize += itemSize + (uint32)size;
1519 }
1520 break;
1521 case TIMEID:
1522 case INTID:
1523 case DOUBLEID:
1524 case CHARDATAID:
1525 case DATAMESSAGEID:
1526 case CONSTCHARINFOID:
1527 case CHARDATAINFOID:
1528 case DATAMESSAGEINFOID:
1529 default:
1530 break;
1531 }
1532 }
1533 src += ((DataMessageEntryHeader*)src)->size;
1534 }
1535
1536 return true;
1537}
1538
1539
1540// The block was allocated with malloc/realloc, hence free() (not delete).
1542 //printf("Deleting msg: %u.%u.%u (%p)...\n", data->type[0], data->type[1], data->type[2], this);
1543 free(data);
1544 data = NULL;
1545}
1546
1547// Swap the underlying flat block for another one WITHOUT copying; returns
1548// the old block so the caller can free or re-adopt it. Used by memory-pool
1549// style callers to re-point a wrapper at shared memory. The find cache must
1550// be dropped because every cached pointer refers to the old block.
1551const char* DataMessage::swapMessageData(const char* data) {
1553 const char* oldData = (const char*)this->data;
1554 this->data = (DataMessageHeader*)data;
1555 return oldData;
1556}
1557
1558
1559// ################# User #################
1560
1561int64 DataMessage::getAsInt(const char* key) {
1562 return utils::Ascii2Int64(getAsString(key).c_str());
1563}
1564
1565uint64 DataMessage::getAsTime(const char* key) {
1566 return utils::Ascii2Uint64(getAsString(key).c_str());
1567}
1568
1569float64 DataMessage::getAsFloat(const char* key) {
1570 return utils::Ascii2Float64(getAsString(key).c_str());
1571}
1572
1573int64 DataMessage::getAsInt(int64 i, const char* key) {
1574 return utils::Ascii2Int64(getAsString(i, key).c_str());
1575}
1576
1577uint64 DataMessage::getAsTime(int64 i, const char* key) {
1578 return utils::Ascii2Uint64(getAsString(i, key).c_str());
1579}
1580
1581float64 DataMessage::getAsFloat(int64 i, const char* key) {
1582 return utils::Ascii2Float64(getAsString(i, key).c_str());
1583}
1584
1585int64 DataMessage::getAsInt(const char* idx, const char* key) {
1586 return utils::Ascii2Int64(getAsString(idx, key).c_str());
1587}
1588
1589uint64 DataMessage::getAsTime(const char* idx, const char* key) {
1590 return utils::Ascii2Uint64(getAsString(idx, key).c_str());
1591}
1592
1593float64 DataMessage::getAsFloat(const char* idx, const char* key) {
1594 return utils::Ascii2Float64(getAsString(idx, key).c_str());
1595}
1596
1597
1598bool DataMessage::getAsBool(const char* key) {
1599
1600 char* src = findEntry(key);
1601 if (src == NULL)
1602 return false;
1603
1604 uint32 cid = ((DataMessageEntryHeader*)src)->cid;
1605 src += sizeof(DataMessageEntryHeader);
1606
1607 switch (cid) {
1608 case CONSTCHARID:
1609 return ( (stricmp(src, "yes") == 0) || (stricmp(src, "true") == 0) || (stricmp(src, "1") == 0));
1610 case TIMEID:
1611 return (*(uint64*)src != 0);
1612 case CHARDATAID:
1613 return true;
1614 case INTID:
1615 return (*(int64*)src != 0);
1616 case DOUBLEID:
1617 return (((int64)(*(float64*)src)) != 0);
1618 case DATAMESSAGEID:
1619 return true;
1620 case CONSTCHARINFOID:
1621 return false;
1622 case CHARDATAINFOID:
1623 return false;
1624 case DATAMESSAGEINFOID:
1625 return false;
1626 default:
1627 return false;
1628 }
1629}
1630
1631std::string DataMessage::getAsString(const char* key) {
1632 char* src = findEntry(key);
1633 if (src == NULL) {
1634 if (stricmp(key, "size") == 0)
1635 return utils::StringFormat("%u", data->size);
1636 else if (stricmp(key, "cid") == 0)
1637 return utils::StringFormat("%llu", data->cid);
1638 else if (stricmp(key, "memid") == 0)
1639 return utils::StringFormat("%llu", data->memid);
1640 else if (stricmp(key, "time") == 0)
1641 return utils::StringFormat("%llu", data->time);
1642 else if (stricmp(key, "sendtime") == 0)
1643 return utils::StringFormat("%llu", data->sendtime);
1644 else if (stricmp(key, "recvtime") == 0)
1645 return utils::StringFormat("%llu", data->recvtime);
1646 else if (stricmp(key, "timetext") == 0)
1647 return data->time ? PrintTimeString(data->time) : "";
1648 else if (stricmp(key, "sendtimetext") == 0)
1649 return data->sendtime ? PrintTimeString(data->sendtime) : "";
1650 else if (stricmp(key, "recvtimetext") == 0)
1651 return data->recvtime ? PrintTimeString(data->recvtime) : "";
1652 else if (stricmp(key, "origin") == 0)
1653 return utils::StringFormat("%u", data->origin);
1654 else if (stricmp(key, "destination") == 0)
1655 return utils::StringFormat("%u", data->destination);
1656 else if (stricmp(key, "ttl") == 0)
1657 return utils::StringFormat("%llu", data->ttl);
1658 else if (stricmp(key, "eol") == 0)
1659 return data->ttl ? utils::StringFormat("%llu", data->time + data->ttl) : "0";
1660 else if (stricmp(key, "eoltext") == 0)
1661 return data->ttl ? PrintTimeString(data->time + data->ttl) : "";
1662 else if (stricmp(key, "priority") == 0)
1663 return utils::StringFormat("%u", data->priority);
1664 else if (stricmp(key, "policy") == 0)
1665 return utils::StringFormat("%u", data->policy);
1666 else if (stricmp(key, "from") == 0)
1667 return utils::StringFormat("%u", data->from);
1668 else if (stricmp(key, "to") == 0)
1669 return utils::StringFormat("%u", data->to);
1670 else if (stricmp(key, "type") == 0)
1671 return data->type.toString();
1672 else if (stricmp(key, "tag") == 0)
1673 return utils::StringFormat("%u", data->tag);
1674 else if (stricmp(key, "status") == 0)
1675 return utils::StringFormat("%u", data->status);
1676 else if (stricmp(key, "reference") == 0)
1677 return utils::StringFormat("%llu", data->reference);
1678 else if (stricmp(key, "serial") == 0)
1679 return utils::StringFormat("%llu", data->serial);
1680 else if (stricmp(key, "contextchange") == 0)
1681 return data->contextchange.isValid() ? data->contextchange.toString() : "";
1682 else if (stricmp(key, "userSize") == 0)
1683 return utils::StringFormat("%u", data->userSize);
1684 else if (stricmp(key, "userCount") == 0)
1685 return utils::StringFormat("%u", data->userCount);
1686 else
1687 return "";
1688 }
1689
1690 switch (((DataMessageEntryHeader*)src)->cid) {
1691 case CONSTCHARID:
1692 return src + sizeof(DataMessageEntryHeader);
1693 case TIMEID:
1694 return PrintTimeString(*(uint64*)(src + sizeof(DataMessageEntryHeader)));
1695 case CHARDATAID:
1696 return utils::StringFormat("BinaryData [%ub]", ((DataMessageEntryHeader*)src)->size);
1697 case INTID:
1698 return utils::StringFormat("%lld", *(int64*)(src + sizeof(DataMessageEntryHeader)));
1699 case DOUBLEID:
1700 return utils::StringFormat("%f", *(float64*)(src + sizeof(DataMessageEntryHeader)));
1701 case DATAMESSAGEID:
1702 return utils::StringFormat("DataMessage [%ub]", ((DataMessageEntryHeader*)src)->size);
1703 case CONSTCHARINFOID:
1704 return utils::StringFormat("(%lld)", *(int64*)(src + sizeof(DataMessageEntryHeader)));
1705 case CHARDATAINFOID:
1706 return utils::StringFormat("(%lld)", *(int64*)(src + sizeof(DataMessageEntryHeader)));
1707 case DATAMESSAGEINFOID:
1708 return utils::StringFormat("(%lld)", *(int64*)(src + sizeof(DataMessageEntryHeader)));
1709 default:
1710 return "";
1711 }
1712}
1713
1714const char* DataMessage::getString(const char* key) {
1715 bool success = false;
1716 return getString(key, success);
1717}
1718
1719const char* DataMessage::getString(const char* key, uint32 &size) {
1720 bool success = false;
1721 return getString(key, size, success);
1722}
1723
1724uint64 DataMessage::getTime(const char* key) {
1725 bool success = false;
1726 return getTime(key, success);
1727}
1728
1729bool DataMessage::getInt(const char* key, int64& value) {
1730 bool success = false;
1731 value = getInt(key, success);
1732 return success;
1733}
1734
1735bool DataMessage::getDouble(const char* key, double& value) {
1736 bool success = false;
1737 value = getDouble(key, success);
1738 return success;
1739}
1740
1741bool DataMessage::getFloat(const char* key, float64& value) {
1742 bool success = false;
1743 value = getFloat(key, success);
1744 return success;
1745}
1746
1747const char* DataMessage::getData(const char* key, uint32& size) {
1748 bool success = false;
1749 return getData(key, size, success);
1750}
1751
1752char* DataMessage::getDataCopy(const char* key, uint32& size) {
1753 bool success = false;
1754 return getDataCopy(key, size, success);
1755}
1756
1758 bool success = false;
1759 return getAttachedMessageCopy(key, success);
1760}
1761
1762
1763
1764
1765
1766// ################# User with success flag #################
1767
1768const char* DataMessage::getString(const char* key, bool& success) {
1769 success = false;
1770 char* src = findEntry(key);
1771 if (src == NULL)
1772 return NULL;
1773
1774 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
1775 success = true;
1776 return src+sizeof(DataMessageEntryHeader);
1777 }
1778
1779 return NULL;
1780}
1781
1782const char* DataMessage::getString(const char* key, uint32 &size, bool& success) {
1783 size = 0;
1784 success = false;
1785 char* src = findEntry(key);
1786 if (src == NULL)
1787 return NULL;
1788
1789 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
1790 success = true;
1791 size = ((DataMessageEntryHeader*)src)->size - sizeof(DataMessageEntryHeader) - 1;
1792 return src+sizeof(DataMessageEntryHeader);
1793 }
1794
1795 return NULL;
1796}
1797
1798uint32 DataMessage::getContentType(const char* key) {
1799 char* src = findEntry(key);
1800 if (src == NULL) return 0;
1801 return ((DataMessageEntryHeader*)src)->cid;
1802}
1803
1804uint32 DataMessage::getContentSize(const char* key) {
1805 char* src = findEntry(key);
1806 if (src == NULL) return 0;
1807 return ((DataMessageEntryHeader*)src)->size;
1808}
1809
1810
1811uint64 DataMessage::getTime(const char* key, bool& success) {
1812 success = false;
1813 char* src = findEntry(key);
1814 if (src == NULL) return 0;
1815
1816 if (((DataMessageEntryHeader*)src)->cid == TIMEID) {
1817 success = true;
1818 return *(uint64*)(src+sizeof(DataMessageEntryHeader));
1819 }
1820
1821 return 0;
1822}
1823
1824int64 DataMessage::getInt(const char* key, bool& success) {
1825 success = false;
1826 char* src = findEntry(key);
1827 if (src == NULL) return 0;
1828
1829 if (((DataMessageEntryHeader*)src)->cid == INTID) {
1830 success = true;
1831 return *(int64*)(src+sizeof(DataMessageEntryHeader));
1832 }
1833 return 0;
1834}
1835
1836int64 DataMessage::getInt(const char* key) {
1837 bool success = false;
1838 return getInt(key, success);
1839}
1840
1841double DataMessage::getDouble(const char* key, bool& success) {
1842 success = false;
1843 char* src = findEntry(key);
1844 if (src == NULL) return false;
1845
1846 if (((DataMessageEntryHeader*)src)->cid == DOUBLEID) {
1847 success = true;
1848 return *(float64*)(src + sizeof(DataMessageEntryHeader));
1849 }
1850 return false;
1851}
1852
1853float64 DataMessage::getFloat(const char* key, bool& success) {
1854 success = false;
1855 char* src = findEntry(key);
1856 if (src == NULL) return false;
1857
1858 if (((DataMessageEntryHeader*)src)->cid == DOUBLEID) {
1859 success = true;
1860 return *(float64*)(src + sizeof(DataMessageEntryHeader));
1861 }
1862 return false;
1863}
1864
1865double DataMessage::getDouble(const char* key) {
1866 bool success = false;
1867 return getDouble(key, success);
1868}
1869
1870double DataMessage::getFloat(const char* key) {
1871 bool success = false;
1872 return getFloat(key, success);
1873}
1874
1875const char* DataMessage::getData(const char* key, uint32& size, bool& success) {
1876 success = false;
1877 char* src = findEntry(key);
1878 if (src == NULL) return NULL;
1879
1880 if (((DataMessageEntryHeader*)src)->cid == CHARDATAID) {
1881 success = true;
1882 size = ((DataMessageEntryHeader*)src)->size - sizeof(DataMessageEntryHeader);
1883 return src+sizeof(DataMessageEntryHeader);
1884 }
1885
1886 return NULL;
1887}
1888
1889char* DataMessage::getDataCopy(const char* key, uint32& size, bool& success) {
1890 success = false;
1891 char* src = findEntry(key);
1892 if (src == NULL) return NULL;
1893
1894 if (((DataMessageEntryHeader*)src)->cid == CHARDATAID) {
1895 success = true;
1896 size = ((DataMessageEntryHeader*)src)->size - sizeof(DataMessageEntryHeader);
1897 char* data = new char[size];
1898 memcpy(data, src+sizeof(DataMessageEntryHeader), size);
1899 return data;
1900 }
1901
1902 return NULL;
1903}
1904
1905DataMessage* DataMessage::getAttachedMessageCopy(const char* key, bool& success) {
1906 success = false;
1907 char* src = findEntry(key);
1908 if (src == NULL) return NULL;
1909
1910 if (((DataMessageEntryHeader*)src)->cid == DATAMESSAGEID) {
1911 success = true;
1912 return new DataMessage(src+sizeof(DataMessageEntryHeader), true);
1913 }
1914 return NULL;
1915}
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929bool DataMessage::setString(const char* key, const char* value) {
1930 if (!key || !value)
1931 return false;
1932 return setRawData(key, value, (uint32)strlen(value)+1, CONSTCHARID);
1933}
1934
1935bool DataMessage::setTime(const char* key, uint64 value) {
1936 return setRawData(key, (char*)&value, sizeof(uint64), TIMEID);
1937}
1938
1939bool DataMessage::setInt(const char* key, int64 value) {
1940 return setRawData(key, (char*)&value, sizeof(int64), INTID);
1941}
1942
1943bool DataMessage::setDouble(const char* key, double value) {
1944 float64 val = value;
1945 return setRawData(key, (char*)&val, sizeof(float64), DOUBLEID);
1946}
1947
1948bool DataMessage::setFloat(const char* key, float64 value) {
1949 return setRawData(key, (char*)&value, sizeof(float64), DOUBLEID);
1950}
1951
1952bool DataMessage::setData(const char* key, const char* value, uint32 size) {
1953 return setRawData(key, value, size, CHARDATAID);
1954}
1955
1957 if (!msg->isValid())
1958 return false;
1959 return setRawData(key, (char*)msg->data, msg->data->size, DATAMESSAGEID);
1960}
1961
1962bool DataMessage::setRawData(const char* key, const char* value, uint32 size, uint32 datatype) {
1964 char* src = findEntry(key);
1965
1966 uint32 spaceReq = sizeof(DataMessageEntryHeader) + size;
1967 uint32 fullSpaceReq = 2 * sizeof(DataMessageEntryHeader) + (uint32)strlen(key) + 1 + size;
1968
1969 if (src != NULL) { // overwrite?
1970 if (((DataMessageEntryHeader*)src)->size >= spaceReq) {
1971 ((DataMessageEntryHeader*)src)->cid = datatype;
1972 memcpy(src+sizeof(DataMessageEntryHeader), value, size);
1973 //data->userCount++;
1974 //data->userSize += fullSpaceReq;
1975 return true;
1976 }
1977 else {
1978 removeEntry(key);
1979 // and act as if not found, ie. continue
1980 }
1981 }
1982
1983 src = findSpace(fullSpaceReq);
1984 if (src == NULL) {
1985 // Space not found, create a new one
1986 // if (!ownsData) return false;
1987
1988 uint32 oldSize = ((DataMessageHeader*)data)->size;
1989 data = (DataMessageHeader*)realloc(data, oldSize + fullSpaceReq);
1990 data->size = oldSize + fullSpaceReq;
1992
1993 src = (char*)data + oldSize;
1994 ((DataMessageEntryHeader*)src)->size = fullSpaceReq;
1995 }
1996
1997 ((DataMessageEntryHeader*)src)->cid = CONSTCHARID;
1998 utils::strcpyavail(src+sizeof(DataMessageEntryHeader), key, (uint32)strlen(key)+1, true);
1999
2000 src += sizeof(DataMessageEntryHeader) + strlen(key) + 1;
2001 ((DataMessageEntryHeader*)src)->cid = datatype;
2002 ((DataMessageEntryHeader*)src)->size = sizeof(DataMessageEntryHeader) + size;
2003 memcpy(src+sizeof(DataMessageEntryHeader), value, size);
2004 data->userCount++;
2005 data->userSize += fullSpaceReq;
2006
2007 return true;
2008}
2009
2010
2011
2012
2013
2014
2015
2016// Arrays
2017
2018bool DataMessage::isArrayContent(const char* key) {
2019 uint32 size;
2020 char* keyStart = utils::StringFormat(size, "%s_-|", key);
2021 if (data->cid != DATAMESSAGEID) return false;
2022 char* src = (char*)data + sizeof(DataMessageHeader);
2023 char* srcEnd = (char*)data + data->size;
2024 while (src < srcEnd) {
2025 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2026 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false) &&
2027 utils::TextEndsWith(src + sizeof(DataMessageEntryHeader), "|-_", false))
2028 return true;
2029 }
2030 src += ((DataMessageEntryHeader*)src)->size;
2031 }
2032 delete[] keyStart;
2033 return false;
2034}
2035
2036bool DataMessage::isMapContent(const char* key) {
2037 uint32 size;
2038 char* keyStart = utils::StringFormat(size, "%s_-[", key);
2039 if (data->cid != DATAMESSAGEID) return false;
2040 char* src = (char*)data + sizeof(DataMessageHeader);
2041 char* srcEnd = (char*)data + data->size;
2042 while (src < srcEnd) {
2043 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2044 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false) &&
2045 utils::TextEndsWith(src + sizeof(DataMessageEntryHeader), "]-_", false) )
2046 return true;
2047 }
2048 src += ((DataMessageEntryHeader*)src)->size;
2049 }
2050 delete[] keyStart;
2051 return false;
2052}
2053
2055 uint32 size;
2056 char* arrayKeyStart = utils::StringFormat(size, "%s_-|", key);
2057 char* mapKeyStart = utils::StringFormat(size, "%s_-[", key);
2058 if (data->cid != DATAMESSAGEID) return NONE;
2059 char* src = (char*)data + sizeof(DataMessageHeader);
2060 char* srcEnd = (char*)data + data->size;
2061 while (src < srcEnd) {
2062 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2063 if (stricmp(key, src + sizeof(DataMessageEntryHeader)) == 0)
2064 return SINGLE;
2065 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), arrayKeyStart, false) &&
2066 utils::TextEndsWith(src + sizeof(DataMessageEntryHeader), "|-_", false))
2067 return ARRAY;
2068 else if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), mapKeyStart, false) &&
2069 utils::TextEndsWith(src + sizeof(DataMessageEntryHeader), "]-_", false))
2070 return MAP;
2071 }
2072 src += ((DataMessageEntryHeader*)src)->size;
2073 }
2074 delete[] arrayKeyStart;
2075 delete[] mapKeyStart;
2076 return NONE;
2077}
2078
2079
2080
2081
2082bool DataMessage::hasKey(const char* key) {
2083 return (findEntry(key) != NULL);
2084}
2085
2086bool DataMessage::hasString(const char* key) {
2087 char* src = findEntry(key);
2088 if (src == NULL) return 0;
2089 return (((DataMessageEntryHeader*)src)->cid == CONSTCHARID);
2090}
2091
2092bool DataMessage::hasInteger(const char* key) {
2093 char* src = findEntry(key);
2094 if (src == NULL) return 0;
2095 return (((DataMessageEntryHeader*)src)->cid == INTID);
2096}
2097
2098bool DataMessage::hasFloat(const char* key) {
2099 char* src = findEntry(key);
2100 if (src == NULL) return 0;
2101 return (((DataMessageEntryHeader*)src)->cid == DOUBLEID);
2102}
2103
2104bool DataMessage::hasTime(const char* key) {
2105 char* src = findEntry(key);
2106 if (src == NULL) return 0;
2107 return (((DataMessageEntryHeader*)src)->cid == TIMEID);
2108}
2109
2110bool DataMessage::hasData(const char* key) {
2111 char* src = findEntry(key);
2112 if (src == NULL) return 0;
2113 return (((DataMessageEntryHeader*)src)->cid == CHARDATAID);
2114}
2115
2116bool DataMessage::hasMessage(const char* key) {
2117 char* src = findEntry(key);
2118 if (src == NULL) return 0;
2119 return (((DataMessageEntryHeader*)src)->cid == DATAMESSAGEID);
2120}
2121
2122
2123bool DataMessage::isSingleValue(const char* key) {
2124 return (findEntry(key) != NULL);
2125}
2126
2127uint32 DataMessage::getContentType(int64 i, const char* key) {
2128 char buf[256];
2129 int n = snprintf(buf, sizeof(buf), "%s_-|%lld|-_", key, i);
2130 if (n < 0 || (size_t)n >= sizeof(buf))
2131 return getContentType(utils::StringFormat("%s_-|%lld|-_", key, i).c_str());
2132 return getContentType(buf);
2133}
2134
2135uint32 DataMessage::getContentSize(int64 i, const char* key) {
2136 return getContentSize(utils::StringFormat("%s_-|%lld|-_", key, i).c_str());
2137}
2138
2139uint64 DataMessage::getTime(int64 i, const char* key) {
2140 return getTime(utils::StringFormat("%s_-|%lld|-_", key, i).c_str());
2141}
2142
2143std::string DataMessage::getAsString(int64 i, const char* key) {
2144 return getAsString(utils::StringFormat("%s_-|%lld|-_", key, i).c_str());
2145}
2146
2147const char* DataMessage::getString(int64 i, const char* key) {
2148 return getString(utils::StringFormat("%s_-|%lld|-_", key, i).c_str());
2149}
2150
2151const char* DataMessage::getString(int64 i, const char* key, uint32 &size) {
2152 return getString(utils::StringFormat("%s_-|%lld|-_", key, i).c_str());
2153}
2154
2155bool DataMessage::getInt(int64 i, const char* key, int64& value) {
2156 return getInt(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), value);
2157}
2158
2159bool DataMessage::getDouble(int64 i, const char* key, double& value) {
2160 return getDouble(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), value);
2161}
2162
2163bool DataMessage::getFloat(int64 i, const char* key, float64& value) {
2164 return getFloat(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), value);
2165}
2166
2167int64 DataMessage::getInt(int64 i, const char* key, bool& success) {
2168 return getInt(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), success);
2169}
2170
2171double DataMessage::getDouble(int64 i, const char* key, bool& success) {
2172 return getDouble(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), success);
2173}
2174
2175float64 DataMessage::getFloat(int64 i, const char* key, bool& success) {
2176 return getFloat(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), success);
2177}
2178
2179int64 DataMessage::getInt(int64 i, const char* key) {
2180 bool success;
2181 return getInt(i, key, success);
2182}
2183
2184double DataMessage::getDouble(int64 i, const char* key) {
2185 bool success;
2186 return getDouble(i, key, success);
2187}
2188
2189float64 DataMessage::getFloat(int64 i, const char* key) {
2190 bool success;
2191 return getFloat(i, key, success);
2192}
2193
2194int64 DataMessage::getInt(const char* idx, const char* key) {
2195 bool success;
2196 return getInt(idx, key, success);
2197}
2198
2199double DataMessage::getDouble(const char* idx, const char* key) {
2200 bool success;
2201 return getDouble(idx, key, success);
2202}
2203
2204float64 DataMessage::getFloat(const char* idx, const char* key) {
2205 bool success;
2206 return getFloat(idx, key, success);
2207}
2208
2209
2210const char* DataMessage::getData(int64 i, const char* key, uint32& size) {
2211 return getData(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), size);
2212}
2213
2214char* DataMessage::getDataCopy(int64 i, const char* key, uint32& size) {
2215 return getDataCopy(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), size);
2216}
2217
2219 return getAttachedMessageCopy(utils::StringFormat("%s_-|%lld|-_", key, i).c_str());
2220}
2221
2222
2223bool DataMessage::setTime(int64 i, const char* key, uint64 value) {
2224 return setTime(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), value);
2225}
2226
2227bool DataMessage::setString(int64 i, const char* key, const char* value) {
2228 return setString(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), value);
2229}
2230
2231bool DataMessage::setInt(int64 i, const char* key, int64 value) {
2232 return setInt(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), value);
2233}
2234
2235bool DataMessage::setDouble(int64 i, const char* key, double value) {
2236 return setDouble(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), value);
2237}
2238
2239bool DataMessage::setFloat(int64 i, const char* key, float64 value) {
2240 return setFloat(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), value);
2241}
2242
2243bool DataMessage::setData(int64 i, const char* key, const char* value, uint32 size) {
2244 return setData(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), value, size);
2245}
2246
2247bool DataMessage::setAttachedMessage(int64 i, const char* key, DataMessage* msg) {
2248 return setAttachedMessage(utils::StringFormat("%s_-|%lld|-_", key, i).c_str(), msg);
2249}
2250
2251
2252// Maps
2253uint32 DataMessage::getContentType(const char* idx, const char* key) {
2254 char buf[256];
2255 int n = snprintf(buf, sizeof(buf), "%s_-[%s]-_", key, idx);
2256 if (n < 0 || (size_t)n >= sizeof(buf))
2257 return getContentType(utils::StringFormat("%s_-[%s]-_", key, idx).c_str());
2258 return getContentType(buf);
2259}
2260
2261uint32 DataMessage::getContentSize(const char* idx, const char* key) {
2262 return getContentSize(utils::StringFormat("%s_-[%s]-_", key, idx).c_str());
2263}
2264
2265uint64 DataMessage::getTime(const char* idx, const char* key) {
2266 return getTime(utils::StringFormat("%s_-[%s]-_", key, idx).c_str());
2267}
2268
2269std::string DataMessage::getAsString(const char* idx, const char* key) {
2270 return getAsString(utils::StringFormat("%s_-[%s]-_", key, idx).c_str());
2271}
2272
2273const char* DataMessage::getString(const char* idx, const char* key) {
2274 return getString(utils::StringFormat("%s_-[%s]-_", key, idx).c_str());
2275}
2276
2277const char* DataMessage::getString(const char* idx, const char* key, uint32 &size) {
2278 return getString(utils::StringFormat("%s_-[%s]-_", key, idx).c_str());
2279}
2280
2281bool DataMessage::getInt(const char* idx, const char* key, int64& value) {
2282 return getInt(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), value);
2283}
2284
2285bool DataMessage::getDouble(const char* idx, const char* key, double& value) {
2286 return getDouble(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), value);
2287}
2288
2289bool DataMessage::getFloat(const char* idx, const char* key, float64& value) {
2290 return getFloat(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), value);
2291}
2292
2293int64 DataMessage::getInt(const char* idx, const char* key, bool& success) {
2294 return getInt(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), success);
2295}
2296
2297double DataMessage::getDouble(const char* idx, const char* key, bool& success) {
2298 return getDouble(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), success);
2299}
2300
2301float64 DataMessage::getFloat(const char* idx, const char* key, bool& success) {
2302 return getFloat(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), success);
2303}
2304
2305const char* DataMessage::getData(const char* idx, const char* key, uint32& size) {
2306 return getData(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), size);
2307}
2308
2309char* DataMessage::getDataCopy(const char* idx, const char* key, uint32& size) {
2310 return getDataCopy(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), size);
2311}
2312
2313DataMessage* DataMessage::getAttachedMessageCopy(const char* idx, const char* key) {
2314 return getAttachedMessageCopy(utils::StringFormat("%s_-[%s]-_", key, idx).c_str());
2315}
2316
2317
2318bool DataMessage::setTime(const char* idx, const char* key, uint64 value) {
2319 return setTime(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), value);
2320}
2321
2322bool DataMessage::setString(const char* idx, const char* key, const char* value) {
2323 return setString(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), value);
2324}
2325
2326bool DataMessage::setInt(const char* idx, const char* key, int64 value) {
2327 return setInt(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), value);
2328}
2329
2330bool DataMessage::setDouble(const char* idx, const char* key, double value) {
2331 return setDouble(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), value);
2332}
2333
2334bool DataMessage::setFloat(const char* idx, const char* key, float64 value) {
2335 return setFloat(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), value);
2336}
2337
2338bool DataMessage::setData(const char* idx, const char* key, const char* value, uint32 size) {
2339 return setData(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), value, size);
2340}
2341
2342bool DataMessage::setAttachedMessage(const char* idx, const char* key, DataMessage* msg) {
2343 return setAttachedMessage(utils::StringFormat("%s_-[%s]-_", key, idx).c_str(), msg);
2344}
2345
2346
2347
2348
2349
2350
2351
2352
2353std::map<int64, uint64> DataMessage::getTimeArray(const char* key) {
2354 std::map<int64, uint64> map;
2355 int64 i;
2356 uint32 size;
2357 char* keyStart = utils::StringFormat(size, "%s_-|", key);
2358 if (data->cid != DATAMESSAGEID) return map;
2359 char* entry;
2360 char* src = (char*)data + sizeof(DataMessageHeader);
2361 char* srcEnd = (char*)data + data->size;
2362 while (src < srcEnd) {
2363 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2364 entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
2365 if (((DataMessageEntryHeader*)entry)->cid == TIMEID) {
2366 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
2367 //i = utils::Ascii2Int64(std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str());
2368 i = utils::Ascii2Int64(src + sizeof(DataMessageEntryHeader) + size);
2369 map[i] = *(uint64*)(entry + sizeof(DataMessageEntryHeader));
2370 }
2371 }
2372 }
2373 src += ((DataMessageEntryHeader*)src)->size;
2374 }
2375 delete[] keyStart;
2376 return map;
2377}
2378
2379std::map<int64, int64> DataMessage::getAsIntArray(const char* key) {
2380 std::map<int64, int64> map;
2381 int64 i;
2382 uint32 size;
2383 char* keyStart = utils::StringFormat(size, "%s_-|", key);
2384 if (data->cid != DATAMESSAGEID) return map;
2385 char* entry;
2386 char* src = (char*)data + sizeof(DataMessageHeader);
2387 char* srcEnd = (char*)data + data->size;
2388 while (src < srcEnd) {
2389 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2390 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
2391 entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
2392
2393 //i = utils::Ascii2Int64(std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str());
2394 i = utils::Ascii2Int64(src + sizeof(DataMessageEntryHeader) + size);
2395 switch (((DataMessageEntryHeader*)entry)->cid) {
2396 case TIMEID:
2397 map[i] = (int64)(*(uint64*)(entry + sizeof(DataMessageEntryHeader)));
2398 break;
2399 case CONSTCHARID:
2400 map[i] = utils::Ascii2Int64(entry + sizeof(DataMessageEntryHeader));
2401 break;
2402 case CHARDATAID:
2403 map[i] = (int64)((DataMessageEntryHeader*)entry)->size;
2404 break;
2405 case INTID:
2406 map[i] = *(int64*)(entry + sizeof(DataMessageEntryHeader));
2407 break;
2408 case DOUBLEID:
2409 map[i] = (int64)(*(float64*)(entry + sizeof(DataMessageEntryHeader)));
2410 break;
2411 case DATAMESSAGEID:
2412 map[i] = (int64)((DataMessageEntryHeader*)entry)->size;
2413 break;
2414 default:
2415 break;
2416 }
2417 }
2418
2419 }
2420 src += ((DataMessageEntryHeader*)src)->size;
2421 }
2422 delete[] keyStart;
2423 return map;
2424}
2425
2426std::map<int64, float64> DataMessage::getAsFloatArray(const char* key) {
2427 std::map<int64, float64> map;
2428 int64 i;
2429 uint32 size;
2430 char* keyStart = utils::StringFormat(size, "%s_-|", key);
2431 if (data->cid != DATAMESSAGEID) return map;
2432 char* entry;
2433 char* src = (char*)data + sizeof(DataMessageHeader);
2434 char* srcEnd = (char*)data + data->size;
2435 while (src < srcEnd) {
2436 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2437 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
2438 entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
2439
2440 //i = utils::Ascii2Int64(std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str());
2441 i = utils::Ascii2Int64(src + sizeof(DataMessageEntryHeader) + size);
2442 switch (((DataMessageEntryHeader*)entry)->cid) {
2443 case TIMEID:
2444 map[i] = (float64)(*(uint64*)(entry + sizeof(DataMessageEntryHeader)));
2445 break;
2446 case CONSTCHARID:
2447 map[i] = utils::Ascii2Float64(entry + sizeof(DataMessageEntryHeader));
2448 break;
2449 case CHARDATAID:
2450 map[i] = (float64)((DataMessageEntryHeader*)entry)->size;
2451 break;
2452 case INTID:
2453 map[i] = (float64)(*(int64*)(entry + sizeof(DataMessageEntryHeader)));
2454 break;
2455 case DOUBLEID:
2456 map[i] = *(float64*)(entry + sizeof(DataMessageEntryHeader));
2457 break;
2458 case DATAMESSAGEID:
2459 map[i] = (float64)((DataMessageEntryHeader*)entry)->size;
2460 break;
2461 default:
2462 break;
2463 }
2464 }
2465
2466 }
2467 src += ((DataMessageEntryHeader*)src)->size;
2468 }
2469 delete[] keyStart;
2470 return map;
2471}
2472
2473std::map<int64, std::string> DataMessage::getAsStringArray(const char* key) {
2474 std::map<int64, std::string> map;
2475 int64 i;
2476 uint32 size;
2477 char* keyStart = utils::StringFormat(size, "%s_-|", key);
2478 if (data->cid != DATAMESSAGEID) return map;
2479 char* entry;
2480 char* src = (char*)data + sizeof(DataMessageHeader);
2481 char* srcEnd = (char*)data + data->size;
2482 while (src < srcEnd) {
2483 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2484 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
2485 entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
2486
2487 //i = utils::Ascii2Int64(std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str());
2488 i = utils::Ascii2Int64(src + sizeof(DataMessageEntryHeader) + size);
2489 switch (((DataMessageEntryHeader*)entry)->cid) {
2490 case TIMEID:
2491 map[i] = PrintTimeString(*(uint64*)(entry + sizeof(DataMessageEntryHeader)));
2492 break;
2493 case CONSTCHARID:
2494 map[i] = entry + sizeof(DataMessageEntryHeader);
2495 break;
2496 case CHARDATAID:
2497 map[i] = utils::StringFormat("BinaryData [%ub]", ((DataMessageEntryHeader*)entry)->size);
2498 break;
2499 case INTID:
2500 map[i] = utils::StringFormat("%lld", *(int64*)(entry + sizeof(DataMessageEntryHeader)));
2501 break;
2502 case DOUBLEID:
2503 map[i] = utils::StringFormat("%f", *(float64*)(entry + sizeof(DataMessageEntryHeader)));
2504 break;
2505 case DATAMESSAGEID:
2506 map[i] = utils::StringFormat("DataMessage [%ub]", ((DataMessageEntryHeader*)entry)->size);
2507 break;
2508 default:
2509 break;
2510 }
2511 }
2512
2513 }
2514 src += ((DataMessageEntryHeader*)src)->size;
2515 }
2516 delete[] keyStart;
2517 return map;
2518}
2519
2520std::map<int64, std::string> DataMessage::getStringArray(const char* key) {
2521 std::map<int64, std::string> map;
2522 int64 i;
2523 uint32 size;
2524 char* keyStart = utils::StringFormat(size, "%s_-|", key);
2525 if (data->cid != DATAMESSAGEID) return map;
2526 char* entry;
2527 char* src = (char*)data + sizeof(DataMessageHeader);
2528 char* srcEnd = (char*)data + data->size;
2529 while (src < srcEnd) {
2530 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2531 entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
2532 if (((DataMessageEntryHeader*)entry)->cid == CONSTCHARID) {
2533 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
2534 //i = utils::Ascii2Int64(std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str());
2535 i = utils::Ascii2Int64(src + sizeof(DataMessageEntryHeader) + size);
2536 map[i] = entry + sizeof(DataMessageEntryHeader);
2537 }
2538 }
2539 }
2540 src += ((DataMessageEntryHeader*)src)->size;
2541 }
2542 delete[] keyStart;
2543 return map;
2544}
2545
2546
2547std::map<int64, int64> DataMessage::getIntArray(const char* key) {
2548 std::map<int64, int64> map;
2549 int64 i;
2550 uint32 size;
2551 char* keyStart = utils::StringFormat(size, "%s_-|", key);
2552 if (data->cid != DATAMESSAGEID) return map;
2553 char* entry;
2554 char* src = (char*)data + sizeof(DataMessageHeader);
2555 char* srcEnd = (char*)data + data->size;
2556 while (src < srcEnd) {
2557 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2558 entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
2559 if (((DataMessageEntryHeader*)entry)->cid == INTID) {
2560 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
2561 //i = utils::Ascii2Int64(std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str());
2562 i = utils::Ascii2Int64(src + sizeof(DataMessageEntryHeader) + size);
2563 map[i] = *(int64*)(entry + sizeof(DataMessageEntryHeader));
2564 }
2565 }
2566 }
2567 src += ((DataMessageEntryHeader*)src)->size;
2568 }
2569 delete[] keyStart;
2570 return map;
2571}
2572
2573std::map<int64, double> DataMessage::getDoubleArray(const char* key) {
2574 std::map<int64, double> map;
2575 int64 i;
2576 uint32 size;
2577 char* keyStart = utils::StringFormat(size, "%s_-|", key);
2578 if (data->cid != DATAMESSAGEID) return map;
2579 char* entry;
2580 char* src = (char*)data + sizeof(DataMessageHeader);
2581 char* srcEnd = (char*)data + data->size;
2582 while (src < srcEnd) {
2583 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2584 entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
2585 if (((DataMessageEntryHeader*)entry)->cid == DOUBLEID) {
2586 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
2587 //i = utils::Ascii2Int64(std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str());
2588 i = utils::Ascii2Int64(src + sizeof(DataMessageEntryHeader) + size);
2589 map[i] = *(float64*)(entry + sizeof(DataMessageEntryHeader));
2590 }
2591 }
2592 }
2593 src += ((DataMessageEntryHeader*)src)->size;
2594 }
2595 delete[] keyStart;
2596 return map;
2597}
2598
2599std::map<int64, float64> DataMessage::getFloatArray(const char* key) {
2600 std::map<int64, float64> map;
2601 int64 i;
2602 uint32 size;
2603 char* keyStart = utils::StringFormat(size, "%s_-|", key);
2604 if (data->cid != DATAMESSAGEID) return map;
2605 char* entry;
2606 char* src = (char*)data + sizeof(DataMessageHeader);
2607 char* srcEnd = (char*)data + data->size;
2608 while (src < srcEnd) {
2609 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2610 entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
2611 if (((DataMessageEntryHeader*)entry)->cid == DOUBLEID) {
2612 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
2613 //i = utils::Ascii2Int64(std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str());
2614 i = utils::Ascii2Int64(src + sizeof(DataMessageEntryHeader) + size);
2615 map[i] = *(float64*)(entry + sizeof(DataMessageEntryHeader));
2616 }
2617 }
2618 }
2619 src += ((DataMessageEntryHeader*)src)->size;
2620 }
2621 delete[] keyStart;
2622 return map;
2623}
2624
2625std::map<int64, DataMessage*> DataMessage::getAttachedMessageArray(const char* key) {
2626 std::map<int64, DataMessage*> map;
2627 int64 i;
2628 uint32 size;
2629 char* keyStart = utils::StringFormat(size, "%s_-|", key);
2630 if (data->cid != DATAMESSAGEID) return map;
2631 char* entry;
2632 char* src = (char*)data + sizeof(DataMessageHeader);
2633 char* srcEnd = (char*)data + data->size;
2634 while (src < srcEnd) {
2635 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2636 entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
2637 if (((DataMessageEntryHeader*)entry)->cid == DATAMESSAGEID) {
2638 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
2639 //i = utils::Ascii2Int64(std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str());
2640 i = utils::Ascii2Int64(src + sizeof(DataMessageEntryHeader) + size);
2641 map[i] = new DataMessage(entry + sizeof(DataMessageEntryHeader), true);
2642 }
2643 }
2644 }
2645 src += ((DataMessageEntryHeader*)src)->size;
2646 }
2647 delete[] keyStart;
2648 return map;
2649}
2650
2651bool DataMessage::setTimeArray(const char* key, std::map<int64, uint64>& map) {
2652 std::map<int64, uint64>::iterator i = map.begin(), e = map.end();
2653 while (i != e) {
2654 if (!setTime(i->first, key, i->second))
2655 return false;
2656 i++;
2657 }
2658 return true;
2659}
2660
2661bool DataMessage::setStringArray(const char* key, std::map<int64, std::string>& map) {
2662 std::map<int64, std::string>::iterator i = map.begin(), e = map.end();
2663 while (i != e) {
2664 if (!setString(i->first, key, i->second.c_str()))
2665 return false;
2666 i++;
2667 }
2668 return true;
2669}
2670
2671bool DataMessage::setIntArray(const char* key, std::map<int64, int64>& map) {
2672 std::map<int64, int64>::iterator i = map.begin(), e = map.end();
2673 while (i != e) {
2674 if (!setInt(i->first, key, i->second))
2675 return false;
2676 i++;
2677 }
2678 return true;
2679}
2680
2681bool DataMessage::setDoubleArray(const char* key, std::map<int64, double>& map) {
2682 std::map<int64, double>::iterator i = map.begin(), e = map.end();
2683 while (i != e) {
2684 if (!setDouble(i->first, key, i->second))
2685 return false;
2686 i++;
2687 }
2688 return true;
2689}
2690
2691bool DataMessage::setFloatArray(const char* key, std::map<int64, float64>& map) {
2692 std::map<int64, float64>::iterator i = map.begin(), e = map.end();
2693 while (i != e) {
2694 if (!setFloat(i->first, key, i->second))
2695 return false;
2696 i++;
2697 }
2698 return true;
2699}
2700
2701bool DataMessage::setAttachedMessageArray(const char* key, std::map<int64, DataMessage*>& map) {
2702 std::map<int64, DataMessage*>::iterator i = map.begin(), e = map.end();
2703 while (i != e) {
2704 if (!setAttachedMessage(i->first, key, i->second))
2705 return false;
2706 i++;
2707 }
2708 return true;
2709}
2710
2711
2712
2713
2714
2715
2716
2717
2718uint32 DataMessage::getArraySize(const char* key) {
2719 uint32 c = 0;
2720 uint32 size;
2721 char* keyStart = utils::StringFormat(size, "%s_-|", key);
2722 if (data->cid != DATAMESSAGEID) return c;
2723 char* entry;
2724 char* src = (char*)data + sizeof(DataMessageHeader);
2725 char* srcEnd = (char*)data + data->size;
2726 while (src < srcEnd) {
2727 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2728 entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
2729 if (((DataMessageEntryHeader*)entry)->cid == CONSTCHARID) {
2730 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false))
2731 c++;
2732 }
2733 }
2734 src += ((DataMessageEntryHeader*)src)->size;
2735 }
2736 delete[] keyStart;
2737 return c;
2738}
2739
2740uint32 DataMessage::getArrayCount(const char* key) {
2741 return getArraySize(key);
2742}
2743
2744uint32 DataMessage::getMapSize(const char* key) {
2745 uint32 c = 0;
2746 uint32 size;
2747 char* keyStart = utils::StringFormat(size, "%s_-[", key);
2748 if (data->cid != DATAMESSAGEID) return c;
2749 char* entry;
2750 char* src = (char*)data + sizeof(DataMessageHeader);
2751 char* srcEnd = (char*)data + data->size;
2752 while (src < srcEnd) {
2753 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2754 entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
2755 if (((DataMessageEntryHeader*)entry)->cid == CONSTCHARID) {
2756 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false))
2757 c++;
2758 }
2759 }
2760 src += ((DataMessageEntryHeader*)src)->size;
2761 }
2762 delete[] keyStart;
2763 return c;
2764}
2765
2766uint32 DataMessage::getMapCount(const char* key) {
2767 return getMapSize(key);
2768}
2769
2770
2771
2772
2773
2774
2775
2776std::map<std::string, uint64> DataMessage::getTimeMap(const char* key) {
2777 std::map<std::string, uint64> map;
2778 std::string str;
2779 uint32 size;
2780 char* keyStart = utils::StringFormat(size, "%s_-[", key);
2781 if (data->cid != DATAMESSAGEID) return map;
2782 char* entry;
2783 char* src = (char*)data + sizeof(DataMessageHeader);
2784 char* srcEnd = (char*)data + data->size;
2785 while (src < srcEnd) {
2786 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2787 entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
2788 if (((DataMessageEntryHeader*)entry)->cid == TIMEID) {
2789 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
2790 str = std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3);
2791 map[str] = *(uint64*)(entry + sizeof(DataMessageEntryHeader));
2792 }
2793 }
2794 }
2795 src += ((DataMessageEntryHeader*)src)->size;
2796 }
2797 delete[] keyStart;
2798 return map;
2799}
2800
2801std::map<std::string, int64> DataMessage::getAsIntMap(const char* key) {
2802 std::map<std::string, int64> map;
2803 std::string str;
2804 uint32 size;
2805 char* keyStart = utils::StringFormat(size, "%s_-[", key);
2806 if (data->cid != DATAMESSAGEID) return map;
2807 char* entry;
2808 char* src = (char*)data + sizeof(DataMessageHeader);
2809 char* srcEnd = (char*)data + data->size;
2810 while (src < srcEnd) {
2811 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2812 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
2813 entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
2814 str = std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str();
2815 switch (((DataMessageEntryHeader*)entry)->cid) {
2816 case TIMEID:
2817 map[str] = (int64)(*(uint64*)(entry + sizeof(DataMessageEntryHeader)));
2818 break;
2819 case CONSTCHARID:
2820 map[str] = utils::Ascii2Int64(entry + sizeof(DataMessageEntryHeader));
2821 break;
2822 case CHARDATAID:
2823 map[str] = (int64)((DataMessageEntryHeader*)entry)->size;
2824 break;
2825 case INTID:
2826 map[str] = *(int64*)(entry + sizeof(DataMessageEntryHeader));
2827 break;
2828 case DOUBLEID:
2829 map[str] = (int64)(*(float64*)(entry + sizeof(DataMessageEntryHeader)));
2830 break;
2831 case DATAMESSAGEID:
2832 map[str] = (int64)((DataMessageEntryHeader*)entry)->size;
2833 break;
2834 default:
2835 break;
2836 }
2837 }
2838 }
2839 src += ((DataMessageEntryHeader*)src)->size;
2840 }
2841 delete[] keyStart;
2842 return map;
2843}
2844
2845std::map<std::string, float64> DataMessage::getAsFloatMap(const char* key) {
2846 std::map<std::string, float64> map;
2847 std::string str;
2848 uint32 size;
2849 char* keyStart = utils::StringFormat(size, "%s_-[", key);
2850 if (data->cid != DATAMESSAGEID) return map;
2851 char* entry;
2852 char* src = (char*)data + sizeof(DataMessageHeader);
2853 char* srcEnd = (char*)data + data->size;
2854 while (src < srcEnd) {
2855 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2856 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
2857 entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
2858 str = std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str();
2859 switch (((DataMessageEntryHeader*)entry)->cid) {
2860 case TIMEID:
2861 map[str] = (float64)(*(uint64*)(entry + sizeof(DataMessageEntryHeader)));
2862 break;
2863 case CONSTCHARID:
2864 map[str] = utils::Ascii2Float64(entry + sizeof(DataMessageEntryHeader));
2865 break;
2866 case CHARDATAID:
2867 map[str] = (float64)((DataMessageEntryHeader*)entry)->size;
2868 break;
2869 case INTID:
2870 map[str] = (float64)(*(int64*)(entry + sizeof(DataMessageEntryHeader)));
2871 break;
2872 case DOUBLEID:
2873 map[str] = *(float64*)(entry + sizeof(DataMessageEntryHeader));
2874 break;
2875 case DATAMESSAGEID:
2876 map[str] = (float64)((DataMessageEntryHeader*)entry)->size;
2877 break;
2878 default:
2879 break;
2880 }
2881 }
2882 }
2883 src += ((DataMessageEntryHeader*)src)->size;
2884 }
2885 delete[] keyStart;
2886 return map;
2887}
2888
2889std::map<std::string, std::string> DataMessage::getAsStringMap(const char* key) {
2890 std::map<std::string, std::string> map;
2891 std::string str;
2892 uint32 size;
2893 char* keyStart = utils::StringFormat(size, "%s_-[", key);
2894 if (data->cid != DATAMESSAGEID) return map;
2895 char* entry;
2896 char* src = (char*)data + sizeof(DataMessageHeader);
2897 char* srcEnd = (char*)data + data->size;
2898 while (src < srcEnd) {
2899 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2900 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
2901 entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
2902 str = std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3).c_str();
2903 switch (((DataMessageEntryHeader*)entry)->cid) {
2904 case TIMEID:
2905 map[str] = PrintTimeString(*(uint64*)(entry + sizeof(DataMessageEntryHeader)));
2906 break;
2907 case CONSTCHARID:
2908 map[str] = entry + sizeof(DataMessageEntryHeader);
2909 break;
2910 case CHARDATAID:
2911 map[str] = utils::StringFormat("BinaryData [%ub]", ((DataMessageEntryHeader*)entry)->size);
2912 break;
2913 case INTID:
2914 map[str] = utils::StringFormat("%lld", *(int64*)(entry + sizeof(DataMessageEntryHeader)));
2915 break;
2916 case DOUBLEID:
2917 map[str] = utils::StringFormat("%f", *(float64*)(entry + sizeof(DataMessageEntryHeader)));
2918 break;
2919 case DATAMESSAGEID:
2920 map[str] = utils::StringFormat("DataMessage [%ub]", ((DataMessageEntryHeader*)entry)->size);
2921 break;
2922 default:
2923 break;
2924 }
2925 }
2926 }
2927 src += ((DataMessageEntryHeader*)src)->size;
2928 }
2929 delete[] keyStart;
2930 return map;
2931}
2932
2933std::map<std::string, std::string> DataMessage::getStringMap(const char* key) {
2934 std::map<std::string, std::string> map;
2935 std::string str;
2936 uint32 size;
2937 char* keyStart = utils::StringFormat(size, "%s_-[", key);
2938 if (data->cid != DATAMESSAGEID) return map;
2939 char* entry;
2940 char* src = (char*)data + sizeof(DataMessageHeader);
2941 char* srcEnd = (char*)data + data->size;
2942 while (src < srcEnd) {
2943 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2944 entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
2945 if (((DataMessageEntryHeader*)entry)->cid == CONSTCHARID) {
2946 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
2947 str = std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3);
2948 map[str] = entry + sizeof(DataMessageEntryHeader);
2949 }
2950 }
2951 }
2952 src += ((DataMessageEntryHeader*)src)->size;
2953 }
2954 delete[] keyStart;
2955 return map;
2956}
2957
2958std::map<std::string, int64> DataMessage::getIntMap(const char* key) {
2959 std::map<std::string, int64> map;
2960 std::string str;
2961 uint32 size;
2962 char* keyStart = utils::StringFormat(size, "%s_-[", key);
2963 if (data->cid != DATAMESSAGEID) return map;
2964 char* entry;
2965 char* src = (char*)data + sizeof(DataMessageHeader);
2966 char* srcEnd = (char*)data + data->size;
2967 while (src < srcEnd) {
2968 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2969 entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
2970 if (((DataMessageEntryHeader*)entry)->cid == INTID) {
2971 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
2972 str = std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3);
2973 map[str] = *(int64*)(entry + sizeof(DataMessageEntryHeader));
2974 }
2975 }
2976 }
2977 src += ((DataMessageEntryHeader*)src)->size;
2978 }
2979 delete[] keyStart;
2980 return map;
2981}
2982
2983std::map<std::string, double> DataMessage::getDoubleMap(const char* key) {
2984 std::map<std::string, double> map;
2985 std::string str;
2986 uint32 size;
2987 char* keyStart = utils::StringFormat(size, "%s_-[", key);
2988 if (data->cid != DATAMESSAGEID) return map;
2989 char* entry;
2990 char* src = (char*)data + sizeof(DataMessageHeader);
2991 char* srcEnd = (char*)data + data->size;
2992 while (src < srcEnd) {
2993 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
2994 entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
2995 if (((DataMessageEntryHeader*)entry)->cid == DOUBLEID) {
2996 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
2997 str = std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3);
2998 map[str] = *(float64*)(entry + sizeof(DataMessageEntryHeader));
2999 }
3000 }
3001 }
3002 src += ((DataMessageEntryHeader*)src)->size;
3003 }
3004 delete[] keyStart;
3005 return map;
3006}
3007
3008std::map<std::string, float64> DataMessage::getFloatMap(const char* key) {
3009 std::map<std::string, float64> map;
3010 std::string str;
3011 uint32 size;
3012 char* keyStart = utils::StringFormat(size, "%s_-[", key);
3013 if (data->cid != DATAMESSAGEID) return map;
3014 char* entry;
3015 char* src = (char*)data + sizeof(DataMessageHeader);
3016 char* srcEnd = (char*)data + data->size;
3017 while (src < srcEnd) {
3018 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
3019 entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
3020 if (((DataMessageEntryHeader*)entry)->cid == DOUBLEID) {
3021 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
3022 str = std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3);
3023 map[str] = *(float64*)(entry + sizeof(DataMessageEntryHeader));
3024 }
3025 }
3026 }
3027 src += ((DataMessageEntryHeader*)src)->size;
3028 }
3029 delete[] keyStart;
3030 return map;
3031}
3032
3033std::map<std::string, DataMessage*> DataMessage::getAttachedMessageMap(const char* key) {
3034 std::map<std::string, DataMessage*> map;
3035 std::string str;
3036 uint32 size;
3037 char* keyStart = utils::StringFormat(size, "%s_-[", key);
3038 if (data->cid != DATAMESSAGEID) return map;
3039 char* entry;
3040 char* src = (char*)data + sizeof(DataMessageHeader);
3041 char* srcEnd = (char*)data + data->size;
3042 while (src < srcEnd) {
3043 if (((DataMessageEntryHeader*)src)->cid == CONSTCHARID) {
3044 entry = src + sizeof(DataMessageEntryHeader) + strlen(src + sizeof(DataMessageEntryHeader)) + 1;
3045 if (((DataMessageEntryHeader*)entry)->cid == DATAMESSAGEID) {
3046 if (utils::TextStartsWith(src + sizeof(DataMessageEntryHeader), keyStart, false)) {
3047 str = std::string(src + sizeof(DataMessageEntryHeader) + size, strlen(src + sizeof(DataMessageEntryHeader)) - size - 3);
3048 map[str] = new DataMessage(entry + sizeof(DataMessageEntryHeader), true);
3049 }
3050 }
3051 }
3052 src += ((DataMessageEntryHeader*)src)->size;
3053 }
3054 delete[] keyStart;
3055 return map;
3056}
3057
3058bool DataMessage::setTimeMap(const char* key, std::map<std::string, uint64>& map) {
3059 std::map<std::string, uint64>::iterator i = map.begin(), e = map.end();
3060 while (i != e) {
3061 if (!setTime(i->first.c_str(), key, i->second))
3062 return false;
3063 i++;
3064 }
3065 return true;
3066}
3067
3068bool DataMessage::setStringMap(const char* key, std::map<std::string, std::string>& map) {
3069 std::map<std::string, std::string>::iterator i = map.begin(), e = map.end();
3070 while (i != e) {
3071 if (!setString(i->first.c_str(), key, i->second.c_str()))
3072 return false;
3073 i++;
3074 }
3075 return true;
3076}
3077
3078bool DataMessage::setIntMap(const char* key, std::map<std::string, int64>& map) {
3079 std::map<std::string, int64>::iterator i = map.begin(), e = map.end();
3080 while (i != e) {
3081 if (!setInt(i->first.c_str(), key, i->second))
3082 return false;
3083 i++;
3084 }
3085 return true;
3086}
3087
3088bool DataMessage::setDoubleMap(const char* key, std::map<std::string, double>& map) {
3089 std::map<std::string, double>::iterator i = map.begin(), e = map.end();
3090 while (i != e) {
3091 if (!setDouble(i->first.c_str(), key, i->second))
3092 return false;
3093 i++;
3094 }
3095 return true;
3096}
3097
3098bool DataMessage::setFloatMap(const char* key, std::map<std::string, float64>& map) {
3099 std::map<std::string, float64>::iterator i = map.begin(), e = map.end();
3100 while (i != e) {
3101 if (!setFloat(i->first.c_str(), key, i->second))
3102 return false;
3103 i++;
3104 }
3105 return true;
3106}
3107
3108bool DataMessage::setAttachedMessageMap(const char* key, std::map<std::string, DataMessage*>& map) {
3109 std::map<std::string, DataMessage*>::iterator i = map.begin(), e = map.end();
3110 while (i != e) {
3111 if (!setAttachedMessage(i->first.c_str(), key, i->second))
3112 return false;
3113 i++;
3114 }
3115 return true;
3116}
3117
3118
3119DataMessage* DataMessage::FindClosestMessage(uint64 t, std::map<uint64, DataMessage*> &messages) {
3120 uint64 bestCandidateDiff = 0, diff;
3121 DataMessage* bestCandidate = NULL;
3122 std::map<uint64, DataMessage*>::reverse_iterator i = messages.rbegin(), e = messages.rend();
3123 while (i != e) {
3124 if (!bestCandidate) {
3125 bestCandidate = i->second;
3126 bestCandidateDiff = (i->first > t) ? i->first - t : t - i->first;
3127 }
3128 else {
3129 diff = (i->first > t) ? i->first - t : t - i->first;
3130 if (diff < bestCandidateDiff) {
3131 bestCandidate = i->second;
3132 bestCandidateDiff = diff;
3133 }
3134 }
3135 i++;
3136 }
3137 return bestCandidate;
3138}
3139
3140bool DataMessage::addTimeUsage(uint32 cycleCPUTime, uint32 cycleWallTime, uint32 chainCPUTime, uint32 chainWallTime, uint32 chainCount) {
3141 if (data->cid != DATAMESSAGEID) return false;
3142
3143 data->chaincputime = chainCPUTime + cycleCPUTime;
3144 data->chainwalltime = chainWallTime + cycleWallTime;
3145 data->chaincount = chainCount;
3146
3147 data->cyclecputime = cycleCPUTime;
3148 data->cyclewalltime = cycleWallTime;
3149 return true;
3150}
3151
3152
3153bool DataMessage::ConvertDataFromOlderMessageFormat(const char* data, char **newData) {
3154 *newData = NULL;
3155 if (!data) return false;
3156 const DataMessageHeader* header = (DataMessageHeader*)data;
3157 if (header->cid == DATAMESSAGEOLDID) {
3159 if (oldHeader->size < sizeof(DataMessageHeader_Old))
3160 return false;
3161
3162 // Data Message Version History
3163 // Initial version:
3164 // - data->cid = DATAMESSAGEOLDID
3165 // - does not contain cver, cyclecputime, cyclewalltime, chaincputime, chainwalltime
3166 // Version 10:
3167 // - data->cid = DATAMESSAGEID
3168 // - now contains cver, cenc, cyclecputime, cyclewalltime, chaincputime, chainwalltime
3169 // we added 18 bytes of space
3170 uint32 newSize = sizeof(DataMessageHeader) + oldHeader->userSize;
3171 *newData = new char[newSize];
3172 // reset buffer
3173 memset(*newData, 0, newSize);
3174 // set new size
3175 ((DataMessageHeader*)*newData)->size = newSize;
3176 // set new object id type
3177 ((DataMessageHeader*)*newData)->cid = DATAMESSAGEID;
3178 ((DataMessageHeader*)*newData)->cver = CURRENTDATAMESSAGEVERSION;
3179 // cenc already set to 0
3180 // copy the rest of the header
3181 ((DataMessageHeader*)*newData)->memid = oldHeader->memid;
3182 ((DataMessageHeader*)*newData)->time = oldHeader->time;
3183 ((DataMessageHeader*)*newData)->sendtime = oldHeader->sendtime;
3184 ((DataMessageHeader*)*newData)->recvtime = oldHeader->recvtime;
3185 ((DataMessageHeader*)*newData)->origin = oldHeader->origin;
3186 ((DataMessageHeader*)*newData)->destination = oldHeader->destination;
3187 ((DataMessageHeader*)*newData)->ttl = oldHeader->ttl;
3188 ((DataMessageHeader*)*newData)->priority = oldHeader->priority;
3189 ((DataMessageHeader*)*newData)->policy = oldHeader->policy;
3190 ((DataMessageHeader*)*newData)->from = oldHeader->from;
3191 ((DataMessageHeader*)*newData)->to = oldHeader->to;
3192 ((DataMessageHeader*)*newData)->type = oldHeader->type;
3193 ((DataMessageHeader*)*newData)->tag = oldHeader->tag;
3194 ((DataMessageHeader*)*newData)->status = oldHeader->status;
3195 ((DataMessageHeader*)*newData)->reference = oldHeader->reference;
3196 ((DataMessageHeader*)*newData)->serial = oldHeader->serial;
3197 ((DataMessageHeader*)*newData)->contextchange = oldHeader->contextchange;
3198 ((DataMessageHeader*)*newData)->userSize = oldHeader->userSize;
3199 ((DataMessageHeader*)*newData)->userCount = oldHeader->userCount;
3200 // cyclecputime, cyclewalltime, chaincputime, chainwalltime already set to 0
3201 if (oldHeader->userSize > 0)
3202 memcpy((*newData) + sizeof(DataMessageHeader), data + sizeof(DataMessageHeader_Old), oldHeader->userSize);
3203 return true;
3204 }
3205 else if (header->cid == DATAMESSAGEID) {
3206 if (header->cver == CURRENTDATAMESSAGEVERSION) {
3207 *newData = new char[header->size];
3208 memcpy(*newData, data, header->size);
3209 return true;
3210 }
3211 switch (header->cver) {
3212 case 10:
3213 *newData = new char[header->size];
3214 memcpy(*newData, data, header->size);
3215 return true;
3216 default:
3217 LogPrint(0, 0, 0, "*** DataMessage format version %u is not supported, only up to version %u ***", header->cver, CURRENTDATAMESSAGEVERSION);
3218 return false;
3219 }
3220 }
3221 return false;
3222}
3223
3225
3226 // 1. Construction and validity
3227 unittest::progress(5, "construction and validity");
3228 {
3229 DataMessage empty;
3230 if (!empty.isValid()) {
3231 unittest::fail("DataMessage test: default constructor invalid\n");
3232 return false;
3233 }
3234 if (empty.getUserCount() != 0) {
3235 unittest::fail("DataMessage test: empty getUserCount != 0\n");
3236 return false;
3237 }
3238
3239 DataMessage withType(CTRL_TEST, 1);
3240 if (!withType.isValid() || withType.getUserCount() != 0) {
3241 unittest::fail("DataMessage test: DataMessage(type, from) invalid\n");
3242 return false;
3243 }
3244
3245 DataMessage full(CTRL_TEST, 1, 2, static_cast<uint64>(1000), static_cast<uint16>(5));
3246 if (!full.isValid()) {
3247 unittest::fail("DataMessage test: DataMessage(type, from, to, ttl, priority) invalid\n");
3248 return false;
3249 }
3250 }
3251
3252 // 2. Single-value write and read
3253 unittest::progress(20, "single-value read/write");
3254 {
3255 DataMessage msg(CTRL_TEST, 0);
3256 const uint64 t = 1234567890ULL;
3257 if (!msg.setTime("T", t)) { unittest::fail("DataMessage test: setTime failed\n"); return false; }
3258 if (!msg.setString("S", "hello")) { unittest::fail("DataMessage test: setString failed\n"); return false; }
3259 if (!msg.setInt("I", -42)) { unittest::fail("DataMessage test: setInt failed\n"); return false; }
3260 if (!msg.setDouble("D", 3.14)) { unittest::fail("DataMessage test: setDouble failed\n"); return false; }
3261 if (!msg.setFloat("F", 2.5f)) { unittest::fail("DataMessage test: setFloat failed\n"); return false; }
3262 const char bin[] = { 'x', 'y', 'z' };
3263 if (!msg.setData("B", bin, 3)) { unittest::fail("DataMessage test: setData failed\n"); return false; }
3264
3265 if (msg.getTime("T") != t) { unittest::fail("DataMessage test: getTime mismatch\n"); return false; }
3266 const char* s = msg.getString("S");
3267 if (!s || strcmp(s, "hello") != 0) { unittest::fail("DataMessage test: getString mismatch\n"); return false; }
3268 int64 i = 0;
3269 if (!msg.getInt("I", i) || i != -42) { unittest::fail("DataMessage test: getInt mismatch\n"); return false; }
3270 double d = 0;
3271 if (!msg.getDouble("D", d) || d < 3.13 || d > 3.15) { unittest::fail("DataMessage test: getDouble mismatch\n"); return false; }
3272 float64 f = 0;
3273 if (!msg.getFloat("F", f) || f < 2.4f || f > 2.6f) { unittest::fail("DataMessage test: getFloat mismatch\n"); return false; }
3274 uint32 bsize = 0;
3275 const char* b = msg.getData("B", bsize);
3276 if (!b || bsize != 3 || b[0] != 'x' || b[1] != 'y' || b[2] != 'z') {
3277 unittest::fail("DataMessage test: getData mismatch\n"); return false;
3278 }
3279
3280 if (msg.getContentType("T") != TIMEID) { unittest::fail("DataMessage test: getContentType T != TIMEID\n"); return false; }
3281 if (msg.getContentType("S") != CONSTCHARID) { unittest::fail("DataMessage test: getContentType S != CONSTCHARID\n"); return false; }
3282 if (msg.getContentType("I") != INTID) { unittest::fail("DataMessage test: getContentType I != INTID\n"); return false; }
3283 if (msg.getContentType("D") != DOUBLEID) { unittest::fail("DataMessage test: getContentType D != DOUBLEID\n"); return false; }
3284 if (msg.getContentType("B") != CHARDATAID) { unittest::fail("DataMessage test: getContentType B != CHARDATAID\n"); return false; }
3285 if (!msg.hasKey("S") || !msg.hasString("S") || !msg.hasInteger("I") || !msg.hasFloat("D") || !msg.hasTime("T") || !msg.hasData("B")) {
3286 unittest::fail("DataMessage test: hasKey/hasString etc failed\n"); return false;
3287 }
3288 if (msg.getKeyType("S") != DataMessage::SINGLE || !msg.isSingleValue("S")) {
3289 unittest::fail("DataMessage test: getKeyType/isSingleValue failed\n"); return false;
3290 }
3291 if (msg.getAsString("I") != "-42" || msg.getAsInt("S") != 0) { /* getAsInt on string may return 0 */ }
3292 if (msg.getAsBool("I") != true) { unittest::fail("DataMessage test: getAsBool failed\n"); return false; }
3293
3294 // getDataCopy
3295 uint32 csize = 0;
3296 char* cpy = msg.getDataCopy("B", csize);
3297 if (!cpy || csize != 3) { unittest::fail("DataMessage test: getDataCopy failed\n"); return false; }
3298 delete[] cpy;
3299
3300 // Attached message
3301 DataMessage* nested = new DataMessage(CTRL_TEST, 99);
3302 nested->setString("nested", "value");
3303 if (!msg.setAttachedMessage("M", nested)) { unittest::fail("DataMessage test: setAttachedMessage failed\n"); delete nested; return false; }
3304 DataMessage* got = msg.getAttachedMessageCopy("M");
3305 if (!got || got->getUserCount() == 0) { unittest::fail("DataMessage test: getAttachedMessageCopy failed\n"); delete got; return false; }
3306 if (got->getAsString("nested") != "value") { unittest::fail("DataMessage test: attached message content mismatch\n"); delete got; return false; }
3307 if (msg.getContentType("M") != DATAMESSAGEID) { unittest::fail("DataMessage test: getContentType M != DATAMESSAGEID\n"); delete got; return false; }
3308 if (!msg.hasMessage("M")) { unittest::fail("DataMessage test: hasMessage failed\n"); delete got; return false; }
3309 delete got;
3310 delete nested;
3311 }
3312
3313 // 3. Array access
3314 unittest::progress(40, "array access");
3315 {
3316 DataMessage msg(CTRL_TEST, 0);
3317 if (!msg.setTime(static_cast<int64>(0), "arr", 100ULL)) { unittest::fail("DataMessage test: setTime array failed\n"); return false; }
3318 if (!msg.setString(1, "arr", "one")) { unittest::fail("DataMessage test: setString array failed\n"); return false; }
3319 if (!msg.setInt(2, "arr", 999)) { unittest::fail("DataMessage test: setInt array failed\n"); return false; }
3320 if (msg.getTime(static_cast<int64>(0), "arr") != 100ULL) { unittest::fail("DataMessage test: getTime array mismatch\n"); return false; }
3321 if (msg.getAsString(1, "arr") != "one") { unittest::fail("DataMessage test: getAsString array mismatch\n"); return false; }
3322 int64 vi = 0;
3323 if (!msg.getInt(2, "arr", vi) || vi != 999) { unittest::fail("DataMessage test: getInt array mismatch\n"); return false; }
3324 if (msg.getKeyType("arr") != DataMessage::ARRAY || !msg.isArrayContent("arr")) {
3325 unittest::fail("DataMessage test: array key type failed\n"); return false;
3326 }
3327 // getArraySize counts only CONSTCHARID value entries; arr has time, string, int so size may be 1
3328 if (msg.getArraySize("arr") < 1) {
3329 unittest::fail("DataMessage test: getArraySize failed\n"); return false;
3330 }
3331
3332 std::map<int64, uint64> tmap; tmap[0] = 10; tmap[1] = 20;
3333 if (!msg.setTimeArray("tarr", tmap)) { unittest::fail("DataMessage test: setTimeArray failed\n"); return false; }
3334 std::map<int64, std::string> smap; smap[0] = "a"; smap[1] = "b";
3335 if (!msg.setStringArray("sarr", smap)) { unittest::fail("DataMessage test: setStringArray failed\n"); return false; }
3336 std::map<int64, int64> imap; imap[0] = 1; imap[1] = 2;
3337 if (!msg.setIntArray("iarr", imap)) { unittest::fail("DataMessage test: setIntArray failed\n"); return false; }
3338 std::map<int64, double> dmap; dmap[0] = 1.1; dmap[1] = 2.2;
3339 if (!msg.setDoubleArray("darr", dmap)) { unittest::fail("DataMessage test: setDoubleArray failed\n"); return false; }
3340 std::map<int64, uint64> gotT = msg.getTimeArray("tarr");
3341 if (gotT.size() != 2 || gotT[0] != 10 || gotT[1] != 20) { unittest::fail("DataMessage test: getTimeArray mismatch\n"); return false; }
3342 std::map<int64, std::string> gotS = msg.getAsStringArray("sarr");
3343 if (gotS.size() != 2 || gotS[0] != "a" || gotS[1] != "b") { unittest::fail("DataMessage test: getAsStringArray mismatch\n"); return false; }
3344 std::map<int64, int64> gotI = msg.getIntArray("iarr");
3345 if (gotI.size() != 2 || gotI[0] != 1 || gotI[1] != 2) { unittest::fail("DataMessage test: getIntArray mismatch\n"); return false; }
3346 std::map<int64, double> gotD = msg.getDoubleArray("darr");
3347 if (gotD.size() != 2 || gotD[0] < 1.0 || gotD[0] > 1.2 || gotD[1] < 2.1 || gotD[1] > 2.3) { unittest::fail("DataMessage test: getDoubleArray mismatch\n"); return false; }
3348 }
3349
3350 // 4. Map access (string index)
3351 unittest::progress(55, "map access");
3352 {
3353 DataMessage msg(CTRL_TEST, 0);
3354 if (!msg.setTime("x", "m", 200ULL)) { unittest::fail("DataMessage test: setTime map failed\n"); return false; }
3355 if (!msg.setString("y", "m", "mapval")) { unittest::fail("DataMessage test: setString map failed\n"); return false; }
3356 if (!msg.setInt("z", "m", -7)) { unittest::fail("DataMessage test: setInt map failed\n"); return false; }
3357 if (msg.getTime("x", "m") != 200ULL) { unittest::fail("DataMessage test: getTime map mismatch\n"); return false; }
3358 if (msg.getAsString("y", "m") != "mapval") { unittest::fail("DataMessage test: getAsString map mismatch\n"); return false; }
3359 int64 vi = 0;
3360 if (!msg.getInt("z", "m", vi) || vi != -7) { unittest::fail("DataMessage test: getInt map mismatch\n"); return false; }
3361 if (msg.getKeyType("m") != DataMessage::MAP || !msg.isMapContent("m")) {
3362 unittest::fail("DataMessage test: map key type failed\n"); return false;
3363 }
3364 // getMapSize counts only CONSTCHARID value entries; m has time, string, int so size may be 1
3365 if (msg.getMapSize("m") < 1) {
3366 unittest::fail("DataMessage test: getMapSize failed\n"); return false;
3367 }
3368
3369 std::map<std::string, uint64> tmap; tmap["a"] = 1; tmap["b"] = 2;
3370 if (!msg.setTimeMap("tm", tmap)) { unittest::fail("DataMessage test: setTimeMap failed\n"); return false; }
3371 std::map<std::string, std::string> smap; smap["k1"] = "v1"; smap["k2"] = "v2";
3372 if (!msg.setStringMap("sm", smap)) { unittest::fail("DataMessage test: setStringMap failed\n"); return false; }
3373 std::map<std::string, int64> imap; imap["i1"] = 10; imap["i2"] = 20;
3374 if (!msg.setIntMap("im", imap)) { unittest::fail("DataMessage test: setIntMap failed\n"); return false; }
3375 std::map<std::string, uint64> gotT = msg.getTimeMap("tm");
3376 if (gotT.size() != 2 || gotT["a"] != 1 || gotT["b"] != 2) { unittest::fail("DataMessage test: getTimeMap mismatch\n"); return false; }
3377 std::map<std::string, std::string> gotS = msg.getAsStringMap("sm");
3378 if (gotS.size() != 2 || gotS["k1"] != "v1" || gotS["k2"] != "v2") { unittest::fail("DataMessage test: getAsStringMap mismatch\n"); return false; }
3379 std::map<std::string, int64> gotI = msg.getIntMap("im");
3380 if (gotI.size() != 2 || gotI["i1"] != 10 || gotI["i2"] != 20) { unittest::fail("DataMessage test: getIntMap mismatch\n"); return false; }
3381 }
3382
3383 // 5. Binary serialisation round-trip
3384 unittest::progress(70, "binary serialisation round-trip");
3385 {
3386 DataMessage orig(CTRL_TEST, 0);
3387 orig.setString("k", "roundtrip");
3388 orig.setInt("n", 77);
3389 orig.setDouble("x", 1.5);
3390 std::map<int64, std::string> amap; amap[0] = "elem0";
3391 orig.setStringArray("arr", amap);
3392 std::map<std::string, int64> mmap; mmap["idx"] = 42;
3393 orig.setIntMap("m", mmap);
3394 char* raw = orig.getRawData();
3395 uint32 sz = orig.getSize();
3396 if (!raw || sz == 0) { unittest::fail("DataMessage test: getRawData/getSize failed\n"); return false; }
3397 DataMessage decoded((const char*)raw);
3398 if (!decoded.isValid()) { unittest::fail("DataMessage test: decoded message invalid\n"); return false; }
3399 if (decoded.getUserCount() != orig.getUserCount()) {
3400 unittest::fail("DataMessage test: round-trip getUserCount mismatch\n"); return false;
3401 }
3402 if (decoded.getAsString("k") != "roundtrip") { unittest::fail("DataMessage test: round-trip string mismatch\n"); return false; }
3403 int64 nval = 0;
3404 if (!decoded.getInt("n", nval) || nval != 77) { unittest::fail("DataMessage test: round-trip int mismatch\n"); return false; }
3405 double xval = 0;
3406 if (!decoded.getDouble("x", xval) || xval < 1.4 || xval > 1.6) { unittest::fail("DataMessage test: round-trip double mismatch\n"); return false; }
3407 if (decoded.getAsStringArray("arr")[0] != "elem0") { unittest::fail("DataMessage test: round-trip array mismatch\n"); return false; }
3408 if (decoded.getIntMap("m")["idx"] != 42) { unittest::fail("DataMessage test: round-trip map mismatch\n"); return false; }
3409 }
3410
3411 // 6. Text / structured serialisation
3412 unittest::progress(82, "text / structured serialisation");
3413 {
3414 DataMessage msg(CTRL_TEST, 0);
3415 msg.setString("foo", "bar");
3416 std::string ustr = msg.getUserEntriesAsString();
3417 if (ustr.empty()) { unittest::fail("DataMessage test: getUserEntriesAsString empty\n"); return false; }
3418 std::string ujson = msg.getUserEntriesAsJSON(false);
3419 if (ujson.empty()) { unittest::fail("DataMessage test: getUserEntriesAsJSON empty\n"); return false; }
3420 msg.getUserEntriesAsJSON(true);
3421 std::string json = msg.toJSON();
3422 if (json.empty()) { unittest::fail("DataMessage test: toJSON empty\n"); return false; }
3423 std::string xml = msg.toXML();
3424 if (xml.empty()) { unittest::fail("DataMessage test: toXML empty\n"); return false; }
3425 std::string csv = msg.toCSV();
3426 if (csv.empty()) { unittest::fail("DataMessage test: toCSV empty\n"); return false; }
3427 std::string hdr = DataMessage::GetCSVHeader();
3428 if (hdr.empty()) { unittest::fail("DataMessage test: GetCSVHeader empty\n"); return false; }
3429 }
3430
3431 // 7. Copy and remove
3432 unittest::progress(90, "copy and remove");
3433 {
3434 DataMessage src(CTRL_TEST, 0);
3435 src.setString("a", "1");
3436 src.setInt("b", 2);
3437 DataMessage dst(CTRL_TEST, 0);
3438 if (dst.copyUserEntriesFromMessage(&src) != 2) {
3439 unittest::fail("DataMessage test: copyUserEntriesFromMessage count\n"); return false;
3440 }
3441 if (dst.getAsString("a") != "1" || dst.getAsInt("b") != 2) {
3442 unittest::fail("DataMessage test: copyUserEntriesFromMessage content\n"); return false;
3443 }
3444 uint32 cnt = dst.getUserCount();
3445 if (!dst.removeEntry("a")) { unittest::fail("DataMessage test: removeEntry failed\n"); return false; }
3446 if (dst.hasKey("a")) { unittest::fail("DataMessage test: removeEntry key still present\n"); return false; }
3447 if (dst.getUserCount() != cnt - 1) { unittest::fail("DataMessage test: removeEntry count\n"); return false; }
3448 }
3449
3450 // 8. Edge / robustness
3451 unittest::progress(96, "edge / robustness");
3452 {
3453 DataMessage msg(CTRL_TEST, 0);
3454 if (msg.hasKey("nonexistent")) { unittest::fail("DataMessage test: hasKey nonexistent true\n"); return false; }
3455 if (msg.getString("nonexistent") != NULL) { unittest::fail("DataMessage test: getString nonexistent non-NULL\n"); return false; }
3456 if (msg.getTime("nonexistent") != 0) { unittest::fail("DataMessage test: getTime nonexistent non-zero\n"); return false; }
3457 DataMessage empty;
3458 if (empty.getUserCount() != 0) { unittest::fail("DataMessage test: empty getUserCount\n"); return false; }
3459 empty.getUserEntriesAsString();
3460 empty.toJSON();
3461 }
3462
3463 unittest::progress(100, "done");
3464 return true;
3465}
3466
3469 "Data message encode/decode, arrays, maps, serialisation", "core");
3470}
3471
3472} // namespace cmlabs
The binary DataMessage container — the central data-exchange object of Psyclone/CMSDK.
#define CURRENTDATAMESSAGEVERSION
#define CONSTCHARID
Definition ObjectIDs.h:38
#define DATAMESSAGEOLDID
Definition ObjectIDs.h:53
#define CHARDATAID
Definition ObjectIDs.h:40
#define CONSTCHARINFOID
Definition ObjectIDs.h:43
#define DOUBLEID
Definition ObjectIDs.h:42
#define DATAMESSAGEINFOID
Definition ObjectIDs.h:69
#define DATAMESSAGEID
Definition ObjectIDs.h:75
#define INTID
Definition ObjectIDs.h:41
#define GetObjID(data)
Extract the cid field from a binary object block: the uint32 at byte offset 4 (after the leading size...
Definition ObjectIDs.h:26
#define CHARDATAINFOID
Definition ObjectIDs.h:44
#define TIMEID
Definition ObjectIDs.h:39
#define DATAMESSAGEDRAFTID
Definition ObjectIDs.h:70
CMSDK time: µs-resolution 64-bit timestamps and the Time Mapping Constant (TMC).
#define MAXVALUINT32
Definition Types.h:87
Small, dependency-free unit test harness used by all CMSDK object tests.
#define stricmp
Definition Utils.h:132
#define LogPrint
Definition Utils.h:313
bool setTime(const char *key, uint64 value)
setTime(const char* key, uint64 value)
std::map< int64, float64 > getAsFloatArray(const char *key)
getAsFloatArray(const char* key)
bool setFloatArray(const char *key, std::map< int64, float64 > &map)
setFloatArray(const char* key, std::map<int64, float64>& map) Sets the whole float array named key in...
static bool UnitTest()
Run the built-in self test for the DataMessage implementation.
DataMessage()
DataMessage() Creates an empty DataMessage.
bool getDouble(const char *key, double &value)
getDouble(const char* key, double& value)
~DataMessage()
~DataMessage() Message destructor
std::string toXML(std::map< uint16, std::string > *subtypes=NULL, std::map< uint16, std::string > *subcontexts=NULL, std::map< uint32, std::string > *compNames=NULL)
toXML()
static DataMessage * FindClosestMessage(uint64 t, std::map< uint64, DataMessage * > &messages)
FindClosestMessage(uint64 t, std::map<uint64, DataMessage*> &messages) In a map of time -> DataMessag...
bool setFloat(const char *key, float64 value)
setFloat(const char* key, float64 value)
std::map< int64, int64 > getIntArray(const char *key)
getIntArray(const char* key)
bool addTimeUsage(uint32 cycleCPUTime, uint32 cycleWallTime, uint32 chainCPUTime=0, uint32 chainWallTime=0, uint32 chainCount=0)
addTimeUsage()
std::map< std::string, double > getDoubleMap(const char *key)
returns the user double entry with this key
bool setString(const char *key, const char *value)
setString(const char* key, const char* value)
bool getInt(const char *key, int64 &value)
getInt(const char* key, int64& value)
bool setInt(const char *key, int64 value)
setInt(const char* key, int64 value)
bool isSingleValue(const char *key)
isSingleValue(const char* key)
bool hasData(const char *key)
Check if key variable exists and is a data entry.
uint32 getMapCount(const char *key)
getMapCount(const char* key) Returns the number of elements in map with name '<key>'
std::map< std::string, uint64 > getTimeMap(const char *key)
returns the user time entry with this key
std::map< std::string, int64 > getIntMap(const char *key)
returns the user integer entry with this key
uint32 getArraySize(const char *key)
getArraySize(const char* key) Returns the number of elements in array with name '<key>'
char * getDataCopy(const char *key, uint32 &size)
getDataCopy(const char* key, uint32& size)
bool setDoubleMap(const char *key, std::map< std::string, double > &map)
sets the user double entry with this key to the value provided
std::string getAsString(const char *key)
getAsString(const char* key)
DataMessageHeader * data
Pointer to the message's flat memory block (header + user entries).
std::string toJSON(std::map< uint16, std::string > *subtypes=NULL, std::map< uint16, std::string > *subcontexts=NULL, std::map< uint32, std::string > *compNames=NULL)
toJSON()
std::map< int64, float64 > getFloatArray(const char *key)
getFloatArray(const char* key)
std::string toCSV(const char *separator=NULL, const char *preample=NULL, std::map< uint16, std::string > *subtypes=NULL, std::map< uint16, std::string > *subcontexts=NULL, std::map< uint32, std::string > *compNames=NULL)
toCSV()
bool hasFloat(const char *key)
Check if key variable exists and is a float.
bool setIntMap(const char *key, std::map< std::string, int64 > &map)
sets the user integer entry with this key
char * findEntry(const char *key)
findEntry(const char* key)
const char * getData(const char *key, uint32 &size)
getData(const char* key, uint32& size)
bool getAsBool(const char *key)
getAsBool(const char* key)
uint32 getUserCount()
getUserCount()
uint32 getSize()
getSize() Get message size Many types of data of any size can be put into a message as user entries; ...
static bool ConvertDataFromOlderMessageFormat(const char *data, char **newData)
Convert a binary block in the legacy (pre-version-10, DATAMESSAGEOLDID) format to the current DataMes...
uint32 copyUserEntriesFromMessage(DataMessage *msg)
copyUserEntriesFromMessage(DataMessage* msg) Copies all user data from a message into this message,...
std::string getUserEntriesAsJSON(bool asText)
getUserEntriesAsJSON(bool asText) Returns the JSON representation of the full message including all u...
bool setAttachedMessage(const char *key, DataMessage *msg)
setAttachedMessage(const char* key, DataMessage* msg)
bool setTimeArray(const char *key, std::map< int64, uint64 > &map)
setTimeArray(const char* key, std::map<int64, uint64>& map) Sets the whole time array named key in on...
std::map< std::string, std::string > getStringMap(const char *key)
returns the user string entry with this key
std::map< int64, std::string > getStringArray(const char *key)
getStringArray(const char* key)
bool setAttachedMessageArray(const char *key, std::map< int64, DataMessage * > &map)
setAttachedMessageArray(const char* key, std::map<int64, DataMessage*>& map) Sets the whole array of ...
bool removeEntry(const char *key)
removeEntry(const char* key)
bool hasTime(const char *key)
Check if key variable exists and is a time.
std::map< int64, std::string > getAsStringArray(const char *key)
getAsStringArray(const char* key)
bool setIntArray(const char *key, std::map< int64, int64 > &map)
setIntArray(const char* key, std::map<int64, int64>& map) Sets the whole integer array named key in o...
std::map< std::string, DataMessage * > getAttachedMessageMap(const char *key)
returns a copy of the user message entry with this key
bool setTimeMap(const char *key, std::map< std::string, uint64 > &map)
sets the user time entry with this key
uint32 getContentSize(const char *key)
getContentSize(const char* key)
void invalidateFindKeyCache()
Internal: clears the single-entry key-lookup cache.
uint32 getArrayCount(const char *key)
getArrayCount(const char* key) Returns the number of elements in array with name '<key>'
std::map< std::string, int64 > getAsIntMap(const char *key)
returns the user entry as an integer map regardless of what type it is
bool setFloatMap(const char *key, std::map< std::string, float64 > &map)
sets the user float entry with this key to the value provided
uint64 getAsTime(const char *key)
getAsTime(const char* key)
bool isMapContent(const char *key)
isMapContent(const char* key)
bool hasKey(const char *key)
Check if key variable exists.
uint64 getTime(const char *key)
getTime(const char* key)
bool getFloat(const char *key, float64 &value)
getFloat(const char* key, float64& value)
bool setRawData(const char *key, const char *value, uint32 size, uint32 datatype)
Internal: low-level entry writer used by all typed set...() overloads.
bool setDouble(const char *key, double value)
setDouble(const char* key, double value)
std::map< std::string, std::string > getAsStringMap(const char *key)
returns the user entry as a string regardless of what type it is
int64 getAsInt(const char *key)
getAsInt(const char* key)
bool setDoubleArray(const char *key, std::map< int64, double > &map)
setDoubleArray(const char* key, std::map<int64, double>& map) Sets the whole double array named key i...
bool setStringMap(const char *key, std::map< std::string, std::string > &map)
sets the user string entry with this key
bool isArrayContent(const char *key)
isArrayContent(const char* key)
DataMessage * getAttachedMessageCopy(const char *key)
getAttachedMessageCopy(const char* key)
bool isValid()
isValid() Checks that the message memory block exists and carries the current-format object id (DATAM...
bool hasMessage(const char *key)
Check if key variable exists and is a message.
char * getRawData()
getRawData() Retrieve a pointer to the raw binary block of the message (header + entries).
const char * swapMessageData(const char *data)
swapMessageData(const char* data)
std::map< int64, uint64 > getTimeArray(const char *key)
uint32 getMapSize(const char *key)
getMapSize(const char* key) Returns the number of elements in map with name '<key>'
std::map< int64, double > getDoubleArray(const char *key)
getDoubleArray(const char* key)
bool setData(const char *key, const char *value, uint32 size)
setData(const char* key, const char* value, uint32 size)
bool hasString(const char *key)
Check if key variable exists and is a string.
std::map< int64, DataMessage * > getAttachedMessageArray(const char *key)
getAttachedMessageArray(const char* key)
const char * getString(const char *key)
getString(const char* key)
char * findSpace(uint32 space)
findSpace(uint32 space)
static std::string GetCSVHeader(const char *separator=NULL, const char *preample=NULL)
toCSVHeader()
bool fillInDraftUserDataFrom(const char *data, uint32 maxDraftSize)
fillInDraftUserDataFrom(const char* data, uint32 maxDraftSize)
KeyType getKeyType(const char *key)
getKeyType(const char* key)
uint32 getContentType(const char *key)
getContentType(const char* key)
bool setStringArray(const char *key, std::map< int64, std::string > &map)
setStringArray(const char* key, std::map<int64, std::string>& map) Sets the whole string array named ...
DataMessage * copy()
copy() Creates a full deep copy of the message and returns it.
bool hasInteger(const char *key)
Check if key variable exists and is an integer.
std::map< int64, int64 > getAsIntArray(const char *key)
getAsIntArray(const char* key)
bool setAttachedMessageMap(const char *key, std::map< std::string, DataMessage * > &map)
sets the user message entry with this key to the provided message
std::string getUserEntriesAsString()
getUserEntriesAsString() Returns the textual representation of the full message including all user en...
float64 getAsFloat(const char *key)
getAsFloat(const char* key)
std::map< std::string, float64 > getFloatMap(const char *key)
returns the user float entry with this key
std::map< std::string, float64 > getAsFloatMap(const char *key)
returns the user entry as a float map regardless of what type it is
static UnitTestRunner & instance()
Access the singleton (created on first use).
void registerTest(const char *name, UnitTestFunc func, const char *description="", const char *category="", bool inDefaultRun=true)
Register a test with the runner.
std::string PrintTimeString(uint64 t, bool local=true, bool us=true, bool ms=true)
Definition PsyTime.cpp:676
uint64 GetTimeNow()
Return the current absolute time (µs since year 0) according to the TMC.
Definition PsyTime.cpp:69
bool TextStartsWith(const char *str, const char *start, bool caseSensitive=true)
Test whether str starts with start.
Definition Utils.cpp:7240
std::string TextIndent(const char *text, const char *indent)
Prefix every line of text with indent.
Definition Utils.cpp:6119
uint32 StringSingleReplace(std::string &text, std::string key, std::string value, bool onlyFirst)
Replace occurrences of key with value in text.
Definition Utils.cpp:6644
std::string StringFormat(const char *format,...)
printf into a std::string.
Definition Utils.cpp:6626
uint64 Ascii2Uint64(const char *ascii, uint32 start=0, uint32 end=0)
Parse an unsigned 64-bit decimal integer from a substring.
Definition Utils.cpp:7480
bool TextEndsWith(const char *str, const char *end, bool caseSensitive=true)
Test whether str ends with end.
Definition Utils.cpp:7233
int64 Ascii2Int64(const char *ascii, uint32 start=0, uint32 end=0)
Parse a signed 64-bit decimal integer from a substring.
Definition Utils.cpp:7462
uint32 strcpyavail(char *dst, const char *src, uint32 maxlen, bool copyAvailable)
Bounded strcpy that always NUL-terminates.
Definition Utils.cpp:6056
float64 Ascii2Float64(const char *ascii, uint32 start=0, uint32 end=0)
Parse a 64-bit float from a substring (decimal point, not locale dependent).
Definition Utils.cpp:7546
void fail(const char *fmt,...)
Set an explanatory reason shown on the FAIL line.
void progress(int percent, const char *action)
Report progress with a short description of the current action.
void Register_DataMessage_Tests()
static struct PsyType CTRL_TEST
Definition ObjectIDs.h:82
Hierarchical message type identifier — the key used for publish/subscribe matching in Psyclone.
Definition Types.h:123
Header preceding every user entry inside a DataMessage's flat memory block.
uint32 size
Total size of this entry in bytes, including this header, the key and the payload.
Legacy (pre-version-10) DataMessage wire header, kept only for format conversion.
The current (version 10) DataMessage wire/shared-memory header.
uint64 sendtime
Time the message was posted/sent, in microseconds.
std::string toJSON(std::map< uint16, std::string > *subtypes=NULL, std::map< uint16, std::string > *subcontexts=NULL, std::map< uint32, std::string > *compNames=NULL)
Render the header fields as a JSON object (header only, no user entries).
uint64 reference
Reference id linking this message to another (e.g.
uint16 destination
NodeID of the target node (0 = local/any).
uint32 chaincputime
Accumulated CPU time across the whole causal message chain, in microseconds.
uint64 serial
Serial number, e.g.
uint64 time
Creation time in microseconds since epoch (see PsyTime).
uint64 memid
Shared-memory id assigned when the message is stored in a memory map.
uint32 size
Total size of the whole message block in bytes (header + all entries).
uint32 userCount
Number of user entries currently in use.
uint16 status
User/application status code.
PsyType type
Hierarchical message type (e.g.
uint16 priority
Scheduling priority; higher values are processed first by whiteboards and modules.
uint32 userSize
Total size in bytes of all user entries currently in use.
uint8 policy
Delivery policy flags, e.g.
uint32 cyclewalltime
Wall-clock time spent in this cycle, in microseconds (profiling).
uint32 cid
Object id, always DATAMESSAGEID for a valid current-format message; used by isValid().
uint16 cver
Message format version (CURRENTDATAMESSAGEVERSION).
uint32 chainwalltime
Accumulated wall time across the whole causal message chain, in microseconds.
uint64 ttl
Time-to-live in microseconds; 0 means deliver-and-forget (not retained in memory).
std::string toXML(std::map< uint16, std::string > *subtypes=NULL, std::map< uint16, std::string > *subcontexts=NULL, std::map< uint32, std::string > *compNames=NULL)
Render the header fields as an XML fragment (header only, no user entries).
PsyContext contextchange
Context switch this message announces (NOCONTEXT if none).
uint32 cyclecputime
CPU time spent processing the triggering message in this cycle, in microseconds (profiling).
uint32 to
Component id of the addressee; 0 for publish/subscribe distribution.
uint16 origin
NodeID of the node the message originated on.
uint32 chaincount
Number of messages in the causal chain leading to (and including) this one.
uint32 from
Component id of the sender.
uint64 recvtime
Time the message was received by the current component, in microseconds.
uint32 tag
User tag id for temporal/semantic grouping of related messages.