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.
35 #include "ExportContext.h"
36 #include "IPersistent.h"
43 __USE_CORTEX_NAMESPACE
46 // -------------------------------------------------------- //
48 // -------------------------------------------------------- //
50 ExportContext::~ExportContext() {}
52 ExportContext::ExportContext() :
60 ExportContext::ExportContext(
74 // -------------------------------------------------------- //
75 // *** XML formatting helpers
76 // -------------------------------------------------------- //
78 // writes a start tag. should only be called from
79 // IPersistent::xmlExportBegin().
80 void ExportContext::beginElement(
85 if(!m_objectStack
.size()) {
86 reportError("beginElement(): no object being written.\n");
89 if(m_state
!= WRITE_BEGIN
&& m_state
!= WRITE_CONTENT
) {
90 reportError("beginElement(): not allowed.\n");
94 // push tag onto element stack, and link to entry for the current object
95 m_elementStack
.push_back(element_entry());
96 m_elementStack
.back().name
= name
;
97 m_objectStack
.back().element
= m_elementStack
.back().name
.String();
101 out
<< "\n" << indentString() << '<' << name
;
106 // writes an end tag corresponding to the current element.
107 // should only be called from IPersistent::xmlExportEnd() or
108 // xmlExportContent().
110 void ExportContext::endElement() {
112 if(!m_objectStack
.size()) {
113 reportError("endElement(): no object being written.\n");
116 ASSERT(m_elementStack
.size());
117 element_entry
& entry
= m_elementStack
.back();
119 if(m_state
!= WRITE_END
&& m_state
!= WRITE_CONTENT
) {
120 reportError("endElement(): not allowed.\n");
129 if(!entry
.hasContent
)
132 out
<< "\n" << indentString() << "</" << entry
.name
.String() << ">";
136 // pop element off stack
137 m_elementStack
.pop_back();
140 // indicates that content follows (writes the end of the
141 // current element's start tag.)
142 void ExportContext::beginContent() {
144 if(!m_objectStack
.size()) {
145 reportError("beginContent(): no object being written.\n");
148 ASSERT(m_elementStack
.size());
149 element_entry
& entry
= m_elementStack
.back();
151 if(m_state
!= WRITE_CONTENT
) {
152 reportError("beginContent(): not allowed.\n");
159 entry
.hasContent
= true;
162 #define _WRITE_ATTR_BODY(VAL_SPEC) \
163 if(!m_objectStack.size()) {\
164 reportError("writeAttr(): no object being written.\n");\
167 ASSERT(m_elementStack.size());\
168 if(m_state != WRITE_ATTRIBUTES &&\
169 m_state != WRITE_CONTENT) {\
170 reportError("writeAttr(): not allowed (state mismatch).\n");\
174 m_elementStack.back().hasAttributes = true;\
177 out << "\n" << indentString() << key;\
178 _pad_with_spaces(out, key, *this, m_attrColumn) << " = '" << VAL_SPEC << '\'';\
182 void ExportContext::writeAttr(
184 int8 value
) {_WRITE_ATTR_BODY(value
)}
186 void ExportContext::writeAttr(
188 uint8 value
) {_WRITE_ATTR_BODY(uint32(value
))}
190 void ExportContext::writeAttr(
192 int16 value
) {_WRITE_ATTR_BODY(value
)}
194 void ExportContext::writeAttr(
196 uint16 value
) {_WRITE_ATTR_BODY(uint32(value
))}
198 void ExportContext::writeAttr(
200 int32 value
) {_WRITE_ATTR_BODY(value
)}
202 void ExportContext::writeAttr(
204 uint32 value
) {_WRITE_ATTR_BODY(value
)}
206 void ExportContext::writeAttr(
208 int64 value
) {_WRITE_ATTR_BODY(value
)}
210 void ExportContext::writeAttr(
212 uint64 value
) {_WRITE_ATTR_BODY(value
)}
214 void ExportContext::writeAttr(
216 const char* value
) {_WRITE_ATTR_BODY(value
)}
218 void ExportContext::writeAttr(
220 const BString
& value
) {_WRITE_ATTR_BODY(value
)}
222 void ExportContext::writeAttr(
224 float value
) {_WRITE_ATTR_BODY(value
)}
226 // writes a child object.
227 // should only be called from IPersistent::xmlExportContent().
228 // returns B_OK on success, or B_ERROR if an error occurred.
229 status_t
ExportContext::writeObject(
230 IPersistent
* object
) {
236 state_t origState
= m_state
;
238 // write entry to object stack
239 m_objectStack
.push_back(object_entry());
240 object_entry
& entry
= m_objectStack
.back();
241 entry
.object
= object
;
244 int elements
= m_elementStack
.size();
245 m_state
= WRITE_BEGIN
;
246 object
->xmlExportBegin(*this);
252 reportError("writeObject(): no start tag for object.\n");
253 else if(m_elementStack
.size() - elements
> 1)
254 reportError("writeObject(): object wrote more than one start tag.\n");
260 m_state
= WRITE_ATTRIBUTES
;
261 object
->xmlExportAttributes(*this);
267 m_state
= WRITE_CONTENT
;
268 object
->xmlExportContent(*this);
275 object
->xmlExportEnd(*this);
280 m_objectStack
.pop_back();
282 return (m_state
== ABORT
) ? B_ERROR
: B_OK
;
285 // writes an arbitrary string to the stream (calls reportError()
288 status_t
ExportContext::writeString(
289 const BString
& string
) {
291 return writeString(string
.String(), string
.Length());
294 status_t
ExportContext::writeString(
298 ssize_t written
= stream
->Write(data
, length
);
300 BString err
= "Write error: '";
301 err
<< strerror(written
) << "'.\n";
302 reportError(err
.String());
305 else if(written
< length
) {
306 BString err
= "Write incomplete: '";
307 err
<< written
<< " of " << length
<< " bytes written.\n";
308 reportError(err
.String());
315 // -------------------------------------------------------- //
316 // *** indentation helpers
317 // -------------------------------------------------------- //
319 const char* ExportContext::indentString() const {
320 return m_indentString
.String();
323 uint16
ExportContext::indentLevel() const {
324 return m_indentLevel
;
327 void ExportContext::indentLess() {
328 m_indentLevel
= (m_indentLevel
> m_indentIncrement
) ?
329 m_indentLevel
- m_indentIncrement
: 0;
330 m_indentString
.SetTo(' ', m_indentLevel
);
333 void ExportContext::indentMore() {
334 m_indentLevel
+= m_indentIncrement
;
335 m_indentString
.SetTo(' ', m_indentLevel
);
338 // -------------------------------------------------------- //
339 // *** error-reporting operations
340 // -------------------------------------------------------- //
342 class dump_element
{ public:
345 dump_element(BString
& s
) : _s(s
) {}
346 void operator()(const ExportContext::element_entry
& entry
) {
347 _s
<< " " << entry
.name
<< '\n';
351 // register a fatal error; halts the write process
352 // as soon as possible.
353 void ExportContext::reportError(
356 m_error
<< "FATAL ERROR: ";
357 m_error
<< text
<< "\n";
358 if(m_elementStack
.size()) {
359 _dumpElementStack(m_error
);
365 void ExportContext::_dumpElementStack(
367 out
<< "Element stack:\n";
368 for_each(m_elementStack
.begin(), m_elementStack
.end(), dump_element(out
));
371 // END -- ExportContext.cpp --