vfs: check userland buffers before reading them.
[haiku.git] / src / apps / icon-o-matic / import_export / styled_text / StyledTextImporter.cpp
blobb5255035728407cef219ead954763880b8684309
1 /*
2 * Copyright 2008-2009, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * François Revol <revol@free.fr>
7 */
9 #include "StyledTextImporter.h"
11 #include <new>
12 #include <stdint.h>
13 #include <stdio.h>
15 #include <Alert.h>
16 #include <Archivable.h>
17 #include <ByteOrder.h>
18 #include <Catalog.h>
19 #include <DataIO.h>
20 #include <File.h>
21 #include <List.h>
22 #include <Locale.h>
23 #include <Message.h>
24 #include <NodeInfo.h>
25 #include <Shape.h>
26 #include <String.h>
27 #include <TextView.h>
29 #include "Defines.h"
30 #include "Icon.h"
31 #include "PathContainer.h"
32 #include "Shape.h"
33 #include "Style.h"
34 #include "StyleContainer.h"
35 #include "VectorPath.h"
38 #undef B_TRANSLATION_CONTEXT
39 #define B_TRANSLATION_CONTEXT "Icon-O-Matic-StyledTextImport"
40 //#define CALLED() printf("%s()\n", __FUNCTION__);
41 #define CALLED() do {} while (0)
44 using std::nothrow;
46 class ShapeIterator : public BShapeIterator {
47 public:
48 ShapeIterator(Icon *icon, Shape *to, BPoint offset, const char *name);
49 ~ShapeIterator() {};
51 virtual status_t IterateMoveTo(BPoint *point);
52 virtual status_t IterateLineTo(int32 lineCount, BPoint *linePts);
53 virtual status_t IterateBezierTo(int32 bezierCount, BPoint *bezierPts);
54 virtual status_t IterateClose();
56 private:
57 VectorPath *CurrentPath();
58 void NextPath();
60 Icon *fIcon;
61 Shape *fShape;
62 VectorPath *fPath;
63 BPoint fOffset;
64 const char *fName;
65 BPoint fLastPoint;
66 bool fHasLastPoint;
69 ShapeIterator::ShapeIterator(Icon *icon, Shape *to, BPoint offset,
70 const char *name)
72 CALLED();
73 fIcon = icon;
74 fShape = to;
75 fPath = NULL;
76 fOffset = offset;
77 fName = name;
78 fLastPoint = offset;
79 fHasLastPoint = false;
82 status_t
83 ShapeIterator::IterateMoveTo(BPoint *point)
85 CALLED();
86 if (fPath)
87 NextPath();
88 if (!CurrentPath())
89 return B_ERROR;
90 //fPath->AddPoint(fOffset + *point);
91 fLastPoint = fOffset + *point;
92 fHasLastPoint = true;
93 return B_OK;
96 status_t
97 ShapeIterator::IterateLineTo(int32 lineCount, BPoint *linePts)
99 CALLED();
100 if (!CurrentPath())
101 return B_ERROR;
102 while (lineCount--) {
103 fPath->AddPoint(fOffset + *linePts);
104 fLastPoint = fOffset + *linePts;
105 fHasLastPoint = true;
106 linePts++;
108 return B_OK;
111 status_t
112 ShapeIterator::IterateBezierTo(int32 bezierCount, BPoint *bezierPts)
114 CALLED();
115 if (!CurrentPath())
116 return B_ERROR;
117 BPoint start(bezierPts[0]);
118 if (fHasLastPoint)
119 start = fLastPoint;
120 while (bezierCount--) {
121 fPath->AddPoint(fOffset + bezierPts[0],
122 fLastPoint, fOffset + bezierPts[1], true);
123 fLastPoint = fOffset + bezierPts[2];
124 bezierPts += 3;
126 fPath->AddPoint(fLastPoint);
127 fHasLastPoint = true;
128 return B_OK;
131 status_t
132 ShapeIterator::IterateClose()
134 CALLED();
135 if (!CurrentPath())
136 return B_ERROR;
137 fPath->SetClosed(true);
138 NextPath();
139 fHasLastPoint = false;
140 return B_OK;
143 VectorPath *
144 ShapeIterator::CurrentPath()
146 CALLED();
147 if (fPath)
148 return fPath;
149 fPath = new (nothrow) VectorPath();
150 fPath->SetName(fName);
151 return fPath;
154 void
155 ShapeIterator::NextPath()
157 CALLED();
158 if (fPath) {
159 fIcon->Paths()->AddPath(fPath);
160 fShape->Paths()->AddPath(fPath);
162 fPath = NULL;
166 // #pragma mark -
168 // constructor
169 StyledTextImporter::StyledTextImporter()
170 : Importer(),
171 fStyleMap(NULL),
172 fStyleCount(0)
174 CALLED();
177 // destructor
178 StyledTextImporter::~StyledTextImporter()
180 CALLED();
183 // Import
184 status_t
185 StyledTextImporter::Import(Icon* icon, BMessage* clipping)
187 CALLED();
188 const char *text;
189 ssize_t textLength;
191 if (clipping == NULL)
192 return ENOENT;
193 if (clipping->FindData("text/plain",
194 B_MIME_TYPE, (const void **)&text, &textLength) == B_OK) {
195 text_run_array *runs = NULL;
196 ssize_t runsLength;
197 if (clipping->FindData("application/x-vnd.Be-text_run_array",
198 B_MIME_TYPE, (const void **)&runs, &runsLength) < B_OK)
199 runs = NULL;
200 BString str(text, textLength);
201 return _Import(icon, str.String(), runs);
203 return ENOENT;
206 // Import
207 status_t
208 StyledTextImporter::Import(Icon* icon, const entry_ref* ref)
210 CALLED();
211 status_t err;
212 BFile file(ref, B_READ_ONLY);
213 err = file.InitCheck();
214 if (err < B_OK)
215 return err;
217 BNodeInfo info(&file);
218 char mime[B_MIME_TYPE_LENGTH];
219 err = info.GetType(mime);
220 if (err < B_OK)
221 return err;
223 if (strncmp(mime, "text/plain", B_MIME_TYPE_LENGTH))
224 return EINVAL;
226 off_t size;
227 err = file.GetSize(&size);
228 if (err < B_OK)
229 return err;
230 if (size > 1 * 1024 * 1024) // Don't load files that big
231 return E2BIG;
233 BMallocIO mio;
234 mio.SetSize((size_t)size + 1);
235 memset((void *)mio.Buffer(), 0, (size_t)size + 1);
237 // TODO: read runs from attribute
239 return _Import(icon, (const char *)mio.Buffer(), NULL);
243 // _Import
244 status_t
245 StyledTextImporter::_Import(Icon* icon, const char *text, text_run_array *runs)
247 CALLED();
248 status_t ret = Init(icon);
249 if (ret < B_OK) {
250 printf("StyledTextImporter::Import() - Init() error: %s\n",
251 strerror(ret));
252 return ret;
255 BString str(text);
256 if (str.Length() > 50) {
257 BAlert* alert = new BAlert(B_TRANSLATE("Text too long"),
258 B_TRANSLATE("The text you are trying to import is quite long, "
259 "are you sure?"),
260 B_TRANSLATE("Yes"), B_TRANSLATE("No"), NULL,
261 B_WIDTH_AS_USUAL, B_WARNING_ALERT);
262 if (alert->Go())
263 return B_CANCELED;
266 // import run colors as styles
267 if (runs) {
268 delete[] fStyleMap;
269 fStyleMap = new struct style_map[runs->count];
270 for (int32 i = 0; runs && i < runs->count; i++) {
271 _AddStyle(icon, &runs->runs[i]);
275 int32 currentRun = 0;
276 text_run *run = NULL;
277 if (runs)
278 run = &runs->runs[0];
279 int32 len = str.Length();
280 int32 chars = str.CountChars();
281 BPoint origin(0, 0);
282 BPoint offset(origin);
284 for (int32 i = 0, c = 0; i < len && c < chars; c++) {
285 // make sure we are still on the (good) run
286 while (run && currentRun < runs->count - 1 &&
287 i >= runs->runs[currentRun + 1].offset) {
288 run = &runs->runs[++currentRun];
289 //printf("switching to run %d\n", currentRun);
292 int charLen;
293 for (charLen = 1; str.ByteAt(i + charLen) & 0x80; charLen++);
295 BShape glyph;
296 BShape *glyphs[1] = { &glyph };
297 BFont font(be_plain_font);
298 if (run)
299 font = run->font;
301 // first char
302 if (offset == BPoint(0,0)) {
303 font_height height;
304 font.GetHeight(&height);
305 origin.y += height.ascent;
306 offset = origin;
308 // LF
309 if (str[i] == '\n') {
310 // XXX: should take the MAX() for the line
311 // XXX: should use descent + leading from previous line
312 font_height height;
313 font.GetHeight(&height);
314 origin.y += height.ascent + height.descent + height.leading;
315 offset = origin;
316 i++;
317 continue;
320 float charWidth;
321 charWidth = font.StringWidth(str.String() + i, charLen);
322 //printf("StringWidth( %d) = %f\n", charLen, charWidth);
323 BString glyphName(str.String() + i, charLen);
324 glyphName.Prepend("Glyph (");
325 glyphName.Append(")");
327 font.GetGlyphShapes((str.String() + i), 1, glyphs);
328 if (glyph.Bounds().IsValid()) {
329 //offset.x += glyph.Bounds().Width();
330 offset.x += charWidth;
331 Shape* shape = new (nothrow) Shape(NULL);
332 if (shape == NULL)
333 return B_NO_MEMORY;
334 shape->SetName(glyphName.String());
335 if (!icon->Shapes()->AddShape(shape)) {
336 delete shape;
337 return B_NO_MEMORY;
339 for (int j = 0; run && j < fStyleCount; j++) {
340 if (fStyleMap[j].run == run) {
341 shape->SetStyle(fStyleMap[j].style);
342 break;
345 ShapeIterator iterator(icon, shape, offset, glyphName.String());
346 if (iterator.Iterate(&glyph) < B_OK)
347 return B_ERROR;
351 // skip the rest of UTF-8 char bytes
352 for (i++; i < len && str[i] & 0x80; i++);
355 delete[] fStyleMap;
356 fStyleMap = NULL;
358 return B_OK;
361 // #pragma mark -
363 // _AddStyle
364 status_t
365 StyledTextImporter::_AddStyle(Icon *icon, text_run *run)
367 CALLED();
368 if (!run)
369 return EINVAL;
370 rgb_color color = run->color;
371 Style* style = new(std::nothrow) Style(color);
372 if (style == NULL)
373 return B_NO_MEMORY;
374 char name[30];
375 sprintf(name, B_TRANSLATE("Color (#%02x%02x%02x)"),
376 color.red, color.green, color.blue);
377 style->SetName(name);
379 bool found = false;
380 for (int i = 0; i < fStyleCount; i++) {
381 if (*style == *(fStyleMap[i].style)) {
382 delete style;
383 style = fStyleMap[i].style;
384 found = true;
385 break;
389 if (!found && !icon->Styles()->AddStyle(style)) {
390 delete style;
391 return B_NO_MEMORY;
394 fStyleMap[fStyleCount].run = run;
395 fStyleMap[fStyleCount].style = style;
396 fStyleCount++;
398 return B_OK;
401 // _AddPaths
402 status_t
403 StyledTextImporter::_AddPaths(Icon *icon, BShape *shape)
405 CALLED();
406 return B_ERROR;
409 // _AddShape
410 status_t
411 StyledTextImporter::_AddShape(Icon *icon, BShape *shape, text_run *run)
413 CALLED();
414 return B_ERROR;