xref: /haiku/src/apps/icon-o-matic/import_export/message/MessageExporter.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
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
28 MessageExporter::MessageExporter()
29 {
30 }
31 
32 // destructor
33 MessageExporter::~MessageExporter()
34 {
35 }
36 
37 // Export
38 status_t
39 MessageExporter::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
126 const char*
127 MessageExporter::MIMEType()
128 {
129 	return kNativeIconMimeType;
130 }
131 
132 // #pragma mark -
133 
134 // _Export
135 status_t
136 MessageExporter::_Export(const VectorPath* path, BMessage* into) const
137 {
138 	return path->Archive(into, true);
139 }
140 
141 // _Export
142 status_t
143 MessageExporter::_Export(const Style* style, BMessage* into) const
144 {
145 	return style->Archive(into, true);
146 }
147 
148 // _Export
149 status_t
150 MessageExporter::_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