[ghex/expand-search-options: 4/14] Add new HexDocument API and refactor existing to expand search options.
- From: Logan Rathbone <larathbone src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [ghex/expand-search-options: 4/14] Add new HexDocument API and refactor existing to expand search options.
- Date: Tue, 19 Apr 2022 22:04:08 +0000 (UTC)
commit e8922c3c678ba76f47271dfe5ce2c55c5414b338
Author: Logan Rathbone <poprocks gmail com>
Date: Tue Apr 12 22:27:46 2022 -0400
Add new HexDocument API and refactor existing to expand search options.
- *_full and *_full_async functions now take FindData structs to
simplify signatures and to make it cleaner to pass and change values
(mostly needed to change ->len value)
- find_data->len can be changed by compare_data_full after a search to
show the length of the *result* - this is a bit confusing upon first
blush but it does allow for easy communication of length of the match
which may not be the same as the length of the search string.
- autohighlighting does not work except for exact matches. This is
because hex_widget_insert_autohighlight() takes a string and
highlights exact matches. Need to decide how to handle that.
- this is still unstable API, but once stabilized, will need to
gtk-doc-ify it.
src/find-options.ui | 11 +-
src/findreplace.c | 44 ++++---
src/hex-document.c | 343 +++++++++++++++++++++++++++++++++++++++-------------
src/hex-document.h | 21 ++++
4 files changed, 319 insertions(+), 100 deletions(-)
---
diff --git a/src/find-options.ui b/src/find-options.ui
index ad9b6e9..7e3a152 100644
--- a/src/find-options.ui
+++ b/src/find-options.ui
@@ -36,7 +36,16 @@
</layout>
</object>
</child>
- </object>
+ <child>
+ <object class="GtkCheckButton" id="find_options_ignore_case">
+ <property name="label">Ignore case</property>
+ <layout>
+ <property name="column">1</property>
+ <property name="row">0</property>
+ </layout>
+ </object>
+ </child>
+ </object> <!-- grid -->
</child>
</object>
</interface>
diff --git a/src/findreplace.c b/src/findreplace.c
index c2d184c..c9b14d6 100644
--- a/src/findreplace.c
+++ b/src/findreplace.c
@@ -73,6 +73,7 @@ typedef struct {
GtkWidget *options_popover;
GtkWidget *options_regex;
gboolean found;
+ size_t last_found_len;
GCancellable *cancellable;
} FindDialogPrivate;
@@ -255,6 +256,8 @@ find_ready_cb (GObject *source_object,
if (find_data->found)
{
f_priv->found = TRUE;
+ f_priv->last_found_len = find_data->len;
+
hex_widget_set_cursor (priv->gh, find_data->offset);
/* If string found, insert auto-highlights of search string */
@@ -294,6 +297,7 @@ find_common (FindDialog *self, enum FindDirection direction,
gint64 str_len;
gint64 offset;
char *str;
+ HexDocumentFindData *find_data;
g_return_if_fail (FIND_IS_DIALOG(self));
@@ -315,31 +319,39 @@ find_common (FindDialog *self, enum FindDirection direction,
}
/* Search for requested string */
+
+ find_data = g_new0 (HexDocumentFindData, 1);
+ find_data->what = str;
+ find_data->len = str_len;
+ find_data->found_msg = found_msg;
+ find_data->not_found_msg = not_found_msg;
+ g_cancellable_reset (f_priv->cancellable);
+
if (direction == FIND_FORWARD)
{
- g_cancellable_reset (f_priv->cancellable);
- hex_document_find_forward_async (doc,
- f_priv->found == FALSE ? cursor_pos : cursor_pos + 1,
- str,
- str_len,
- &offset,
- found_msg,
- not_found_msg,
+ // TEST
+
+ find_data->start = f_priv->found == FALSE ?
+ cursor_pos :
+ cursor_pos + f_priv->last_found_len;
+
+ hex_document_find_forward_full_async (doc,
+ find_data,
+ HEX_SEARCH_REGEX, // TEST
f_priv->cancellable,
find_ready_cb,
self);
}
else /* FIND_BACKWARD */
{
- hex_document_find_backward_async (doc,
- cursor_pos,
- str,
- str_len,
- &offset,
- found_msg,
- not_found_msg,
- NULL,
+ // TEST
+ find_data->start = cursor_pos;
+
+ hex_document_find_backward_full_async (doc,
+ find_data,
+ HEX_SEARCH_REGEX, // TEST
+ f_priv->cancellable,
find_ready_cb,
self);
}
diff --git a/src/hex-document.c b/src/hex-document.c
index 8b7cb91..cbc6130 100644
--- a/src/hex-document.c
+++ b/src/hex-document.c
@@ -52,6 +52,7 @@ static void undo_stack_ascend (HexDocument *doc);
static void undo_stack_free (HexDocument *doc);
#define DEFAULT_UNDO_DEPTH 1024
+#define REGEX_SEARCH_LEN 1024 /* FIXME/TODO: This is kind of lazy. Stopgap? */
enum {
DOCUMENT_CHANGED,
@@ -83,6 +84,19 @@ hex_document_find_data_copy (HexDocumentFindData *data)
G_DEFINE_BOXED_TYPE (HexDocumentFindData, hex_document_find_data,
hex_document_find_data_copy, g_free)
+/* HexDocumentFindFullData (private) */
+typedef struct
+{
+ HexDocumentFindData *find_data;
+ HexSearchFlags flags;
+} HexDocumentFindFullData;
+
+static void
+hex_document_find_full_data_free (HexDocumentFindFullData *full_data)
+{
+ g_clear_pointer (&full_data->find_data, g_free);
+ g_free (full_data);
+}
/* HexChangeData GType Definitions */
@@ -1095,6 +1109,93 @@ hex_document_export_html (HexDocument *doc,
return TRUE;
}
+static int
+hex_document_compare_data_full (HexDocument *doc,
+ HexDocumentFindData *find_data,
+ HexSearchFlags flags,
+ gint64 pos)
+{
+ char *cp = 0;
+ GError *local_error = NULL;
+ int retval = 1; /* match will make it zero, so set it non-zero now. */
+
+ g_return_val_if_fail (find_data, 0);
+ g_return_val_if_fail (find_data->what, 0);
+
+ if (flags & HEX_SEARCH_REGEX)
+ {
+ GRegex *regex;
+ GMatchInfo *match_info;
+ char *regex_search_str;
+
+ /* GRegex doesn't let you specify the length of the search string, so
+ * it needs to be NULL-terminated.
+ */
+ regex_search_str = g_malloc (find_data->len+1);
+
+ memcpy (regex_search_str, find_data->what, find_data->len);
+ regex_search_str[find_data->len] = 0;
+
+ cp = hex_buffer_get_data (doc->buffer, pos, REGEX_SEARCH_LEN);
+
+ regex = g_regex_new (regex_search_str,
+ G_REGEX_RAW,
+ G_REGEX_MATCH_ANCHORED,
+ &local_error);
+
+ g_free (regex_search_str);
+
+ /* sanity check */
+ if (!regex || local_error)
+ {
+ g_debug ("%s: error: %s", __func__, local_error->message);
+ goto out;
+ }
+
+ if (g_regex_match_full (regex, cp,
+ REGEX_SEARCH_LEN, /* length of string being searched */
+ 0, /* start pos */
+ 0, /* addl match_options */
+ &match_info,
+ &local_error))
+ {
+ char *word = g_match_info_fetch (match_info, 0);
+
+ g_debug ("Found: %s", word);
+ find_data->len = strlen (word);
+ g_free (word);
+ retval = 0;
+ }
+ else
+ {
+ if (local_error)
+ {
+ g_debug ("%s: error: %s",
+ __func__,
+ local_error ? local_error->message : NULL);
+ }
+ retval = 1;
+ }
+ }
+ else
+ {
+ cp = hex_buffer_get_data (doc->buffer, pos, find_data->len);
+
+ if (flags & HEX_SEARCH_IGNORE_CASE)
+ {
+ retval = g_ascii_strncasecmp (cp, find_data->what, find_data->len);
+ }
+ else
+ {
+ retval = memcmp (cp, find_data->what, find_data->len);
+ }
+ }
+out:
+ g_clear_error (&local_error);
+ g_free (cp);
+ return retval;
+}
+
/**
* hex_document_compare_data:
* @doc: a [class@Hex.Document] object
@@ -1110,19 +1211,42 @@ int
hex_document_compare_data (HexDocument *doc,
const char *what, gint64 pos, size_t len)
{
- char c;
+ int retval;
+ HexDocumentFindData *find_data = g_new0 (HexDocumentFindData, 1);
- g_return_val_if_fail (what, 0);
+ find_data->what = what;
+ find_data->len = len;
- for (size_t i = 0; i < len; i++, what++)
- {
- c = hex_buffer_get_byte (doc->buffer, pos + i);
+ retval = hex_document_compare_data_full (doc, find_data, HEX_SEARCH_NONE,
+ pos);
+ g_free (find_data);
+
+ return retval;
+}
- if (c != *what)
- return (c - *what);
+gboolean
+hex_document_find_forward_full (HexDocument *doc,
+ HexDocumentFindData *find_data,
+ HexSearchFlags flags)
+{
+ gint64 pos;
+ gint64 payload = hex_buffer_get_payload_size (
+ hex_document_get_buffer (doc));
+
+ g_return_val_if_fail (find_data != NULL, FALSE);
+
+ pos = find_data->start;
+ while (pos < payload)
+ {
+ if (hex_document_compare_data_full (doc, find_data, flags, pos) == 0)
+ {
+ find_data->offset = pos;
+ return TRUE;
+ }
+ pos++;
}
-
- return 0;
+
+ return FALSE;
}
/**
@@ -1148,22 +1272,19 @@ gboolean
hex_document_find_forward (HexDocument *doc, gint64 start, const char *what,
size_t len, gint64 *offset)
{
- gint64 pos;
- gint64 payload = hex_buffer_get_payload_size (
- hex_document_get_buffer (doc));
+ gboolean retval;
+ HexDocumentFindData *find_data = g_new0 (HexDocumentFindData, 1);
- pos = start;
- while (pos < payload)
- {
- if (hex_document_compare_data (doc, what, pos, len) == 0)
- {
- *offset = pos;
- return TRUE;
- }
- pos++;
- }
+ find_data->start = start;
+ find_data->what = what;
+ find_data->len = len;
- return FALSE;
+ retval = hex_document_find_forward_full (doc, find_data, HEX_SEARCH_NONE);
+ *offset = find_data->offset;
+
+ g_free (find_data);
+
+ return retval;
}
/**
@@ -1185,6 +1306,27 @@ hex_document_find_finish (HexDocument *doc,
return g_task_propagate_pointer (G_TASK(result), NULL);
}
+#define FIND_FULL_THREAD_TEMPLATE(FUNC_NAME, FUNC_TO_CALL) \
+static void \
+FUNC_NAME (GTask *task, \
+ gpointer source_object, \
+ gpointer task_data, \
+ GCancellable *cancellable) \
+{ \
+ HexDocument *doc = HEX_DOCUMENT (source_object); \
+ HexDocumentFindFullData *full_data = task_data; \
+ HexDocumentFindData *find_data = full_data->find_data; \
+ \
+ g_return_if_fail (find_data); \
+ \
+ find_data->found = FUNC_TO_CALL (doc, find_data, full_data->flags); \
+ \
+ g_task_return_pointer (task, find_data, g_free); \
+}
+
+FIND_FULL_THREAD_TEMPLATE(hex_document_find_forward_full_thread,
+ hex_document_find_forward_full)
+
static void
hex_document_find_forward_thread (GTask *task,
gpointer source_object,
@@ -1201,6 +1343,34 @@ hex_document_find_forward_thread (GTask *task,
g_task_return_pointer (task, find_data, g_free);
}
+#define FIND_FULL_ASYNC_TEMPLATE(FUNC_NAME, FUNC_TO_CALL) \
+void \
+FUNC_NAME (HexDocument *doc, \
+ HexDocumentFindData *find_data, \
+ HexSearchFlags flags, \
+ GCancellable *cancellable, \
+ GAsyncReadyCallback callback, \
+ gpointer user_data) \
+{ \
+ GTask *task; \
+ HexDocumentFindFullData *full_data = g_new0 (HexDocumentFindFullData, 1); \
+ \
+ /* This is kind of gross, but we can't really do any better without \
+ * breaking libgtkhex-4.0 ABI \
+ */ \
+ full_data->find_data = find_data; \
+ full_data->flags = flags; \
+ \
+ task = g_task_new (doc, cancellable, callback, user_data); \
+ g_task_set_return_on_cancel (task, TRUE); \
+ g_task_set_task_data (task, full_data, \
+ (GDestroyNotify)hex_document_find_full_data_free); \
+ g_task_run_in_thread (task, FUNC_TO_CALL); \
+}
+
+FIND_FULL_ASYNC_TEMPLATE(hex_document_find_forward_full_async,
+ hex_document_find_forward_full_thread)
+
/* CROSSREF: hex-document.h - HexDocumentFindData */
/**
* hex_document_find_forward_async:
@@ -1221,31 +1391,57 @@ hex_document_find_forward_thread (GTask *task,
* function that should generally be used by a GUI client to find a string
* forwards in a #HexDocument.
*/
-void
-hex_document_find_forward_async (HexDocument *doc,
- gint64 start,
- const char *what,
- size_t len,
- gint64 *offset,
- const char *found_msg,
- const char *not_found_msg,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+
+#define FIND_ASYNC_TEMPLATE(FUNC_NAME, FUNC_TO_CALL) \
+void \
+FUNC_NAME (HexDocument *doc, \
+ gint64 start, \
+ const char *what, \
+ size_t len, \
+ gint64 *offset, \
+ const char *found_msg, \
+ const char *not_found_msg, \
+ GCancellable *cancellable, \
+ GAsyncReadyCallback callback, \
+ gpointer user_data) \
+{ \
+ GTask *task; \
+ HexDocumentFindData *find_data = g_new0 (HexDocumentFindData, 1); \
+ \
+ find_data->start = start; \
+ find_data->what = what; \
+ find_data->len = len; \
+ find_data->found_msg = found_msg; \
+ find_data->not_found_msg = not_found_msg; \
+ \
+ task = g_task_new (doc, cancellable, callback, user_data); \
+ g_task_set_return_on_cancel (task, TRUE); \
+ g_task_set_task_data (task, find_data, g_free); \
+ g_task_run_in_thread (task, FUNC_TO_CALL); \
+}
+
+FIND_ASYNC_TEMPLATE(hex_document_find_forward_async,
+ hex_document_find_forward_thread)
+
+gboolean
+hex_document_find_backward_full (HexDocument *doc,
+ HexDocumentFindData *find_data,
+ HexSearchFlags flags)
{
- GTask *task;
- HexDocumentFindData *find_data = g_new0 (HexDocumentFindData, 1);
+ gint64 pos = find_data->start;
+
+ if (pos == 0)
+ return FALSE;
- find_data->start = start;
- find_data->what = what;
- find_data->len = len;
- find_data->found_msg = found_msg;
- find_data->not_found_msg = not_found_msg;
+ do {
+ pos--;
+ if (hex_document_compare_data_full (doc, find_data, flags, pos) == 0) {
+ find_data->offset = pos;
+ return TRUE;
+ }
+ } while (pos > 0);
- task = g_task_new (doc, cancellable, callback, user_data);
- g_task_set_return_on_cancel (task, TRUE);
- g_task_set_task_data (task, find_data, g_free);
- g_task_run_in_thread (task, hex_document_find_forward_thread);
+ return FALSE;
}
/**
@@ -1271,22 +1467,24 @@ gboolean
hex_document_find_backward (HexDocument *doc, gint64 start, const char *what,
size_t len, gint64 *offset)
{
- gint64 pos = start;
-
- if (pos == 0)
- return FALSE;
+ gboolean retval;
+ HexDocumentFindData *find_data = g_new0 (HexDocumentFindData, 1);
- do {
- pos--;
- if (hex_document_compare_data (doc, what, pos, len) == 0) {
- *offset = pos;
- return TRUE;
- }
- } while (pos > 0);
+ find_data->start = start;
+ find_data->what = what;
+ find_data->len = len;
- return FALSE;
+ retval = hex_document_find_backward_full (doc, find_data, HEX_SEARCH_NONE);
+ *offset = find_data->offset;
+
+ g_free (find_data);
+
+ return retval;
}
+FIND_FULL_THREAD_TEMPLATE(hex_document_find_backward_full_thread,
+ hex_document_find_backward_full)
+
static void
hex_document_find_backward_thread (GTask *task,
gpointer source_object,
@@ -1303,6 +1501,9 @@ hex_document_find_backward_thread (GTask *task,
g_task_return_pointer (task, find_data, g_free);
}
+FIND_FULL_ASYNC_TEMPLATE(hex_document_find_backward_full_async,
+ hex_document_find_backward_full_thread)
+
/**
* hex_document_find_backward_async:
* @doc: a [class@Hex.Document] object
@@ -1322,32 +1523,8 @@ hex_document_find_backward_thread (GTask *task,
* function that should generally be used by a GUI client to find a string
* backwards in a #HexDocument.
*/
-void
-hex_document_find_backward_async (HexDocument *doc,
- gint64 start,
- const char *what,
- size_t len,
- gint64 *offset,
- const char *found_msg,
- const char *not_found_msg,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GTask *task;
- HexDocumentFindData *find_data = g_new0 (HexDocumentFindData, 1);
-
- find_data->start = start;
- find_data->what = what;
- find_data->len = len;
- find_data->found_msg = found_msg;
- find_data->not_found_msg = not_found_msg;
-
- task = g_task_new (doc, cancellable, callback, user_data);
- g_task_set_return_on_cancel (task, TRUE);
- g_task_set_task_data (task, find_data, g_free);
- g_task_run_in_thread (task, hex_document_find_backward_thread);
-}
+FIND_ASYNC_TEMPLATE(hex_document_find_backward_async,
+ hex_document_find_backward_thread)
/**
* hex_document_undo:
diff --git a/src/hex-document.h b/src/hex-document.h
index 41f09f4..20ec536 100644
--- a/src/hex-document.h
+++ b/src/hex-document.h
@@ -55,6 +55,13 @@ typedef enum
HEX_CHANGE_BYTE
} HexChangeType;
+typedef enum
+{
+ HEX_SEARCH_NONE = 0,
+ HEX_SEARCH_REGEX = 1 << 0,
+ HEX_SEARCH_IGNORE_CASE = 1 << 1,
+} HexSearchFlags;
+
/**
* HexDocumentFindData:
* @found: whether the string was found
@@ -161,18 +168,32 @@ int hex_document_compare_data (HexDocument *doc, const char *what,
gint64 pos, size_t len);
gboolean hex_document_find_forward (HexDocument *doc, gint64 start,
const char *what, size_t len, gint64 *offset);
+gboolean hex_document_find_forward_full (HexDocument *doc,
+ HexDocumentFindData *find_data,
+ HexSearchFlags flags);
void hex_document_find_forward_async (HexDocument *doc, gint64 start,
const char *what, size_t len, gint64 *offset, const char *found_msg,
const char *not_found_msg, GCancellable *cancellable,
GAsyncReadyCallback callback, gpointer user_data);
+void hex_document_find_forward_full_async (HexDocument *doc,
+ HexDocumentFindData *find_data, HexSearchFlags flags,
+ GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+
gboolean hex_document_find_backward (HexDocument *doc, gint64 start,
const char *what, size_t len, gint64 *offset);
+
+gboolean hex_document_find_backward_full (HexDocument *doc,
+ HexDocumentFindData *find_data,
+ HexSearchFlags flags);
void hex_document_find_backward_async (HexDocument *doc, gint64 start,
const char *what, size_t len, gint64 *offset, const char *found_msg,
const char *not_found_msg, GCancellable *cancellable,
GAsyncReadyCallback callback, gpointer user_data);
+void hex_document_find_backward_full_async (HexDocument *doc,
+ HexDocumentFindData *find_data, HexSearchFlags flags,
+ GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
HexDocumentFindData *
hex_document_find_finish (HexDocument *doc, GAsyncResult *result);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]