xref: /haiku/src/libs/icon/message/MessageImporter.cpp (revision 445d4fd926c569e7b9ae28017da86280aaecbae2)
1 /*
2  * Copyright 2006-2010, 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 
11 #include "MessageImporter.h"
12 
13 #include <new>
14 #include <stdio.h>
15 
16 #include <Archivable.h>
17 #ifdef ICON_O_MATIC
18 #include <Bitmap.h>
19 #endif
20 #include <ByteOrder.h>
21 #include <DataIO.h>
22 #include <Message.h>
23 
24 #include "Defines.h"
25 #include "Icon.h"
26 #include "PathContainer.h"
27 #include "PathSourceShape.h"
28 #ifdef ICON_O_MATIC
29 #include "ReferenceImage.h"
30 #endif
31 #include "Shape.h"
32 #include "Style.h"
33 #include "StyleContainer.h"
34 #include "VectorPath.h"
35 
36 
37 using std::nothrow;
38 
39 
40 MessageImporter::MessageImporter()
41 #ifdef ICON_O_MATIC
42 	: Importer()
43 #endif
44 {
45 }
46 
47 
48 MessageImporter::~MessageImporter()
49 {
50 }
51 
52 
53 status_t
54 MessageImporter::Import(Icon* icon, BPositionIO* stream)
55 {
56 #ifdef ICON_O_MATIC
57 	status_t ret = Init(icon);
58 	if (ret < B_OK) {
59 		printf("MessageImporter::Import() - "
60 			   "Init() error: %s\n", strerror(ret));
61 		return ret;
62 	}
63 #else
64 	status_t ret;
65 #endif
66 
67 	uint32 magic = 0;
68 	ssize_t size = sizeof(magic);
69 	off_t position = stream->Position();
70 	ssize_t read = stream->Read(&magic, size);
71 	if (read != size) {
72 		if (read < 0)
73 			ret = (status_t)read;
74 		else
75 			ret = B_IO_ERROR;
76 		return ret;
77 	}
78 
79 	if (B_BENDIAN_TO_HOST_INT32(magic) != kNativeIconMagicNumber) {
80 		// this might be an old native icon file, where
81 		// we didn't prepend the magic number yet, seek back
82 		if (stream->Seek(position, SEEK_SET) != position) {
83 			printf("MessageImporter::Import() - "
84 				   "failed to seek back to beginning of stream\n");
85 			return B_IO_ERROR;
86 		}
87 	}
88 
89 	BMessage archive;
90 	ret = archive.Unflatten(stream);
91 	if (ret != B_OK)
92 		return ret;
93 
94 	// paths
95 	PathContainer* paths = icon->Paths();
96 	ret = _ImportPaths(&archive, paths);
97 	if (ret < B_OK) {
98 		printf("MessageImporter::Import() - "
99 			   "error importing paths: %s\n", strerror(ret));
100 		return ret;
101 	}
102 
103 	// styles
104 	StyleContainer* styles = icon->Styles();
105 	ret = _ImportStyles(&archive, styles);
106 	if (ret < B_OK) {
107 		printf("MessageImporter::Import() - "
108 			   "error importing styles: %s\n", strerror(ret));
109 		return ret;
110 	}
111 
112 	// shapes
113 	ret = _ImportShapes(&archive, paths, styles, icon->Shapes());
114 	if (ret < B_OK) {
115 		printf("MessageImporter::Import() - "
116 			   "error importing shapes: %s\n", strerror(ret));
117 		return ret;
118 	}
119 
120 	return B_OK;
121 }
122 
123 
124 // #pragma mark -
125 
126 
127 status_t
128 MessageImporter::_ImportPaths(const BMessage* archive,
129 	PathContainer* paths) const
130 {
131 	BMessage allPaths;
132 	status_t ret = archive->FindMessage("paths", &allPaths);
133 	if (ret < B_OK)
134 		return ret;
135 
136 	BMessage pathArchive;
137 	for (int32 i = 0;
138 		 allPaths.FindMessage("path", i, &pathArchive) == B_OK; i++) {
139 		VectorPath* path = new (nothrow) VectorPath(&pathArchive);
140 		if (!path || !paths->AddPath(path)) {
141 			delete path;
142 			ret = B_NO_MEMORY;
143 		}
144 		if (ret < B_OK)
145 			break;
146 	}
147 
148 	return ret;
149 }
150 
151 
152 status_t
153 MessageImporter::_ImportStyles(const BMessage* archive,
154 	StyleContainer* styles) const
155 {
156 	BMessage allStyles;
157 	status_t ret = archive->FindMessage("styles", &allStyles);
158 	if (ret < B_OK)
159 		return ret;
160 
161 	BMessage styleArchive;
162 	for (int32 i = 0;
163 		 allStyles.FindMessage("style", i, &styleArchive) == B_OK; i++) {
164 		Style* style = new (nothrow) Style(&styleArchive);
165 		if (!style || !styles->AddStyle(style)) {
166 			delete style;
167 			ret = B_NO_MEMORY;
168 		}
169 		if (ret < B_OK)
170 			break;
171 	}
172 
173 	return ret;
174 }
175 
176 
177 status_t
178 MessageImporter::_ImportShapes(const BMessage* archive, PathContainer* paths,
179 	StyleContainer* styles, ShapeContainer* shapes) const
180 {
181 	BMessage allShapes;
182 	status_t ret = archive->FindMessage("shapes", &allShapes);
183 	if (ret < B_OK)
184 		return ret;
185 
186 	BMessage shapeArchive;
187 	for (int32 i = 0;
188 		 allShapes.FindMessage("shape", i, &shapeArchive) == B_OK; i++) {
189 		int32 type;
190 		status_t typeFound = shapeArchive.FindInt32("type", &type);
191 		if (typeFound != B_OK || type == PathSourceShape::archive_code) {
192 				// Type not being found shows an older format that did not support
193 				// reference images
194 
195 			// find the right style
196 			int32 styleIndex;
197 			if (shapeArchive.FindInt32("style ref", &styleIndex) < B_OK) {
198 				printf("MessageImporter::_ImportShapes() - "
199 					   "Shape %" B_PRId32 " doesn't reference a Style!", i);
200 				continue;
201 			}
202 	#ifdef ICON_O_MATIC
203 			Style* style = styles->StyleAt(StyleIndexFor(styleIndex));
204 	#else
205 			Style* style = styles->StyleAt(styleIndex);
206 	#endif
207 			if (style == NULL) {
208 				printf("MessageImporter::_ImportShapes() - "
209 					   "Shape %" B_PRId32 " wants Style %" B_PRId32 ", which does not exist\n",
210 					i, styleIndex);
211 				continue;
212 			}
213 
214 			// create shape
215 			PathSourceShape* shape = new (nothrow) PathSourceShape(style);
216 			if (shape == NULL || shape->InitCheck() < B_OK || !shapes->AddShape(shape)) {
217 				delete shape;
218 				ret = B_NO_MEMORY;
219 			}
220 			if (ret < B_OK)
221 				break;
222 
223 			// find the referenced paths
224 			int32 pathIndex;
225 			for (int32 j = 0;
226 				 shapeArchive.FindInt32("path ref", j, &pathIndex) == B_OK;
227 				 j++) {
228 	#ifdef ICON_O_MATIC
229 				VectorPath* path = paths->PathAt(PathIndexFor(pathIndex));
230 	#else
231 				VectorPath* path = paths->PathAt(pathIndex);
232 	#endif
233 				if (path == NULL) {
234 					printf("MessageImporter::_ImportShapes() - "
235 						   "Shape %" B_PRId32 " referenced path %" B_PRId32 ", "
236 						   "which does not exist\n", i, pathIndex);
237 					continue;
238 				}
239 				shape->Paths()->AddPath(path);
240 			}
241 
242 			// Shape properties
243 			if (ret == B_OK)
244 				shape->Unarchive(&shapeArchive);
245 		}
246 	#ifdef ICON_O_MATIC
247 		else if (type == ReferenceImage::archive_code) {
248 			ReferenceImage* shape = new (nothrow) ReferenceImage(&shapeArchive);
249 			if (shape == NULL || shape->InitCheck() < B_OK || !shapes->AddShape(shape)) {
250 				delete shape;
251 				ret = B_NO_MEMORY;
252 			}
253 		}
254 	#endif // ICON_O_MATIC
255 	}
256 
257 	return ret;
258 }
259