BTRFS: Implement BTree::Path and change _Find.
[haiku.git] / src / apps / cortex / Persistence / Wrappers / MessageIO.cpp
blob7d581dbe1c72b08a50c644e9ffa43a0421d11f1d
1 /*
2 * Copyright (c) 1999-2000, Eric Moon.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions, and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions, and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 // MessageIO.cpp
34 #include "MessageIO.h"
36 #include <BeBuild.h>
37 #include <Debug.h>
39 #include <cstdlib>
40 #include <cstring>
41 #include <cctype>
43 #include <vector>
44 #include <utility>
46 using namespace std;
48 __USE_CORTEX_NAMESPACE
50 // -------------------------------------------------------- //
51 // constants
52 // -------------------------------------------------------- //
54 const char* const MessageIO::s_element = "BMessage";
56 const char* _boolEl = "bool";
57 const char* _int8El = "int8";
58 const char* _int16El = "int16";
59 const char* _int32El = "int32";
60 const char* _int64El = "int64";
61 const char* _floatEl = "float";
62 const char* _doubleEl = "double";
63 const char* _stringEl = "string";
64 const char* _pointEl = "point";
65 const char* _rectEl = "rect";
67 // -------------------------------------------------------- //
68 // *** ctor/dtor/accessor
69 // -------------------------------------------------------- //
71 MessageIO::~MessageIO() {
72 if(m_ownMessage && m_message)
73 delete m_message;
76 MessageIO::MessageIO() :
77 m_ownMessage(true),
78 m_message(0) {}
80 // When given a message to export, this object does NOT take
81 // responsibility for deleting it. It will, however, handle
82 // deletion of an imported BMessage.
84 MessageIO::MessageIO(
85 const BMessage* message) :
86 m_ownMessage(false),
87 m_message(const_cast<BMessage*>(message)) {
89 ASSERT(m_message);
92 void MessageIO::setMessage(
93 BMessage* message) {
95 if(m_ownMessage && m_message)
96 delete m_message;
97 m_ownMessage = false;
98 m_message = message;
100 ASSERT(m_message);
103 // -------------------------------------------------------- //
104 // *** static setup method
105 // -------------------------------------------------------- //
106 // call this method to install hooks for the tags needed by
107 // MessageIO into the given document type
109 /*static*/
110 void MessageIO::AddTo(
111 XML::DocumentType* docType) {
113 docType->addMapping(new Mapping<MessageIO>(s_element));
116 // -------------------------------------------------------- //
117 // EXPORT:
118 // -------------------------------------------------------- //
120 void MessageIO::xmlExportBegin(
121 ExportContext& context) const {
123 if(!m_message) {
124 context.reportError("No message data to export.\n");
125 return;
127 context.beginElement(s_element);
130 void MessageIO::xmlExportAttributes(
131 ExportContext& context) const {
133 if(m_message->what)
134 context.writeAttr("what", m_message->what);
135 if(m_name.Length())
136 context.writeAttr("name", m_name.String());
139 void MessageIO::xmlExportContent(
140 ExportContext& context) const {
143 ASSERT(m_message);
144 status_t err;
146 // +++++ the approach:
147 // 1) build a list of field names
148 // 2) export fields sorted first by index, then name
150 typedef vector<BString> field_set;
151 field_set fields;
153 #ifdef B_BEOS_VERSION_DANO
154 const
155 #endif
156 char* name;
157 type_code type;
158 int32 count;
159 for(
160 int32 n = 0;
161 m_message->GetInfo(B_ANY_TYPE, n, &name, &type, &count) == B_OK;
162 ++n) {
163 fields.push_back(name);
166 if(!fields.size())
167 return;
169 context.beginContent();
171 bool done = false;
172 for(int32 n = 0; !done; ++n) {
174 done = true;
176 for(
177 uint32 fieldIndex = 0;
178 fieldIndex < fields.size();
179 ++fieldIndex) {
181 if(m_message->GetInfo(
182 fields[fieldIndex].String(),
183 &type,
184 &count) < B_OK || n >= count)
185 continue;
187 // found a field at the current index, so don't give up
188 done = false;
190 err = _exportField(
191 context,
192 m_message,
193 type,
194 fields[fieldIndex].String(),
197 if(err < B_OK) {
198 BString errText;
199 errText << "Couldn't export field '" << fields[fieldIndex] <<
200 "' index " << n << ": " << strerror(err) << "\n";
201 context.reportError(errText.String());
202 return;
208 void MessageIO::xmlExportEnd(
209 ExportContext& context) const {
210 context.endElement();
214 // -------------------------------------------------------- //
215 // IMPORT:
216 // -------------------------------------------------------- //
218 void MessageIO::xmlImportBegin(
219 ImportContext& context) {
221 // create the message
222 if(m_message) {
223 if(m_ownMessage)
224 delete m_message;
226 m_message = new BMessage();
227 m_name.SetTo("");
230 void MessageIO::xmlImportAttribute(
231 const char* key,
232 const char* value,
233 ImportContext& context) {
235 ASSERT(m_message);
237 if(!strcmp(key, "what"))
238 m_message->what = atol(value);
239 else if(!strcmp(key, "name"))
240 m_name.SetTo(value);
243 void MessageIO::xmlImportContent(
244 const char* data,
245 uint32 length,
246 ImportContext& context) {}
248 void MessageIO::xmlImportChild(
249 IPersistent* child,
250 ImportContext& context) {
252 ASSERT(m_message);
254 if(strcmp(context.element(), s_element) != 0) {
255 context.reportError("Unexpected child element.\n");
256 return;
259 MessageIO* childMessageIO = dynamic_cast<MessageIO*>(child);
260 ASSERT(childMessageIO);
262 m_message->AddMessage(
263 childMessageIO->m_name.String(),
264 childMessageIO->m_message);
267 void MessageIO::xmlImportComplete(
268 ImportContext& context) {}
270 void MessageIO::xmlImportChildBegin(
271 const char* name,
272 ImportContext& context) {
274 // sanity checks
276 ASSERT(m_message);
278 if(strcmp(context.parentElement(), s_element) != 0) {
279 context.reportError("Unexpected parent element.\n");
280 return;
283 if(!_isValidMessageElement(context.element())) {
284 context.reportError("Invalid message field element.\n");
285 return;
288 m_fieldData.SetTo("");
291 void MessageIO::xmlImportChildAttribute(
292 const char* key,
293 const char* value,
294 ImportContext& context) {
296 if(!strcmp(key, "name"))
297 m_fieldName.SetTo(value);
298 if(!strcmp(key, "value"))
299 m_fieldData.SetTo(value);
302 void MessageIO::xmlImportChildContent(
303 const char* data,
304 uint32 length,
305 ImportContext& context) {
307 m_fieldData.Append(data, length);
310 void MessageIO::xmlImportChildComplete(
311 const char* name,
312 ImportContext& context) {
314 ASSERT(m_message);
316 status_t err = _importField(
317 m_message,
318 name,
319 m_fieldName.String(),
320 m_fieldData.String());
321 if(err < B_OK) {
322 context.reportWarning("Invalid field data.\n");
326 // -------------------------------------------------------- //
327 // implementation
328 // -------------------------------------------------------- //
330 bool MessageIO::_isValidMessageElement(
331 const char* element) const {
333 if(!strcmp(element, _boolEl)) return true;
334 if(!strcmp(element, _int8El)) return true;
335 if(!strcmp(element, _int16El)) return true;
336 if(!strcmp(element, _int32El)) return true;
337 if(!strcmp(element, _int64El)) return true;
338 if(!strcmp(element, _floatEl)) return true;
339 if(!strcmp(element, _doubleEl)) return true;
340 if(!strcmp(element, _stringEl)) return true;
341 if(!strcmp(element, _pointEl)) return true;
342 if(!strcmp(element, _rectEl)) return true;
344 return false;
347 status_t MessageIO::_importField(
348 BMessage* message,
349 const char* element,
350 const char* name,
351 const char* data) {
353 // skip leading whitespace
354 while(*data && isspace(*data)) ++data;
356 if(!strcmp(element, _boolEl)) {
357 bool v;
358 if(!strcmp(data, "true") || !strcmp(data, "1"))
359 v = true;
360 else if(!strcmp(data, "false") || !strcmp(data, "0"))
361 v = false;
362 else
363 return B_BAD_VALUE;
364 return message->AddBool(name, v);
367 if(!strcmp(element, _int8El)) {
368 int8 v = atoi(data);
369 return message->AddInt8(name, v);
371 if(!strcmp(element, _int16El)) {
372 int16 v = atoi(data);
373 return message->AddInt16(name, v);
375 if(!strcmp(element, _int32El)) {
376 int32 v = atol(data);
377 return message->AddInt32(name, v);
379 if(!strcmp(element, _int64El)) {
380 // int64 v = atoll(data);
381 int64 v = strtoll(data, 0, 10);
382 return message->AddInt64(name, v);
384 if(!strcmp(element, _floatEl)) {
385 float v = (float)atof(data);
386 return message->AddFloat(name, v);
388 if(!strcmp(element, _doubleEl)) {
389 double v = atof(data);
390 return message->AddDouble(name, v);
393 if(!strcmp(element, _stringEl)) {
394 // +++++ chomp leading/trailing whitespace?
396 return message->AddString(name, data);
399 if(!strcmp(element, _pointEl)) {
400 BPoint p;
401 const char* ystart = strchr(data, ',');
402 if(!ystart)
403 return B_BAD_VALUE;
404 ++ystart;
405 if(!*ystart)
406 return B_BAD_VALUE;
407 p.x = (float)atof(data);
408 p.y = (float)atof(ystart);
410 return message->AddPoint(name, p);
413 if(!strcmp(element, _rectEl)) {
414 BRect r;
415 const char* topstart = strchr(data, ',');
416 if(!topstart)
417 return B_BAD_VALUE;
418 ++topstart;
419 if(!*topstart)
420 return B_BAD_VALUE;
422 const char* rightstart = strchr(topstart, ',');
423 if(!rightstart)
424 return B_BAD_VALUE;
425 ++rightstart;
426 if(!*rightstart)
427 return B_BAD_VALUE;
429 const char* bottomstart = strchr(rightstart, ',');
430 if(!bottomstart)
431 return B_BAD_VALUE;
432 ++bottomstart;
433 if(!*bottomstart)
434 return B_BAD_VALUE;
436 r.left = (float)atof(data);
437 r.top = (float)atof(topstart);
438 r.right = (float)atof(rightstart);
439 r.bottom = (float)atof(bottomstart);
441 return message->AddRect(name, r);
444 return B_BAD_INDEX;
447 status_t MessageIO::_exportField(
448 ExportContext& context,
449 BMessage* message,
450 type_code type,
451 const char* name,
452 int32 index) const {
454 status_t err;
455 BString elementName;
456 BString content;
458 switch(type) {
459 case B_BOOL_TYPE: {
460 bool v;
461 err = message->FindBool(name, index, &v);
462 if(err < B_OK)
463 return err;
464 elementName = _boolEl;
465 content = (v ? "true" : "false");
466 break;
469 case B_INT8_TYPE: {
470 int8 v;
471 err = message->FindInt8(name, index, &v);
472 if(err < B_OK)
473 return err;
474 elementName = _int8El;
475 content << (int32)v;
476 break;
479 case B_INT16_TYPE: {
480 int16 v;
481 err = message->FindInt16(name, index, &v);
482 if(err < B_OK)
483 return err;
484 elementName = _int16El;
485 content << (int32)v;
486 break;
489 case B_INT32_TYPE: {
490 int32 v;
491 err = message->FindInt32(name, index, &v);
492 if(err < B_OK)
493 return err;
494 elementName = _int32El;
495 content << v;
496 break;
499 case B_INT64_TYPE: {
500 int64 v;
501 err = message->FindInt64(name, index, &v);
502 if(err < B_OK)
503 return err;
504 elementName = _int64El;
505 content << v;
506 break;
509 case B_FLOAT_TYPE: {
510 float v;
511 err = message->FindFloat(name, index, &v);
512 if(err < B_OK)
513 return err;
514 elementName = _floatEl;
515 content << v; // +++++ need adjustable precision!
516 break;
519 case B_DOUBLE_TYPE: {
520 double v;
521 err = message->FindDouble(name, index, &v);
522 if(err < B_OK)
523 return err;
524 elementName = _doubleEl;
525 content << (float)v; // +++++ need adjustable precision!
526 break;
529 case B_STRING_TYPE: {
530 const char* v;
531 err = message->FindString(name, index, &v);
532 if(err < B_OK)
533 return err;
534 elementName = _stringEl;
535 content = v;
536 break;
539 case B_POINT_TYPE: {
540 BPoint v;
541 err = message->FindPoint(name, index, &v);
542 if(err < B_OK)
543 return err;
544 elementName = _pointEl;
545 content << v.x << ", " << v.y;
546 break;
549 case B_RECT_TYPE: {
550 BRect v;
551 err = message->FindRect(name, index, &v);
552 if(err < B_OK)
553 return err;
554 elementName = _rectEl;
555 content << v.left << ", " << v.top << ", " <<
556 v.right << ", " << v.bottom;
557 break;
560 case B_MESSAGE_TYPE: {
561 BMessage m;
562 err = message->FindMessage(name, index, &m);
563 if(err < B_OK)
564 return err;
566 // write child message
567 MessageIO io(&m);
568 io.m_name = name;
569 return context.writeObject(&io);
572 default:
573 return B_BAD_TYPE;
576 // spew the element
577 context.beginElement(elementName.String());
578 context.writeAttr("name", name);
579 context.writeAttr("value", content.String());
580 // context.beginContent();
581 // context.writeString(content);
582 context.endElement();
584 return B_OK;
586 // END -- MessageIO.cpp --