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