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