1 /* 2 * Copyright 2006, 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 #include "MessageExporter.h" 11 12 #include <ByteOrder.h> 13 #include <DataIO.h> 14 #include <Message.h> 15 #include <TypeConstants.h> 16 17 #include "Defines.h" 18 #include "Icon.h" 19 #include "PathContainer.h" 20 #include "PathSourceShape.h" 21 #include "ReferenceImage.h" 22 #include "Shape.h" 23 #include "Style.h" 24 #include "StyleContainer.h" 25 #include "Transformer.h" 26 #include "VectorPath.h" 27 28 // constructor 29 MessageExporter::MessageExporter() 30 { 31 } 32 33 // destructor 34 MessageExporter::~MessageExporter() 35 { 36 } 37 38 // Export 39 status_t 40 MessageExporter::Export(const Icon* icon, BPositionIO* stream) 41 { 42 status_t ret = B_OK; 43 BMessage archive; 44 45 PathContainer* paths = icon->Paths(); 46 StyleContainer* styles = icon->Styles(); 47 48 // paths 49 if (ret == B_OK) { 50 BMessage allPaths; 51 int32 count = paths->CountPaths(); 52 for (int32 i = 0; i < count; i++) { 53 VectorPath* path = paths->PathAtFast(i); 54 BMessage pathArchive; 55 ret = _Export(path, &pathArchive); 56 if (ret < B_OK) 57 break; 58 ret = allPaths.AddMessage("path", &pathArchive); 59 if (ret < B_OK) 60 break; 61 } 62 63 if (ret == B_OK) 64 ret = archive.AddMessage("paths", &allPaths); 65 } 66 67 // styles 68 if (ret == B_OK) { 69 BMessage allStyles; 70 int32 count = styles->CountStyles(); 71 for (int32 i = 0; i < count; i++) { 72 Style* style = styles->StyleAtFast(i); 73 BMessage styleArchive; 74 ret = _Export(style, &styleArchive); 75 if (ret < B_OK) 76 break; 77 ret = allStyles.AddMessage("style", &styleArchive); 78 if (ret < B_OK) 79 break; 80 } 81 82 if (ret == B_OK) 83 ret = archive.AddMessage("styles", &allStyles); 84 } 85 86 // shapes 87 if (ret == B_OK) { 88 BMessage allShapes; 89 ShapeContainer* shapes = icon->Shapes(); 90 int32 count = shapes->CountShapes(); 91 for (int32 i = 0; i < count; i++) { 92 Shape* shape = shapes->ShapeAtFast(i); 93 BMessage shapeArchive; 94 ret = _Export(shape, paths, styles, &shapeArchive); 95 if (ret < B_OK) 96 break; 97 ret = allShapes.AddMessage("shape", &shapeArchive); 98 if (ret < B_OK) 99 break; 100 } 101 102 if (ret == B_OK) 103 ret = archive.AddMessage("shapes", &allShapes); 104 } 105 106 // prepend the magic number to the file which 107 // later tells us that this file is one of us 108 if (ret == B_OK) { 109 ssize_t size = sizeof(uint32); 110 uint32 magic = B_HOST_TO_BENDIAN_INT32(kNativeIconMagicNumber); 111 ssize_t written = stream->Write(&magic, size); 112 if (written != size) { 113 if (written < 0) 114 ret = (status_t)written; 115 else 116 ret = B_IO_ERROR; 117 } 118 } 119 120 if (ret == B_OK) 121 ret = archive.Flatten(stream); 122 123 return ret; 124 } 125 126 // MIMEType 127 const char* 128 MessageExporter::MIMEType() 129 { 130 return kNativeIconMimeType; 131 } 132 133 // #pragma mark - 134 135 // _Export 136 status_t 137 MessageExporter::_Export(const VectorPath* path, BMessage* into) const 138 { 139 return path->Archive(into, true); 140 } 141 142 // _Export 143 status_t 144 MessageExporter::_Export(const Style* style, BMessage* into) const 145 { 146 return style->Archive(into, true); 147 } 148 149 // _Export 150 status_t 151 MessageExporter::_Export(const Shape* shape, 152 const PathContainer* globalPaths, 153 const StyleContainer* globalStyles, 154 BMessage* into) const 155 { 156 status_t ret = B_OK; 157 158 const PathSourceShape* pathSourceShape = dynamic_cast<const PathSourceShape*>(shape); 159 if (pathSourceShape != NULL) { 160 ret = into->AddInt32("type", PathSourceShape::archive_code); 161 162 // NOTE: when the same path is used in two different 163 // documents, and these are to be merged, each path 164 // having a "globally unique" id would make it possible 165 // to reference the same path across documents... 166 // For now, we simply use the index of the path in the 167 // globalPaths container. 168 169 // index of used style 170 if (ret == B_OK) { 171 Style* style = pathSourceShape->Style(); 172 ret = into->AddInt32("style ref", globalStyles->IndexOf(style)); 173 } 174 175 // indices of used paths 176 if (ret == B_OK) { 177 int32 count = pathSourceShape->Paths()->CountPaths(); 178 for (int32 i = 0; i < count; i++) { 179 VectorPath* path = pathSourceShape->Paths()->PathAtFast(i); 180 ret = into->AddInt32("path ref", globalPaths->IndexOf(path)); 181 if (ret < B_OK) 182 break; 183 } 184 } 185 } 186 187 const ReferenceImage* referenceImage = dynamic_cast<const ReferenceImage*>(shape); 188 if (referenceImage != NULL) { 189 ret = into->AddInt32("type", ReferenceImage::archive_code); 190 } 191 192 // Shape properties 193 if (ret == B_OK) 194 ret = shape->Archive(into); 195 196 return ret; 197 } 198 199