BTRFS: Implement BTree::Path and change _Find.
[haiku.git] / src / apps / cortex / Persistence / ExportContext.cpp
blob684ea0e73f48a7c4104b2aa7c69a0417736931a8
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 // ExportContext.cpp
33 // e.moon 30jun99
35 #include "ExportContext.h"
36 #include "IPersistent.h"
38 #include <DataIO.h>
40 #include <algorithm>
41 #include <cstdio>
43 __USE_CORTEX_NAMESPACE
46 // -------------------------------------------------------- //
47 // ctor/dtor
48 // -------------------------------------------------------- //
50 ExportContext::~ExportContext() {}
52 ExportContext::ExportContext() :
54 stream(0),
55 m_indentLevel(0),
56 m_indentIncrement(4),
57 m_attrColumn(30),
58 m_state(INIT) {}
60 ExportContext::ExportContext(
61 BDataIO* _stream) :
63 stream(_stream),
64 m_indentLevel(0),
65 m_indentIncrement(2),
66 m_attrColumn(30),
67 m_state(INIT) {
69 ASSERT(_stream);
74 // -------------------------------------------------------- //
75 // *** XML formatting helpers
76 // -------------------------------------------------------- //
78 // writes a start tag. should only be called from
79 // IPersistent::xmlExportBegin().
80 void ExportContext::beginElement(
81 const char* name) {
83 ASSERT(name);
85 if(!m_objectStack.size()) {
86 reportError("beginElement(): no object being written.\n");
87 return;
89 if(m_state != WRITE_BEGIN && m_state != WRITE_CONTENT) {
90 reportError("beginElement(): not allowed.\n");
91 return;
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();
99 // write tag
100 BString out;
101 out << "\n" << indentString() << '<' << name;
102 writeString(out);
103 indentMore();
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");
114 return;
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");
121 return;
124 indentLess();
126 BString out;
128 // write closing tag
129 if(!entry.hasContent)
130 out << "/>";
131 else
132 out << "\n" << indentString() << "</" << entry.name.String() << ">";
134 writeString(out);
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");
146 return;
148 ASSERT(m_elementStack.size());
149 element_entry& entry = m_elementStack.back();
151 if(m_state != WRITE_CONTENT) {
152 reportError("beginContent(): not allowed.\n");
153 return;
156 BString out = ">";
157 writeString(out);
159 entry.hasContent = true;
162 #define _WRITE_ATTR_BODY(VAL_SPEC) \
163 if(!m_objectStack.size()) {\
164 reportError("writeAttr(): no object being written.\n");\
165 return;\
167 ASSERT(m_elementStack.size());\
168 if(m_state != WRITE_ATTRIBUTES &&\
169 m_state != WRITE_CONTENT) {\
170 reportError("writeAttr(): not allowed (state mismatch).\n");\
171 return;\
174 m_elementStack.back().hasAttributes = true;\
176 BString out;\
177 out << "\n" << indentString() << key;\
178 _pad_with_spaces(out, key, *this, m_attrColumn) << " = '" << VAL_SPEC << '\'';\
180 writeString(out);
182 void ExportContext::writeAttr(
183 const char* key,
184 int8 value) {_WRITE_ATTR_BODY(value)}
186 void ExportContext::writeAttr(
187 const char* key,
188 uint8 value) {_WRITE_ATTR_BODY(uint32(value))}
190 void ExportContext::writeAttr(
191 const char* key,
192 int16 value) {_WRITE_ATTR_BODY(value)}
194 void ExportContext::writeAttr(
195 const char* key,
196 uint16 value) {_WRITE_ATTR_BODY(uint32(value))}
198 void ExportContext::writeAttr(
199 const char* key,
200 int32 value) {_WRITE_ATTR_BODY(value)}
202 void ExportContext::writeAttr(
203 const char* key,
204 uint32 value) {_WRITE_ATTR_BODY(value)}
206 void ExportContext::writeAttr(
207 const char* key,
208 int64 value) {_WRITE_ATTR_BODY(value)}
210 void ExportContext::writeAttr(
211 const char* key,
212 uint64 value) {_WRITE_ATTR_BODY(value)}
214 void ExportContext::writeAttr(
215 const char* key,
216 const char* value) {_WRITE_ATTR_BODY(value)}
218 void ExportContext::writeAttr(
219 const char* key,
220 const BString& value) {_WRITE_ATTR_BODY(value)}
222 void ExportContext::writeAttr(
223 const char* key,
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) {
232 // * SETUP
233 ASSERT(object);
234 if(m_state == ABORT)
235 return B_ERROR;
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;
243 // * START TAG
244 int elements = m_elementStack.size();
245 m_state = WRITE_BEGIN;
246 object->xmlExportBegin(*this);
248 if(m_state == ABORT)
249 return B_ERROR;
251 if(!entry.element)
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");
256 if(m_state == ABORT)
257 return B_ERROR;
259 // * ATTRIBUTES
260 m_state = WRITE_ATTRIBUTES;
261 object->xmlExportAttributes(*this);
263 if(m_state == ABORT)
264 return B_ERROR;
266 // * CONTENT
267 m_state = WRITE_CONTENT;
268 object->xmlExportContent(*this);
270 if(m_state == ABORT)
271 return B_ERROR;
273 // * END
274 m_state = WRITE_END;
275 object->xmlExportEnd(*this);
277 m_state = origState;
279 // pop object entry
280 m_objectStack.pop_back();
282 return (m_state == ABORT) ? B_ERROR : B_OK;
285 // writes an arbitrary string to the stream (calls reportError()
286 // on failure.)
288 status_t ExportContext::writeString(
289 const BString& string) {
291 return writeString(string.String(), string.Length());
294 status_t ExportContext::writeString(
295 const char* data,
296 ssize_t length) {
298 ssize_t written = stream->Write(data, length);
299 if(written < 0) {
300 BString err = "Write error: '";
301 err << strerror(written) << "'.\n";
302 reportError(err.String());
303 return written;
305 else if(written < length) {
306 BString err = "Write incomplete: '";
307 err << written << " of " << length << " bytes written.\n";
308 reportError(err.String());
309 return B_IO_ERROR;
311 return B_OK;
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:
343 BString& _s;
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(
354 const char* text) {
356 m_error << "FATAL ERROR: ";
357 m_error << text << "\n";
358 if(m_elementStack.size()) {
359 _dumpElementStack(m_error);
362 m_state = ABORT;
365 void ExportContext::_dumpElementStack(
366 BString& out) {
367 out << "Element stack:\n";
368 for_each(m_elementStack.begin(), m_elementStack.end(), dump_element(out));
371 // END -- ExportContext.cpp --