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