[ghex/expand-search-options: 5/12] Add new HexDocument API to expand search options




commit b2ba3a5ef31f9740615a1b5db72db1c34464758d
Author: Logan Rathbone <poprocks gmail com>
Date:   Tue Apr 19 19:37:29 2022 -0400

    Add new HexDocument API to expand search options

 src/hex-document.c | 330 +++++++++++++++++++++++++++++++++++++++--------------
 src/hex-document.h |  23 ++++
 2 files changed, 269 insertions(+), 84 deletions(-)
---
diff --git a/src/hex-document.c b/src/hex-document.c
index f47ed66..fdd7f97 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,7 +84,6 @@ hex_document_find_data_copy (HexDocumentFindData *data)
 G_DEFINE_BOXED_TYPE (HexDocumentFindData, hex_document_find_data,
                hex_document_find_data_copy, g_free)
 
-
 /* HexChangeData GType Definitions */
 
 /* FIXME - unused and could be unreliable */
@@ -1095,6 +1095,101 @@ hex_document_export_html (HexDocument *doc,
        return TRUE;
 }
 
+int
+hex_document_compare_data_full (HexDocument *doc,
+               HexDocumentFindData *find_data,
+               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 (find_data->flags & HEX_SEARCH_REGEX)
+       {
+               GRegex *regex;
+               GMatchInfo *match_info;
+               char *regex_search_str;
+               GRegexCompileFlags regex_compile_flags;
+
+               /* 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;
+
+               /* match string doesn't have to be UTF-8 */
+               regex_compile_flags = G_REGEX_RAW;
+
+               if (find_data->flags & HEX_SEARCH_IGNORE_CASE)
+                       regex_compile_flags |= G_REGEX_CASELESS;
+
+               regex = g_regex_new (regex_search_str,
+                               regex_compile_flags,
+                               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;
+               }
+
+               cp = hex_buffer_get_data (doc->buffer, pos, REGEX_SEARCH_LEN);
+
+               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->found_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    /* non regex */
+       {
+               cp = hex_buffer_get_data (doc->buffer, pos, find_data->len);
+
+               if (find_data->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);
+               }
+
+               if (retval == 0)
+                       find_data->found_len = 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 +1205,41 @@ 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;
+       find_data->flags = HEX_SEARCH_NONE;
 
-       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, pos);
+       g_free (find_data);
+
+       return retval;
+}
+
+gboolean
+hex_document_find_forward_full (HexDocument *doc,
+               HexDocumentFindData *find_data)
+{
+       gint64 pos;
+       gint64 payload = hex_buffer_get_payload_size (
+                       hex_document_get_buffer (doc));
 
-               if (c != *what)
-                       return (c - *what);
+       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, pos) == 0)
+               {
+                       find_data->offset = pos;
+                       return TRUE;
+               }
+               pos++;
        }
-       
-       return 0;
+
+       return FALSE;
 }
 
 /**
@@ -1148,22 +1265,20 @@ 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;
+       find_data->flags = HEX_SEARCH_NONE;
 
-       return FALSE;
+       retval = hex_document_find_forward_full (doc, find_data);
+       *offset = find_data->offset;
+
+       g_free (find_data);
+
+       return retval;
 }
 
 /**
@@ -1185,6 +1300,26 @@ 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); \
+       HexDocumentFindData *find_data = task_data; \
+ \
+       g_return_if_fail (find_data); \
+ \
+       find_data->found = FUNC_TO_CALL (doc, find_data); \
+ \
+       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 +1336,25 @@ 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, \
+               GCancellable *cancellable, \
+               GAsyncReadyCallback callback, \
+               gpointer user_data) \
+{ \
+       GTask *task; \
+ \
+       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_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 +1375,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); \
+       g_object_unref (task);  /* _run_in_thread takes a ref */ \
+}
+
+FIND_ASYNC_TEMPLATE(hex_document_find_forward_async,
+               hex_document_find_forward_thread)
+
+gboolean
+hex_document_find_backward_full (HexDocument *doc,
+               HexDocumentFindData *find_data)
 {
-       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, 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 +1451,25 @@ 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;
+       find_data->flags = HEX_SEARCH_NONE;
 
-       return FALSE;
+       retval = hex_document_find_backward_full (doc, find_data);
+       *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 +1486,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 +1508,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..1dc238c 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
@@ -80,7 +87,9 @@ typedef struct
        gint64 start;
        const char *what;
        size_t len;
+       HexSearchFlags flags;   /* TODO: Since: 4.1 */
        gint64 offset;
+       size_t found_len;               /* TODO: Since: 4.1 */
        const char *found_msg;
        const char *not_found_msg;
 } HexDocumentFindData;
@@ -159,20 +168,34 @@ gboolean  hex_document_undo (HexDocument *doc);
 gboolean       hex_document_redo (HexDocument *doc);
 int                    hex_document_compare_data (HexDocument *doc, const char *what,
                gint64 pos, size_t len);
+int                    hex_document_compare_data_full (HexDocument *doc,
+               HexDocumentFindData *find_data, gint64 pos);
 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);
 
 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, 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);
 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, 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]