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