1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* findreplace.c - finding & replacing data
3
4 Copyright (C) 1998 - 2004 Free Software Foundation
5
6 GHex is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
10
11 GHex is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GHex; see the file COPYING.
18 If not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21 Author: Jaka Mocnik <jaka@gnu.org>
22 */
23
24 #ifdef HAVE_CONFIG_H
25 # include <config.h>
26 #endif
27
28 #include <gtk/gtk.h>
29 #include <glib/gi18n.h>
30
31 #include "findreplace.h"
32 #include "ui.h"
33 #include "gtkhex.h"
34 #include "configuration.h"
35
36 static gint find_delete_event_cb(GtkWidget *w, GdkEventAny *e,
37 FindDialog *dialog);
38 static void find_cancel_cb(GtkWidget *w, FindDialog *dialog);
39 static gint advanced_find_delete_event_cb(GtkWidget *w, GdkEventAny *e,
40 AdvancedFindDialog *dialog);
41 static void advanced_find_close_cb(GtkWidget *w, AdvancedFindDialog *dialog);
42
43 static void find_next_cb(GtkButton *button, FindDialog *);
44 static void find_prev_cb(GtkButton *button, FindDialog *);
45 static void replace_next_cb(GtkButton *button, gpointer);
46 static void replace_one_cb(GtkButton *button, gpointer);
47 static void replace_all_cb(GtkButton *button, gpointer);
48 static void goto_byte_cb(GtkButton *button, GtkWidget *);
49 static gint get_search_string(HexDocument *doc, gchar **str);
50
51 static void advanced_find_add_add_cb(GtkButton *button,
52 AdvancedFind_AddDialog *dialog);
53 static void advanced_find_add_cb(GtkButton *button, AdvancedFindDialog *);
54 static void advanced_find_delete_cb(GtkButton *button, AdvancedFindDialog *dialog);
55 static void advanced_find_next_cb(GtkButton *button, AdvancedFindDialog *dialog);
56 static void advanced_find_prev_cb(GtkButton *button, AdvancedFindDialog *dialog);
57
58
59 FindDialog *find_dialog = NULL;
60 ReplaceDialog *replace_dialog = NULL;
61 JumpDialog *jump_dialog = NULL;
62
63 /* basic structure to hold private information to be stored in the
64 * gtk list.
65 */
66 typedef struct
67 {
68 gchar *str;
69 gint str_len;
70 GtkHex_AutoHighlight *auto_highlight;
71 } AdvancedFind_ListData;
72
create_hex_view(HexDocument * doc)73 static GtkWidget *create_hex_view(HexDocument *doc)
74 {
75 GtkWidget *gh = hex_document_add_view(doc);
76
77 gtk_hex_set_group_type(GTK_HEX(gh), def_group_type);
78 if (def_metrics && def_font_desc) {
79 gtk_hex_set_font(GTK_HEX(gh), def_metrics, def_font_desc);
80 }
81 gtk_hex_set_insert_mode(GTK_HEX(gh), TRUE);
82 gtk_hex_set_geometry(GTK_HEX(gh), 16, 4);
83 return gh;
84 }
85
86 /* Helper functions to set up copy/paste keybindings */
87 static gboolean
keypress_cb(GtkWidget * dialog,GdkEventKey * event,gpointer user_data)88 keypress_cb (GtkWidget *dialog, GdkEventKey *event, gpointer user_data)
89 {
90 GtkWidget *gh = gtk_window_get_focus (GTK_WINDOW(dialog));
91
92 /* If there isn't a GtkHex widget with focus, bail out. */
93 if (! GTK_IS_HEX (gh)) goto out;
94
95 /* Otherwise, handle clipboard shortcuts. */
96 if (event->state & GDK_CONTROL_MASK)
97 {
98 switch (event->keyval)
99 {
100 case 'c':
101 gtk_hex_copy_to_clipboard (GTK_HEX(gh));
102 return GDK_EVENT_STOP;
103 break;
104
105 case 'x':
106 gtk_hex_cut_to_clipboard (GTK_HEX(gh));
107 return GDK_EVENT_STOP;
108 break;
109
110 case 'v':
111 gtk_hex_paste_from_clipboard (GTK_HEX(gh));
112 return GDK_EVENT_STOP;
113 break;
114 }
115 }
116 out:
117 return GDK_EVENT_PROPAGATE;
118 }
119
120 static void
setup_clipboard_keybindings(GtkWidget * dialog)121 setup_clipboard_keybindings (GtkWidget *dialog)
122 {
123 /* sanity check: all find/replace/etc. dialogs are GtkDialogs at their core */
124 g_assert (GTK_IS_DIALOG (dialog));
125
126 g_signal_connect (dialog, "key-press-event", G_CALLBACK(keypress_cb), NULL);
127 }
128
create_find_dialog()129 FindDialog *create_find_dialog()
130 {
131 FindDialog *dialog;
132 GtkWidget *frame;
133
134 dialog = g_new0(FindDialog, 1);
135
136 dialog->window = gtk_dialog_new();
137 g_signal_connect(G_OBJECT(dialog->window), "delete_event",
138 G_CALLBACK(find_delete_event_cb), dialog);
139
140 create_dialog_title(dialog->window, _("GHex (%s): Find Data"));
141
142 dialog->f_doc = hex_document_new();
143 dialog->f_gh = create_hex_view(dialog->f_doc);
144 frame = gtk_frame_new(_("Find String"));
145 gtk_container_add(GTK_CONTAINER(frame), dialog->f_gh);
146 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog->window))), frame,
147 TRUE, TRUE, 0);
148 gtk_widget_show(frame);
149 gtk_widget_show(dialog->f_gh);
150
151 dialog->f_next = create_button(dialog->window, GTK_STOCK_GO_FORWARD, _("Find _Next"));
152 g_signal_connect (G_OBJECT (dialog->f_next), "clicked",
153 G_CALLBACK(find_next_cb), dialog);
154 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(dialog->window))), dialog->f_next,
155 TRUE, TRUE, 0);
156 gtk_widget_set_can_default(dialog->f_next, TRUE);
157 gtk_widget_show(dialog->f_next);
158 dialog->f_prev = create_button(dialog->window, GTK_STOCK_GO_BACK, _("Find _Previous"));
159 g_signal_connect (G_OBJECT (dialog->f_prev), "clicked",
160 G_CALLBACK(find_prev_cb), dialog);
161 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(dialog->window))), dialog->f_prev,
162 TRUE, TRUE, 0);
163
164 gtk_widget_set_can_default(dialog->f_prev, TRUE);
165 gtk_widget_show(dialog->f_prev);
166
167 dialog->f_close = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
168 g_signal_connect (G_OBJECT (dialog->f_close),
169 "clicked", G_CALLBACK(find_cancel_cb),
170 dialog);
171 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(dialog->window))), dialog->f_close,
172 TRUE, TRUE, 0);
173
174 gtk_widget_set_can_default(dialog->f_close, TRUE);
175 gtk_widget_show(dialog->f_close);
176
177 gtk_container_set_border_width(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog->window))), 2);
178 gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog->window))), 2);
179
180 setup_clipboard_keybindings (dialog->window);
181
182 if (GTK_IS_ACCESSIBLE (gtk_widget_get_accessible (dialog->f_gh))) {
183 add_atk_namedesc (dialog->f_gh, _("Find Data"), _("Enter the hex data or ASCII data to search for"));
184 add_atk_namedesc (dialog->f_next, _("Find Next"), _("Finds the next occurrence of the search string"));
185 add_atk_namedesc (dialog->f_prev, _("Find previous"), _("Finds the previous occurrence of the search string "));
186 add_atk_namedesc (dialog->f_close, _("Cancel"), _("Closes find data window"));
187 }
188
189 return dialog;
190 }
191
create_advanced_find_add_dialog(AdvancedFindDialog * parent)192 static AdvancedFind_AddDialog *create_advanced_find_add_dialog(AdvancedFindDialog *parent)
193 {
194 AdvancedFind_AddDialog *dialog = g_new0(AdvancedFind_AddDialog, 1);
195 GtkWidget *button, *frame, *sep;
196
197 dialog->window = gtk_dialog_new();
198 gtk_widget_hide(dialog->window);
199 g_signal_connect(G_OBJECT(dialog->window), "delete_event",
200 G_CALLBACK(delete_event_cb), dialog->window);
201
202 create_dialog_title(dialog->window, _("GHex (%s): Find Data: Add search"));
203
204 dialog->f_doc = hex_document_new();
205 dialog->f_gh = create_hex_view(dialog->f_doc);
206 frame = gtk_frame_new(_("Find String"));
207 gtk_container_add(GTK_CONTAINER(frame), dialog->f_gh);
208 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog->window))), frame,
209 TRUE, TRUE, 0);
210 gtk_widget_show(frame);
211 gtk_widget_show(dialog->f_gh);
212
213 sep = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
214 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog->window))), sep,
215 FALSE, FALSE, 0);
216
217 dialog->colour = gtk_color_selection_new();
218 gtk_color_selection_set_has_opacity_control(GTK_COLOR_SELECTION(dialog->colour),
219 FALSE);
220 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog->window))),
221 dialog->colour, FALSE, FALSE, 0);
222 gtk_widget_show(dialog->colour);
223
224 button = create_button(dialog->window, GTK_STOCK_ADD, _("Add"));
225 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(dialog->window))), button,
226 TRUE, TRUE, 0);
227 g_signal_connect (G_OBJECT (button),
228 "clicked", G_CALLBACK(advanced_find_add_add_cb),
229 dialog);
230 gtk_widget_set_can_default(button, TRUE);
231 gtk_widget_show(button);
232
233 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
234 g_signal_connect (G_OBJECT (button),
235 "clicked", G_CALLBACK(cancel_cb),
236 dialog->window);
237 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(dialog->window))), button,
238 TRUE, TRUE, 0);
239 gtk_widget_set_can_default(button, TRUE);
240 gtk_widget_show(button);
241
242 setup_clipboard_keybindings (dialog->window);
243
244 return dialog;
245 }
246
create_advanced_find_dialog(GHexWindow * parent)247 AdvancedFindDialog *create_advanced_find_dialog(GHexWindow *parent)
248 {
249 AdvancedFindDialog *dialog;
250 GtkCellRenderer *renderer;
251 GtkTreeViewColumn *column;
252 GtkTreeSelection *selection;
253
254 GtkWidget *sep;
255
256 dialog = g_new0(AdvancedFindDialog, 1);
257
258 dialog->parent = parent;
259
260 dialog->addDialog = create_advanced_find_add_dialog(dialog);
261
262 dialog->window = gtk_dialog_new();
263 g_signal_connect(G_OBJECT(dialog->window), "delete_event",
264 G_CALLBACK(advanced_find_delete_event_cb), dialog);
265
266 gtk_window_set_default_size(GTK_WINDOW(dialog->window), 300, 350);
267
268 create_dialog_title(dialog->window, _("GHex (%s): Find Data"));
269
270 dialog->hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
271 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog->window))),
272 dialog->hbox, TRUE, TRUE, 4);
273 gtk_widget_show(dialog->hbox);
274
275 dialog->list = gtk_list_store_new(3,
276 G_TYPE_STRING, G_TYPE_STRING,
277 G_TYPE_POINTER, G_TYPE_POINTER);
278 dialog->tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (dialog->list));
279 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->tree));
280 gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
281 renderer = gtk_cell_renderer_text_new ();
282 column = gtk_tree_view_column_new_with_attributes (_("Search String"),
283 renderer,
284 "text", 0,
285 "foreground", 1,
286 NULL);
287 gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->tree), column);
288
289 renderer = gtk_cell_renderer_text_new ();
290 column = gtk_tree_view_column_new_with_attributes (_("Highlight Colour"),
291 renderer,
292 "background", 1,
293 NULL);
294 gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->tree), column);
295
296 gtk_box_pack_start(GTK_BOX(dialog->hbox), dialog->tree,
297 TRUE, TRUE, 4);
298 gtk_widget_show (dialog->tree);
299
300 dialog->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
301 gtk_box_pack_start(GTK_BOX(dialog->hbox), dialog->vbox,
302 FALSE, FALSE, 4);
303 gtk_widget_show(dialog->vbox);
304
305 dialog->f_next = create_button(dialog->window, GTK_STOCK_GO_FORWARD, _("Find _Next"));
306 gtk_box_pack_start(GTK_BOX(dialog->vbox), dialog->f_next,
307 FALSE, FALSE, 0);
308 g_signal_connect (G_OBJECT (dialog->f_next),
309 "clicked", G_CALLBACK(advanced_find_next_cb),
310 dialog);
311 gtk_widget_set_can_default(dialog->f_next, TRUE);
312 gtk_widget_show(dialog->f_next);
313
314 dialog->f_prev = create_button(dialog->window, GTK_STOCK_GO_BACK, _("Find _Previous"));
315 gtk_box_pack_start(GTK_BOX(dialog->vbox), dialog->f_prev,
316 FALSE, FALSE, 0);
317 g_signal_connect (G_OBJECT (dialog->f_prev),
318 "clicked", G_CALLBACK(advanced_find_prev_cb),
319 dialog);
320 gtk_widget_set_can_default(dialog->f_prev, TRUE);
321 gtk_widget_show(dialog->f_prev);
322
323 sep = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
324 gtk_box_pack_start(GTK_BOX(dialog->vbox), sep, FALSE, FALSE, 4);
325 gtk_widget_show(sep);
326
327 dialog->f_new = create_button(dialog->window, GTK_STOCK_ADD, _("_Add New"));
328 gtk_box_pack_start(GTK_BOX(dialog->vbox), dialog->f_new,
329 FALSE, FALSE, 0);
330 g_signal_connect (G_OBJECT (dialog->f_new),
331 "clicked", G_CALLBACK(advanced_find_add_cb),
332 dialog);
333 gtk_widget_set_can_default(dialog->f_new, TRUE);
334 gtk_widget_show(dialog->f_new);
335
336 dialog->f_remove = create_button(dialog->window, GTK_STOCK_REMOVE, _("_Remove Selected"));
337 gtk_box_pack_start(GTK_BOX(dialog->vbox), dialog->f_remove,
338 FALSE, FALSE, 0);
339 g_signal_connect (G_OBJECT (dialog->f_remove),
340 "clicked", G_CALLBACK(advanced_find_delete_cb),
341 dialog);
342 gtk_widget_set_can_default(dialog->f_remove, TRUE);
343 gtk_widget_show(dialog->f_remove);
344
345 dialog->f_close = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
346 g_signal_connect(G_OBJECT(dialog->f_close),
347 "clicked", G_CALLBACK(advanced_find_close_cb),
348 dialog);
349 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(dialog->window))),
350 dialog->f_close, TRUE, TRUE, 0);
351 gtk_widget_set_can_default(dialog->f_close, TRUE);
352 gtk_widget_show(dialog->f_close);
353
354 if (GTK_IS_ACCESSIBLE (gtk_widget_get_accessible (dialog->f_close)))
355 {
356 add_atk_namedesc(dialog->f_close, _("Close"), _("Closes advanced find window"));
357 }
358
359 return dialog;
360 }
361
delete_advanced_find_add_dialog(AdvancedFind_AddDialog * dialog)362 static void delete_advanced_find_add_dialog(AdvancedFind_AddDialog *dialog)
363 {
364 gtk_widget_destroy(GTK_WIDGET(dialog->window));
365 g_free(dialog);
366 }
367
advanced_find_foreachfunc_cb(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)368 static gboolean advanced_find_foreachfunc_cb (GtkTreeModel *model,
369 GtkTreePath *path,
370 GtkTreeIter *iter,
371 gpointer data)
372 {
373 AdvancedFind_ListData *udata;
374 GtkHex *gh = (GtkHex *)data;
375 gtk_tree_model_get(model, iter, 2, &udata, -1);
376 gtk_hex_delete_autohighlight(gh, udata->auto_highlight);
377 if(NULL != udata->str)
378 g_free(udata->str);
379 g_free(udata);
380 return FALSE;
381 }
382
delete_advanced_find_dialog(AdvancedFindDialog * dialog)383 void delete_advanced_find_dialog(AdvancedFindDialog *dialog)
384 {
385 delete_advanced_find_add_dialog(dialog->addDialog);
386 gtk_tree_model_foreach(GTK_TREE_MODEL(dialog->list),
387 advanced_find_foreachfunc_cb, (gpointer *)dialog->parent->gh);
388 g_free(dialog);
389 }
390
create_replace_dialog()391 ReplaceDialog *create_replace_dialog()
392 {
393 ReplaceDialog *dialog;
394 GtkWidget *frame;
395
396 dialog = g_new0(ReplaceDialog, 1);
397
398 dialog->window = gtk_dialog_new();
399 g_signal_connect(G_OBJECT(dialog->window), "delete_event",
400 G_CALLBACK(delete_event_cb), dialog->window);
401
402 create_dialog_title(dialog->window, _("GHex (%s): Find & Replace Data"));
403
404 dialog->f_doc = hex_document_new();
405 dialog->f_gh = create_hex_view(dialog->f_doc);
406 frame = gtk_frame_new(_("Find String"));
407 gtk_container_add(GTK_CONTAINER(frame), dialog->f_gh);
408 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog->window))), frame,
409 TRUE, TRUE, 0);
410 gtk_widget_show(frame);
411 gtk_widget_show(dialog->f_gh);
412
413 dialog->r_doc = hex_document_new();
414 dialog->r_gh = create_hex_view(dialog->r_doc);
415 frame = gtk_frame_new(_("Replace With"));
416 gtk_container_add(GTK_CONTAINER(frame), dialog->r_gh);
417 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog->window))), frame,
418 TRUE, TRUE, 0);
419 gtk_widget_show(frame);
420 gtk_widget_show(dialog->r_gh);
421
422 dialog->next = create_button(dialog->window, GTK_STOCK_GO_FORWARD, _("Find _next"));
423 g_signal_connect (G_OBJECT (dialog->next),
424 "clicked", G_CALLBACK(replace_next_cb),
425 NULL);
426 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(dialog->window))), dialog->next,
427 TRUE, TRUE, 0);
428 gtk_widget_set_can_default(dialog->next, TRUE);
429 gtk_widget_show(dialog->next);
430 dialog->replace = gtk_button_new_with_mnemonic(_("_Replace"));
431 g_signal_connect (G_OBJECT (dialog->replace),
432 "clicked", G_CALLBACK(replace_one_cb),
433 NULL);
434 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(dialog->window))), dialog->replace,
435 TRUE, TRUE, 0);
436 gtk_widget_set_can_default(dialog->replace, TRUE);
437 gtk_widget_show(dialog->replace);
438 dialog->replace_all= gtk_button_new_with_mnemonic(_("Replace _All"));
439 g_signal_connect (G_OBJECT (dialog->replace_all),
440 "clicked", G_CALLBACK(replace_all_cb),
441 NULL);
442 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(dialog->window))), dialog->replace_all,
443 TRUE, TRUE, 0);
444 gtk_widget_set_can_default(dialog->replace_all, TRUE);
445 gtk_widget_show(dialog->replace_all);
446
447 dialog->close = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
448 g_signal_connect (G_OBJECT (dialog->close),
449 "clicked", G_CALLBACK(cancel_cb),
450 dialog->window);
451 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(dialog->window))), dialog->close,
452 TRUE, TRUE, 0);
453 gtk_widget_set_can_default(dialog->close, TRUE);
454 gtk_widget_show(dialog->close);
455
456 gtk_container_set_border_width(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog->window))), 2);
457 gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog->window))), 2);
458
459 setup_clipboard_keybindings (dialog->window);
460
461 if (GTK_IS_ACCESSIBLE(gtk_widget_get_accessible(dialog->f_gh))) {
462 add_atk_namedesc (dialog->f_gh, _("Find Data"), _("Enter the hex data or ASCII data to search for"));
463 add_atk_namedesc (dialog->r_gh, _("Replace Data"), _("Enter the hex data or ASCII data to replace with"));
464 add_atk_namedesc (dialog->next, _("Find next"), _("Finds the next occurrence of the search string"));
465 add_atk_namedesc (dialog->replace, _("Replace"), _("Replaces the search string with the replace string"));
466 add_atk_namedesc (dialog->replace_all, _("Replace All"), _("Replaces all occurrences of the search string with the replace string"));
467 add_atk_namedesc (dialog->close, _("Cancel"), _("Closes find and replace data window"));
468 }
469
470 return dialog;
471 }
472
create_jump_dialog()473 JumpDialog *create_jump_dialog()
474 {
475 JumpDialog *dialog;
476
477 dialog = g_new0(JumpDialog, 1);
478
479 dialog->window = gtk_dialog_new();
480 g_signal_connect(G_OBJECT(dialog->window), "delete_event",
481 G_CALLBACK(delete_event_cb), dialog->window);
482
483 create_dialog_title(dialog->window, _("GHex (%s): Jump To Byte"));
484
485 dialog->int_entry = gtk_entry_new();
486 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog->window))), dialog->int_entry,
487 TRUE, TRUE, 0);
488 g_signal_connect_swapped (G_OBJECT (dialog->int_entry),
489 "activate", G_CALLBACK(gtk_window_activate_default),
490 GTK_WINDOW (dialog->window));
491 gtk_widget_show(dialog->int_entry);
492
493 dialog->ok = gtk_button_new_from_stock (GTK_STOCK_OK);
494 g_signal_connect (G_OBJECT (dialog->ok),
495 "clicked", G_CALLBACK(goto_byte_cb),
496 dialog->int_entry);
497 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(dialog->window))), dialog->ok,
498 TRUE, TRUE, 0);
499
500 gtk_widget_set_can_default(dialog->ok, TRUE);
501 gtk_widget_show(dialog->ok);
502 dialog->cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
503 g_signal_connect (G_OBJECT (dialog->cancel),
504 "clicked", G_CALLBACK(cancel_cb),
505 dialog->window);
506 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(dialog->window))), dialog->cancel,
507 TRUE, TRUE, 0);
508
509 gtk_widget_set_can_default(dialog->cancel, TRUE);
510 gtk_widget_show(dialog->cancel);
511
512 gtk_container_set_border_width(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog->window))), 2);
513 gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog->window))), 2);
514
515 if (GTK_IS_ACCESSIBLE (gtk_widget_get_accessible(dialog->int_entry))) {
516 add_atk_namedesc (dialog->int_entry, _("Jump to byte"), _("Enter the byte to jump to"));
517 add_atk_namedesc (dialog->ok, _("OK"), _("Jumps to the specified byte"));
518 add_atk_namedesc (dialog->cancel, _("Cancel"), _("Closes jump to byte window"));
519 }
520
521 return dialog;
522 }
523
get_search_string(HexDocument * doc,gchar ** str)524 static gint get_search_string(HexDocument *doc, gchar **str)
525 {
526 guint size = doc->file_size;
527
528 if(size > 0)
529 *str = (gchar *)hex_document_get_data(doc, 0, size);
530 else
531 *str = NULL;
532 return size;
533 }
534
535 /* find and advanced find need special close dialogs, since they
536 * need to do stuff with the highlights
537 */
find_delete_event_cb(GtkWidget * w,GdkEventAny * e,FindDialog * dialog)538 static gint find_delete_event_cb(GtkWidget *w, GdkEventAny *e, FindDialog *dialog)
539 {
540 GHexWindow *win = ghex_window_get_active();
541 GtkHex *gh = win->gh;
542
543 if (dialog->auto_highlight) gtk_hex_delete_autohighlight(gh, dialog->auto_highlight);
544 dialog->auto_highlight = NULL;
545 gtk_widget_hide(w);
546
547 return TRUE;
548 }
549
find_cancel_cb(GtkWidget * w,FindDialog * dialog)550 static void find_cancel_cb(GtkWidget *w, FindDialog *dialog)
551 {
552 GHexWindow *win = ghex_window_get_active();
553 GtkHex *gh = win->gh;
554
555 if (dialog->auto_highlight) gtk_hex_delete_autohighlight(gh, dialog->auto_highlight);
556 dialog->auto_highlight = NULL;
557 gtk_widget_hide(dialog->window);
558 }
559
advanced_find_delete_event_cb(GtkWidget * w,GdkEventAny * e,AdvancedFindDialog * dialog)560 static gint advanced_find_delete_event_cb(GtkWidget *w, GdkEventAny *e,
561 AdvancedFindDialog *dialog)
562 {
563 gtk_widget_hide(w);
564
565 return TRUE;
566 }
567
advanced_find_close_cb(GtkWidget * w,AdvancedFindDialog * dialog)568 static void advanced_find_close_cb(GtkWidget *w, AdvancedFindDialog *dialog)
569 {
570 gtk_widget_hide(dialog->window);
571 }
572
find_next_cb(GtkButton * button,FindDialog * dialog)573 static void find_next_cb(GtkButton *button, FindDialog *dialog)
574 {
575 GtkHex *gh;
576 guint offset, str_len;
577 gchar *str;
578 GHexWindow *win = ghex_window_get_active();
579
580 if(win == NULL || win->gh == NULL) {
581 display_error_dialog (win, _("There is no active document to search!"));
582 return;
583 }
584
585 gh = win->gh;
586
587 if((str_len = get_search_string(find_dialog->f_doc, &str)) == 0) {
588 display_error_dialog (win, _("There is no string to search for!"));
589 return;
590 }
591 if (dialog->auto_highlight) gtk_hex_delete_autohighlight(gh, dialog->auto_highlight);
592 dialog->auto_highlight = NULL;
593 dialog->auto_highlight = gtk_hex_insert_autohighlight(gh, str, str_len, "red");
594 if(hex_document_find_forward(gh->document,
595 gh->cursor_pos+1, str, str_len, &offset))
596 {
597 gtk_hex_set_cursor(gh, offset);
598 }
599 else {
600 ghex_window_flash(win, _("End Of File reached"));
601 display_info_dialog(win, _("String was not found!\n"));
602 }
603 if(NULL != str)
604 g_free(str);
605 }
606
find_prev_cb(GtkButton * button,FindDialog * dialog)607 static void find_prev_cb(GtkButton *button, FindDialog *dialog)
608 {
609 GtkHex *gh;
610 guint offset, str_len;
611 gchar *str;
612 GHexWindow *win = ghex_window_get_active();
613
614 if(win == NULL || win->gh == NULL) {
615 display_error_dialog (win, _("There is no active document to search!"));
616 return;
617 }
618
619 gh = win->gh;
620
621 if((str_len = get_search_string(find_dialog->f_doc, &str)) == 0) {
622 display_error_dialog (win, _("There is no string to search for!"));
623 return;
624 }
625
626 if (dialog->auto_highlight) gtk_hex_delete_autohighlight(gh, dialog->auto_highlight);
627 dialog->auto_highlight = NULL;
628 dialog->auto_highlight = gtk_hex_insert_autohighlight(gh, str, str_len, "red");
629 if(hex_document_find_backward(gh->document,
630 gh->cursor_pos, str, str_len, &offset))
631 gtk_hex_set_cursor(gh, offset);
632 else {
633 ghex_window_flash(win, _("Beginning Of File reached"));
634 display_info_dialog(win, _("String was not found!\n"));
635 }
636 if(NULL != str)
637 g_free(str);
638 }
639
goto_byte_cb(GtkButton * button,GtkWidget * w)640 static void goto_byte_cb(GtkButton *button, GtkWidget *w)
641 {
642 guint byte = 2, len, i;
643 gint is_relative = 0;
644 gboolean is_hex;
645 const gchar *byte_str = gtk_entry_get_text(GTK_ENTRY(jump_dialog->int_entry));
646 GHexWindow *win = ghex_window_get_active();
647
648 if(win == NULL || win->gh == NULL) {
649 display_error_dialog (win,
650 _("There is no active document to move the "
651 "cursor in!"));
652 return;
653 }
654
655 len = strlen(byte_str);
656
657 if(len > 1 && byte_str[0] == '+') {
658 is_relative = 1;
659 byte_str++;
660 len--;
661 } else if(len > 1 && byte_str[0] == '-') {
662 is_relative = -1;
663 byte_str++;
664 len--;
665 }
666
667 if(len == 0) {
668 display_error_dialog (win, _("No offset has been specified!"));
669 return;
670 }
671
672 is_hex = ((len > 2) && (byte_str[0] == '0') && (byte_str[1] == 'x'));
673
674 if(!is_hex) {
675 for(i = 0; i < len; i++)
676 if(!(byte_str[i] >= '0' && byte_str[i] <= '9'))
677 break;
678 }
679 else {
680 for(i = 2; i < len; i++)
681 if(!((byte_str[i] >= '0' && byte_str[i] <= '9') ||
682 (byte_str[i] >= 'A' && byte_str[i] <= 'F') ||
683 (byte_str[i] >= 'a' && byte_str[i] <= 'f')))
684 break;
685 }
686
687 if((i == len) &&
688 ((sscanf(byte_str, "0x%x", &byte) == 1) ||
689 (sscanf(byte_str, "%d", &byte) == 1))) {
690 if(is_relative) {
691 if(is_relative == -1 && byte > win->gh->cursor_pos) {
692 display_error_dialog(win,
693 _("The specified offset is beyond the "
694 " file boundaries!"));
695 return;
696 }
697 byte = byte * is_relative + win->gh->cursor_pos;
698 }
699 if(byte >= win->gh->document->file_size)
700 display_error_dialog(win,
701 _("Can not position cursor beyond the "
702 "End Of File!"));
703 else
704 gtk_hex_set_cursor(win->gh, byte);
705 }
706 else
707 display_error_dialog(win,
708 _("You may only give the offset as:\n"
709 " - a positive decimal number, or\n"
710 " - a hex number, beginning with '0x', or\n"
711 " - a '+' or '-' sign, followed by a relative offset"));
712 }
713
replace_next_cb(GtkButton * button,gpointer unused)714 static void replace_next_cb(GtkButton *button, gpointer unused)
715 {
716 GtkHex *gh;
717 guint offset, str_len;
718 gchar *str = NULL;
719 GHexWindow *win = ghex_window_get_active();
720
721 if(win == NULL || win->gh == NULL) {
722 display_error_dialog (win, _("There is no active document to search!"));
723 return;
724 }
725
726 gh = win->gh;
727
728 if((str_len = get_search_string(replace_dialog->f_doc, &str)) == 0) {
729 display_error_dialog (win, _("There is no string to search for!"));
730 return;
731 }
732
733 if(hex_document_find_forward(gh->document,
734 gh->cursor_pos+1, str, str_len, &offset))
735 gtk_hex_set_cursor(gh, offset);
736 else {
737 display_info_dialog(win, _("String was not found!\n"));
738 ghex_window_flash(win, _("End Of File reached"));
739 }
740
741 if(NULL != str)
742 g_free(str);
743 }
744
replace_one_cb(GtkButton * button,gpointer unused)745 static void replace_one_cb(GtkButton *button, gpointer unused)
746 {
747 gchar *find_str = NULL, *rep_str = NULL;
748 guint find_len, rep_len, offset;
749 GtkHex *gh;
750 HexDocument *doc;
751 GHexWindow *win = ghex_window_get_active();
752
753 if(win == NULL || win->gh == NULL) {
754 display_error_dialog (win, _("There is no active buffer to replace data in!"));
755 return;
756 }
757
758 gh = win->gh;
759
760 doc = win->gh->document;
761
762 if((find_len = get_search_string(replace_dialog->f_doc, &find_str)) == 0) {
763 display_error_dialog (win, _("There is no string to search for!"));
764 return;
765 }
766 rep_len = get_search_string(replace_dialog->r_doc, &rep_str);
767
768 if(find_len > doc->file_size - gh->cursor_pos)
769 goto clean_up;
770
771 if(hex_document_compare_data(doc, find_str, gh->cursor_pos, find_len) == 0)
772 hex_document_set_data(doc, gh->cursor_pos,
773 rep_len, find_len, rep_str, TRUE);
774
775 if(hex_document_find_forward(doc, gh->cursor_pos + rep_len, find_str, find_len,
776 &offset))
777 gtk_hex_set_cursor(gh, offset);
778 else {
779 display_info_dialog(win, _("End Of File reached!"));
780 ghex_window_flash(win, _("End Of File reached!"));
781 }
782
783 clean_up:
784 if(NULL != find_str)
785 g_free(find_str);
786 if(NULL != rep_str)
787 g_free(rep_str);
788 }
789
replace_all_cb(GtkButton * button,gpointer unused)790 static void replace_all_cb(GtkButton *button, gpointer unused)
791 {
792 gchar *find_str = NULL, *rep_str = NULL, *flash;
793 guint find_len, rep_len, offset, count, cursor_pos;
794 GtkHex *gh;
795 HexDocument *doc;
796 GHexWindow *win = ghex_window_get_active();
797
798 if(win == NULL || win->gh == NULL) {
799 display_error_dialog (win, _("There is no active document to replace data in!"));
800 return;
801 }
802
803 gh = win->gh;
804
805 doc = gh->document;
806
807 if((find_len = get_search_string(replace_dialog->f_doc, &find_str)) == 0) {
808 display_error_dialog (win, _("There is no string to search for!"));
809 return;
810 }
811 rep_len = get_search_string(replace_dialog->r_doc, &rep_str);
812
813 if(find_len > doc->file_size - gh->cursor_pos)
814 goto clean_up;
815
816 count = 0;
817 cursor_pos = 0;
818
819 while(hex_document_find_forward(doc, cursor_pos, find_str, find_len,
820 &offset)) {
821 hex_document_set_data(doc, offset, rep_len, find_len, rep_str, TRUE);
822 cursor_pos = offset + rep_len;
823 count++;
824 }
825
826 gtk_hex_set_cursor(gh, MIN(offset, doc->file_size));
827
828 if(count == 0) {
829 display_info_dialog(win, _("No occurrences were found."));
830 }
831
832 flash = g_strdup_printf(ngettext("Replaced %d occurrence.",
833 "Replaced %d occurrences.",
834 count), count);
835 ghex_window_flash(win, flash);
836 g_free(flash);
837
838 clean_up:
839 if(NULL != find_str)
840 g_free(find_str);
841 if(NULL != rep_str)
842 g_free(rep_str);
843 }
844
advanced_find_add_add_cb(GtkButton * button,AdvancedFind_AddDialog * dialog)845 static void advanced_find_add_add_cb(GtkButton *button,
846 AdvancedFind_AddDialog *dialog)
847 {
848 gtk_dialog_response(GTK_DIALOG(dialog->window), GTK_RESPONSE_OK);
849 }
850
advanced_find_add_cb(GtkButton * button,AdvancedFindDialog * dialog)851 static void advanced_find_add_cb(GtkButton *button, AdvancedFindDialog *dialog)
852 {
853 gint ret;
854 if(!gtk_widget_get_visible(dialog->addDialog->window)) {
855 gtk_window_set_position (GTK_WINDOW(dialog->addDialog->window), GTK_WIN_POS_MOUSE);
856 gtk_widget_show(dialog->addDialog->window);
857 }
858
859 ret = gtk_dialog_run(GTK_DIALOG(dialog->addDialog->window));
860 gtk_widget_hide(dialog->addDialog->window);
861 if (ret != GTK_RESPONSE_NONE)
862 {
863 gchar *colour;
864 GdkRGBA rgba;
865 AdvancedFind_ListData *data = g_new0(AdvancedFind_ListData, 1);
866 GtkHex *gh = dialog->parent->gh;
867 GtkTreeIter iter;
868
869 g_return_if_fail (gh != NULL);
870
871 if((data->str_len = get_search_string(dialog->addDialog->f_doc, &data->str)) == 0) {
872 display_error_dialog (dialog->parent, _("No string to search for!"));
873 return;
874 }
875 gtk_color_selection_get_current_rgba (GTK_COLOR_SELECTION (dialog->addDialog->colour),
876 &rgba);
877 colour = gdk_rgba_to_string (&rgba);
878 data->auto_highlight = gtk_hex_insert_autohighlight(gh, data->str, data->str_len, colour);
879 gtk_list_store_append(dialog->list, &iter);
880 gtk_list_store_set(dialog->list, &iter,
881 0, data->str,
882 1, colour,
883 2, data,
884 -1);
885 g_free(colour);
886 }
887 }
888
advanced_find_delete_cb(GtkButton * button,AdvancedFindDialog * dialog)889 static void advanced_find_delete_cb(GtkButton *button, AdvancedFindDialog *dialog)
890 {
891 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->tree));
892 GtkTreeIter iter;
893 GtkTreeModel *model;
894 AdvancedFind_ListData *data;
895 GtkHex *gh = dialog->parent->gh;
896
897 if (gtk_tree_selection_get_selected(selection, &model, &iter) != TRUE)
898 return;
899
900 gtk_tree_model_get(model, &iter, 2, &data, -1);
901 gtk_hex_delete_autohighlight(gh, data->auto_highlight);
902 if(NULL != data->str)
903 g_free(data->str);
904 g_free(data);
905 gtk_list_store_remove(dialog->list, &iter);
906 }
907
advanced_find_next_cb(GtkButton * button,AdvancedFindDialog * dialog)908 static void advanced_find_next_cb(GtkButton *button, AdvancedFindDialog *dialog)
909 {
910 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->tree));
911 GtkTreeIter iter;
912 GtkTreeModel *model;
913 AdvancedFind_ListData *data;
914 GtkHex *gh = dialog->parent->gh;
915 guint offset;
916 GHexWindow *win = ghex_window_get_active();
917
918 if (gtk_tree_selection_get_selected(selection, &model, &iter) != TRUE)
919 return;
920
921 gtk_tree_model_get(model, &iter, 2, &data, -1);
922 if(hex_document_find_forward(gh->document,
923 gh->cursor_pos+1, data->str, data->str_len, &offset))
924 {
925 gtk_hex_set_cursor(gh, offset);
926 }
927 else {
928 ghex_window_flash(win, _("End Of File reached"));
929 display_info_dialog(win, _("String was not found!\n"));
930 }
931 }
932
advanced_find_prev_cb(GtkButton * button,AdvancedFindDialog * dialog)933 static void advanced_find_prev_cb(GtkButton *button, AdvancedFindDialog *dialog)
934 {
935 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->tree));
936 GtkTreeIter iter;
937 GtkTreeModel *model;
938 AdvancedFind_ListData *data;
939 GtkHex *gh = dialog->parent->gh;
940 guint offset;
941 GHexWindow *win = ghex_window_get_active();
942
943 if (gtk_tree_selection_get_selected(selection, &model, &iter) != TRUE)
944 return;
945
946 gtk_tree_model_get(model, &iter, 2, &data, -1);
947 if(hex_document_find_backward(gh->document,
948 gh->cursor_pos, data->str, data->str_len, &offset))
949 gtk_hex_set_cursor(gh, offset);
950 else {
951 ghex_window_flash(win, _("Beginning Of File reached"));
952 display_info_dialog(win, _("String was not found!\n"));
953 }
954 }
955
956