xref: /haiku/src/apps/icon-o-matic/import_export/message/MessageExporter.cpp (revision 6427935280aaac0a1a4557bae55184708819560d)
10e1ba39fSStephan Aßmus /*
2098eaec6SZardshard  * Copyright 2006, 2023, Haiku. All rights reserved.
30e1ba39fSStephan Aßmus  * Distributed under the terms of the MIT License.
40e1ba39fSStephan Aßmus  *
50e1ba39fSStephan Aßmus  * Authors:
60e1ba39fSStephan Aßmus  *		Stephan Aßmus <superstippi@gmx.de>
7098eaec6SZardshard  *		Zardshard
80e1ba39fSStephan Aßmus  */
90e1ba39fSStephan Aßmus 
100e1ba39fSStephan Aßmus #include "MessageExporter.h"
110e1ba39fSStephan Aßmus 
121518e410SStephan Aßmus #include <ByteOrder.h>
130e1ba39fSStephan Aßmus #include <DataIO.h>
140e1ba39fSStephan Aßmus #include <Message.h>
150e1ba39fSStephan Aßmus #include <TypeConstants.h>
160e1ba39fSStephan Aßmus 
17*64279352SZardshard #include "Container.h"
181518e410SStephan Aßmus #include "Defines.h"
190e1ba39fSStephan Aßmus #include "Icon.h"
20098eaec6SZardshard #include "PathSourceShape.h"
21098eaec6SZardshard #include "ReferenceImage.h"
220e1ba39fSStephan Aßmus #include "Shape.h"
230e1ba39fSStephan Aßmus #include "Style.h"
240e1ba39fSStephan Aßmus #include "Transformer.h"
250e1ba39fSStephan Aßmus #include "VectorPath.h"
260e1ba39fSStephan Aßmus 
270e1ba39fSStephan Aßmus // constructor
MessageExporter()280e1ba39fSStephan Aßmus MessageExporter::MessageExporter()
290e1ba39fSStephan Aßmus {
300e1ba39fSStephan Aßmus }
310e1ba39fSStephan Aßmus 
320e1ba39fSStephan Aßmus // destructor
~MessageExporter()330e1ba39fSStephan Aßmus MessageExporter::~MessageExporter()
340e1ba39fSStephan Aßmus {
350e1ba39fSStephan Aßmus }
360e1ba39fSStephan Aßmus 
370e1ba39fSStephan Aßmus // Export
380e1ba39fSStephan Aßmus status_t
Export(const Icon * icon,BPositionIO * stream)390e1ba39fSStephan Aßmus MessageExporter::Export(const Icon* icon, BPositionIO* stream)
400e1ba39fSStephan Aßmus {
410e1ba39fSStephan Aßmus 	status_t ret = B_OK;
420e1ba39fSStephan Aßmus 	BMessage archive;
430e1ba39fSStephan Aßmus 
44*64279352SZardshard 	const Container<VectorPath>* paths = icon->Paths();
45*64279352SZardshard 	const Container<Style>* styles = icon->Styles();
460e1ba39fSStephan Aßmus 
470e1ba39fSStephan Aßmus 	// paths
480e1ba39fSStephan Aßmus 	if (ret == B_OK) {
490e1ba39fSStephan Aßmus 		BMessage allPaths;
50*64279352SZardshard 		int32 count = paths->CountItems();
510e1ba39fSStephan Aßmus 		for (int32 i = 0; i < count; i++) {
52*64279352SZardshard 			VectorPath* path = paths->ItemAtFast(i);
530e1ba39fSStephan Aßmus 			BMessage pathArchive;
540e1ba39fSStephan Aßmus 			ret = _Export(path, &pathArchive);
550e1ba39fSStephan Aßmus 			if (ret < B_OK)
560e1ba39fSStephan Aßmus 				break;
570e1ba39fSStephan Aßmus 			ret = allPaths.AddMessage("path", &pathArchive);
580e1ba39fSStephan Aßmus 			if (ret < B_OK)
590e1ba39fSStephan Aßmus 				break;
600e1ba39fSStephan Aßmus 		}
610e1ba39fSStephan Aßmus 
620e1ba39fSStephan Aßmus 		if (ret == B_OK)
630e1ba39fSStephan Aßmus 			ret = archive.AddMessage("paths", &allPaths);
640e1ba39fSStephan Aßmus 	}
650e1ba39fSStephan Aßmus 
660e1ba39fSStephan Aßmus 	// styles
670e1ba39fSStephan Aßmus 	if (ret == B_OK) {
680e1ba39fSStephan Aßmus 		BMessage allStyles;
69*64279352SZardshard 		int32 count = styles->CountItems();
700e1ba39fSStephan Aßmus 		for (int32 i = 0; i < count; i++) {
71*64279352SZardshard 			Style* style = styles->ItemAtFast(i);
720e1ba39fSStephan Aßmus 			BMessage styleArchive;
730e1ba39fSStephan Aßmus 			ret = _Export(style, &styleArchive);
740e1ba39fSStephan Aßmus 			if (ret < B_OK)
750e1ba39fSStephan Aßmus 				break;
760e1ba39fSStephan Aßmus 			ret = allStyles.AddMessage("style", &styleArchive);
770e1ba39fSStephan Aßmus 			if (ret < B_OK)
780e1ba39fSStephan Aßmus 				break;
790e1ba39fSStephan Aßmus 		}
800e1ba39fSStephan Aßmus 
810e1ba39fSStephan Aßmus 		if (ret == B_OK)
820e1ba39fSStephan Aßmus 			ret = archive.AddMessage("styles", &allStyles);
830e1ba39fSStephan Aßmus 	}
840e1ba39fSStephan Aßmus 
850e1ba39fSStephan Aßmus 	// shapes
860e1ba39fSStephan Aßmus 	if (ret == B_OK) {
870e1ba39fSStephan Aßmus 		BMessage allShapes;
88*64279352SZardshard 		const Container<Shape>* shapes = icon->Shapes();
89*64279352SZardshard 		int32 count = shapes->CountItems();
900e1ba39fSStephan Aßmus 		for (int32 i = 0; i < count; i++) {
91*64279352SZardshard 			Shape* shape = shapes->ItemAtFast(i);
920e1ba39fSStephan Aßmus 			BMessage shapeArchive;
930e1ba39fSStephan Aßmus 			ret = _Export(shape, paths, styles, &shapeArchive);
940e1ba39fSStephan Aßmus 			if (ret < B_OK)
950e1ba39fSStephan Aßmus 				break;
960e1ba39fSStephan Aßmus 			ret = allShapes.AddMessage("shape", &shapeArchive);
970e1ba39fSStephan Aßmus 			if (ret < B_OK)
980e1ba39fSStephan Aßmus 				break;
990e1ba39fSStephan Aßmus 		}
1000e1ba39fSStephan Aßmus 
1010e1ba39fSStephan Aßmus 		if (ret == B_OK)
1020e1ba39fSStephan Aßmus 			ret = archive.AddMessage("shapes", &allShapes);
1030e1ba39fSStephan Aßmus 	}
1040e1ba39fSStephan Aßmus 
1051518e410SStephan Aßmus 	// prepend the magic number to the file which
1061518e410SStephan Aßmus 	// later tells us that this file is one of us
1071518e410SStephan Aßmus 	if (ret == B_OK) {
1081518e410SStephan Aßmus 		ssize_t size = sizeof(uint32);
109609bc8caSStephan Aßmus 		uint32 magic = B_HOST_TO_BENDIAN_INT32(kNativeIconMagicNumber);
1101518e410SStephan Aßmus 		ssize_t written = stream->Write(&magic, size);
1111518e410SStephan Aßmus 		if (written != size) {
1121518e410SStephan Aßmus 			if (written < 0)
1131518e410SStephan Aßmus 				ret = (status_t)written;
1141518e410SStephan Aßmus 			else
1151518e410SStephan Aßmus 				ret = B_IO_ERROR;
1161518e410SStephan Aßmus 		}
1171518e410SStephan Aßmus 	}
1181518e410SStephan Aßmus 
1190e1ba39fSStephan Aßmus 	if (ret == B_OK)
1200e1ba39fSStephan Aßmus 		ret = archive.Flatten(stream);
1210e1ba39fSStephan Aßmus 
1220e1ba39fSStephan Aßmus 	return ret;
1230e1ba39fSStephan Aßmus }
1240e1ba39fSStephan Aßmus 
1250e1ba39fSStephan Aßmus // MIMEType
1260e1ba39fSStephan Aßmus const char*
MIMEType()1270e1ba39fSStephan Aßmus MessageExporter::MIMEType()
1280e1ba39fSStephan Aßmus {
1291518e410SStephan Aßmus 	return kNativeIconMimeType;
1300e1ba39fSStephan Aßmus }
1310e1ba39fSStephan Aßmus 
1320e1ba39fSStephan Aßmus // #pragma mark -
1330e1ba39fSStephan Aßmus 
1340e1ba39fSStephan Aßmus // _Export
1350e1ba39fSStephan Aßmus status_t
_Export(const VectorPath * path,BMessage * into) const1360e1ba39fSStephan Aßmus MessageExporter::_Export(const VectorPath* path, BMessage* into) const
1370e1ba39fSStephan Aßmus {
1380e1ba39fSStephan Aßmus 	return path->Archive(into, true);
1390e1ba39fSStephan Aßmus }
1400e1ba39fSStephan Aßmus 
1410e1ba39fSStephan Aßmus // _Export
1420e1ba39fSStephan Aßmus status_t
_Export(const Style * style,BMessage * into) const1430e1ba39fSStephan Aßmus MessageExporter::_Export(const Style* style, BMessage* into) const
1440e1ba39fSStephan Aßmus {
1450e1ba39fSStephan Aßmus 	return style->Archive(into, true);
1460e1ba39fSStephan Aßmus }
1470e1ba39fSStephan Aßmus 
1480e1ba39fSStephan Aßmus // _Export
1490e1ba39fSStephan Aßmus status_t
_Export(const Shape * shape,const Container<VectorPath> * globalPaths,const Container<Style> * globalStyles,BMessage * into) const1500e1ba39fSStephan Aßmus MessageExporter::_Export(const Shape* shape,
151*64279352SZardshard 						 const Container<VectorPath>* globalPaths,
152*64279352SZardshard 						 const Container<Style>* globalStyles,
1530e1ba39fSStephan Aßmus 						 BMessage* into) const
1540e1ba39fSStephan Aßmus {
155098eaec6SZardshard 	status_t ret = B_OK;
156098eaec6SZardshard 
157098eaec6SZardshard 	const PathSourceShape* pathSourceShape = dynamic_cast<const PathSourceShape*>(shape);
158098eaec6SZardshard 	if (pathSourceShape != NULL) {
159098eaec6SZardshard 		ret = into->AddInt32("type", PathSourceShape::archive_code);
160098eaec6SZardshard 
1610e1ba39fSStephan Aßmus 		// NOTE: when the same path is used in two different
1620e1ba39fSStephan Aßmus 		// documents, and these are to be merged, each path
1630e1ba39fSStephan Aßmus 		// having a "globally unique" id would make it possible
1640e1ba39fSStephan Aßmus 		// to reference the same path across documents...
1650e1ba39fSStephan Aßmus 		// For now, we simply use the index of the path in the
1660e1ba39fSStephan Aßmus 		// globalPaths container.
1670e1ba39fSStephan Aßmus 
1680e1ba39fSStephan Aßmus 		// index of used style
169098eaec6SZardshard 		if (ret == B_OK) {
170098eaec6SZardshard 			Style* style = pathSourceShape->Style();
171098eaec6SZardshard 			ret = into->AddInt32("style ref", globalStyles->IndexOf(style));
172098eaec6SZardshard 		}
1730e1ba39fSStephan Aßmus 
1740e1ba39fSStephan Aßmus 		// indices of used paths
1750e1ba39fSStephan Aßmus 		if (ret == B_OK) {
176*64279352SZardshard 			int32 count = pathSourceShape->Paths()->CountItems();
1770e1ba39fSStephan Aßmus 			for (int32 i = 0; i < count; i++) {
178*64279352SZardshard 				VectorPath* path = pathSourceShape->Paths()->ItemAtFast(i);
1790e1ba39fSStephan Aßmus 				ret = into->AddInt32("path ref", globalPaths->IndexOf(path));
1800e1ba39fSStephan Aßmus 				if (ret < B_OK)
1810e1ba39fSStephan Aßmus 					break;
1820e1ba39fSStephan Aßmus 			}
1830e1ba39fSStephan Aßmus 		}
184098eaec6SZardshard 	}
185098eaec6SZardshard 
186098eaec6SZardshard 	const ReferenceImage* referenceImage = dynamic_cast<const ReferenceImage*>(shape);
187098eaec6SZardshard 	if (referenceImage != NULL) {
188098eaec6SZardshard 		ret = into->AddInt32("type", ReferenceImage::archive_code);
189098eaec6SZardshard 	}
1900e1ba39fSStephan Aßmus 
1910e1ba39fSStephan Aßmus 	// Shape properties
1920e1ba39fSStephan Aßmus 	if (ret == B_OK)
1930e1ba39fSStephan Aßmus 		ret = shape->Archive(into);
1940e1ba39fSStephan Aßmus 
1950e1ba39fSStephan Aßmus 	return ret;
1960e1ba39fSStephan Aßmus }
1970e1ba39fSStephan Aßmus 
198