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