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
36using std::nothrow;
37
38
39MessageImporter::MessageImporter()
40#ifdef ICON_O_MATIC
41	: Importer()
42#endif
43{
44}
45
46
47MessageImporter::~MessageImporter()
48{
49}
50
51
52status_t
53MessageImporter::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
126status_t
127MessageImporter::_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
151status_t
152MessageImporter::_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
176status_t
177MessageImporter::_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