1/*
2 * Copyright 2006, Haiku. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Stephan Aßmus <superstippi@gmx.de>
7 */
8
9#include "MessageExporter.h"
10
11#include <ByteOrder.h>
12#include <DataIO.h>
13#include <Message.h>
14#include <TypeConstants.h>
15
16#include "Defines.h"
17#include "Icon.h"
18#include "PathContainer.h"
19#include "Shape.h"
20#include "Style.h"
21#include "StyleContainer.h"
22#include "Transformer.h"
23#include "VectorPath.h"
24
25// constructor
26MessageExporter::MessageExporter()
27{
28}
29
30// destructor
31MessageExporter::~MessageExporter()
32{
33}
34
35// Export
36status_t
37MessageExporter::Export(const Icon* icon, BPositionIO* stream)
38{
39	status_t ret = B_OK;
40	BMessage archive;
41
42	PathContainer* paths = icon->Paths();
43	StyleContainer* styles = icon->Styles();
44
45	// paths
46	if (ret == B_OK) {
47		BMessage allPaths;
48		int32 count = paths->CountPaths();
49		for (int32 i = 0; i < count; i++) {
50			VectorPath* path = paths->PathAtFast(i);
51			BMessage pathArchive;
52			ret = _Export(path, &pathArchive);
53			if (ret < B_OK)
54				break;
55			ret = allPaths.AddMessage("path", &pathArchive);
56			if (ret < B_OK)
57				break;
58		}
59
60		if (ret == B_OK)
61			ret = archive.AddMessage("paths", &allPaths);
62	}
63
64	// styles
65	if (ret == B_OK) {
66		BMessage allStyles;
67		int32 count = styles->CountStyles();
68		for (int32 i = 0; i < count; i++) {
69			Style* style = styles->StyleAtFast(i);
70			BMessage styleArchive;
71			ret = _Export(style, &styleArchive);
72			if (ret < B_OK)
73				break;
74			ret = allStyles.AddMessage("style", &styleArchive);
75			if (ret < B_OK)
76				break;
77		}
78
79		if (ret == B_OK)
80			ret = archive.AddMessage("styles", &allStyles);
81	}
82
83	// shapes
84	if (ret == B_OK) {
85		BMessage allShapes;
86		ShapeContainer* shapes = icon->Shapes();
87		int32 count = shapes->CountShapes();
88		for (int32 i = 0; i < count; i++) {
89			Shape* shape = shapes->ShapeAtFast(i);
90			BMessage shapeArchive;
91			ret = _Export(shape, paths, styles, &shapeArchive);
92			if (ret < B_OK)
93				break;
94			ret = allShapes.AddMessage("shape", &shapeArchive);
95			if (ret < B_OK)
96				break;
97		}
98
99		if (ret == B_OK)
100			ret = archive.AddMessage("shapes", &allShapes);
101	}
102
103	// prepend the magic number to the file which
104	// later tells us that this file is one of us
105	if (ret == B_OK) {
106		ssize_t size = sizeof(uint32);
107		uint32 magic = B_HOST_TO_BENDIAN_INT32(kNativeIconMagicNumber);
108		ssize_t written = stream->Write(&magic, size);
109		if (written != size) {
110			if (written < 0)
111				ret = (status_t)written;
112			else
113				ret = B_IO_ERROR;
114		}
115	}
116
117	if (ret == B_OK)
118		ret = archive.Flatten(stream);
119
120	return ret;
121}
122
123// MIMEType
124const char*
125MessageExporter::MIMEType()
126{
127	return kNativeIconMimeType;
128}
129
130// #pragma mark -
131
132// _Export
133status_t
134MessageExporter::_Export(const VectorPath* path, BMessage* into) const
135{
136	return path->Archive(into, true);
137}
138
139// _Export
140status_t
141MessageExporter::_Export(const Style* style, BMessage* into) const
142{
143	return style->Archive(into, true);
144}
145
146// _Export
147status_t
148MessageExporter::_Export(const Shape* shape,
149						 const PathContainer* globalPaths,
150						 const StyleContainer* globalStyles,
151						 BMessage* into) const
152{
153	// NOTE: when the same path is used in two different
154	// documents, and these are to be merged, each path
155	// having a "globally unique" id would make it possible
156	// to reference the same path across documents...
157	// For now, we simply use the index of the path in the
158	// globalPaths container.
159
160	// index of used style
161	Style* style = shape->Style();
162	status_t ret = into->AddInt32("style ref", globalStyles->IndexOf(style));
163
164	// indices of used paths
165	if (ret == B_OK) {
166		int32 count = shape->Paths()->CountPaths();
167		for (int32 i = 0; i < count; i++) {
168			VectorPath* path = shape->Paths()->PathAtFast(i);
169			ret = into->AddInt32("path ref", globalPaths->IndexOf(path));
170			if (ret < B_OK)
171				break;
172		}
173	}
174
175	// Shape properties
176	if (ret == B_OK)
177		ret = shape->Archive(into);
178
179	return ret;
180}
181
182