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