vfs: check userland buffers before reading them.
[haiku.git] / src / apps / icon-o-matic / IconEditorApp.cpp
blobd667ce90cec5f48d94524e2fcefb2b3c5a0f82d4
1 /*
2 * Copyright 2006, 2011, Stephan Aßmus <superstippi@gmx.de>.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "IconEditorApp.h"
9 #include <new>
10 #include <stdio.h>
11 #include <string.h>
13 #include <Alert.h>
14 #include <Catalog.h>
15 #include <FilePanel.h>
16 #include <FindDirectory.h>
17 #include <IconEditorProtocol.h>
18 #include <Locale.h>
19 #include <Message.h>
20 #include <Mime.h>
21 #include <Path.h>
23 #include "support_settings.h"
25 #include "AutoLocker.h"
26 #include "Defines.h"
27 #include "MainWindow.h"
28 #include "SavePanel.h"
31 #undef B_TRANSLATION_CONTEXT
32 #define B_TRANSLATION_CONTEXT "Icon-O-Matic-Main"
35 using std::nothrow;
37 static const char* kAppSig = "application/x-vnd.haiku-icon_o_matic";
39 static const float kWindowOffset = 20;
42 IconEditorApp::IconEditorApp()
44 BApplication(kAppSig),
45 fWindowCount(0),
46 fLastWindowFrame(50, 50, 900, 750),
48 fOpenPanel(NULL),
49 fSavePanel(NULL),
51 fLastOpenPath(""),
52 fLastSavePath(""),
53 fLastExportPath("")
55 // create file panels
56 BMessenger messenger(this, this);
57 BMessage message(B_REFS_RECEIVED);
58 fOpenPanel = new BFilePanel(B_OPEN_PANEL, &messenger, NULL, B_FILE_NODE,
59 true, &message);
61 message.what = MSG_SAVE_AS;
62 fSavePanel = new SavePanel("save panel", &messenger, NULL, B_FILE_NODE
63 | B_DIRECTORY_NODE | B_SYMLINK_NODE, false, &message);
65 _RestoreSettings();
69 IconEditorApp::~IconEditorApp()
71 delete fOpenPanel;
72 delete fSavePanel;
76 // #pragma mark -
79 bool
80 IconEditorApp::QuitRequested()
82 // Run the QuitRequested() hook in each window's own thread. Otherwise
83 // the BAlert which a window shows when an icon is not saved will not
84 // repaint the window. (BAlerts check which thread is running Go() and
85 // will repaint windows when it's a BWindow.)
86 bool quit = true;
87 for (int32 i = 0; BWindow* window = WindowAt(i); i++) {
88 if (!window->Lock())
89 continue;
90 // Try to cast the window while the pointer must be valid.
91 MainWindow* mainWindow = dynamic_cast<MainWindow*>(window);
92 window->Unlock();
93 if (mainWindow == NULL)
94 continue;
95 BMessenger messenger(window, window);
96 BMessage reply;
97 if (messenger.SendMessage(B_QUIT_REQUESTED, &reply) != B_OK)
98 continue;
99 bool result;
100 if (reply.FindBool("result", &result) == B_OK && !result)
101 quit = false;
104 if (!quit)
105 return false;
107 _StoreSettings();
109 return true;
113 void
114 IconEditorApp::MessageReceived(BMessage* message)
116 switch (message->what) {
117 case MSG_NEW:
118 _NewWindow()->Show();
119 break;
120 case MSG_OPEN:
122 BMessage openMessage(B_REFS_RECEIVED);
123 MainWindow* window;
124 if (message->FindPointer("window", (void**)&window) == B_OK)
125 openMessage.AddPointer("window", window);
126 fOpenPanel->SetMessage(&openMessage);
127 fOpenPanel->Show();
128 break;
130 case MSG_APPEND:
132 MainWindow* window;
133 if (message->FindPointer("window", (void**)&window) != B_OK)
134 break;
135 BMessage openMessage(B_REFS_RECEIVED);
136 openMessage.AddBool("append", true);
137 openMessage.AddPointer("window", window);
138 fOpenPanel->SetMessage(&openMessage);
139 fOpenPanel->Show();
140 break;
142 case B_EDIT_ICON_DATA:
144 BMessenger messenger;
145 if (message->FindMessenger("reply to", &messenger) < B_OK) {
146 // required
147 break;
149 const uint8* data;
150 ssize_t size;
151 if (message->FindData("icon data", B_VECTOR_ICON_TYPE,
152 (const void**)&data, &size) < B_OK) {
153 // optional (new icon will be created)
154 data = NULL;
155 size = 0;
157 MainWindow* window = _NewWindow();
158 window->Open(messenger, data, size);
159 window->Show();
160 break;
162 case MSG_SAVE_AS:
163 case MSG_EXPORT_AS:
165 BMessenger messenger;
166 if (message->FindMessenger("target", &messenger) != B_OK)
167 break;
169 fSavePanel->SetExportMode(message->what == MSG_EXPORT_AS);
170 // fSavePanel->Refresh();
171 const char* saveText;
172 if (message->FindString("save text", &saveText) == B_OK)
173 fSavePanel->SetSaveText(saveText);
174 fSavePanel->SetTarget(messenger);
175 fSavePanel->Show();
176 break;
179 case MSG_WINDOW_CLOSED:
181 fWindowCount--;
182 if (fWindowCount == 0)
183 PostMessage(B_QUIT_REQUESTED);
184 BMessage settings;
185 if (message->FindMessage("settings", &settings) == B_OK)
186 fLastWindowSettings = settings;
187 BRect frame;
188 if (message->FindRect("window frame", &frame) == B_OK) {
189 fLastWindowFrame = frame;
190 fLastWindowFrame.OffsetBy(-kWindowOffset, -kWindowOffset);
192 break;
195 default:
196 BApplication::MessageReceived(message);
197 break;
202 void
203 IconEditorApp::ReadyToRun()
205 // create main window
206 if (fWindowCount == 0)
207 _NewWindow()->Show();
209 _InstallDocumentMimeType();
213 void
214 IconEditorApp::RefsReceived(BMessage* message)
216 bool append;
217 if (message->FindBool("append", &append) != B_OK)
218 append = false;
219 MainWindow* window;
220 if (message->FindPointer("window", (void**)&window) != B_OK)
221 window = NULL;
222 // When appending, we need to know a window.
223 if (append && window == NULL)
224 return;
225 entry_ref ref;
226 if (append) {
227 if (!window->Lock())
228 return;
229 for (int32 i = 0; message->FindRef("refs", i, &ref) == B_OK; i++)
230 window->Open(ref, true);
231 window->Unlock();
232 } else {
233 for (int32 i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) {
234 if (window != NULL && i == 0) {
235 window->Lock();
236 window->Open(ref, false);
237 window->Unlock();
238 } else {
239 window = _NewWindow();
240 window->Open(ref, false);
241 window->Show();
246 if (fOpenPanel != NULL && fSavePanel != NULL)
247 _SyncPanels(fOpenPanel, fSavePanel);
251 void
252 IconEditorApp::ArgvReceived(int32 argc, char** argv)
254 if (argc < 2)
255 return;
257 entry_ref ref;
259 for (int32 i = 1; i < argc; i++) {
260 if (get_ref_for_path(argv[i], &ref) == B_OK) {
261 MainWindow* window = _NewWindow();
262 window->Open(ref);
263 window->Show();
269 // #pragma mark -
272 MainWindow*
273 IconEditorApp::_NewWindow()
275 fLastWindowFrame.OffsetBy(kWindowOffset, kWindowOffset);
276 MainWindow* window = new MainWindow(fLastWindowFrame, this,
277 &fLastWindowSettings);
278 fWindowCount++;
279 return window;
283 void
284 IconEditorApp::_SyncPanels(BFilePanel* from, BFilePanel* to)
286 if (from->Window()->Lock()) {
287 // location
288 if (to->Window()->Lock()) {
289 BRect frame = from->Window()->Frame();
290 to->Window()->MoveTo(frame.left, frame.top);
291 to->Window()->ResizeTo(frame.Width(), frame.Height());
292 to->Window()->Unlock();
294 // current folder
295 entry_ref panelDir;
296 from->GetPanelDirectory(&panelDir);
297 to->SetPanelDirectory(&panelDir);
298 from->Window()->Unlock();
303 const char*
304 IconEditorApp::_LastFilePath(path_kind which)
306 const char* path = NULL;
308 switch (which) {
309 case LAST_PATH_OPEN:
310 if (fLastOpenPath.Length() > 0)
311 path = fLastOpenPath.String();
312 else if (fLastSavePath.Length() > 0)
313 path = fLastSavePath.String();
314 else if (fLastExportPath.Length() > 0)
315 path = fLastExportPath.String();
316 break;
317 case LAST_PATH_SAVE:
318 if (fLastSavePath.Length() > 0)
319 path = fLastSavePath.String();
320 else if (fLastExportPath.Length() > 0)
321 path = fLastExportPath.String();
322 else if (fLastOpenPath.Length() > 0)
323 path = fLastOpenPath.String();
324 break;
325 case LAST_PATH_EXPORT:
326 if (fLastExportPath.Length() > 0)
327 path = fLastExportPath.String();
328 else if (fLastSavePath.Length() > 0)
329 path = fLastSavePath.String();
330 else if (fLastOpenPath.Length() > 0)
331 path = fLastOpenPath.String();
332 break;
334 if (path == NULL) {
336 BPath homePath;
337 if (find_directory(B_USER_DIRECTORY, &homePath) == B_OK)
338 path = homePath.Path();
339 else
340 path = "/boot/home";
343 return path;
347 // #pragma mark -
350 void
351 IconEditorApp::_StoreSettings()
353 BMessage settings('stns');
355 settings.AddRect("window frame", fLastWindowFrame);
356 settings.AddMessage("window settings", &fLastWindowSettings);
357 settings.AddInt32("export mode", fSavePanel->ExportMode());
359 save_settings(&settings, "Icon-O-Matic");
363 void
364 IconEditorApp::_RestoreSettings()
366 BMessage settings('stns');
367 load_settings(&settings, "Icon-O-Matic");
369 BRect frame;
370 if (settings.FindRect("window frame", &frame) == B_OK) {
371 fLastWindowFrame = frame;
372 // Compensate offset for next window...
373 fLastWindowFrame.OffsetBy(-kWindowOffset, -kWindowOffset);
375 BMessage lastSettings;
376 if (settings.FindMessage("window settings", &lastSettings)
377 == B_OK) {
378 fLastWindowSettings = lastSettings;
381 int32 mode;
382 if (settings.FindInt32("export mode", &mode) >= B_OK)
383 fSavePanel->SetExportMode(mode);
387 void
388 IconEditorApp::_InstallDocumentMimeType()
390 // install mime type of documents
391 BMimeType mime(kNativeIconMimeType);
392 status_t ret = mime.InitCheck();
393 if (ret < B_OK) {
394 fprintf(stderr, "Could not init native document mime type (%s): %s.\n",
395 kNativeIconMimeType, strerror(ret));
396 return;
399 if (mime.IsInstalled() && !(modifiers() & B_SHIFT_KEY)) {
400 // mime is already installed, and the user is not
401 // pressing the shift key to force a re-install
402 return;
405 ret = mime.Install();
406 if (ret < B_OK) {
407 fprintf(stderr, "Could not install native document mime type (%s): "
408 "%s.\n", kNativeIconMimeType, strerror(ret));
409 return;
411 // set preferred app
412 ret = mime.SetPreferredApp(kAppSig);
413 if (ret < B_OK)
414 fprintf(stderr, "Could not set native document preferred app: %s\n",
415 strerror(ret));
417 // set descriptions
418 ret = mime.SetShortDescription("Haiku Icon");
419 if (ret < B_OK)
420 fprintf(stderr, "Could not set short description of mime type: %s\n",
421 strerror(ret));
422 ret = mime.SetLongDescription("Native Haiku vector icon");
423 if (ret < B_OK)
424 fprintf(stderr, "Could not set long description of mime type: %s\n",
425 strerror(ret));
427 // set extensions
428 BMessage message('extn');
429 message.AddString("extensions", "icon");
430 ret = mime.SetFileExtensions(&message);
431 if (ret < B_OK)
432 fprintf(stderr, "Could not set extensions of mime type: %s\n",
433 strerror(ret));
435 // set sniffer rule
436 const char* snifferRule = "0.9 ('IMSG')";
437 ret = mime.SetSnifferRule(snifferRule);
438 if (ret < B_OK) {
439 BString parseError;
440 BMimeType::CheckSnifferRule(snifferRule, &parseError);
441 fprintf(stderr, "Could not set sniffer rule of mime type: %s\n",
442 parseError.String());