2 * Copyright (c) 1999-2000, Eric Moon.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
34 #include "MessageIO.h"
48 __USE_CORTEX_NAMESPACE
50 // -------------------------------------------------------- //
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
)
76 MessageIO::MessageIO() :
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.
85 const BMessage
* message
) :
87 m_message(const_cast<BMessage
*>(message
)) {
92 void MessageIO::setMessage(
95 if(m_ownMessage
&& 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
110 void MessageIO::AddTo(
111 XML::DocumentType
* docType
) {
113 docType
->addMapping(new Mapping
<MessageIO
>(s_element
));
116 // -------------------------------------------------------- //
118 // -------------------------------------------------------- //
120 void MessageIO::xmlExportBegin(
121 ExportContext
& context
) const {
124 context
.reportError("No message data to export.\n");
127 context
.beginElement(s_element
);
130 void MessageIO::xmlExportAttributes(
131 ExportContext
& context
) const {
134 context
.writeAttr("what", m_message
->what
);
136 context
.writeAttr("name", m_name
.String());
139 void MessageIO::xmlExportContent(
140 ExportContext
& context
) const {
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
;
153 #ifdef B_BEOS_VERSION_DANO
161 m_message
->GetInfo(B_ANY_TYPE
, n
, &name
, &type
, &count
) == B_OK
;
163 fields
.push_back(name
);
169 context
.beginContent();
172 for(int32 n
= 0; !done
; ++n
) {
177 uint32 fieldIndex
= 0;
178 fieldIndex
< fields
.size();
181 if(m_message
->GetInfo(
182 fields
[fieldIndex
].String(),
184 &count
) < B_OK
|| n
>= count
)
187 // found a field at the current index, so don't give up
194 fields
[fieldIndex
].String(),
199 errText
<< "Couldn't export field '" << fields
[fieldIndex
] <<
200 "' index " << n
<< ": " << strerror(err
) << "\n";
201 context
.reportError(errText
.String());
208 void MessageIO::xmlExportEnd(
209 ExportContext
& context
) const {
210 context
.endElement();
214 // -------------------------------------------------------- //
216 // -------------------------------------------------------- //
218 void MessageIO::xmlImportBegin(
219 ImportContext
& context
) {
221 // create the message
226 m_message
= new BMessage();
230 void MessageIO::xmlImportAttribute(
233 ImportContext
& context
) {
237 if(!strcmp(key
, "what"))
238 m_message
->what
= atol(value
);
239 else if(!strcmp(key
, "name"))
243 void MessageIO::xmlImportContent(
246 ImportContext
& context
) {}
248 void MessageIO::xmlImportChild(
250 ImportContext
& context
) {
254 if(strcmp(context
.element(), s_element
) != 0) {
255 context
.reportError("Unexpected child element.\n");
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(
272 ImportContext
& context
) {
278 if(strcmp(context
.parentElement(), s_element
) != 0) {
279 context
.reportError("Unexpected parent element.\n");
283 if(!_isValidMessageElement(context
.element())) {
284 context
.reportError("Invalid message field element.\n");
288 m_fieldData
.SetTo("");
291 void MessageIO::xmlImportChildAttribute(
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(
305 ImportContext
& context
) {
307 m_fieldData
.Append(data
, length
);
310 void MessageIO::xmlImportChildComplete(
312 ImportContext
& context
) {
316 status_t err
= _importField(
319 m_fieldName
.String(),
320 m_fieldData
.String());
322 context
.reportWarning("Invalid field data.\n");
326 // -------------------------------------------------------- //
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;
347 status_t
MessageIO::_importField(
353 // skip leading whitespace
354 while(*data
&& isspace(*data
)) ++data
;
356 if(!strcmp(element
, _boolEl
)) {
358 if(!strcmp(data
, "true") || !strcmp(data
, "1"))
360 else if(!strcmp(data
, "false") || !strcmp(data
, "0"))
364 return message
->AddBool(name
, v
);
367 if(!strcmp(element
, _int8El
)) {
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
)) {
401 const char* ystart
= strchr(data
, ',');
407 p
.x
= (float)atof(data
);
408 p
.y
= (float)atof(ystart
);
410 return message
->AddPoint(name
, p
);
413 if(!strcmp(element
, _rectEl
)) {
415 const char* topstart
= strchr(data
, ',');
422 const char* rightstart
= strchr(topstart
, ',');
429 const char* bottomstart
= strchr(rightstart
, ',');
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
);
447 status_t
MessageIO::_exportField(
448 ExportContext
& context
,
461 err
= message
->FindBool(name
, index
, &v
);
464 elementName
= _boolEl
;
465 content
= (v
? "true" : "false");
471 err
= message
->FindInt8(name
, index
, &v
);
474 elementName
= _int8El
;
481 err
= message
->FindInt16(name
, index
, &v
);
484 elementName
= _int16El
;
491 err
= message
->FindInt32(name
, index
, &v
);
494 elementName
= _int32El
;
501 err
= message
->FindInt64(name
, index
, &v
);
504 elementName
= _int64El
;
511 err
= message
->FindFloat(name
, index
, &v
);
514 elementName
= _floatEl
;
515 content
<< v
; // +++++ need adjustable precision!
519 case B_DOUBLE_TYPE
: {
521 err
= message
->FindDouble(name
, index
, &v
);
524 elementName
= _doubleEl
;
525 content
<< (float)v
; // +++++ need adjustable precision!
529 case B_STRING_TYPE
: {
531 err
= message
->FindString(name
, index
, &v
);
534 elementName
= _stringEl
;
541 err
= message
->FindPoint(name
, index
, &v
);
544 elementName
= _pointEl
;
545 content
<< v
.x
<< ", " << v
.y
;
551 err
= message
->FindRect(name
, index
, &v
);
554 elementName
= _rectEl
;
555 content
<< v
.left
<< ", " << v
.top
<< ", " <<
556 v
.right
<< ", " << v
.bottom
;
560 case B_MESSAGE_TYPE
: {
562 err
= message
->FindMessage(name
, index
, &m
);
566 // write child message
569 return context
.writeObject(&io
);
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();
586 // END -- MessageIO.cpp --