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