diff --git a/.gitignore b/.gitignore index 7b88e1d..b21b841 100644 --- a/.gitignore +++ b/.gitignore @@ -64,3 +64,4 @@ evince-3.0.0.tar.bz2 /evince-3.22.0.tar.xz /evince-3.22.1.tar.xz /evince-3.24.0.tar.xz +/evince-3.25.4.tar.xz diff --git a/0001-Resolves-rhbz-1404656-crash-on-opening-second-evince.patch b/0001-Resolves-rhbz-1404656-crash-on-opening-second-evince.patch deleted file mode 100644 index 7fae308..0000000 --- a/0001-Resolves-rhbz-1404656-crash-on-opening-second-evince.patch +++ /dev/null @@ -1,77 +0,0 @@ -From ca83dd9054abdaae93308f27bdf927e050230027 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= -Date: Tue, 10 Jan 2017 12:04:58 +0000 -Subject: [PATCH] Resolves: rhbz#1404656 crash on opening second evince window - -e.g. - -export G_SLICE=always-malloc -open https://www.antennahouse.com/XSLsample/pdf/sample-link_1.pdf -right click on the first link and open in new window -close the new window -repeat -crash - -This is similar to https://bugzilla.gnome.org/show_bug.cgi?id=726812 ---- - shell/ev-window.c | 34 ++++++++++++++++++++++++---------- - 1 file changed, 24 insertions(+), 10 deletions(-) - -diff --git a/shell/ev-window.c b/shell/ev-window.c -index 11f2fd5..a648ed7 100644 ---- a/shell/ev-window.c -+++ b/shell/ev-window.c -@@ -6666,10 +6666,32 @@ _gtk_css_provider_load_from_resource (GtkCssProvider *provider, - } - - static void -+ev_window_init_css (void) -+{ -+ static gsize initialization_value = 0; -+ -+ if (g_once_init_enter (&initialization_value)) { -+ GtkCssProvider *css_provider; -+ GError *error = NULL; -+ -+ css_provider = gtk_css_provider_new (); -+ _gtk_css_provider_load_from_resource (css_provider, -+ "/org/gnome/evince/ui/evince.css", -+ &error); -+ g_assert_no_error (error); -+ gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), -+ GTK_STYLE_PROVIDER (css_provider), -+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); -+ g_object_unref (css_provider); -+ -+ g_once_init_leave (&initialization_value, 1); -+ } -+} -+ -+static void - ev_window_init (EvWindow *ev_window) - { - GtkBuilder *builder; -- GtkCssProvider *css_provider; - GError *error = NULL; - GtkWidget *sidebar_widget; - GtkWidget *overlay; -@@ -6748,15 +6770,7 @@ ev_window_init (EvWindow *ev_window) - actions, G_N_ELEMENTS (actions), - ev_window); - -- css_provider = gtk_css_provider_new (); -- _gtk_css_provider_load_from_resource (css_provider, -- "/org/gnome/evince/ui/evince.css", -- &error); -- g_assert_no_error (error); -- gtk_style_context_add_provider_for_screen (gtk_widget_get_screen (GTK_WIDGET (ev_window)), -- GTK_STYLE_PROVIDER (css_provider), -- GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); -- g_object_unref (css_provider); -+ ev_window_init_css (); - - ev_window->priv->recent_manager = gtk_recent_manager_get_default (); - --- -2.9.3 - diff --git a/0001-sidebar-thumbnails-fix-clunky-scrolling.patch b/0001-sidebar-thumbnails-fix-clunky-scrolling.patch deleted file mode 100644 index 6d7aecc..0000000 --- a/0001-sidebar-thumbnails-fix-clunky-scrolling.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 6480c7039bdf7e8f15f7d1415460db255910c40b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Nelson=20Ben=C3=ADtez=20Le=C3=B3n?= - -Date: Sun, 28 May 2017 22:35:05 +0500 -Subject: [PATCH] sidebar-thumbnails: fix clunky scrolling - -Caused by GtkIconView doing an invalidate and relayout of *all* -items in the view anytime we update model data in any indiviual -item (which happens with all the items that are getting in and out -of the scrolling area while we scroll). This caused GtkIconView to -machine-gunned us with "size-allocate" signals, a signal we were -using to update thumbnails when the sidebar is resized. - -Fixed by connecting to the GtkTreeModel "row-changed" signal before -GtkIconView does it, and stop emission from there. - -As we don't depend now on "size-allocate" signals to show thumbnails -while we scroll, just queue a draw on the icon view when a -thumbnail finish rendering. - -Thanks Jose Aliste for first spotting the problem. - -https://bugzilla.gnome.org/show_bug.cgi?id=691448 ---- - shell/ev-sidebar-thumbnails.c | 24 ++++++++++++++++++++++++ - 1 file changed, 24 insertions(+) - -diff --git a/shell/ev-sidebar-thumbnails.c b/shell/ev-sidebar-thumbnails.c -index 253eabf..c22e92e 100644 ---- a/shell/ev-sidebar-thumbnails.c -+++ b/shell/ev-sidebar-thumbnails.c -@@ -802,9 +802,26 @@ ev_sidebar_thumbnails_device_scale_factor_changed_cb (EvSidebarThumbnails *sideb - } - - static void -+ev_sidebar_thumbnails_row_changed (GtkTreeModel *model, -+ GtkTreePath *path, -+ GtkTreeIter *iter, -+ gpointer data) -+{ -+ guint signal_id; -+ -+ signal_id = GPOINTER_TO_UINT (data); -+ -+ /* PREVENT GtkIconView "row-changed" handler to be reached, as it will -+ * perform a full invalidate and relayout of all items, See bug: -+ * https://bugzilla.gnome.org/show_bug.cgi?id=691448#c9 */ -+ g_signal_stop_emission (model, signal_id, 0); -+} -+ -+static void - ev_sidebar_thumbnails_init (EvSidebarThumbnails *ev_sidebar_thumbnails) - { - EvSidebarThumbnailsPrivate *priv; -+ guint signal_id; - - priv = ev_sidebar_thumbnails->priv = EV_SIDEBAR_THUMBNAILS_GET_PRIVATE (ev_sidebar_thumbnails); - -@@ -814,6 +831,11 @@ ev_sidebar_thumbnails_init (EvSidebarThumbnails *ev_sidebar_thumbnails) - G_TYPE_BOOLEAN, - EV_TYPE_JOB_THUMBNAIL); - -+ signal_id = g_signal_lookup ("row-changed", GTK_TYPE_TREE_MODEL); -+ g_signal_connect (GTK_TREE_MODEL (priv->list_store), "row-changed", -+ G_CALLBACK (ev_sidebar_thumbnails_row_changed), -+ GUINT_TO_POINTER (signal_id)); -+ - priv->swindow = gtk_scrolled_window_new (NULL, NULL); - - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->swindow), -@@ -962,6 +984,8 @@ thumbnail_job_completed_callback (EvJobThumbnail *job, - COLUMN_JOB, NULL, - -1); - cairo_surface_destroy (surface); -+ -+ gtk_widget_queue_draw (priv->icon_view); - } - - static void --- -2.9.3 - diff --git a/evince-libarchive-gnome-3-24.patch b/evince-libarchive-gnome-3-24.patch deleted file mode 100644 index 3dc9f34..0000000 --- a/evince-libarchive-gnome-3-24.patch +++ /dev/null @@ -1,11479 +0,0 @@ -From 275560fc30cf3fc3bf630941dd70b04e771c05f5 Mon Sep 17 00:00:00 2001 -From: Bastien Nocera -Date: Thu, 29 Jan 2015 16:54:21 +0100 -Subject: [PATCH 01/10] comics: Port to using libarchive for unarchiving - -v8: -- Fix double-free in error path when decompressing images - -v7: -- Bump buffer size in ev-archive, good performance increase for - local files - -v6: -- Fix 2 pretty big memory leaks -- Remove unneeded archive_read_data_skip() calls -- Optimise the "no rotation" case (could also be done for gnome-3-24) -- Use render_pixbuf_size_prepared_cb() -- Add debug to "next header" archive calls - -v5: -- Remove unused members of ComicsDocument struct -- Split archive handling into an EvArchive object -- Fix copy/paste error in configure.ac - -v4: -- Fix crash caused by a bug in comics_document_list() - (the array was not NULL terminated) -- Remove duplicate "!cb_files" check -- Use "size-prepared" instead of "area-prepared" to get the doc size -- Fix link to libarchive bug in code, not working yet :/ - -v3: -- Rebase against latest evince, making sure to bring back: - - Use Unicode in translatable strings - - Sort pages in natural order - - Fix mime-type comparisons -- https://github.com/libarchive/libarchive/issues/373 looks - like it's fixed! - -v2: -- Rebase against latest evince -- Update libarchive bug URL - -https://bugzilla.gnome.org/show_bug.cgi?id=720742 ---- - backend/comics/Makefile.am | 6 +- - backend/comics/comics-document.c | 841 ++++++++++----------------------------- - backend/comics/ev-archive.c | 277 +++++++++++++ - backend/comics/ev-archive.h | 47 +++ - configure.ac | 12 +- - 5 files changed, 560 insertions(+), 623 deletions(-) - create mode 100644 backend/comics/ev-archive.c - create mode 100644 backend/comics/ev-archive.h - -diff --git a/backend/comics/Makefile.am b/backend/comics/Makefile.am -index b047ad36..856f469c 100644 ---- a/backend/comics/Makefile.am -+++ b/backend/comics/Makefile.am -@@ -2,7 +2,9 @@ backend_LTLIBRARIES = libcomicsdocument.la - - libcomicsdocument_la_SOURCES = \ - comics-document.c \ -- comics-document.h -+ comics-document.h \ -+ ev-archive.c \ -+ ev-archive.h - - libcomicsdocument_la_CPPFLAGS = \ - -I$(top_srcdir) \ -@@ -13,12 +15,14 @@ libcomicsdocument_la_CPPFLAGS = \ - - libcomicsdocument_la_CFLAGS = \ - $(BACKEND_CFLAGS) \ -+ $(LIBARCHIVE_CFLAGS) \ - $(LIB_CFLAGS) \ - $(AM_CFLAGS) - - libcomicsdocument_la_LDFLAGS = $(BACKEND_LIBTOOL_FLAGS) - libcomicsdocument_la_LIBADD = \ - $(top_builddir)/libdocument/libevdocument3.la \ -+ $(LIBARCHIVE_LIBS) \ - $(BACKEND_LIBS) \ - $(LIB_LIBS) - -diff --git a/backend/comics/comics-document.c b/backend/comics/comics-document.c -index 4c747310..b55c25b3 100644 ---- a/backend/comics/comics-document.c -+++ b/backend/comics/comics-document.c -@@ -2,6 +2,7 @@ - /* - * Copyright (C) 2009-2010 Juanjo Marín - * Copyright (C) 2005, Teemu Tervo -+ * Copyright (C) 2016-2017, Bastien Nocera - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -30,35 +31,12 @@ - #include - #include - --#ifdef G_OS_WIN32 --# define WIFEXITED(x) ((x) != 3) --# define WEXITSTATUS(x) (x) --#else --# include --#endif -- - #include "comics-document.h" - #include "ev-document-misc.h" - #include "ev-file-helpers.h" -+#include "ev-archive.h" - --#ifdef G_OS_WIN32 --/* On windows g_spawn_command_line_sync reads stdout in O_BINARY mode, not in O_TEXT mode. -- * As a consequence, newlines are in a platform dependent representation (\r\n). This -- * might be considered a bug in glib. -- */ --#define EV_EOL "\r\n" --#else --#define EV_EOL "\n" --#endif -- --typedef enum --{ -- RARLABS, -- GNAUNRAR, -- UNZIP, -- P7ZIP, -- TAR --} ComicBookDecompressType; -+#define BLOCK_SIZE 10240 - - typedef struct _ComicsDocumentClass ComicsDocumentClass; - -@@ -69,383 +47,98 @@ struct _ComicsDocumentClass - - struct _ComicsDocument - { -- EvDocument parent_instance; -- -- gchar *archive, *dir; -- GPtrArray *page_names; -- gchar *selected_command, *alternative_command; -- gchar *extract_command, *list_command, *decompress_tmp; -- gboolean regex_arg; -- gint offset; -- ComicBookDecompressType command_usage; --}; -- --#define OFFSET_7Z 53 --#define OFFSET_ZIP 2 --#define NO_OFFSET 0 -- --/* For perfomance reasons of 7z* we've choosen to decompress on the temporary -- * directory instead of decompressing on the stdout */ -- --/** -- * @extract: command line arguments to pass to extract a file from the archive -- * to stdout. -- * @list: command line arguments to list the archive contents -- * @decompress_tmp: command line arguments to pass to extract the archive -- * into a directory. -- * @regex_arg: whether the command can accept regex expressions -- * @offset: the position offset of the filename on each line in the output of -- * running the @list command -- */ --typedef struct { -- char *extract; -- char *list; -- char *decompress_tmp; -- gboolean regex_arg; -- gint offset; --} ComicBookDecompressCommand; -- --static const ComicBookDecompressCommand command_usage_def[] = { -- /* RARLABS unrar */ -- {"%s p -c- -ierr --", "%s vb -c- -- %s", NULL , FALSE, NO_OFFSET}, -- -- /* GNA! unrar */ -- {NULL , "%s t %s" , "%s -xf %s %s" , FALSE, NO_OFFSET}, -- -- /* unzip */ -- {"%s -p -C --" , "%s %s" , NULL , TRUE , OFFSET_ZIP}, -- -- /* 7zip */ -- {NULL , "%s l -- %s" , "%s x -y %s -o%s", FALSE, OFFSET_7Z}, -- -- /* tar */ -- {"%s -xOf" , "%s -tf %s" , NULL , FALSE, NO_OFFSET} -+ EvDocument parent_instance; -+ EvArchive *a; -+ EvArchiveType a_type; -+ gchar *archive_path; -+ gchar *archive_uri; -+ GPtrArray *page_names; - }; - - static GSList* get_supported_image_extensions (void); --static void get_page_size_area_prepared_cb (GdkPixbufLoader *loader, -- gpointer data); -+static void get_page_size_prepared_cb (GdkPixbufLoader *loader, -+ int width, -+ int height, -+ gpointer data); - static void render_pixbuf_size_prepared_cb (GdkPixbufLoader *loader, - gint width, - gint height, - EvRenderContext *rc); --static char** extract_argv (EvDocument *document, -- gint page); -- - - EV_BACKEND_REGISTER (ComicsDocument, comics_document) - --/** -- * comics_regex_quote: -- * @unquoted_string: a literal string -- * -- * Quotes a string so unzip will not interpret the regex expressions of -- * @unquoted_string. Basically, this functions uses [] to disable regex -- * expressions. The return value must be freed with * g_free() -- * -- * Return value: quoted and disabled-regex string -- **/ --static gchar * --comics_regex_quote (const gchar *unquoted_string) -+static void -+comics_document_reset_archive (ComicsDocument *comics_document) - { -- const gchar *p; -- GString *dest; -- -- dest = g_string_new ("'"); -- -- p = unquoted_string; -- -- while (*p) { -- switch (*p) { -- /* * matches a sequence of 0 or more characters */ -- case ('*'): -- /* ? matches exactly 1 charactere */ -- case ('?'): -- /* [...] matches any single character found inside -- * the brackets. Disabling the first bracket is enough. -- */ -- case ('['): -- g_string_append (dest, "["); -- g_string_append_c (dest, *p); -- g_string_append (dest, "]"); -- break; -- /* Because \ escapes regex expressions that we are -- * disabling for unzip, we need to disable \ too */ -- case ('\\'): -- g_string_append (dest, "[\\\\]"); -- break; -- /* Escape single quote inside the string */ -- case ('\''): -- g_string_append (dest, "'\\''"); -- break; -- default: -- g_string_append_c (dest, *p); -- break; -- } -- ++p; -- } -- g_string_append_c (dest, '\''); -- return g_string_free (dest, FALSE); -+ g_clear_object (&comics_document->a); -+ comics_document->a = ev_archive_new (); -+ ev_archive_set_archive_type (comics_document->a, comics_document->a_type); - } - -- --/* This function manages the command for decompressing a comic book */ --static gboolean --comics_decompress_temp_dir (const gchar *command_decompress_tmp, -- const gchar *command, -- GError **error) -+static char ** -+comics_document_list (ComicsDocument *comics_document) - { -- gboolean success; -- gchar *std_out, *basename; -- GError *err = NULL; -- gint retval; -- -- success = g_spawn_command_line_sync (command_decompress_tmp, &std_out, -- NULL, &retval, &err); -- basename = g_path_get_basename (command); -- if (!success) { -- g_set_error (error, -- EV_DOCUMENT_ERROR, -- EV_DOCUMENT_ERROR_INVALID, -- _("Error launching the command “%s” in order to " -- "decompress the comic book: %s"), -- basename, -- err->message); -- g_error_free (err); -- } else if (WIFEXITED (retval)) { -- if (WEXITSTATUS (retval) == EXIT_SUCCESS) { -- g_free (std_out); -- g_free (basename); -- return TRUE; -- } else { -- g_set_error (error, -- EV_DOCUMENT_ERROR, -- EV_DOCUMENT_ERROR_INVALID, -- _("The command “%s” failed at " -- "decompressing the comic book."), -- basename); -- g_free (std_out); -+ char **ret = NULL; -+ GPtrArray *array; -+ -+ if (!ev_archive_open_filename (comics_document->a, comics_document->archive_path, NULL)) -+ goto out; -+ -+ array = g_ptr_array_new (); -+ -+ while (1) { -+ const char *name; -+ GError *error = NULL; -+ -+ if (!ev_archive_read_next_header (comics_document->a, &error)) { -+ if (error != NULL) { -+ g_warning ("Fatal error handling archive: %s", error->message); -+ g_error_free (error); -+ } -+ break; - } -- } else { -- g_set_error (error, -- EV_DOCUMENT_ERROR, -- EV_DOCUMENT_ERROR_INVALID, -- _("The command “%s” did not end normally."), -- basename); -- g_free (std_out); -- } -- g_free (basename); -- return FALSE; --} - --/* This function shows how to use the chosen command for decompressing a -- * comic book file. It modifies fields of the ComicsDocument struct with -- * this information */ --#pragma GCC diagnostic push --#pragma GCC diagnostic ignored "-Wformat-nonliteral" --static gboolean --comics_generate_command_lines (ComicsDocument *comics_document, -- GError **error) --{ -- gchar *quoted_file, *quoted_file_aux; -- gchar *quoted_command; -- ComicBookDecompressType type; -- -- type = comics_document->command_usage; -- comics_document->regex_arg = command_usage_def[type].regex_arg; -- quoted_command = g_shell_quote (comics_document->selected_command); -- if (comics_document->regex_arg) { -- quoted_file = comics_regex_quote (comics_document->archive); -- quoted_file_aux = g_shell_quote (comics_document->archive); -- comics_document->list_command = -- g_strdup_printf (command_usage_def[type].list, -- comics_document->alternative_command, -- quoted_file_aux); -- g_free (quoted_file_aux); -- } else { -- quoted_file = g_shell_quote (comics_document->archive); -- comics_document->list_command = -- g_strdup_printf (command_usage_def[type].list, -- quoted_command, quoted_file); -+ name = ev_archive_get_entry_pathname (comics_document->a); -+ -+ g_debug ("Adding '%s' to the list of files in the comics", name); -+ g_ptr_array_add (array, g_strdup (name)); - } -- comics_document->extract_command = -- g_strdup_printf (command_usage_def[type].extract, -- quoted_command); -- comics_document->offset = command_usage_def[type].offset; -- if (command_usage_def[type].decompress_tmp) { -- comics_document->dir = ev_mkdtemp ("evince-comics-XXXXXX", error); -- if (comics_document->dir == NULL) -- return FALSE; -- -- /* unrar-free can't create directories, but ev_mkdtemp already created the dir */ -- -- comics_document->decompress_tmp = -- g_strdup_printf (command_usage_def[type].decompress_tmp, -- quoted_command, quoted_file, -- comics_document->dir); -- g_free (quoted_file); -- g_free (quoted_command); -- -- if (!comics_decompress_temp_dir (comics_document->decompress_tmp, -- comics_document->selected_command, error)) -- return FALSE; -- else -- return TRUE; -+ -+ if (array->len == 0) { -+ g_ptr_array_free (array, TRUE); - } else { -- g_free (quoted_file); -- g_free (quoted_command); -- return TRUE; -+ g_ptr_array_add (array, NULL); -+ ret = (char **) g_ptr_array_free (array, FALSE); - } - -+out: -+ comics_document_reset_archive (comics_document); -+ return ret; - } --#pragma GCC diagnostic pop - --/* This function chooses an external command for decompressing a comic -- * book based on its mime tipe. */ --static gboolean --comics_check_decompress_command (gchar *mime_type, -+/* This function chooses the archive decompression support -+ * book based on its mime type. */ -+static gboolean -+comics_check_decompress_support (gchar *mime_type, - ComicsDocument *comics_document, - GError **error) - { -- gboolean success; -- gchar *std_out, *std_err; -- gint retval; -- GError *err = NULL; -- -- /* FIXME, use proper cbr/cbz mime types once they're -- * included in shared-mime-info */ -- - if (g_content_type_is_a (mime_type, "application/x-cbr") || - g_content_type_is_a (mime_type, "application/x-rar")) { -- /* The RARLAB provides a no-charge proprietary (freeware) -- * decompress-only client for Linux called unrar. Another -- * option is a GPLv2-licensed command-line tool developed by -- * the Gna! project. Confusingly enough, the free software RAR -- * decoder is also named unrar. For this reason we need to add -- * some lines for disambiguation. Sorry for the added the -- * complexity but it's life :) -- * Finally, some distributions, like Debian, rename this free -- * option as unrar-free. -- * */ -- comics_document->selected_command = -- g_find_program_in_path ("unrar"); -- if (comics_document->selected_command) { -- /* We only use std_err to avoid printing useless error -- * messages on the terminal */ -- success = -- g_spawn_command_line_sync ( -- comics_document->selected_command, -- &std_out, &std_err, -- &retval, &err); -- if (!success) { -- g_propagate_error (error, err); -- g_error_free (err); -- return FALSE; -- /* I don't check retval status because RARLAB unrar -- * doesn't have a way to return 0 without involving an -- * operation with a file*/ -- } else if (WIFEXITED (retval)) { -- if (g_strrstr (std_out,"freeware") != NULL) -- /* The RARLAB freeware client */ -- comics_document->command_usage = RARLABS; -- else -- /* The Gna! free software client */ -- comics_document->command_usage = GNAUNRAR; -- -- g_free (std_out); -- g_free (std_err); -- return TRUE; -- } -- } -- /* The Gna! free software client with Debian naming convention */ -- comics_document->selected_command = -- g_find_program_in_path ("unrar-free"); -- if (comics_document->selected_command) { -- comics_document->command_usage = GNAUNRAR; -- return TRUE; -- } -- comics_document->selected_command = -- g_find_program_in_path ("bsdtar"); -- if (comics_document->selected_command) { -- comics_document->command_usage = TAR; -+ if (ev_archive_set_archive_type (comics_document->a, EV_ARCHIVE_TYPE_RAR)) - return TRUE; -- } -- - } else if (g_content_type_is_a (mime_type, "application/x-cbz") || - g_content_type_is_a (mime_type, "application/zip")) { -- /* InfoZIP's unzip program */ -- comics_document->selected_command = -- g_find_program_in_path ("unzip"); -- comics_document->alternative_command = -- g_find_program_in_path ("zipnote"); -- if (comics_document->selected_command && -- comics_document->alternative_command) { -- comics_document->command_usage = UNZIP; -- return TRUE; -- } -- /* fallback mode using 7za and 7z from p7zip project */ -- comics_document->selected_command = -- g_find_program_in_path ("7za"); -- if (comics_document->selected_command) { -- comics_document->command_usage = P7ZIP; -- return TRUE; -- } -- comics_document->selected_command = -- g_find_program_in_path ("7z"); -- if (comics_document->selected_command) { -- comics_document->command_usage = P7ZIP; -+ if (ev_archive_set_archive_type (comics_document->a, EV_ARCHIVE_TYPE_ZIP)) - return TRUE; -- } -- comics_document->selected_command = -- g_find_program_in_path ("bsdtar"); -- if (comics_document->selected_command) { -- comics_document->command_usage = TAR; -- return TRUE; -- } -- - } else if (g_content_type_is_a (mime_type, "application/x-cb7") || - g_content_type_is_a (mime_type, "application/x-7z-compressed")) { -- /* 7zr, 7za and 7z are the commands from the p7zip project able -- * to decompress .7z files */ -- comics_document->selected_command = -- g_find_program_in_path ("7zr"); -- if (comics_document->selected_command) { -- comics_document->command_usage = P7ZIP; -- return TRUE; -- } -- comics_document->selected_command = -- g_find_program_in_path ("7za"); -- if (comics_document->selected_command) { -- comics_document->command_usage = P7ZIP; -- return TRUE; -- } -- comics_document->selected_command = -- g_find_program_in_path ("7z"); -- if (comics_document->selected_command) { -- comics_document->command_usage = P7ZIP; -- return TRUE; -- } -- comics_document->selected_command = -- g_find_program_in_path ("bsdtar"); -- if (comics_document->selected_command) { -- comics_document->command_usage = TAR; -+ if (ev_archive_set_archive_type (comics_document->a, EV_ARCHIVE_TYPE_7Z)) - return TRUE; -- } - } else if (g_content_type_is_a (mime_type, "application/x-cbt") || - g_content_type_is_a (mime_type, "application/x-tar")) { -- /* tar utility (Tape ARchive) */ -- comics_document->selected_command = -- g_find_program_in_path ("tar"); -- if (comics_document->selected_command) { -- comics_document->command_usage = TAR; -+ if (ev_archive_set_archive_type (comics_document->a, EV_ARCHIVE_TYPE_TAR)) - return TRUE; -- } -- comics_document->selected_command = -- g_find_program_in_path ("bsdtar"); -- if (comics_document->selected_command) { -- comics_document->command_usage = TAR; -- return TRUE; -- } - } else { - g_set_error (error, - EV_DOCUMENT_ERROR, -@@ -457,8 +150,8 @@ comics_check_decompress_command (gchar *mime_type, - g_set_error_literal (error, - EV_DOCUMENT_ERROR, - EV_DOCUMENT_ERROR_INVALID, -- _("Can’t find an appropriate command to " -- "decompress this type of comic book")); -+ _("libarchive lacks support for this comic book’s " -+ "compression, please contact your distributor")); - return FALSE; - } - -@@ -487,56 +180,45 @@ comics_document_load (EvDocument *document, - { - ComicsDocument *comics_document = COMICS_DOCUMENT (document); - GSList *supported_extensions; -- gchar *std_out; - gchar *mime_type; - gchar **cb_files, *cb_file; -- gboolean success; -- int i, retval; -+ int i; - GError *err = NULL; -+ GFile *file; - -- comics_document->archive = g_filename_from_uri (uri, NULL, error); -- if (!comics_document->archive) -+ file = g_file_new_for_uri (uri); -+ comics_document->archive_path = g_file_get_path (file); -+ g_object_unref (file); -+ -+ if (!comics_document->archive_path) { -+ g_set_error_literal (error, -+ EV_DOCUMENT_ERROR, -+ EV_DOCUMENT_ERROR_INVALID, -+ _("Can not get local path for archive")); - return FALSE; -+ } -+ -+ comics_document->archive_uri = g_strdup (uri); - - mime_type = ev_file_get_mime_type (uri, FALSE, &err); - if (mime_type == NULL) - return FALSE; -- -- if (!comics_check_decompress_command (mime_type, comics_document, -- error)) { -+ -+ if (!comics_check_decompress_support (mime_type, comics_document, error)) { - g_free (mime_type); - return FALSE; -- } else if (!comics_generate_command_lines (comics_document, error)) { -- g_free (mime_type); -- return FALSE; - } -+ comics_document->a_type = ev_archive_get_archive_type (comics_document->a); - - g_free (mime_type); - - /* Get list of files in archive */ -- success = g_spawn_command_line_sync (comics_document->list_command, -- &std_out, NULL, &retval, error); -- -- if (!success) { -- return FALSE; -- } else if (!WIFEXITED(retval) || WEXITSTATUS(retval) != EXIT_SUCCESS) { -+ cb_files = comics_document_list (comics_document); -+ if (!cb_files) { - g_set_error_literal (error, - EV_DOCUMENT_ERROR, - EV_DOCUMENT_ERROR_INVALID, -- _("File corrupted")); -- return FALSE; -- } -- -- /* FIXME: is this safe against filenames containing \n in the archive ? */ -- cb_files = g_strsplit (std_out, EV_EOL, 0); -- -- g_free (std_out); -- -- if (!cb_files) { -- g_set_error_literal (error, -- EV_DOCUMENT_ERROR, -- EV_DOCUMENT_ERROR_INVALID, -- _("No files in archive")); -+ _("File corrupted or no files in archive")); - return FALSE; - } - -@@ -544,18 +226,7 @@ comics_document_load (EvDocument *document, - - supported_extensions = get_supported_image_extensions (); - for (i = 0; cb_files[i] != NULL; i++) { -- if (comics_document->offset != NO_OFFSET) { -- if (g_utf8_strlen (cb_files[i],-1) > -- comics_document->offset) { -- cb_file = -- g_utf8_offset_to_pointer (cb_files[i], -- comics_document->offset); -- } else { -- continue; -- } -- } else { -- cb_file = cb_files[i]; -- } -+ cb_file = cb_files[i]; - gchar *suffix = g_strrstr (cb_file, "."); - if (!suffix) - continue; -@@ -586,7 +257,6 @@ comics_document_load (EvDocument *document, - return TRUE; - } - -- - static gboolean - comics_document_save (EvDocument *document, - const char *uri, -@@ -594,7 +264,7 @@ comics_document_save (EvDocument *document, - { - ComicsDocument *comics_document = COMICS_DOCUMENT (document); - -- return ev_xfer_uri_simple (comics_document->archive, uri, error); -+ return ev_xfer_uri_simple (comics_document->archive_uri, uri, error); - } - - static int -@@ -608,6 +278,12 @@ comics_document_get_n_pages (EvDocument *document) - return comics_document->page_names->len; - } - -+typedef struct { -+ gboolean got_info; -+ int height; -+ int width; -+} pixbuf_info; -+ - static void - comics_document_get_page_size (EvDocument *document, - EvPage *page, -@@ -615,74 +291,79 @@ comics_document_get_page_size (EvDocument *document, - double *height) - { - GdkPixbufLoader *loader; -- char **argv; -- guchar buf[1024]; -- gboolean success, got_size = FALSE; -- gint outpipe = -1; -- GPid child_pid; -- gssize bytes; -- GdkPixbuf *pixbuf; -- gchar *filename; - ComicsDocument *comics_document = COMICS_DOCUMENT (document); -- -- if (!comics_document->decompress_tmp) { -- argv = extract_argv (document, page->index); -- success = g_spawn_async_with_pipes (NULL, argv, NULL, -- G_SPAWN_SEARCH_PATH | -- G_SPAWN_STDERR_TO_DEV_NULL, -- NULL, NULL, -- &child_pid, -- NULL, &outpipe, NULL, NULL); -- g_strfreev (argv); -- g_return_if_fail (success == TRUE); -- -- loader = gdk_pixbuf_loader_new (); -- g_signal_connect (loader, "area-prepared", -- G_CALLBACK (get_page_size_area_prepared_cb), -- &got_size); -- -- while (outpipe >= 0) { -- bytes = read (outpipe, buf, 1024); -- -- if (bytes > 0) -- gdk_pixbuf_loader_write (loader, buf, bytes, NULL); -- if (bytes <= 0 || got_size) { -- close (outpipe); -- outpipe = -1; -- gdk_pixbuf_loader_close (loader, NULL); -+ const char *page_path; -+ pixbuf_info info; -+ GError *error = NULL; -+ -+ if (!ev_archive_open_filename (comics_document->a, comics_document->archive_path, &error)) { -+ g_warning ("Fatal error opening archive: %s", error->message); -+ g_error_free (error); -+ goto out; -+ } -+ -+ loader = gdk_pixbuf_loader_new (); -+ info.got_info = FALSE; -+ g_signal_connect (loader, "size-prepared", -+ G_CALLBACK (get_page_size_prepared_cb), -+ &info); -+ -+ page_path = g_ptr_array_index (comics_document->page_names, page->index); -+ -+ while (1) { -+ const char *name; -+ GError *error = NULL; -+ -+ if (!ev_archive_read_next_header (comics_document->a, &error)) { -+ if (error != NULL) { -+ g_warning ("Fatal error handling archive: %s", error->message); -+ g_error_free (error); - } -+ break; - } -- pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); -- if (pixbuf) { -- if (width) -- *width = gdk_pixbuf_get_width (pixbuf); -- if (height) -- *height = gdk_pixbuf_get_height (pixbuf); -- } -- g_spawn_close_pid (child_pid); -- g_object_unref (loader); -- } else { -- filename = g_build_filename (comics_document->dir, -- (char *) comics_document->page_names->pdata[page->index], -- NULL); -- pixbuf = gdk_pixbuf_new_from_file (filename, NULL); -- if (pixbuf) { -- if (width) -- *width = gdk_pixbuf_get_width (pixbuf); -- if (height) -- *height = gdk_pixbuf_get_height (pixbuf); -- g_object_unref (pixbuf); -+ -+ name = ev_archive_get_entry_pathname (comics_document->a); -+ if (g_strcmp0 (name, page_path) == 0) { -+ char buf[BLOCK_SIZE]; -+ gssize read; -+ -+ read = ev_archive_read_data (comics_document->a, buf, sizeof(buf), &error); -+ while (read > 0 && !info.got_info) { -+ gdk_pixbuf_loader_write (loader, (guchar *) buf, read, NULL); -+ read = ev_archive_read_data (comics_document->a, buf, BLOCK_SIZE, &error); -+ } -+ if (read < 0) { -+ g_warning ("Fatal error reading '%s' in archive: %s", name, error->message); -+ g_error_free (error); -+ } -+ break; - } -- g_free (filename); - } -+ -+ gdk_pixbuf_loader_close (loader, NULL); -+ g_object_unref (loader); -+ -+ if (info.got_info) { -+ if (width) -+ *width = info.width; -+ if (height) -+ *height = info.height; -+ } -+ -+out: -+ comics_document_reset_archive (comics_document); - } - - static void --get_page_size_area_prepared_cb (GdkPixbufLoader *loader, -- gpointer data) -+get_page_size_prepared_cb (GdkPixbufLoader *loader, -+ int width, -+ int height, -+ gpointer data) - { -- gboolean *got_size = data; -- *got_size = TRUE; -+ pixbuf_info *info = data; -+ info->got_info = TRUE; -+ info->height = height; -+ info->width = width; - } - - static GdkPixbuf * -@@ -690,73 +371,73 @@ comics_document_render_pixbuf (EvDocument *document, - EvRenderContext *rc) - { - GdkPixbufLoader *loader; -- GdkPixbuf *rotated_pixbuf, *tmp_pixbuf; -- char **argv; -- guchar buf[4096]; -- gboolean success; -- gint outpipe = -1; -- GPid child_pid; -- gssize bytes; -- gint width, height; -- gchar *filename; -+ GdkPixbuf *tmp_pixbuf; -+ GdkPixbuf *rotated_pixbuf; - ComicsDocument *comics_document = COMICS_DOCUMENT (document); -- -- if (!comics_document->decompress_tmp) { -- argv = extract_argv (document, rc->page->index); -- success = g_spawn_async_with_pipes (NULL, argv, NULL, -- G_SPAWN_SEARCH_PATH | -- G_SPAWN_STDERR_TO_DEV_NULL, -- NULL, NULL, -- &child_pid, -- NULL, &outpipe, NULL, NULL); -- g_strfreev (argv); -- g_return_val_if_fail (success == TRUE, NULL); -- -- loader = gdk_pixbuf_loader_new (); -- g_signal_connect (loader, "size-prepared", -- G_CALLBACK (render_pixbuf_size_prepared_cb), -- rc); -- -- while (outpipe >= 0) { -- bytes = read (outpipe, buf, 4096); -- -- if (bytes > 0) { -- gdk_pixbuf_loader_write (loader, buf, bytes, -- NULL); -- } else if (bytes <= 0) { -- close (outpipe); -- gdk_pixbuf_loader_close (loader, NULL); -- outpipe = -1; -+ const char *page_path; -+ GError *error = NULL; -+ -+ if (!ev_archive_open_filename (comics_document->a, comics_document->archive_path, &error)) { -+ g_warning ("Fatal error opening archive: %s", error->message); -+ g_error_free (error); -+ goto out; -+ } -+ -+ loader = gdk_pixbuf_loader_new (); -+ g_signal_connect (loader, "size-prepared", -+ G_CALLBACK (render_pixbuf_size_prepared_cb), -+ rc); -+ -+ page_path = g_ptr_array_index (comics_document->page_names, rc->page->index); -+ -+ while (1) { -+ const char *name; -+ -+ if (!ev_archive_read_next_header (comics_document->a, &error)) { -+ if (error != NULL) { -+ g_warning ("Fatal error handling archive: %s", error->message); -+ g_error_free (error); - } -+ break; -+ } -+ -+ name = ev_archive_get_entry_pathname (comics_document->a); -+ if (g_strcmp0 (name, page_path) == 0) { -+ size_t size = ev_archive_get_entry_size (comics_document->a); -+ char *buf; -+ ssize_t read; -+ -+ buf = g_malloc (size); -+ read = ev_archive_read_data (comics_document->a, buf, size, &error); -+ if (read <= 0) { -+ if (read < 0) { -+ g_warning ("Fatal error reading '%s' in archive: %s", name, error->message); -+ g_error_free (error); -+ } else { -+ g_warning ("Read an empty file from the archive"); -+ } -+ } else { -+ gdk_pixbuf_loader_write (loader, (guchar *) buf, size, NULL); -+ } -+ g_free (buf); -+ gdk_pixbuf_loader_close (loader, NULL); -+ break; - } -- tmp_pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); -- rotated_pixbuf = -- gdk_pixbuf_rotate_simple (tmp_pixbuf, -- 360 - rc->rotation); -- g_spawn_close_pid (child_pid); -- g_object_unref (loader); -- } else { -- int scaled_width, scaled_height; -- -- filename = -- g_build_filename (comics_document->dir, -- (char *) comics_document->page_names->pdata[rc->page->index], -- NULL); -- -- gdk_pixbuf_get_file_info (filename, &width, &height); -- -- ev_render_context_compute_scaled_size (rc, width, height, -- &scaled_width, &scaled_height); -- -- tmp_pixbuf = -- gdk_pixbuf_new_from_file_at_size ( -- filename, scaled_width, scaled_height, NULL); -- rotated_pixbuf = -- gdk_pixbuf_rotate_simple (tmp_pixbuf, -- 360 - rc->rotation); -- g_free (filename); -- g_object_unref (tmp_pixbuf); - } -+ -+ tmp_pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); -+ rotated_pixbuf = NULL; -+ if (tmp_pixbuf) { -+ if ((rc->rotation % 360) == 0) -+ rotated_pixbuf = g_object_ref (tmp_pixbuf); -+ else -+ rotated_pixbuf = gdk_pixbuf_rotate_simple (tmp_pixbuf, -+ 360 - rc->rotation); -+ } -+ g_object_unref (loader); -+ -+out: -+ comics_document_reset_archive (comics_document); - return rotated_pixbuf; - } - -@@ -770,7 +451,7 @@ comics_document_render (EvDocument *document, - pixbuf = comics_document_render_pixbuf (document, rc); - surface = ev_document_misc_surface_from_pixbuf (pixbuf); - g_object_unref (pixbuf); -- -+ - return surface; - } - -@@ -786,60 +467,19 @@ render_pixbuf_size_prepared_cb (GdkPixbufLoader *loader, - gdk_pixbuf_loader_set_size (loader, scaled_width, scaled_height); - } - --/** -- * comics_remove_dir: Removes a directory recursively. -- * Returns: -- * 0 if it was successfully deleted, -- * -1 if an error occurred -- */ --static int --comics_remove_dir (gchar *path_name) --{ -- GDir *content_dir; -- const gchar *filename; -- gchar *filename_with_path; -- -- if (g_file_test (path_name, G_FILE_TEST_IS_DIR)) { -- content_dir = g_dir_open (path_name, 0, NULL); -- filename = g_dir_read_name (content_dir); -- while (filename) { -- filename_with_path = -- g_build_filename (path_name, -- filename, NULL); -- comics_remove_dir (filename_with_path); -- g_free (filename_with_path); -- filename = g_dir_read_name (content_dir); -- } -- g_dir_close (content_dir); -- } -- /* Note from g_remove() documentation: on Windows, it is in general not -- * possible to remove a file that is open to some process, or mapped -- * into memory.*/ -- return (g_remove (path_name)); --} -- - static void - comics_document_finalize (GObject *object) - { - ComicsDocument *comics_document = COMICS_DOCUMENT (object); -- -- if (comics_document->decompress_tmp) { -- if (comics_remove_dir (comics_document->dir) == -1) -- g_warning (_("There was an error deleting “%s”."), -- comics_document->dir); -- g_free (comics_document->dir); -- } -- -+ - if (comics_document->page_names) { - g_ptr_array_foreach (comics_document->page_names, (GFunc) g_free, NULL); - g_ptr_array_free (comics_document->page_names, TRUE); - } - -- g_free (comics_document->archive); -- g_free (comics_document->selected_command); -- g_free (comics_document->alternative_command); -- g_free (comics_document->extract_command); -- g_free (comics_document->list_command); -+ g_clear_object (&comics_document->a); -+ g_free (comics_document->archive_path); -+ g_free (comics_document->archive_uri); - - G_OBJECT_CLASS (comics_document_parent_class)->finalize (object); - } -@@ -862,9 +502,8 @@ comics_document_class_init (ComicsDocumentClass *klass) - static void - comics_document_init (ComicsDocument *comics_document) - { -- comics_document->archive = NULL; -+ comics_document->a = ev_archive_new (); - comics_document->page_names = NULL; -- comics_document->extract_command = NULL; - } - - /* Returns a list of file extensions supported by gdk-pixbuf */ -@@ -890,41 +529,3 @@ get_supported_image_extensions(void) - g_slist_free (formats); - return extensions; - } -- --static char** --extract_argv (EvDocument *document, gint page) --{ -- ComicsDocument *comics_document = COMICS_DOCUMENT (document); -- char **argv; -- char *command_line, *quoted_archive, *quoted_filename; -- GError *err = NULL; -- -- if (page >= comics_document->page_names->len) -- return NULL; -- -- if (comics_document->regex_arg) { -- quoted_archive = g_shell_quote (comics_document->archive); -- quoted_filename = -- comics_regex_quote (comics_document->page_names->pdata[page]); -- } else { -- quoted_archive = g_shell_quote (comics_document->archive); -- quoted_filename = g_shell_quote (comics_document->page_names->pdata[page]); -- } -- -- command_line = g_strdup_printf ("%s %s %s", -- comics_document->extract_command, -- quoted_archive, -- quoted_filename); -- g_shell_parse_argv (command_line, NULL, &argv, &err); -- -- if (err) { -- g_warning (_("Error %s"), err->message); -- g_error_free (err); -- return NULL; -- } -- -- g_free (command_line); -- g_free (quoted_archive); -- g_free (quoted_filename); -- return argv; --} -diff --git a/backend/comics/ev-archive.c b/backend/comics/ev-archive.c -new file mode 100644 -index 00000000..9efa69f8 ---- /dev/null -+++ b/backend/comics/ev-archive.c -@@ -0,0 +1,277 @@ -+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */ -+/* -+ * Copyright (C) 2017, Bastien Nocera -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2, or (at your option) -+ * any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -+ */ -+ -+#include "ev-archive.h" -+ -+#include -+#include -+#include -+ -+#define BUFFER_SIZE (64 * 1024) -+ -+struct _EvArchive { -+ GObject parent_instance; -+ EvArchiveType type; -+ -+ /* libarchive */ -+ struct archive *libar; -+ struct archive_entry *libar_entry; -+}; -+ -+G_DEFINE_TYPE(EvArchive, ev_archive, G_TYPE_OBJECT); -+ -+static void -+ev_archive_finalize (GObject *object) -+{ -+ EvArchive *archive = EV_ARCHIVE (object); -+ -+ switch (archive->type) { -+ case EV_ARCHIVE_TYPE_RAR: -+ break; -+ case EV_ARCHIVE_TYPE_ZIP: -+ case EV_ARCHIVE_TYPE_7Z: -+ case EV_ARCHIVE_TYPE_TAR: -+ g_clear_pointer (&archive->libar, archive_free); -+ break; -+ default: -+ break; -+ } -+ -+ G_OBJECT_CLASS (ev_archive_parent_class)->finalize (object); -+} -+ -+static void -+ev_archive_class_init (EvArchiveClass *class) -+{ -+ GObjectClass *object_class = (GObjectClass *) class; -+ object_class->finalize = ev_archive_finalize; -+} -+ -+EvArchive * -+ev_archive_new (void) -+{ -+ return g_object_new (EV_TYPE_ARCHIVE, NULL); -+} -+ -+static void -+libarchive_set_archive_type (EvArchive *archive, -+ EvArchiveType archive_type) -+{ -+ archive->type = archive_type; -+ archive->libar = archive_read_new (); -+ -+ if (archive_type == EV_ARCHIVE_TYPE_ZIP) -+ archive_read_support_format_zip (archive->libar); -+ else if (archive_type == EV_ARCHIVE_TYPE_7Z) -+ archive_read_support_format_7zip (archive->libar); -+ else if (archive_type == EV_ARCHIVE_TYPE_TAR) -+ archive_read_support_format_tar (archive->libar); -+} -+ -+EvArchiveType -+ev_archive_get_archive_type (EvArchive *archive) -+{ -+ g_return_val_if_fail (EV_IS_ARCHIVE (archive), EV_ARCHIVE_TYPE_NONE); -+ return archive->type; -+} -+ -+gboolean -+ev_archive_set_archive_type (EvArchive *archive, -+ EvArchiveType archive_type) -+{ -+ g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE); -+ g_return_val_if_fail (archive->type == EV_ARCHIVE_TYPE_NONE, FALSE); -+ -+ switch (archive_type) { -+ case EV_ARCHIVE_TYPE_RAR: -+ /* Disabled until this is fixed: -+ * https://github.com/libarchive/libarchive/issues/373 */ -+ return FALSE; -+ case EV_ARCHIVE_TYPE_ZIP: -+ case EV_ARCHIVE_TYPE_7Z: -+ case EV_ARCHIVE_TYPE_TAR: -+ libarchive_set_archive_type (archive, archive_type); -+ break; -+ default: -+ g_assert_not_reached (); -+ } -+ -+ return TRUE; -+} -+ -+gboolean -+ev_archive_open_filename (EvArchive *archive, -+ const char *path, -+ GError **error) -+{ -+ int r; -+ -+ g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE); -+ g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, FALSE); -+ g_return_val_if_fail (path != NULL, FALSE); -+ -+ switch (archive->type) { -+ case EV_ARCHIVE_TYPE_NONE: -+ g_assert_not_reached (); -+ case EV_ARCHIVE_TYPE_RAR: -+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, -+ "Archive type 'RAR' not supported"); -+ return FALSE; -+ case EV_ARCHIVE_TYPE_ZIP: -+ case EV_ARCHIVE_TYPE_7Z: -+ case EV_ARCHIVE_TYPE_TAR: -+ r = archive_read_open_filename (archive->libar, path, BUFFER_SIZE); -+ if (r != ARCHIVE_OK) { -+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, -+ "Error opening archive: %s", archive_error_string (archive->libar)); -+ return FALSE; -+ } -+ return TRUE; -+ } -+ -+ return FALSE; -+} -+ -+static gboolean -+libarchive_read_next_header (EvArchive *archive, -+ GError **error) -+{ -+ while (1) { -+ int r; -+ -+ r = archive_read_next_header (archive->libar, &archive->libar_entry); -+ if (r != ARCHIVE_OK) { -+ if (r != ARCHIVE_EOF) -+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, -+ "Error reading archive: %s", archive_error_string (archive->libar)); -+ return FALSE; -+ } -+ -+ if (archive_entry_filetype (archive->libar_entry) != AE_IFREG) { -+ g_debug ("Skipping '%s' as it's not a regular file", -+ archive_entry_pathname (archive->libar_entry)); -+ continue; -+ } -+ -+ g_debug ("At header for file '%s'", archive_entry_pathname (archive->libar_entry)); -+ -+ break; -+ } -+ -+ return TRUE; -+} -+ -+gboolean -+ev_archive_read_next_header (EvArchive *archive, -+ GError **error) -+{ -+ g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE); -+ g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, FALSE); -+ -+ switch (archive->type) { -+ case EV_ARCHIVE_TYPE_NONE: -+ case EV_ARCHIVE_TYPE_RAR: -+ g_assert_not_reached (); -+ case EV_ARCHIVE_TYPE_ZIP: -+ case EV_ARCHIVE_TYPE_7Z: -+ case EV_ARCHIVE_TYPE_TAR: -+ return libarchive_read_next_header (archive, error); -+ } -+ -+ return FALSE; -+} -+ -+const char * -+ev_archive_get_entry_pathname (EvArchive *archive) -+{ -+ g_return_val_if_fail (EV_IS_ARCHIVE (archive), NULL); -+ g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, NULL); -+ g_return_val_if_fail (archive->libar_entry != NULL, NULL); -+ -+ switch (archive->type) { -+ case EV_ARCHIVE_TYPE_NONE: -+ g_assert_not_reached (); -+ case EV_ARCHIVE_TYPE_RAR: -+ return NULL; -+ case EV_ARCHIVE_TYPE_ZIP: -+ case EV_ARCHIVE_TYPE_7Z: -+ case EV_ARCHIVE_TYPE_TAR: -+ return archive_entry_pathname (archive->libar_entry); -+ } -+ -+ return NULL; -+} -+ -+gint64 -+ev_archive_get_entry_size (EvArchive *archive) -+{ -+ gint64 r; -+ -+ g_return_val_if_fail (EV_IS_ARCHIVE (archive), -1); -+ g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, -1); -+ g_return_val_if_fail (archive->libar_entry != NULL, -1); -+ -+ switch (archive->type) { -+ case EV_ARCHIVE_TYPE_RAR: -+ case EV_ARCHIVE_TYPE_NONE: -+ g_assert_not_reached (); -+ case EV_ARCHIVE_TYPE_ZIP: -+ case EV_ARCHIVE_TYPE_7Z: -+ case EV_ARCHIVE_TYPE_TAR: -+ r = archive_entry_size (archive->libar_entry); -+ break; -+ } -+ -+ return r; -+} -+ -+gssize -+ev_archive_read_data (EvArchive *archive, -+ void *buf, -+ gsize count, -+ GError **error) -+{ -+ gssize r = -1; -+ -+ g_return_val_if_fail (EV_IS_ARCHIVE (archive), -1); -+ g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, -1); -+ g_return_val_if_fail (archive->libar_entry != NULL, -1); -+ -+ switch (archive->type) { -+ case EV_ARCHIVE_TYPE_RAR: -+ case EV_ARCHIVE_TYPE_NONE: -+ g_assert_not_reached (); -+ case EV_ARCHIVE_TYPE_ZIP: -+ case EV_ARCHIVE_TYPE_7Z: -+ case EV_ARCHIVE_TYPE_TAR: -+ r = archive_read_data (archive->libar, buf, count); -+ if (r < 0) { -+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, -+ "Failed to decompress data: %s", archive_error_string (archive->libar)); -+ } -+ break; -+ } -+ -+ return r; -+} -+ -+static void -+ev_archive_init (EvArchive *archive) -+{ -+} -diff --git a/backend/comics/ev-archive.h b/backend/comics/ev-archive.h -new file mode 100644 -index 00000000..38d47d79 ---- /dev/null -+++ b/backend/comics/ev-archive.h -@@ -0,0 +1,47 @@ -+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */ -+/* -+ * Copyright (C) 2017, Bastien Nocera -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2, or (at your option) -+ * any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -+ */ -+ -+#include -+ -+#define EV_TYPE_ARCHIVE ev_archive_get_type () -+G_DECLARE_FINAL_TYPE (EvArchive, ev_archive, EV, ARCHIVE, GObject) -+ -+typedef enum { -+ EV_ARCHIVE_TYPE_NONE = 0, -+ EV_ARCHIVE_TYPE_RAR, -+ EV_ARCHIVE_TYPE_ZIP, -+ EV_ARCHIVE_TYPE_7Z, -+ EV_ARCHIVE_TYPE_TAR -+} EvArchiveType; -+ -+EvArchive *ev_archive_new (void); -+gboolean ev_archive_set_archive_type (EvArchive *archive, -+ EvArchiveType archive_type); -+EvArchiveType ev_archive_get_archive_type (EvArchive *archive); -+gboolean ev_archive_open_filename (EvArchive *archive, -+ const char *path, -+ GError **error); -+gboolean ev_archive_read_next_header (EvArchive *archive, -+ GError **error); -+const char *ev_archive_get_entry_pathname (EvArchive *archive); -+gint64 ev_archive_get_entry_size (EvArchive *archive); -+gssize ev_archive_read_data (EvArchive *archive, -+ void *buf, -+ gsize count, -+ GError **error); -diff --git a/configure.ac b/configure.ac -index 9e9f8316..a5ae8ccd 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -688,9 +688,17 @@ AC_ARG_ENABLE(comics, - [Compile with support for comic book archives])], - [enable_comics=$enableval], - [enable_comics=yes]) -- -+ - if test "x$enable_comics" = "xyes"; then -- AC_DEFINE([ENABLE_COMICS], [1], [Enable support for comics.]) -+ LIBARCHIVE_REQUIRED=3.1.2 -+ PKG_CHECK_MODULES(LIBARCHIVE, libarchive >= $LIBARCHIVE_REQUIRED,enable_comics=yes,enable_comics=no) -+ -+ if test "x$enable_comics" = "xyes"; then -+ AC_DEFINE([ENABLE_COMICS], [1], [Enable support for comics.]) -+ else -+ enable_comics="no" -+ AC_MSG_WARN([Comics support is disabled since libarchive (version >= $LIBARCHIVE_REQUIRED) is needed]) -+ fi - fi - AM_CONDITIONAL(ENABLE_COMICS, test x$enable_comics = xyes) - --- -2.13.0 - - -From dda98ee300df709c10c7025ad527a7969796c527 Mon Sep 17 00:00:00 2001 -From: Carlos Garcia Campos -Date: Sat, 25 Mar 2017 11:33:42 +0100 -Subject: [PATCH 02/10] comics: cosmetic changes - ---- - backend/comics/comics-document.c | 109 ++++++++++++++++++--------------------- - backend/comics/ev-archive.c | 30 +++++------ - backend/comics/ev-archive.h | 33 +++++++----- - 3 files changed, 85 insertions(+), 87 deletions(-) - -diff --git a/backend/comics/comics-document.c b/backend/comics/comics-document.c -index b55c25b3..87c25270 100644 ---- a/backend/comics/comics-document.c -+++ b/backend/comics/comics-document.c -@@ -48,31 +48,23 @@ struct _ComicsDocumentClass - struct _ComicsDocument - { - EvDocument parent_instance; -- EvArchive *a; -- EvArchiveType a_type; -+ EvArchive *archive; -+ EvArchiveType archive_type; - gchar *archive_path; - gchar *archive_uri; - GPtrArray *page_names; - }; - --static GSList* get_supported_image_extensions (void); --static void get_page_size_prepared_cb (GdkPixbufLoader *loader, -- int width, -- int height, -- gpointer data); --static void render_pixbuf_size_prepared_cb (GdkPixbufLoader *loader, -- gint width, -- gint height, -- EvRenderContext *rc); -+static GSList* get_supported_image_extensions (void); - - EV_BACKEND_REGISTER (ComicsDocument, comics_document) - - static void - comics_document_reset_archive (ComicsDocument *comics_document) - { -- g_clear_object (&comics_document->a); -- comics_document->a = ev_archive_new (); -- ev_archive_set_archive_type (comics_document->a, comics_document->a_type); -+ g_clear_object (&comics_document->archive); -+ comics_document->archive = ev_archive_new (); -+ ev_archive_set_archive_type (comics_document->archive, comics_document->archive_type); - } - - static char ** -@@ -81,7 +73,7 @@ comics_document_list (ComicsDocument *comics_document) - char **ret = NULL; - GPtrArray *array; - -- if (!ev_archive_open_filename (comics_document->a, comics_document->archive_path, NULL)) -+ if (!ev_archive_open_filename (comics_document->archive, comics_document->archive_path, NULL)) - goto out; - - array = g_ptr_array_new (); -@@ -90,7 +82,7 @@ comics_document_list (ComicsDocument *comics_document) - const char *name; - GError *error = NULL; - -- if (!ev_archive_read_next_header (comics_document->a, &error)) { -+ if (!ev_archive_read_next_header (comics_document->archive, &error)) { - if (error != NULL) { - g_warning ("Fatal error handling archive: %s", error->message); - g_error_free (error); -@@ -98,7 +90,7 @@ comics_document_list (ComicsDocument *comics_document) - break; - } - -- name = ev_archive_get_entry_pathname (comics_document->a); -+ name = ev_archive_get_entry_pathname (comics_document->archive); - - g_debug ("Adding '%s' to the list of files in the comics", name); - g_ptr_array_add (array, g_strdup (name)); -@@ -125,19 +117,19 @@ comics_check_decompress_support (gchar *mime_type, - { - if (g_content_type_is_a (mime_type, "application/x-cbr") || - g_content_type_is_a (mime_type, "application/x-rar")) { -- if (ev_archive_set_archive_type (comics_document->a, EV_ARCHIVE_TYPE_RAR)) -+ if (ev_archive_set_archive_type (comics_document->archive, EV_ARCHIVE_TYPE_RAR)) - return TRUE; - } else if (g_content_type_is_a (mime_type, "application/x-cbz") || - g_content_type_is_a (mime_type, "application/zip")) { -- if (ev_archive_set_archive_type (comics_document->a, EV_ARCHIVE_TYPE_ZIP)) -+ if (ev_archive_set_archive_type (comics_document->archive, EV_ARCHIVE_TYPE_ZIP)) - return TRUE; - } else if (g_content_type_is_a (mime_type, "application/x-cb7") || - g_content_type_is_a (mime_type, "application/x-7z-compressed")) { -- if (ev_archive_set_archive_type (comics_document->a, EV_ARCHIVE_TYPE_7Z)) -+ if (ev_archive_set_archive_type (comics_document->archive, EV_ARCHIVE_TYPE_7Z)) - return TRUE; - } else if (g_content_type_is_a (mime_type, "application/x-cbt") || - g_content_type_is_a (mime_type, "application/x-tar")) { -- if (ev_archive_set_archive_type (comics_document->a, EV_ARCHIVE_TYPE_TAR)) -+ if (ev_archive_set_archive_type (comics_document->archive, EV_ARCHIVE_TYPE_TAR)) - return TRUE; - } else { - g_set_error (error, -@@ -208,10 +200,10 @@ comics_document_load (EvDocument *document, - g_free (mime_type); - return FALSE; - } -- comics_document->a_type = ev_archive_get_archive_type (comics_document->a); -- - g_free (mime_type); - -+ comics_document->archive_type = ev_archive_get_archive_type (comics_document->archive); -+ - /* Get list of files in archive */ - cb_files = comics_document_list (comics_document); - if (!cb_files) { -@@ -282,7 +274,18 @@ typedef struct { - gboolean got_info; - int height; - int width; --} pixbuf_info; -+} PixbufInfo; -+ -+static void -+get_page_size_prepared_cb (GdkPixbufLoader *loader, -+ int width, -+ int height, -+ PixbufInfo *info) -+{ -+ info->got_info = TRUE; -+ info->height = height; -+ info->width = width; -+} - - static void - comics_document_get_page_size (EvDocument *document, -@@ -293,10 +296,10 @@ comics_document_get_page_size (EvDocument *document, - GdkPixbufLoader *loader; - ComicsDocument *comics_document = COMICS_DOCUMENT (document); - const char *page_path; -- pixbuf_info info; -+ PixbufInfo info; - GError *error = NULL; - -- if (!ev_archive_open_filename (comics_document->a, comics_document->archive_path, &error)) { -+ if (!ev_archive_open_filename (comics_document->archive, comics_document->archive_path, &error)) { - g_warning ("Fatal error opening archive: %s", error->message); - g_error_free (error); - goto out; -@@ -314,7 +317,7 @@ comics_document_get_page_size (EvDocument *document, - const char *name; - GError *error = NULL; - -- if (!ev_archive_read_next_header (comics_document->a, &error)) { -+ if (!ev_archive_read_next_header (comics_document->archive, &error)) { - if (error != NULL) { - g_warning ("Fatal error handling archive: %s", error->message); - g_error_free (error); -@@ -322,15 +325,15 @@ comics_document_get_page_size (EvDocument *document, - break; - } - -- name = ev_archive_get_entry_pathname (comics_document->a); -+ name = ev_archive_get_entry_pathname (comics_document->archive); - if (g_strcmp0 (name, page_path) == 0) { - char buf[BLOCK_SIZE]; - gssize read; - -- read = ev_archive_read_data (comics_document->a, buf, sizeof(buf), &error); -+ read = ev_archive_read_data (comics_document->archive, buf, sizeof(buf), &error); - while (read > 0 && !info.got_info) { - gdk_pixbuf_loader_write (loader, (guchar *) buf, read, NULL); -- read = ev_archive_read_data (comics_document->a, buf, BLOCK_SIZE, &error); -+ read = ev_archive_read_data (comics_document->archive, buf, BLOCK_SIZE, &error); - } - if (read < 0) { - g_warning ("Fatal error reading '%s' in archive: %s", name, error->message); -@@ -355,15 +358,15 @@ out: - } - - static void --get_page_size_prepared_cb (GdkPixbufLoader *loader, -- int width, -- int height, -- gpointer data) -+render_pixbuf_size_prepared_cb (GdkPixbufLoader *loader, -+ gint width, -+ gint height, -+ EvRenderContext *rc) - { -- pixbuf_info *info = data; -- info->got_info = TRUE; -- info->height = height; -- info->width = width; -+ int scaled_width, scaled_height; -+ -+ ev_render_context_compute_scaled_size (rc, width, height, &scaled_width, &scaled_height); -+ gdk_pixbuf_loader_set_size (loader, scaled_width, scaled_height); - } - - static GdkPixbuf * -@@ -372,12 +375,12 @@ comics_document_render_pixbuf (EvDocument *document, - { - GdkPixbufLoader *loader; - GdkPixbuf *tmp_pixbuf; -- GdkPixbuf *rotated_pixbuf; -+ GdkPixbuf *rotated_pixbuf = NULL; - ComicsDocument *comics_document = COMICS_DOCUMENT (document); - const char *page_path; - GError *error = NULL; - -- if (!ev_archive_open_filename (comics_document->a, comics_document->archive_path, &error)) { -+ if (!ev_archive_open_filename (comics_document->archive, comics_document->archive_path, &error)) { - g_warning ("Fatal error opening archive: %s", error->message); - g_error_free (error); - goto out; -@@ -393,7 +396,7 @@ comics_document_render_pixbuf (EvDocument *document, - while (1) { - const char *name; - -- if (!ev_archive_read_next_header (comics_document->a, &error)) { -+ if (!ev_archive_read_next_header (comics_document->archive, &error)) { - if (error != NULL) { - g_warning ("Fatal error handling archive: %s", error->message); - g_error_free (error); -@@ -401,14 +404,14 @@ comics_document_render_pixbuf (EvDocument *document, - break; - } - -- name = ev_archive_get_entry_pathname (comics_document->a); -+ name = ev_archive_get_entry_pathname (comics_document->archive); - if (g_strcmp0 (name, page_path) == 0) { -- size_t size = ev_archive_get_entry_size (comics_document->a); -+ size_t size = ev_archive_get_entry_size (comics_document->archive); - char *buf; - ssize_t read; - - buf = g_malloc (size); -- read = ev_archive_read_data (comics_document->a, buf, size, &error); -+ read = ev_archive_read_data (comics_document->archive, buf, size, &error); - if (read <= 0) { - if (read < 0) { - g_warning ("Fatal error reading '%s' in archive: %s", name, error->message); -@@ -426,7 +429,6 @@ comics_document_render_pixbuf (EvDocument *document, - } - - tmp_pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); -- rotated_pixbuf = NULL; - if (tmp_pixbuf) { - if ((rc->rotation % 360) == 0) - rotated_pixbuf = g_object_ref (tmp_pixbuf); -@@ -456,18 +458,6 @@ comics_document_render (EvDocument *document, - } - - static void --render_pixbuf_size_prepared_cb (GdkPixbufLoader *loader, -- gint width, -- gint height, -- EvRenderContext *rc) --{ -- int scaled_width, scaled_height; -- -- ev_render_context_compute_scaled_size (rc, width, height, &scaled_width, &scaled_height); -- gdk_pixbuf_loader_set_size (loader, scaled_width, scaled_height); --} -- --static void - comics_document_finalize (GObject *object) - { - ComicsDocument *comics_document = COMICS_DOCUMENT (object); -@@ -477,7 +467,7 @@ comics_document_finalize (GObject *object) - g_ptr_array_free (comics_document->page_names, TRUE); - } - -- g_clear_object (&comics_document->a); -+ g_clear_object (&comics_document->archive); - g_free (comics_document->archive_path); - g_free (comics_document->archive_uri); - -@@ -502,8 +492,7 @@ comics_document_class_init (ComicsDocumentClass *klass) - static void - comics_document_init (ComicsDocument *comics_document) - { -- comics_document->a = ev_archive_new (); -- comics_document->page_names = NULL; -+ comics_document->archive = ev_archive_new (); - } - - /* Returns a list of file extensions supported by gdk-pixbuf */ -diff --git a/backend/comics/ev-archive.c b/backend/comics/ev-archive.c -index 9efa69f8..333db470 100644 ---- a/backend/comics/ev-archive.c -+++ b/backend/comics/ev-archive.c -@@ -17,6 +17,7 @@ - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -+#include "config.h" - #include "ev-archive.h" - - #include -@@ -57,9 +58,10 @@ ev_archive_finalize (GObject *object) - } - - static void --ev_archive_class_init (EvArchiveClass *class) -+ev_archive_class_init (EvArchiveClass *klass) - { -- GObjectClass *object_class = (GObjectClass *) class; -+ GObjectClass *object_class = (GObjectClass *) klass; -+ - object_class->finalize = ev_archive_finalize; - } - -@@ -88,6 +90,7 @@ EvArchiveType - ev_archive_get_archive_type (EvArchive *archive) - { - g_return_val_if_fail (EV_IS_ARCHIVE (archive), EV_ARCHIVE_TYPE_NONE); -+ - return archive->type; - } - -@@ -149,8 +152,8 @@ ev_archive_open_filename (EvArchive *archive, - } - - static gboolean --libarchive_read_next_header (EvArchive *archive, -- GError **error) -+libarchive_read_next_header (EvArchive *archive, -+ GError **error) - { - while (1) { - int r; -@@ -178,8 +181,8 @@ libarchive_read_next_header (EvArchive *archive, - } - - gboolean --ev_archive_read_next_header (EvArchive *archive, -- GError **error) -+ev_archive_read_next_header (EvArchive *archive, -+ GError **error) - { - g_return_val_if_fail (EV_IS_ARCHIVE (archive), FALSE); - g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, FALSE); -@@ -221,8 +224,6 @@ ev_archive_get_entry_pathname (EvArchive *archive) - gint64 - ev_archive_get_entry_size (EvArchive *archive) - { -- gint64 r; -- - g_return_val_if_fail (EV_IS_ARCHIVE (archive), -1); - g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, -1); - g_return_val_if_fail (archive->libar_entry != NULL, -1); -@@ -234,18 +235,17 @@ ev_archive_get_entry_size (EvArchive *archive) - case EV_ARCHIVE_TYPE_ZIP: - case EV_ARCHIVE_TYPE_7Z: - case EV_ARCHIVE_TYPE_TAR: -- r = archive_entry_size (archive->libar_entry); -- break; -+ return archive_entry_size (archive->libar_entry); - } - -- return r; -+ return -1; - } - - gssize --ev_archive_read_data (EvArchive *archive, -- void *buf, -- gsize count, -- GError **error) -+ev_archive_read_data (EvArchive *archive, -+ void *buf, -+ gsize count, -+ GError **error) - { - gssize r = -1; - -diff --git a/backend/comics/ev-archive.h b/backend/comics/ev-archive.h -index 38d47d79..3e206939 100644 ---- a/backend/comics/ev-archive.h -+++ b/backend/comics/ev-archive.h -@@ -17,8 +17,13 @@ - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -+#ifndef __EV_ARCHIVE_H__ -+#define __EV_ARCHIVE_H__ -+ - #include - -+G_BEGIN_DECLS -+ - #define EV_TYPE_ARCHIVE ev_archive_get_type () - G_DECLARE_FINAL_TYPE (EvArchive, ev_archive, EV, ARCHIVE, GObject) - -@@ -33,15 +38,19 @@ typedef enum { - EvArchive *ev_archive_new (void); - gboolean ev_archive_set_archive_type (EvArchive *archive, - EvArchiveType archive_type); --EvArchiveType ev_archive_get_archive_type (EvArchive *archive); --gboolean ev_archive_open_filename (EvArchive *archive, -- const char *path, -- GError **error); --gboolean ev_archive_read_next_header (EvArchive *archive, -- GError **error); --const char *ev_archive_get_entry_pathname (EvArchive *archive); --gint64 ev_archive_get_entry_size (EvArchive *archive); --gssize ev_archive_read_data (EvArchive *archive, -- void *buf, -- gsize count, -- GError **error); -+EvArchiveType ev_archive_get_archive_type (EvArchive *archive); -+gboolean ev_archive_open_filename (EvArchive *archive, -+ const char *path, -+ GError **error); -+gboolean ev_archive_read_next_header (EvArchive *archive, -+ GError **error); -+const char *ev_archive_get_entry_pathname (EvArchive *archive); -+gint64 ev_archive_get_entry_size (EvArchive *archive); -+gssize ev_archive_read_data (EvArchive *archive, -+ void *buf, -+ gsize count, -+ GError **error); -+ -+G_END_DECLS -+ -+#endif /* __EV_ARCHIVE_H__ */ --- -2.13.0 - - -From 1497b8f6bd30a7a560d190399dd150aa15a96301 Mon Sep 17 00:00:00 2001 -From: Bastien Nocera -Date: Wed, 15 Mar 2017 18:10:17 +0100 -Subject: [PATCH 03/10] comics: Add unarr copy/paste - -To allow us to decompress CBR comics compressed with recent versions of -RAR, from https://github.com/sumatrapdfreader/sumatrapdf/tree/master/ext/unarr - -https://bugzilla.gnome.org/show_bug.cgi?id=720742 ---- - configure.ac | 1 + - cut-n-paste/Makefile.am | 2 +- - cut-n-paste/unarr/AUTHORS | 12 + - cut-n-paste/unarr/COPYING | 165 +++++ - cut-n-paste/unarr/Makefile.am | 36 + - cut-n-paste/unarr/common/allocator.h | 29 + - cut-n-paste/unarr/common/conv.c | 96 +++ - cut-n-paste/unarr/common/crc32.c | 51 ++ - cut-n-paste/unarr/common/stream.c | 217 ++++++ - cut-n-paste/unarr/common/unarr-imp.h | 81 +++ - cut-n-paste/unarr/common/unarr.c | 109 ++++ - cut-n-paste/unarr/lzmasdk/7zTypes.h | 256 ++++++++ - cut-n-paste/unarr/lzmasdk/CpuArch.c | 190 ++++++ - cut-n-paste/unarr/lzmasdk/CpuArch.h | 157 +++++ - cut-n-paste/unarr/lzmasdk/LzmaDec.c | 1025 +++++++++++++++++++++++++++++ - cut-n-paste/unarr/lzmasdk/LzmaDec.h | 227 +++++++ - cut-n-paste/unarr/lzmasdk/Ppmd.h | 85 +++ - cut-n-paste/unarr/lzmasdk/Ppmd7.c | 710 ++++++++++++++++++++ - cut-n-paste/unarr/lzmasdk/Ppmd7.h | 140 ++++ - cut-n-paste/unarr/lzmasdk/Ppmd7Dec.c | 189 ++++++ - cut-n-paste/unarr/lzmasdk/Ppmd8.c | 1122 ++++++++++++++++++++++++++++++++ - cut-n-paste/unarr/lzmasdk/Ppmd8.h | 137 ++++ - cut-n-paste/unarr/lzmasdk/Ppmd8Dec.c | 157 +++++ - cut-n-paste/unarr/lzmasdk/Precomp.h | 15 + - cut-n-paste/unarr/rar/filter-rar.c | 704 ++++++++++++++++++++ - cut-n-paste/unarr/rar/huffman-rar.c | 142 ++++ - cut-n-paste/unarr/rar/lzss.h | 88 +++ - cut-n-paste/unarr/rar/parse-rar.c | 236 +++++++ - cut-n-paste/unarr/rar/rar.c | 223 +++++++ - cut-n-paste/unarr/rar/rar.h | 252 +++++++ - cut-n-paste/unarr/rar/rarvm.c | 616 ++++++++++++++++++ - cut-n-paste/unarr/rar/rarvm.h | 117 ++++ - cut-n-paste/unarr/rar/uncompress-rar.c | 1038 +++++++++++++++++++++++++++++ - cut-n-paste/unarr/unarr.h | 94 +++ - 34 files changed, 8718 insertions(+), 1 deletion(-) - create mode 100644 cut-n-paste/unarr/AUTHORS - create mode 100644 cut-n-paste/unarr/COPYING - create mode 100644 cut-n-paste/unarr/Makefile.am - create mode 100644 cut-n-paste/unarr/common/allocator.h - create mode 100644 cut-n-paste/unarr/common/conv.c - create mode 100644 cut-n-paste/unarr/common/crc32.c - create mode 100644 cut-n-paste/unarr/common/stream.c - create mode 100644 cut-n-paste/unarr/common/unarr-imp.h - create mode 100644 cut-n-paste/unarr/common/unarr.c - create mode 100644 cut-n-paste/unarr/lzmasdk/7zTypes.h - create mode 100644 cut-n-paste/unarr/lzmasdk/CpuArch.c - create mode 100644 cut-n-paste/unarr/lzmasdk/CpuArch.h - create mode 100644 cut-n-paste/unarr/lzmasdk/LzmaDec.c - create mode 100644 cut-n-paste/unarr/lzmasdk/LzmaDec.h - create mode 100644 cut-n-paste/unarr/lzmasdk/Ppmd.h - create mode 100644 cut-n-paste/unarr/lzmasdk/Ppmd7.c - create mode 100644 cut-n-paste/unarr/lzmasdk/Ppmd7.h - create mode 100644 cut-n-paste/unarr/lzmasdk/Ppmd7Dec.c - create mode 100644 cut-n-paste/unarr/lzmasdk/Ppmd8.c - create mode 100644 cut-n-paste/unarr/lzmasdk/Ppmd8.h - create mode 100644 cut-n-paste/unarr/lzmasdk/Ppmd8Dec.c - create mode 100644 cut-n-paste/unarr/lzmasdk/Precomp.h - create mode 100644 cut-n-paste/unarr/rar/filter-rar.c - create mode 100644 cut-n-paste/unarr/rar/huffman-rar.c - create mode 100644 cut-n-paste/unarr/rar/lzss.h - create mode 100644 cut-n-paste/unarr/rar/parse-rar.c - create mode 100644 cut-n-paste/unarr/rar/rar.c - create mode 100644 cut-n-paste/unarr/rar/rar.h - create mode 100644 cut-n-paste/unarr/rar/rarvm.c - create mode 100644 cut-n-paste/unarr/rar/rarvm.h - create mode 100644 cut-n-paste/unarr/rar/uncompress-rar.c - create mode 100644 cut-n-paste/unarr/unarr.h - -diff --git a/configure.ac b/configure.ac -index a5ae8ccd..e7ee360f 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -907,6 +907,7 @@ cut-n-paste/Makefile - cut-n-paste/gimpcellrenderertoggle/Makefile - cut-n-paste/synctex/Makefile - cut-n-paste/libgd/Makefile -+cut-n-paste/unarr/Makefile - data/evince.desktop.in - data/evince-previewer.desktop.in - data/Makefile -diff --git a/cut-n-paste/Makefile.am b/cut-n-paste/Makefile.am -index 2d5684d8..a049b7fd 100644 ---- a/cut-n-paste/Makefile.am -+++ b/cut-n-paste/Makefile.am -@@ -1,3 +1,3 @@ --SUBDIRS = gimpcellrenderertoggle synctex libgd -+SUBDIRS = gimpcellrenderertoggle synctex libgd unarr - - -include $(top_srcdir)/git.mk -diff --git a/cut-n-paste/unarr/AUTHORS b/cut-n-paste/unarr/AUTHORS -new file mode 100644 -index 00000000..4af1be7c ---- /dev/null -+++ b/cut-n-paste/unarr/AUTHORS -@@ -0,0 +1,12 @@ -+unarr contains code by: -+ -+* The Unarchiver project (https://code.google.com/p/theunarchiver/) -+* Simon Bünzli (zeniko at gmail.com, http://www.zeniko.ch/#SumatraPDF) -+ -+Most code is licensed under LGPLv3 (see COPYING). Exceptions are in code -+included from other projects: -+ -+Files License URL -+---------------------------------------------------------------------------------- -+common/crc32.c Public Domain https://gnunet.org/svn/gnunet/src/util/crypto_crc.c -+lzmasdk/*.* Public Domain http://www.7-zip.org/sdk.html -diff --git a/cut-n-paste/unarr/COPYING b/cut-n-paste/unarr/COPYING -new file mode 100644 -index 00000000..65c5ca88 ---- /dev/null -+++ b/cut-n-paste/unarr/COPYING -@@ -0,0 +1,165 @@ -+ GNU LESSER GENERAL PUBLIC LICENSE -+ Version 3, 29 June 2007 -+ -+ Copyright (C) 2007 Free Software Foundation, Inc. -+ Everyone is permitted to copy and distribute verbatim copies -+ of this license document, but changing it is not allowed. -+ -+ -+ This version of the GNU Lesser General Public License incorporates -+the terms and conditions of version 3 of the GNU General Public -+License, supplemented by the additional permissions listed below. -+ -+ 0. Additional Definitions. -+ -+ As used herein, "this License" refers to version 3 of the GNU Lesser -+General Public License, and the "GNU GPL" refers to version 3 of the GNU -+General Public License. -+ -+ "The Library" refers to a covered work governed by this License, -+other than an Application or a Combined Work as defined below. -+ -+ An "Application" is any work that makes use of an interface provided -+by the Library, but which is not otherwise based on the Library. -+Defining a subclass of a class defined by the Library is deemed a mode -+of using an interface provided by the Library. -+ -+ A "Combined Work" is a work produced by combining or linking an -+Application with the Library. The particular version of the Library -+with which the Combined Work was made is also called the "Linked -+Version". -+ -+ The "Minimal Corresponding Source" for a Combined Work means the -+Corresponding Source for the Combined Work, excluding any source code -+for portions of the Combined Work that, considered in isolation, are -+based on the Application, and not on the Linked Version. -+ -+ The "Corresponding Application Code" for a Combined Work means the -+object code and/or source code for the Application, including any data -+and utility programs needed for reproducing the Combined Work from the -+Application, but excluding the System Libraries of the Combined Work. -+ -+ 1. Exception to Section 3 of the GNU GPL. -+ -+ You may convey a covered work under sections 3 and 4 of this License -+without being bound by section 3 of the GNU GPL. -+ -+ 2. Conveying Modified Versions. -+ -+ If you modify a copy of the Library, and, in your modifications, a -+facility refers to a function or data to be supplied by an Application -+that uses the facility (other than as an argument passed when the -+facility is invoked), then you may convey a copy of the modified -+version: -+ -+ a) under this License, provided that you make a good faith effort to -+ ensure that, in the event an Application does not supply the -+ function or data, the facility still operates, and performs -+ whatever part of its purpose remains meaningful, or -+ -+ b) under the GNU GPL, with none of the additional permissions of -+ this License applicable to that copy. -+ -+ 3. Object Code Incorporating Material from Library Header Files. -+ -+ The object code form of an Application may incorporate material from -+a header file that is part of the Library. You may convey such object -+code under terms of your choice, provided that, if the incorporated -+material is not limited to numerical parameters, data structure -+layouts and accessors, or small macros, inline functions and templates -+(ten or fewer lines in length), you do both of the following: -+ -+ a) Give prominent notice with each copy of the object code that the -+ Library is used in it and that the Library and its use are -+ covered by this License. -+ -+ b) Accompany the object code with a copy of the GNU GPL and this license -+ document. -+ -+ 4. Combined Works. -+ -+ You may convey a Combined Work under terms of your choice that, -+taken together, effectively do not restrict modification of the -+portions of the Library contained in the Combined Work and reverse -+engineering for debugging such modifications, if you also do each of -+the following: -+ -+ a) Give prominent notice with each copy of the Combined Work that -+ the Library is used in it and that the Library and its use are -+ covered by this License. -+ -+ b) Accompany the Combined Work with a copy of the GNU GPL and this license -+ document. -+ -+ c) For a Combined Work that displays copyright notices during -+ execution, include the copyright notice for the Library among -+ these notices, as well as a reference directing the user to the -+ copies of the GNU GPL and this license document. -+ -+ d) Do one of the following: -+ -+ 0) Convey the Minimal Corresponding Source under the terms of this -+ License, and the Corresponding Application Code in a form -+ suitable for, and under terms that permit, the user to -+ recombine or relink the Application with a modified version of -+ the Linked Version to produce a modified Combined Work, in the -+ manner specified by section 6 of the GNU GPL for conveying -+ Corresponding Source. -+ -+ 1) Use a suitable shared library mechanism for linking with the -+ Library. A suitable mechanism is one that (a) uses at run time -+ a copy of the Library already present on the user's computer -+ system, and (b) will operate properly with a modified version -+ of the Library that is interface-compatible with the Linked -+ Version. -+ -+ e) Provide Installation Information, but only if you would otherwise -+ be required to provide such information under section 6 of the -+ GNU GPL, and only to the extent that such information is -+ necessary to install and execute a modified version of the -+ Combined Work produced by recombining or relinking the -+ Application with a modified version of the Linked Version. (If -+ you use option 4d0, the Installation Information must accompany -+ the Minimal Corresponding Source and Corresponding Application -+ Code. If you use option 4d1, you must provide the Installation -+ Information in the manner specified by section 6 of the GNU GPL -+ for conveying Corresponding Source.) -+ -+ 5. Combined Libraries. -+ -+ You may place library facilities that are a work based on the -+Library side by side in a single library together with other library -+facilities that are not Applications and are not covered by this -+License, and convey such a combined library under terms of your -+choice, if you do both of the following: -+ -+ a) Accompany the combined library with a copy of the same work based -+ on the Library, uncombined with any other library facilities, -+ conveyed under the terms of this License. -+ -+ b) Give prominent notice with the combined library that part of it -+ is a work based on the Library, and explaining where to find the -+ accompanying uncombined form of the same work. -+ -+ 6. Revised Versions of the GNU Lesser General Public License. -+ -+ The Free Software Foundation may publish revised and/or new versions -+of the GNU Lesser General Public License from time to time. Such new -+versions will be similar in spirit to the present version, but may -+differ in detail to address new problems or concerns. -+ -+ Each version is given a distinguishing version number. If the -+Library as you received it specifies that a certain numbered version -+of the GNU Lesser General Public License "or any later version" -+applies to it, you have the option of following the terms and -+conditions either of that published version or of any later version -+published by the Free Software Foundation. If the Library as you -+received it does not specify a version number of the GNU Lesser -+General Public License, you may choose any version of the GNU Lesser -+General Public License ever published by the Free Software Foundation. -+ -+ If the Library as you received it specifies that a proxy can decide -+whether future versions of the GNU Lesser General Public License shall -+apply, that proxy's public statement of acceptance of any version is -+permanent authorization for you to choose that version for the -+Library. -diff --git a/cut-n-paste/unarr/Makefile.am b/cut-n-paste/unarr/Makefile.am -new file mode 100644 -index 00000000..368efb6a ---- /dev/null -+++ b/cut-n-paste/unarr/Makefile.am -@@ -0,0 +1,36 @@ -+noinst_LTLIBRARIES = libunarr.la -+ -+libunarr_la_SOURCES = \ -+ unarr.h \ -+ rar/filter-rar.c \ -+ rar/lzss.h \ -+ rar/rar.h \ -+ rar/rarvm.h \ -+ rar/huffman-rar.c \ -+ rar/uncompress-rar.c \ -+ rar/rar.c \ -+ rar/rarvm.c \ -+ rar/parse-rar.c \ -+ common/unarr-imp.h \ -+ common/allocator.h \ -+ common/unarr.c \ -+ common/stream.c \ -+ common/conv.c \ -+ common/crc32.c \ -+ lzmasdk/LzmaDec.c \ -+ lzmasdk/Ppmd8.c \ -+ lzmasdk/Precomp.h \ -+ lzmasdk/7zTypes.h \ -+ lzmasdk/Ppmd7.h \ -+ lzmasdk/Ppmd7Dec.c \ -+ lzmasdk/Ppmd8Dec.c \ -+ lzmasdk/CpuArch.h \ -+ lzmasdk/LzmaDec.h \ -+ lzmasdk/CpuArch.c \ -+ lzmasdk/Ppmd8.h \ -+ lzmasdk/Ppmd7.c \ -+ lzmasdk/Ppmd.h -+ -+EXTRA_DIST = COPYING AUTHORS -+ -+-include $(top_srcdir)/git.mk -diff --git a/cut-n-paste/unarr/common/allocator.h b/cut-n-paste/unarr/common/allocator.h -new file mode 100644 -index 00000000..41199c80 ---- /dev/null -+++ b/cut-n-paste/unarr/common/allocator.h -@@ -0,0 +1,29 @@ -+/* Copyright 2015 the unarr project authors (see AUTHORS file). -+ License: LGPLv3 */ -+ -+#ifndef common_allocator_h -+#define common_allocator_h -+ -+#ifdef USE_CUSTOM_ALLOCATOR -+ -+#include -+ -+typedef void *(* custom_malloc_fn)(void *opaque, size_t size); -+typedef void (* custom_free_fn)(void *opaque, void *ptr); -+ -+void ar_set_custom_allocator(custom_malloc_fn custom_malloc, custom_free_fn custom_free, void *opaque); -+ -+#define malloc(size) ar_malloc(size) -+#define calloc(count, size) ar_calloc(count, size) -+#define free(ptr) ar_free(ptr) -+ -+#define realloc(ptr, size) _use_malloc_memcpy_free_instead(ptr, size) -+#define strdup(str) _use_malloc_memcpy_instead(str) -+ -+#elif !defined(NDEBUG) && defined(_MSC_VER) -+ -+#include -+ -+#endif -+ -+#endif -diff --git a/cut-n-paste/unarr/common/conv.c b/cut-n-paste/unarr/common/conv.c -new file mode 100644 -index 00000000..4398539b ---- /dev/null -+++ b/cut-n-paste/unarr/common/conv.c -@@ -0,0 +1,96 @@ -+/* Copyright 2015 the unarr project authors (see AUTHORS file). -+ License: LGPLv3 */ -+ -+#include "unarr-imp.h" -+ -+#include -+ -+/* data from http://en.wikipedia.org/wiki/Cp437 */ -+static const wchar_t gCp437[256] = { -+ 0, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266C, 0x263C, -+ 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, -+ ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', -+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', -+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', -+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', -+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', -+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 0x2302, -+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, -+ 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, -+ 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, -+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, -+ 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, -+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, -+ 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, -+ 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0, -+}; -+ -+size_t ar_conv_rune_to_utf8(wchar_t rune, char *out, size_t size) -+{ -+ if (size < 1) -+ return 0; -+ if (rune < 0x0080) { -+ *out++ = rune & 0x7F; -+ return 1; -+ } -+ if (rune < 0x0800 && size >= 2) { -+ *out++ = 0xC0 | ((rune >> 6) & 0x1F); -+ *out++ = 0x80 | (rune & 0x3F); -+ return 2; -+ } -+ if (size >= 3) { -+ if ((0xD800 <= rune && rune <= 0xDFFF) || rune >= 0x10000) -+ rune = 0xFFFD; -+ *out++ = 0xE0 | ((rune >> 12) & 0x0F); -+ *out++ = 0x80 | ((rune >> 6) & 0x3F); -+ *out++ = 0x80 | (rune & 0x3F); -+ return 3; -+ } -+ *out++ = '?'; -+ return 1; -+} -+ -+char *ar_conv_dos_to_utf8(const char *astr) -+{ -+ char *str, *out; -+ const char *in; -+ size_t size; -+ -+ size = 0; -+ for (in = astr; *in; in++) { -+ char buf[4]; -+ size += ar_conv_rune_to_utf8(gCp437[(uint8_t)*in], buf, sizeof(buf)); -+ } -+ -+ if (size == (size_t)-1) -+ return NULL; -+ str = malloc(size + 1); -+ if (!str) -+ return NULL; -+ -+ for (in = astr, out = str; *in; in++) { -+ out += ar_conv_rune_to_utf8(gCp437[(uint8_t)*in], out, str + size - out); -+ } -+ *out = '\0'; -+ -+ return str; -+} -+ -+time64_t ar_conv_dosdate_to_filetime(uint32_t dosdate) -+{ -+ struct tm tm; -+ time_t t1, t2; -+ -+ tm.tm_sec = (dosdate & 0x1F) * 2; -+ tm.tm_min = (dosdate >> 5) & 0x3F; -+ tm.tm_hour = (dosdate >> 11) & 0x1F; -+ tm.tm_mday = (dosdate >> 16) & 0x1F; -+ tm.tm_mon = ((dosdate >> 21) & 0x0F) - 1; -+ tm.tm_year = ((dosdate >> 25) & 0x7F) + 80; -+ tm.tm_isdst = -1; -+ -+ t1 = mktime(&tm); -+ t2 = mktime(gmtime(&t1)); -+ -+ return (time64_t)(2 * t1 - t2 + 11644473600) * 10000000; -+} -diff --git a/cut-n-paste/unarr/common/crc32.c b/cut-n-paste/unarr/common/crc32.c -new file mode 100644 -index 00000000..b482e6e3 ---- /dev/null -+++ b/cut-n-paste/unarr/common/crc32.c -@@ -0,0 +1,51 @@ -+/* Copyright 2015 the unarr project authors (see AUTHORS file). -+ License: LGPLv3 */ -+ -+#include "unarr-imp.h" -+ -+#ifndef HAVE_ZLIB -+ -+/* code adapted from https://gnunet.org/svn/gnunet/src/util/crypto_crc.c (public domain) */ -+ -+static bool crc_table_ready = false; -+static uint32_t crc_table[256]; -+ -+uint32_t ar_crc32(uint32_t crc32, const unsigned char *data, size_t data_len) -+{ -+ if (!crc_table_ready) { -+ uint32_t i, j; -+ uint32_t h = 1; -+ crc_table[0] = 0; -+ for (i = 128; i; i >>= 1) { -+ h = (h >> 1) ^ ((h & 1) ? 0xEDB88320 : 0); -+ for (j = 0; j < 256; j += 2 * i) { -+ crc_table[i + j] = crc_table[j] ^ h; -+ } -+ } -+ crc_table_ready = true; -+ } -+ -+ crc32 = crc32 ^ 0xFFFFFFFF; -+ while (data_len-- > 0) { -+ crc32 = (crc32 >> 8) ^ crc_table[(crc32 ^ *data++) & 0xFF]; -+ } -+ return crc32 ^ 0xFFFFFFFF; -+} -+ -+#else -+ -+#include -+ -+uint32_t ar_crc32(uint32_t crc, const unsigned char *data, size_t data_len) -+{ -+#if SIZE_MAX > UINT32_MAX -+ while (data_len > UINT32_MAX) { -+ crc = crc32(crc, data, UINT32_MAX); -+ data += UINT32_MAX; -+ data_len -= UINT32_MAX; -+ } -+#endif -+ return crc32(crc, data, (uint32_t)data_len); -+} -+ -+#endif -diff --git a/cut-n-paste/unarr/common/stream.c b/cut-n-paste/unarr/common/stream.c -new file mode 100644 -index 00000000..64fe19b3 ---- /dev/null -+++ b/cut-n-paste/unarr/common/stream.c -@@ -0,0 +1,217 @@ -+/* Copyright 2015 the unarr project authors (see AUTHORS file). -+ License: LGPLv3 */ -+ -+#include "unarr-imp.h" -+ -+ar_stream *ar_open_stream(void *data, ar_stream_close_fn close, ar_stream_read_fn read, ar_stream_seek_fn seek, ar_stream_tell_fn tell) -+{ -+ ar_stream *stream = malloc(sizeof(ar_stream)); -+ if (!stream) { -+ close(data); -+ return NULL; -+ } -+ stream->data = data; -+ stream->close = close; -+ stream->read = read; -+ stream->seek = seek; -+ stream->tell = tell; -+ return stream; -+} -+ -+void ar_close(ar_stream *stream) -+{ -+ if (stream) -+ stream->close(stream->data); -+ free(stream); -+} -+ -+size_t ar_read(ar_stream *stream, void *buffer, size_t count) -+{ -+ return stream->read(stream->data, buffer, count); -+} -+ -+bool ar_seek(ar_stream *stream, off64_t offset, int origin) -+{ -+ return stream->seek(stream->data, offset, origin); -+} -+ -+bool ar_skip(ar_stream *stream, off64_t count) -+{ -+ return stream->seek(stream->data, count, SEEK_CUR); -+} -+ -+off64_t ar_tell(ar_stream *stream) -+{ -+ return stream->tell(stream->data); -+} -+ -+/***** stream based on FILE *****/ -+ -+static void file_close(void *data) -+{ -+ fclose(data); -+} -+ -+static size_t file_read(void *data, void *buffer, size_t count) -+{ -+ return fread(buffer, 1, count, data); -+} -+ -+static bool file_seek(void *data, off64_t offset, int origin) -+{ -+#ifdef _MSC_VER -+ return _fseeki64(data, offset, origin) == 0; -+#else -+#if _POSIX_C_SOURCE >= 200112L -+ if (sizeof(off_t) == 8) -+ return fseeko(data, offset, origin) == 0; -+#endif -+ if (offset > INT32_MAX || offset < INT32_MIN) -+ return false; -+ return fseek(data, (long)offset, origin) == 0; -+#endif -+} -+ -+static off64_t file_tell(void *data) -+{ -+#ifdef _MSC_VER -+ return _ftelli64(data); -+#elif _POSIX_C_SOURCE >= 200112L -+ return ftello(data); -+#else -+ return ftell(data); -+#endif -+} -+ -+ar_stream *ar_open_file(const char *path) -+{ -+ FILE *f = path ? fopen(path, "rb") : NULL; -+ if (!f) -+ return NULL; -+ return ar_open_stream(f, file_close, file_read, file_seek, file_tell); -+} -+ -+#ifdef _WIN32 -+ar_stream *ar_open_file_w(const wchar_t *path) -+{ -+ FILE *f = path ? _wfopen(path, L"rb") : NULL; -+ if (!f) -+ return NULL; -+ return ar_open_stream(f, file_close, file_read, file_seek, file_tell); -+} -+#endif -+ -+/***** stream based on preallocated memory *****/ -+ -+struct MemoryStream { -+ const uint8_t *data; -+ size_t length; -+ size_t offset; -+}; -+ -+static void memory_close(void *data) -+{ -+ struct MemoryStream *stm = data; -+ free(stm); -+} -+ -+static size_t memory_read(void *data, void *buffer, size_t count) -+{ -+ struct MemoryStream *stm = data; -+ if (count > stm->length - stm->offset) -+ count = stm->length - stm->offset; -+ memcpy(buffer, stm->data + stm->offset, count); -+ stm->offset += count; -+ return count; -+} -+ -+static bool memory_seek(void *data, off64_t offset, int origin) -+{ -+ struct MemoryStream *stm = data; -+ if (origin == SEEK_CUR) -+ offset += stm->offset; -+ else if (origin == SEEK_END) -+ offset += stm->length; -+ if (offset < 0 || offset > (off64_t)stm->length || (size_t)offset > stm->length) -+ return false; -+ stm->offset = (size_t)offset; -+ return true; -+} -+ -+static off64_t memory_tell(void *data) -+{ -+ struct MemoryStream *stm = data; -+ return stm->offset; -+} -+ -+ar_stream *ar_open_memory(const void *data, size_t datalen) -+{ -+ struct MemoryStream *stm = malloc(sizeof(struct MemoryStream)); -+ if (!stm) -+ return NULL; -+ stm->data = data; -+ stm->length = datalen; -+ stm->offset = 0; -+ return ar_open_stream(stm, memory_close, memory_read, memory_seek, memory_tell); -+} -+ -+#ifdef _WIN32 -+/***** stream based on IStream *****/ -+ -+#define COBJMACROS -+#include -+ -+static void stream_close(void *data) -+{ -+ IUnknown_Release((IStream *)data); -+} -+ -+static size_t stream_read(void *data, void *buffer, size_t count) -+{ -+ size_t read = 0; -+ HRESULT res; -+ ULONG cbRead; -+#ifdef _WIN64 -+ while (count > ULONG_MAX) { -+ res = IStream_Read((IStream *)data, buffer, ULONG_MAX, &cbRead); -+ if (FAILED(res)) -+ return read; -+ read += cbRead; -+ buffer = (BYTE *)buffer + ULONG_MAX; -+ count -= ULONG_MAX; -+ } -+#endif -+ res = IStream_Read((IStream *)data, buffer, (ULONG)count, &cbRead); -+ if (SUCCEEDED(res)) -+ read += cbRead; -+ return read; -+} -+ -+static bool stream_seek(void *data, off64_t offset, int origin) -+{ -+ LARGE_INTEGER off; -+ ULARGE_INTEGER n; -+ HRESULT res; -+ off.QuadPart = offset; -+ res = IStream_Seek((IStream *)data, off, origin, &n); -+ return SUCCEEDED(res); -+} -+ -+static off64_t stream_tell(void *data) -+{ -+ LARGE_INTEGER zero = { 0 }; -+ ULARGE_INTEGER n = { 0 }; -+ IStream_Seek((IStream *)data, zero, SEEK_CUR, &n); -+ return (off64_t)n.QuadPart; -+} -+ -+ar_stream *ar_open_istream(IStream *stream) -+{ -+ LARGE_INTEGER zero = { 0 }; -+ HRESULT res = IStream_Seek(stream, zero, STREAM_SEEK_SET, NULL); -+ if (FAILED(res)) -+ return NULL; -+ IUnknown_AddRef(stream); -+ return ar_open_stream(stream, stream_close, stream_read, stream_seek, stream_tell); -+} -+#endif -diff --git a/cut-n-paste/unarr/common/unarr-imp.h b/cut-n-paste/unarr/common/unarr-imp.h -new file mode 100644 -index 00000000..90ad3178 ---- /dev/null -+++ b/cut-n-paste/unarr/common/unarr-imp.h -@@ -0,0 +1,81 @@ -+/* Copyright 2015 the unarr project authors (see AUTHORS file). -+ License: LGPLv3 */ -+ -+/* this is the common private/implementation API of unarr which should only be used by unarr code */ -+ -+#ifndef common_unarr_imp_h -+#define common_unarr_imp_h -+ -+#include "../unarr.h" -+#include "allocator.h" -+ -+#include -+#include -+#include -+#include -+#include -+ -+/***** conv ****/ -+ -+size_t ar_conv_rune_to_utf8(wchar_t rune, char *out, size_t size); -+char *ar_conv_dos_to_utf8(const char *astr); -+time64_t ar_conv_dosdate_to_filetime(uint32_t dosdate); -+ -+/***** crc32 *****/ -+ -+uint32_t ar_crc32(uint32_t crc32, const unsigned char *data, size_t data_len); -+ -+/***** stream *****/ -+ -+typedef void (* ar_stream_close_fn)(void *data); -+typedef size_t (* ar_stream_read_fn)(void *data, void *buffer, size_t count); -+typedef bool (* ar_stream_seek_fn)(void *data, off64_t offset, int origin); -+typedef off64_t (* ar_stream_tell_fn)(void *data); -+ -+struct ar_stream_s { -+ ar_stream_close_fn close; -+ ar_stream_read_fn read; -+ ar_stream_seek_fn seek; -+ ar_stream_tell_fn tell; -+ void *data; -+}; -+ -+ar_stream *ar_open_stream(void *data, ar_stream_close_fn close, ar_stream_read_fn read, ar_stream_seek_fn seek, ar_stream_tell_fn tell); -+ -+/***** unarr *****/ -+ -+#define warn(...) ar_log("!", __FILE__, __LINE__, __VA_ARGS__) -+#ifndef NDEBUG -+#define log(...) ar_log("-", __FILE__, __LINE__, __VA_ARGS__) -+#else -+#define log(...) ((void)0) -+#endif -+void ar_log(const char *prefix, const char *file, int line, const char *msg, ...); -+ -+typedef void (* ar_archive_close_fn)(ar_archive *ar); -+typedef bool (* ar_parse_entry_fn)(ar_archive *ar, off64_t offset); -+typedef const char *(* ar_entry_get_name_fn)(ar_archive *ar); -+typedef bool (* ar_entry_uncompress_fn)(ar_archive *ar, void *buffer, size_t count); -+typedef size_t (* ar_get_global_comment_fn)(ar_archive *ar, void *buffer, size_t count); -+ -+struct ar_archive_s { -+ ar_archive_close_fn close; -+ ar_parse_entry_fn parse_entry; -+ ar_entry_get_name_fn get_name; -+ ar_entry_uncompress_fn uncompress; -+ ar_get_global_comment_fn get_comment; -+ -+ ar_stream *stream; -+ bool at_eof; -+ off64_t entry_offset; -+ off64_t entry_offset_first; -+ off64_t entry_offset_next; -+ size_t entry_size_uncompressed; -+ time64_t entry_filetime; -+}; -+ -+ar_archive *ar_open_archive(ar_stream *stream, size_t struct_size, ar_archive_close_fn close, ar_parse_entry_fn parse_entry, -+ ar_entry_get_name_fn get_name, ar_entry_uncompress_fn uncompress, ar_get_global_comment_fn get_comment, -+ off64_t first_entry_offset); -+ -+#endif -diff --git a/cut-n-paste/unarr/common/unarr.c b/cut-n-paste/unarr/common/unarr.c -new file mode 100644 -index 00000000..97ec92ae ---- /dev/null -+++ b/cut-n-paste/unarr/common/unarr.c -@@ -0,0 +1,109 @@ -+/* Copyright 2015 the unarr project authors (see AUTHORS file). -+ License: LGPLv3 */ -+ -+#include "unarr-imp.h" -+ -+ar_archive *ar_open_archive(ar_stream *stream, size_t struct_size, ar_archive_close_fn close, ar_parse_entry_fn parse_entry, -+ ar_entry_get_name_fn get_name, ar_entry_uncompress_fn uncompress, ar_get_global_comment_fn get_comment, -+ off64_t first_entry_offset) -+{ -+ ar_archive *ar = malloc(struct_size); -+ if (!ar) -+ return NULL; -+ memset(ar, 0, struct_size); -+ ar->close = close; -+ ar->parse_entry = parse_entry; -+ ar->get_name = get_name; -+ ar->uncompress = uncompress; -+ ar->get_comment = get_comment; -+ ar->stream = stream; -+ ar->entry_offset_first = first_entry_offset; -+ ar->entry_offset_next = first_entry_offset; -+ return ar; -+} -+ -+void ar_close_archive(ar_archive *ar) -+{ -+ if (ar) -+ ar->close(ar); -+ free(ar); -+} -+ -+bool ar_at_eof(ar_archive *ar) -+{ -+ return ar->at_eof; -+} -+ -+bool ar_parse_entry(ar_archive *ar) -+{ -+ return ar->parse_entry(ar, ar->entry_offset_next); -+} -+ -+bool ar_parse_entry_at(ar_archive *ar, off64_t offset) -+{ -+ ar->at_eof = false; -+ return ar->parse_entry(ar, offset ? offset : ar->entry_offset_first); -+} -+ -+bool ar_parse_entry_for(ar_archive *ar, const char *entry_name) -+{ -+ ar->at_eof = false; -+ if (!entry_name) -+ return false; -+ if (!ar_parse_entry_at(ar, ar->entry_offset_first)) -+ return false; -+ do { -+ const char *name = ar_entry_get_name(ar); -+ if (name && strcmp(name, entry_name) == 0) -+ return true; -+ } while (ar_parse_entry(ar)); -+ return false; -+} -+ -+const char *ar_entry_get_name(ar_archive *ar) -+{ -+ return ar->get_name(ar); -+} -+ -+off64_t ar_entry_get_offset(ar_archive *ar) -+{ -+ return ar->entry_offset; -+} -+ -+size_t ar_entry_get_size(ar_archive *ar) -+{ -+ return ar->entry_size_uncompressed; -+} -+ -+time64_t ar_entry_get_filetime(ar_archive *ar) -+{ -+ return ar->entry_filetime; -+} -+ -+bool ar_entry_uncompress(ar_archive *ar, void *buffer, size_t count) -+{ -+ return ar->uncompress(ar, buffer, count); -+} -+ -+size_t ar_get_global_comment(ar_archive *ar, void *buffer, size_t count) -+{ -+ if (!ar->get_comment) -+ return 0; -+ return ar->get_comment(ar, buffer, count); -+} -+ -+void ar_log(const char *prefix, const char *file, int line, const char *msg, ...) -+{ -+ va_list args; -+ va_start(args, msg); -+ if (prefix) -+ fprintf(stderr, "%s ", prefix); -+ if (strrchr(file, '/')) -+ file = strrchr(file, '/') + 1; -+ if (strrchr(file, '\\')) -+ file = strrchr(file, '\\') + 1; -+ fprintf(stderr, "%s:%d: ", file, line); -+ vfprintf(stderr, msg, args); -+ fprintf(stderr, "\n"); -+ va_end(args); -+} -diff --git a/cut-n-paste/unarr/lzmasdk/7zTypes.h b/cut-n-paste/unarr/lzmasdk/7zTypes.h -new file mode 100644 -index 00000000..778413ef ---- /dev/null -+++ b/cut-n-paste/unarr/lzmasdk/7zTypes.h -@@ -0,0 +1,256 @@ -+/* 7zTypes.h -- Basic types -+2013-11-12 : Igor Pavlov : Public domain */ -+ -+#ifndef __7Z_TYPES_H -+#define __7Z_TYPES_H -+ -+#ifdef _WIN32 -+/* #include */ -+#endif -+ -+#include -+ -+#ifndef EXTERN_C_BEGIN -+#ifdef __cplusplus -+#define EXTERN_C_BEGIN extern "C" { -+#define EXTERN_C_END } -+#else -+#define EXTERN_C_BEGIN -+#define EXTERN_C_END -+#endif -+#endif -+ -+EXTERN_C_BEGIN -+ -+#define SZ_OK 0 -+ -+#define SZ_ERROR_DATA 1 -+#define SZ_ERROR_MEM 2 -+#define SZ_ERROR_CRC 3 -+#define SZ_ERROR_UNSUPPORTED 4 -+#define SZ_ERROR_PARAM 5 -+#define SZ_ERROR_INPUT_EOF 6 -+#define SZ_ERROR_OUTPUT_EOF 7 -+#define SZ_ERROR_READ 8 -+#define SZ_ERROR_WRITE 9 -+#define SZ_ERROR_PROGRESS 10 -+#define SZ_ERROR_FAIL 11 -+#define SZ_ERROR_THREAD 12 -+ -+#define SZ_ERROR_ARCHIVE 16 -+#define SZ_ERROR_NO_ARCHIVE 17 -+ -+typedef int SRes; -+ -+#ifdef _WIN32 -+/* typedef DWORD WRes; */ -+typedef unsigned WRes; -+#else -+typedef int WRes; -+#endif -+ -+#ifndef RINOK -+#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } -+#endif -+ -+typedef unsigned char Byte; -+typedef short Int16; -+typedef unsigned short UInt16; -+ -+#ifdef _LZMA_UINT32_IS_ULONG -+typedef long Int32; -+typedef unsigned long UInt32; -+#else -+typedef int Int32; -+typedef unsigned int UInt32; -+#endif -+ -+#ifdef _SZ_NO_INT_64 -+ -+/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. -+ NOTES: Some code will work incorrectly in that case! */ -+ -+typedef long Int64; -+typedef unsigned long UInt64; -+ -+#else -+ -+#if defined(_MSC_VER) || defined(__BORLANDC__) -+typedef __int64 Int64; -+typedef unsigned __int64 UInt64; -+#define UINT64_CONST(n) n -+#else -+typedef long long int Int64; -+typedef unsigned long long int UInt64; -+#define UINT64_CONST(n) n ## ULL -+#endif -+ -+#endif -+ -+#ifdef _LZMA_NO_SYSTEM_SIZE_T -+typedef UInt32 SizeT; -+#else -+typedef size_t SizeT; -+#endif -+ -+typedef int Bool; -+#define True 1 -+#define False 0 -+ -+ -+#ifdef _WIN32 -+#define MY_STD_CALL __stdcall -+#else -+#define MY_STD_CALL -+#endif -+ -+#ifdef _MSC_VER -+ -+#if _MSC_VER >= 1300 -+#define MY_NO_INLINE __declspec(noinline) -+#else -+#define MY_NO_INLINE -+#endif -+ -+#define MY_CDECL __cdecl -+#define MY_FAST_CALL __fastcall -+ -+#else -+ -+#define MY_NO_INLINE -+#define MY_CDECL -+#define MY_FAST_CALL -+ -+#endif -+ -+ -+/* The following interfaces use first parameter as pointer to structure */ -+ -+typedef struct -+{ -+ Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */ -+} IByteIn; -+ -+typedef struct -+{ -+ void (*Write)(void *p, Byte b); -+} IByteOut; -+ -+typedef struct -+{ -+ SRes (*Read)(void *p, void *buf, size_t *size); -+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. -+ (output(*size) < input(*size)) is allowed */ -+} ISeqInStream; -+ -+/* it can return SZ_ERROR_INPUT_EOF */ -+SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); -+SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); -+SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); -+ -+typedef struct -+{ -+ size_t (*Write)(void *p, const void *buf, size_t size); -+ /* Returns: result - the number of actually written bytes. -+ (result < size) means error */ -+} ISeqOutStream; -+ -+typedef enum -+{ -+ SZ_SEEK_SET = 0, -+ SZ_SEEK_CUR = 1, -+ SZ_SEEK_END = 2 -+} ESzSeek; -+ -+typedef struct -+{ -+ SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ -+ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); -+} ISeekInStream; -+ -+typedef struct -+{ -+ SRes (*Look)(void *p, const void **buf, size_t *size); -+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. -+ (output(*size) > input(*size)) is not allowed -+ (output(*size) < input(*size)) is allowed */ -+ SRes (*Skip)(void *p, size_t offset); -+ /* offset must be <= output(*size) of Look */ -+ -+ SRes (*Read)(void *p, void *buf, size_t *size); -+ /* reads directly (without buffer). It's same as ISeqInStream::Read */ -+ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); -+} ILookInStream; -+ -+SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); -+SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); -+ -+/* reads via ILookInStream::Read */ -+SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); -+SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); -+ -+#define LookToRead_BUF_SIZE (1 << 14) -+ -+typedef struct -+{ -+ ILookInStream s; -+ ISeekInStream *realStream; -+ size_t pos; -+ size_t size; -+ Byte buf[LookToRead_BUF_SIZE]; -+} CLookToRead; -+ -+void LookToRead_CreateVTable(CLookToRead *p, int lookahead); -+void LookToRead_Init(CLookToRead *p); -+ -+typedef struct -+{ -+ ISeqInStream s; -+ ILookInStream *realStream; -+} CSecToLook; -+ -+void SecToLook_CreateVTable(CSecToLook *p); -+ -+typedef struct -+{ -+ ISeqInStream s; -+ ILookInStream *realStream; -+} CSecToRead; -+ -+void SecToRead_CreateVTable(CSecToRead *p); -+ -+typedef struct -+{ -+ SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); -+ /* Returns: result. (result != SZ_OK) means break. -+ Value (UInt64)(Int64)-1 for size means unknown value. */ -+} ICompressProgress; -+ -+typedef struct -+{ -+ void *(*Alloc)(void *p, size_t size); -+ void (*Free)(void *p, void *address); /* address can be 0 */ -+} ISzAlloc; -+ -+#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) -+#define IAlloc_Free(p, a) (p)->Free((p), a) -+ -+#ifdef _WIN32 -+ -+#define CHAR_PATH_SEPARATOR '\\' -+#define WCHAR_PATH_SEPARATOR L'\\' -+#define STRING_PATH_SEPARATOR "\\" -+#define WSTRING_PATH_SEPARATOR L"\\" -+ -+#else -+ -+#define CHAR_PATH_SEPARATOR '/' -+#define WCHAR_PATH_SEPARATOR L'/' -+#define STRING_PATH_SEPARATOR "/" -+#define WSTRING_PATH_SEPARATOR L"/" -+ -+#endif -+ -+EXTERN_C_END -+ -+#endif -diff --git a/cut-n-paste/unarr/lzmasdk/CpuArch.c b/cut-n-paste/unarr/lzmasdk/CpuArch.c -new file mode 100644 -index 00000000..d7f8b1d8 ---- /dev/null -+++ b/cut-n-paste/unarr/lzmasdk/CpuArch.c -@@ -0,0 +1,190 @@ -+/* CpuArch.c -- CPU specific code -+2012-05-29: Igor Pavlov : Public domain */ -+ -+#include "Precomp.h" -+ -+#include "CpuArch.h" -+ -+#ifdef MY_CPU_X86_OR_AMD64 -+ -+#if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__) -+#define USE_ASM -+#endif -+ -+#if !defined(USE_ASM) && _MSC_VER >= 1500 -+#include -+#endif -+ -+#if defined(USE_ASM) && !defined(MY_CPU_AMD64) -+static UInt32 CheckFlag(UInt32 flag) -+{ -+ #ifdef _MSC_VER -+ __asm pushfd; -+ __asm pop EAX; -+ __asm mov EDX, EAX; -+ __asm xor EAX, flag; -+ __asm push EAX; -+ __asm popfd; -+ __asm pushfd; -+ __asm pop EAX; -+ __asm xor EAX, EDX; -+ __asm push EDX; -+ __asm popfd; -+ __asm and flag, EAX; -+ #else -+ __asm__ __volatile__ ( -+ "pushf\n\t" -+ "pop %%EAX\n\t" -+ "movl %%EAX,%%EDX\n\t" -+ "xorl %0,%%EAX\n\t" -+ "push %%EAX\n\t" -+ "popf\n\t" -+ "pushf\n\t" -+ "pop %%EAX\n\t" -+ "xorl %%EDX,%%EAX\n\t" -+ "push %%EDX\n\t" -+ "popf\n\t" -+ "andl %%EAX, %0\n\t": -+ "=c" (flag) : "c" (flag)); -+ #endif -+ return flag; -+} -+#define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False; -+#else -+#define CHECK_CPUID_IS_SUPPORTED -+#endif -+ -+static void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d) -+{ -+ #ifdef USE_ASM -+ -+ #ifdef _MSC_VER -+ -+ UInt32 a2, b2, c2, d2; -+ __asm xor EBX, EBX; -+ __asm xor ECX, ECX; -+ __asm xor EDX, EDX; -+ __asm mov EAX, function; -+ __asm cpuid; -+ __asm mov a2, EAX; -+ __asm mov b2, EBX; -+ __asm mov c2, ECX; -+ __asm mov d2, EDX; -+ -+ *a = a2; -+ *b = b2; -+ *c = c2; -+ *d = d2; -+ -+ #else -+ -+ __asm__ __volatile__ ( -+ #if defined(MY_CPU_X86) && defined(__PIC__) -+ "mov %%ebx, %%edi;" -+ "cpuid;" -+ "xchgl %%ebx, %%edi;" -+ : "=a" (*a) , -+ "=D" (*b) , -+ #else -+ "cpuid" -+ : "=a" (*a) , -+ "=b" (*b) , -+ #endif -+ "=c" (*c) , -+ "=d" (*d) -+ : "0" (function)) ; -+ -+ #endif -+ -+ #else -+ -+ int CPUInfo[4]; -+ __cpuid(CPUInfo, function); -+ *a = CPUInfo[0]; -+ *b = CPUInfo[1]; -+ *c = CPUInfo[2]; -+ *d = CPUInfo[3]; -+ -+ #endif -+} -+ -+Bool x86cpuid_CheckAndRead(Cx86cpuid *p) -+{ -+ CHECK_CPUID_IS_SUPPORTED -+ MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]); -+ MyCPUID(1, &p->ver, &p->b, &p->c, &p->d); -+ return True; -+} -+ -+static UInt32 kVendors[][3] = -+{ -+ { 0x756E6547, 0x49656E69, 0x6C65746E}, -+ { 0x68747541, 0x69746E65, 0x444D4163}, -+ { 0x746E6543, 0x48727561, 0x736C7561} -+}; -+ -+int x86cpuid_GetFirm(const Cx86cpuid *p) -+{ -+ unsigned i; -+ for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++) -+ { -+ const UInt32 *v = kVendors[i]; -+ if (v[0] == p->vendor[0] && -+ v[1] == p->vendor[1] && -+ v[2] == p->vendor[2]) -+ return (int)i; -+ } -+ return -1; -+} -+ -+Bool CPU_Is_InOrder() -+{ -+ Cx86cpuid p; -+ int firm; -+ UInt32 family, model; -+ if (!x86cpuid_CheckAndRead(&p)) -+ return True; -+ family = x86cpuid_GetFamily(&p); -+ model = x86cpuid_GetModel(&p); -+ firm = x86cpuid_GetFirm(&p); -+ switch (firm) -+ { -+ case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && ( -+ /* Atom CPU */ -+ model == 0x100C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */ -+ || model == 0x2006 /* 45 nm, Z6xx */ -+ || model == 0x2007 /* 32 nm, Z2460 */ -+ || model == 0x3005 /* 32 nm, Z2760 */ -+ || model == 0x3006 /* 32 nm, N2xxx, D2xxx */ -+ ))); -+ case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA))); -+ case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF)); -+ } -+ return True; -+} -+ -+#if !defined(MY_CPU_AMD64) && defined(_WIN32) -+#include -+static Bool CPU_Sys_Is_SSE_Supported() -+{ -+ OSVERSIONINFO vi; -+ vi.dwOSVersionInfoSize = sizeof(vi); -+ if (!GetVersionEx(&vi)) -+ return False; -+ return (vi.dwMajorVersion >= 5); -+} -+#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False; -+#else -+#define CHECK_SYS_SSE_SUPPORT -+#endif -+ -+Bool CPU_Is_Aes_Supported() -+{ -+ Cx86cpuid p; -+ CHECK_SYS_SSE_SUPPORT -+ if (!x86cpuid_CheckAndRead(&p)) -+ return False; -+ return (p.c >> 25) & 1; -+} -+ -+#endif -diff --git a/cut-n-paste/unarr/lzmasdk/CpuArch.h b/cut-n-paste/unarr/lzmasdk/CpuArch.h -new file mode 100644 -index 00000000..4fee0093 ---- /dev/null -+++ b/cut-n-paste/unarr/lzmasdk/CpuArch.h -@@ -0,0 +1,157 @@ -+/* CpuArch.h -- CPU specific code -+2013-11-12: Igor Pavlov : Public domain */ -+ -+#ifndef __CPU_ARCH_H -+#define __CPU_ARCH_H -+ -+#include "7zTypes.h" -+ -+EXTERN_C_BEGIN -+ -+/* -+MY_CPU_LE means that CPU is LITTLE ENDIAN. -+If MY_CPU_LE is not defined, we don't know about that property of platform (it can be LITTLE ENDIAN). -+ -+MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses. -+If MY_CPU_LE_UNALIGN is not defined, we don't know about these properties of platform. -+*/ -+ -+#if defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__) -+#define MY_CPU_AMD64 -+#endif -+ -+#if defined(MY_CPU_AMD64) || defined(_M_IA64) -+#define MY_CPU_64BIT -+#endif -+ -+#if defined(_M_IX86) || defined(__i386__) -+#define MY_CPU_X86 -+#endif -+ -+#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64) -+#define MY_CPU_X86_OR_AMD64 -+#endif -+ -+#if defined(MY_CPU_X86) || defined(_M_ARM) -+#define MY_CPU_32BIT -+#endif -+ -+#if defined(_WIN32) && defined(_M_ARM) -+#define MY_CPU_ARM_LE -+#endif -+ -+#if defined(_WIN32) && defined(_M_IA64) -+#define MY_CPU_IA64_LE -+#endif -+ -+#if defined(MY_CPU_X86_OR_AMD64) -+#define MY_CPU_LE_UNALIGN -+#endif -+ -+#if defined(MY_CPU_X86_OR_AMD64) || defined(MY_CPU_ARM_LE) || defined(MY_CPU_IA64_LE) || defined(__ARMEL__) || defined(__MIPSEL__) || defined(__LITTLE_ENDIAN__) -+#define MY_CPU_LE -+#endif -+ -+#if defined(__BIG_ENDIAN__) || defined(__m68k__) || defined(__ARMEB__) || defined(__MIPSEB__) -+#define MY_CPU_BE -+#endif -+ -+#if defined(MY_CPU_LE) && defined(MY_CPU_BE) -+Stop_Compiling_Bad_Endian -+#endif -+ -+#ifdef MY_CPU_LE_UNALIGN -+ -+#define GetUi16(p) (*(const UInt16 *)(const void *)(p)) -+#define GetUi32(p) (*(const UInt32 *)(const void *)(p)) -+#define GetUi64(p) (*(const UInt64 *)(const void *)(p)) -+#define SetUi16(p, d) *(UInt16 *)(p) = (d); -+#define SetUi32(p, d) *(UInt32 *)(p) = (d); -+#define SetUi64(p, d) *(UInt64 *)(p) = (d); -+ -+#else -+ -+#define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8)) -+ -+#define GetUi32(p) ( \ -+ ((const Byte *)(p))[0] | \ -+ ((UInt32)((const Byte *)(p))[1] << 8) | \ -+ ((UInt32)((const Byte *)(p))[2] << 16) | \ -+ ((UInt32)((const Byte *)(p))[3] << 24)) -+ -+#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32)) -+ -+#define SetUi16(p, d) { UInt32 _x_ = (d); \ -+ ((Byte *)(p))[0] = (Byte)_x_; \ -+ ((Byte *)(p))[1] = (Byte)(_x_ >> 8); } -+ -+#define SetUi32(p, d) { UInt32 _x_ = (d); \ -+ ((Byte *)(p))[0] = (Byte)_x_; \ -+ ((Byte *)(p))[1] = (Byte)(_x_ >> 8); \ -+ ((Byte *)(p))[2] = (Byte)(_x_ >> 16); \ -+ ((Byte *)(p))[3] = (Byte)(_x_ >> 24); } -+ -+#define SetUi64(p, d) { UInt64 _x64_ = (d); \ -+ SetUi32(p, (UInt32)_x64_); \ -+ SetUi32(((Byte *)(p)) + 4, (UInt32)(_x64_ >> 32)); } -+ -+#endif -+ -+#if defined(MY_CPU_LE_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300) -+ -+#include -+ -+#pragma intrinsic(_byteswap_ulong) -+#pragma intrinsic(_byteswap_uint64) -+#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p)) -+#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p)) -+ -+#else -+ -+#define GetBe32(p) ( \ -+ ((UInt32)((const Byte *)(p))[0] << 24) | \ -+ ((UInt32)((const Byte *)(p))[1] << 16) | \ -+ ((UInt32)((const Byte *)(p))[2] << 8) | \ -+ ((const Byte *)(p))[3] ) -+ -+#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4)) -+ -+#endif -+ -+#define GetBe16(p) ((UInt16)(((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1])) -+ -+ -+#ifdef MY_CPU_X86_OR_AMD64 -+ -+typedef struct -+{ -+ UInt32 maxFunc; -+ UInt32 vendor[3]; -+ UInt32 ver; -+ UInt32 b; -+ UInt32 c; -+ UInt32 d; -+} Cx86cpuid; -+ -+enum -+{ -+ CPU_FIRM_INTEL, -+ CPU_FIRM_AMD, -+ CPU_FIRM_VIA -+}; -+ -+Bool x86cpuid_CheckAndRead(Cx86cpuid *p); -+int x86cpuid_GetFirm(const Cx86cpuid *p); -+ -+#define x86cpuid_GetFamily(p) (((p)->ver >> 8) & 0xFF00F) -+#define x86cpuid_GetModel(p) (((p)->ver >> 4) & 0xF00F) -+#define x86cpuid_GetStepping(p) ((p)->ver & 0xF) -+ -+Bool CPU_Is_InOrder(); -+Bool CPU_Is_Aes_Supported(); -+ -+#endif -+ -+EXTERN_C_END -+ -+#endif -diff --git a/cut-n-paste/unarr/lzmasdk/LzmaDec.c b/cut-n-paste/unarr/lzmasdk/LzmaDec.c -new file mode 100644 -index 00000000..bbf650de ---- /dev/null -+++ b/cut-n-paste/unarr/lzmasdk/LzmaDec.c -@@ -0,0 +1,1025 @@ -+/* LzmaDec.c -- LZMA Decoder -+2015-01-01 : Igor Pavlov : Public domain */ -+ -+#include "Precomp.h" -+ -+#include "LzmaDec.h" -+ -+#include -+ -+#define kNumTopBits 24 -+#define kTopValue ((UInt32)1 << kNumTopBits) -+ -+#define kNumBitModelTotalBits 11 -+#define kBitModelTotal (1 << kNumBitModelTotalBits) -+#define kNumMoveBits 5 -+ -+#define RC_INIT_SIZE 5 -+ -+#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } -+ -+#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) -+#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); -+#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); -+#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ -+ { UPDATE_0(p); i = (i + i); A0; } else \ -+ { UPDATE_1(p); i = (i + i) + 1; A1; } -+#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) -+ -+#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } -+#define TREE_DECODE(probs, limit, i) \ -+ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } -+ -+/* #define _LZMA_SIZE_OPT */ -+ -+#ifdef _LZMA_SIZE_OPT -+#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) -+#else -+#define TREE_6_DECODE(probs, i) \ -+ { i = 1; \ -+ TREE_GET_BIT(probs, i); \ -+ TREE_GET_BIT(probs, i); \ -+ TREE_GET_BIT(probs, i); \ -+ TREE_GET_BIT(probs, i); \ -+ TREE_GET_BIT(probs, i); \ -+ TREE_GET_BIT(probs, i); \ -+ i -= 0x40; } -+#endif -+ -+#define NORMAL_LITER_DEC GET_BIT(prob + symbol, symbol) -+#define MATCHED_LITER_DEC \ -+ matchByte <<= 1; \ -+ bit = (matchByte & offs); \ -+ probLit = prob + offs + bit + symbol; \ -+ GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) -+ -+#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } -+ -+#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) -+#define UPDATE_0_CHECK range = bound; -+#define UPDATE_1_CHECK range -= bound; code -= bound; -+#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ -+ { UPDATE_0_CHECK; i = (i + i); A0; } else \ -+ { UPDATE_1_CHECK; i = (i + i) + 1; A1; } -+#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) -+#define TREE_DECODE_CHECK(probs, limit, i) \ -+ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } -+ -+ -+#define kNumPosBitsMax 4 -+#define kNumPosStatesMax (1 << kNumPosBitsMax) -+ -+#define kLenNumLowBits 3 -+#define kLenNumLowSymbols (1 << kLenNumLowBits) -+#define kLenNumMidBits 3 -+#define kLenNumMidSymbols (1 << kLenNumMidBits) -+#define kLenNumHighBits 8 -+#define kLenNumHighSymbols (1 << kLenNumHighBits) -+ -+#define LenChoice 0 -+#define LenChoice2 (LenChoice + 1) -+#define LenLow (LenChoice2 + 1) -+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) -+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) -+#define kNumLenProbs (LenHigh + kLenNumHighSymbols) -+ -+ -+#define kNumStates 12 -+#define kNumLitStates 7 -+ -+#define kStartPosModelIndex 4 -+#define kEndPosModelIndex 14 -+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) -+ -+#define kNumPosSlotBits 6 -+#define kNumLenToPosStates 4 -+ -+#define kNumAlignBits 4 -+#define kAlignTableSize (1 << kNumAlignBits) -+ -+#define kMatchMinLen 2 -+#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) -+ -+#define IsMatch 0 -+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) -+#define IsRepG0 (IsRep + kNumStates) -+#define IsRepG1 (IsRepG0 + kNumStates) -+#define IsRepG2 (IsRepG1 + kNumStates) -+#define IsRep0Long (IsRepG2 + kNumStates) -+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) -+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) -+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) -+#define LenCoder (Align + kAlignTableSize) -+#define RepLenCoder (LenCoder + kNumLenProbs) -+#define Literal (RepLenCoder + kNumLenProbs) -+ -+#define LZMA_BASE_SIZE 1846 -+#define LZMA_LIT_SIZE 768 -+ -+#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) -+ -+#if Literal != LZMA_BASE_SIZE -+StopCompilingDueBUG -+#endif -+ -+#define LZMA_DIC_MIN (1 << 12) -+ -+/* First LZMA-symbol is always decoded. -+And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization -+Out: -+ Result: -+ SZ_OK - OK -+ SZ_ERROR_DATA - Error -+ p->remainLen: -+ < kMatchSpecLenStart : normal remain -+ = kMatchSpecLenStart : finished -+ = kMatchSpecLenStart + 1 : Flush marker -+ = kMatchSpecLenStart + 2 : State Init Marker -+*/ -+ -+static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) -+{ -+ CLzmaProb *probs = p->probs; -+ -+ unsigned state = p->state; -+ UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; -+ unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; -+ unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; -+ unsigned lc = p->prop.lc; -+ -+ Byte *dic = p->dic; -+ SizeT dicBufSize = p->dicBufSize; -+ SizeT dicPos = p->dicPos; -+ -+ UInt32 processedPos = p->processedPos; -+ UInt32 checkDicSize = p->checkDicSize; -+ unsigned len = 0; -+ -+ const Byte *buf = p->buf; -+ UInt32 range = p->range; -+ UInt32 code = p->code; -+ -+ do -+ { -+ CLzmaProb *prob; -+ UInt32 bound; -+ unsigned ttt; -+ unsigned posState = processedPos & pbMask; -+ -+ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; -+ IF_BIT_0(prob) -+ { -+ unsigned symbol; -+ UPDATE_0(prob); -+ prob = probs + Literal; -+ if (checkDicSize != 0 || processedPos != 0) -+ prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + -+ (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); -+ -+ if (state < kNumLitStates) -+ { -+ state -= (state < 4) ? state : 3; -+ symbol = 1; -+ #ifdef _LZMA_SIZE_OPT -+ do { NORMAL_LITER_DEC } while (symbol < 0x100); -+ #else -+ NORMAL_LITER_DEC -+ NORMAL_LITER_DEC -+ NORMAL_LITER_DEC -+ NORMAL_LITER_DEC -+ NORMAL_LITER_DEC -+ NORMAL_LITER_DEC -+ NORMAL_LITER_DEC -+ NORMAL_LITER_DEC -+ #endif -+ } -+ else -+ { -+ unsigned matchByte = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; -+ unsigned offs = 0x100; -+ state -= (state < 10) ? 3 : 6; -+ symbol = 1; -+ #ifdef _LZMA_SIZE_OPT -+ do -+ { -+ unsigned bit; -+ CLzmaProb *probLit; -+ MATCHED_LITER_DEC -+ } -+ while (symbol < 0x100); -+ #else -+ { -+ unsigned bit; -+ CLzmaProb *probLit; -+ MATCHED_LITER_DEC -+ MATCHED_LITER_DEC -+ MATCHED_LITER_DEC -+ MATCHED_LITER_DEC -+ MATCHED_LITER_DEC -+ MATCHED_LITER_DEC -+ MATCHED_LITER_DEC -+ MATCHED_LITER_DEC -+ } -+ #endif -+ } -+ dic[dicPos++] = (Byte)symbol; -+ processedPos++; -+ continue; -+ } -+ else -+ { -+ UPDATE_1(prob); -+ prob = probs + IsRep + state; -+ IF_BIT_0(prob) -+ { -+ UPDATE_0(prob); -+ state += kNumStates; -+ prob = probs + LenCoder; -+ } -+ else -+ { -+ UPDATE_1(prob); -+ if (checkDicSize == 0 && processedPos == 0) -+ return SZ_ERROR_DATA; -+ prob = probs + IsRepG0 + state; -+ IF_BIT_0(prob) -+ { -+ UPDATE_0(prob); -+ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; -+ IF_BIT_0(prob) -+ { -+ UPDATE_0(prob); -+ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; -+ dicPos++; -+ processedPos++; -+ state = state < kNumLitStates ? 9 : 11; -+ continue; -+ } -+ UPDATE_1(prob); -+ } -+ else -+ { -+ UInt32 distance; -+ UPDATE_1(prob); -+ prob = probs + IsRepG1 + state; -+ IF_BIT_0(prob) -+ { -+ UPDATE_0(prob); -+ distance = rep1; -+ } -+ else -+ { -+ UPDATE_1(prob); -+ prob = probs + IsRepG2 + state; -+ IF_BIT_0(prob) -+ { -+ UPDATE_0(prob); -+ distance = rep2; -+ } -+ else -+ { -+ UPDATE_1(prob); -+ distance = rep3; -+ rep3 = rep2; -+ } -+ rep2 = rep1; -+ } -+ rep1 = rep0; -+ rep0 = distance; -+ } -+ state = state < kNumLitStates ? 8 : 11; -+ prob = probs + RepLenCoder; -+ } -+ { -+ unsigned limit, offset; -+ CLzmaProb *probLen = prob + LenChoice; -+ IF_BIT_0(probLen) -+ { -+ UPDATE_0(probLen); -+ probLen = prob + LenLow + (posState << kLenNumLowBits); -+ offset = 0; -+ limit = (1 << kLenNumLowBits); -+ } -+ else -+ { -+ UPDATE_1(probLen); -+ probLen = prob + LenChoice2; -+ IF_BIT_0(probLen) -+ { -+ UPDATE_0(probLen); -+ probLen = prob + LenMid + (posState << kLenNumMidBits); -+ offset = kLenNumLowSymbols; -+ limit = (1 << kLenNumMidBits); -+ } -+ else -+ { -+ UPDATE_1(probLen); -+ probLen = prob + LenHigh; -+ offset = kLenNumLowSymbols + kLenNumMidSymbols; -+ limit = (1 << kLenNumHighBits); -+ } -+ } -+ TREE_DECODE(probLen, limit, len); -+ len += offset; -+ } -+ -+ if (state >= kNumStates) -+ { -+ UInt32 distance; -+ prob = probs + PosSlot + -+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); -+ TREE_6_DECODE(prob, distance); -+ if (distance >= kStartPosModelIndex) -+ { -+ unsigned posSlot = (unsigned)distance; -+ int numDirectBits = (int)(((distance >> 1) - 1)); -+ distance = (2 | (distance & 1)); -+ if (posSlot < kEndPosModelIndex) -+ { -+ distance <<= numDirectBits; -+ prob = probs + SpecPos + distance - posSlot - 1; -+ { -+ UInt32 mask = 1; -+ unsigned i = 1; -+ do -+ { -+ GET_BIT2(prob + i, i, ; , distance |= mask); -+ mask <<= 1; -+ } -+ while (--numDirectBits != 0); -+ } -+ } -+ else -+ { -+ numDirectBits -= kNumAlignBits; -+ do -+ { -+ NORMALIZE -+ range >>= 1; -+ -+ { -+ UInt32 t; -+ code -= range; -+ t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ -+ distance = (distance << 1) + (t + 1); -+ code += range & t; -+ } -+ /* -+ distance <<= 1; -+ if (code >= range) -+ { -+ code -= range; -+ distance |= 1; -+ } -+ */ -+ } -+ while (--numDirectBits != 0); -+ prob = probs + Align; -+ distance <<= kNumAlignBits; -+ { -+ unsigned i = 1; -+ GET_BIT2(prob + i, i, ; , distance |= 1); -+ GET_BIT2(prob + i, i, ; , distance |= 2); -+ GET_BIT2(prob + i, i, ; , distance |= 4); -+ GET_BIT2(prob + i, i, ; , distance |= 8); -+ } -+ if (distance == (UInt32)0xFFFFFFFF) -+ { -+ len += kMatchSpecLenStart; -+ state -= kNumStates; -+ break; -+ } -+ } -+ } -+ rep3 = rep2; -+ rep2 = rep1; -+ rep1 = rep0; -+ rep0 = distance + 1; -+ if (checkDicSize == 0) -+ { -+ if (distance >= processedPos) -+ return SZ_ERROR_DATA; -+ } -+ else if (distance >= checkDicSize) -+ return SZ_ERROR_DATA; -+ state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; -+ } -+ -+ len += kMatchMinLen; -+ -+ if (limit == dicPos) -+ return SZ_ERROR_DATA; -+ { -+ SizeT rem = limit - dicPos; -+ unsigned curLen = ((rem < len) ? (unsigned)rem : len); -+ SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); -+ -+ processedPos += curLen; -+ -+ len -= curLen; -+ if (pos + curLen <= dicBufSize) -+ { -+ Byte *dest = dic + dicPos; -+ ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; -+ const Byte *lim = dest + curLen; -+ dicPos += curLen; -+ do -+ *(dest) = (Byte)*(dest + src); -+ while (++dest != lim); -+ } -+ else -+ { -+ do -+ { -+ dic[dicPos++] = dic[pos]; -+ if (++pos == dicBufSize) -+ pos = 0; -+ } -+ while (--curLen != 0); -+ } -+ } -+ } -+ } -+ while (dicPos < limit && buf < bufLimit); -+ NORMALIZE; -+ p->buf = buf; -+ p->range = range; -+ p->code = code; -+ p->remainLen = len; -+ p->dicPos = dicPos; -+ p->processedPos = processedPos; -+ p->reps[0] = rep0; -+ p->reps[1] = rep1; -+ p->reps[2] = rep2; -+ p->reps[3] = rep3; -+ p->state = state; -+ -+ return SZ_OK; -+} -+ -+static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) -+{ -+ if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) -+ { -+ Byte *dic = p->dic; -+ SizeT dicPos = p->dicPos; -+ SizeT dicBufSize = p->dicBufSize; -+ unsigned len = p->remainLen; -+ UInt32 rep0 = p->reps[0]; -+ if (limit - dicPos < len) -+ len = (unsigned)(limit - dicPos); -+ -+ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) -+ p->checkDicSize = p->prop.dicSize; -+ -+ p->processedPos += len; -+ p->remainLen -= len; -+ while (len != 0) -+ { -+ len--; -+ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; -+ dicPos++; -+ } -+ p->dicPos = dicPos; -+ } -+} -+ -+static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) -+{ -+ do -+ { -+ SizeT limit2 = limit; -+ if (p->checkDicSize == 0) -+ { -+ UInt32 rem = p->prop.dicSize - p->processedPos; -+ if (limit - p->dicPos > rem) -+ limit2 = p->dicPos + rem; -+ } -+ RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); -+ if (p->processedPos >= p->prop.dicSize) -+ p->checkDicSize = p->prop.dicSize; -+ LzmaDec_WriteRem(p, limit); -+ } -+ while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); -+ -+ if (p->remainLen > kMatchSpecLenStart) -+ { -+ p->remainLen = kMatchSpecLenStart; -+ } -+ return 0; -+} -+ -+typedef enum -+{ -+ DUMMY_ERROR, /* unexpected end of input stream */ -+ DUMMY_LIT, -+ DUMMY_MATCH, -+ DUMMY_REP -+} ELzmaDummy; -+ -+static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) -+{ -+ UInt32 range = p->range; -+ UInt32 code = p->code; -+ const Byte *bufLimit = buf + inSize; -+ CLzmaProb *probs = p->probs; -+ unsigned state = p->state; -+ ELzmaDummy res; -+ -+ { -+ CLzmaProb *prob; -+ UInt32 bound; -+ unsigned ttt; -+ unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); -+ -+ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; -+ IF_BIT_0_CHECK(prob) -+ { -+ UPDATE_0_CHECK -+ -+ /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ -+ -+ prob = probs + Literal; -+ if (p->checkDicSize != 0 || p->processedPos != 0) -+ prob += (LZMA_LIT_SIZE * -+ ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + -+ (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); -+ -+ if (state < kNumLitStates) -+ { -+ unsigned symbol = 1; -+ do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); -+ } -+ else -+ { -+ unsigned matchByte = p->dic[p->dicPos - p->reps[0] + -+ ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; -+ unsigned offs = 0x100; -+ unsigned symbol = 1; -+ do -+ { -+ unsigned bit; -+ CLzmaProb *probLit; -+ matchByte <<= 1; -+ bit = (matchByte & offs); -+ probLit = prob + offs + bit + symbol; -+ GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) -+ } -+ while (symbol < 0x100); -+ } -+ res = DUMMY_LIT; -+ } -+ else -+ { -+ unsigned len; -+ UPDATE_1_CHECK; -+ -+ prob = probs + IsRep + state; -+ IF_BIT_0_CHECK(prob) -+ { -+ UPDATE_0_CHECK; -+ state = 0; -+ prob = probs + LenCoder; -+ res = DUMMY_MATCH; -+ } -+ else -+ { -+ UPDATE_1_CHECK; -+ res = DUMMY_REP; -+ prob = probs + IsRepG0 + state; -+ IF_BIT_0_CHECK(prob) -+ { -+ UPDATE_0_CHECK; -+ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; -+ IF_BIT_0_CHECK(prob) -+ { -+ UPDATE_0_CHECK; -+ NORMALIZE_CHECK; -+ return DUMMY_REP; -+ } -+ else -+ { -+ UPDATE_1_CHECK; -+ } -+ } -+ else -+ { -+ UPDATE_1_CHECK; -+ prob = probs + IsRepG1 + state; -+ IF_BIT_0_CHECK(prob) -+ { -+ UPDATE_0_CHECK; -+ } -+ else -+ { -+ UPDATE_1_CHECK; -+ prob = probs + IsRepG2 + state; -+ IF_BIT_0_CHECK(prob) -+ { -+ UPDATE_0_CHECK; -+ } -+ else -+ { -+ UPDATE_1_CHECK; -+ } -+ } -+ } -+ state = kNumStates; -+ prob = probs + RepLenCoder; -+ } -+ { -+ unsigned limit, offset; -+ CLzmaProb *probLen = prob + LenChoice; -+ IF_BIT_0_CHECK(probLen) -+ { -+ UPDATE_0_CHECK; -+ probLen = prob + LenLow + (posState << kLenNumLowBits); -+ offset = 0; -+ limit = 1 << kLenNumLowBits; -+ } -+ else -+ { -+ UPDATE_1_CHECK; -+ probLen = prob + LenChoice2; -+ IF_BIT_0_CHECK(probLen) -+ { -+ UPDATE_0_CHECK; -+ probLen = prob + LenMid + (posState << kLenNumMidBits); -+ offset = kLenNumLowSymbols; -+ limit = 1 << kLenNumMidBits; -+ } -+ else -+ { -+ UPDATE_1_CHECK; -+ probLen = prob + LenHigh; -+ offset = kLenNumLowSymbols + kLenNumMidSymbols; -+ limit = 1 << kLenNumHighBits; -+ } -+ } -+ TREE_DECODE_CHECK(probLen, limit, len); -+ len += offset; -+ } -+ -+ if (state < 4) -+ { -+ unsigned posSlot; -+ prob = probs + PosSlot + -+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << -+ kNumPosSlotBits); -+ TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); -+ if (posSlot >= kStartPosModelIndex) -+ { -+ int numDirectBits = ((posSlot >> 1) - 1); -+ -+ /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ -+ -+ if (posSlot < kEndPosModelIndex) -+ { -+ prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; -+ } -+ else -+ { -+ numDirectBits -= kNumAlignBits; -+ do -+ { -+ NORMALIZE_CHECK -+ range >>= 1; -+ code -= range & (((code - range) >> 31) - 1); -+ /* if (code >= range) code -= range; */ -+ } -+ while (--numDirectBits != 0); -+ prob = probs + Align; -+ numDirectBits = kNumAlignBits; -+ } -+ { -+ unsigned i = 1; -+ do -+ { -+ GET_BIT_CHECK(prob + i, i); -+ } -+ while (--numDirectBits != 0); -+ } -+ } -+ } -+ } -+ } -+ NORMALIZE_CHECK; -+ return res; -+} -+ -+ -+static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) -+{ -+ p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); -+ p->range = 0xFFFFFFFF; -+ p->needFlush = 0; -+} -+ -+void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) -+{ -+ p->needFlush = 1; -+ p->remainLen = 0; -+ p->tempBufSize = 0; -+ -+ if (initDic) -+ { -+ p->processedPos = 0; -+ p->checkDicSize = 0; -+ p->needInitState = 1; -+ } -+ if (initState) -+ p->needInitState = 1; -+} -+ -+void LzmaDec_Init(CLzmaDec *p) -+{ -+ p->dicPos = 0; -+ LzmaDec_InitDicAndState(p, True, True); -+} -+ -+static void LzmaDec_InitStateReal(CLzmaDec *p) -+{ -+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); -+ UInt32 i; -+ CLzmaProb *probs = p->probs; -+ for (i = 0; i < numProbs; i++) -+ probs[i] = kBitModelTotal >> 1; -+ p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; -+ p->state = 0; -+ p->needInitState = 0; -+} -+ -+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, -+ ELzmaFinishMode finishMode, ELzmaStatus *status) -+{ -+ SizeT inSize = *srcLen; -+ (*srcLen) = 0; -+ LzmaDec_WriteRem(p, dicLimit); -+ -+ *status = LZMA_STATUS_NOT_SPECIFIED; -+ -+ while (p->remainLen != kMatchSpecLenStart) -+ { -+ int checkEndMarkNow; -+ -+ if (p->needFlush != 0) -+ { -+ for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) -+ p->tempBuf[p->tempBufSize++] = *src++; -+ if (p->tempBufSize < RC_INIT_SIZE) -+ { -+ *status = LZMA_STATUS_NEEDS_MORE_INPUT; -+ return SZ_OK; -+ } -+ if (p->tempBuf[0] != 0) -+ return SZ_ERROR_DATA; -+ -+ LzmaDec_InitRc(p, p->tempBuf); -+ p->tempBufSize = 0; -+ } -+ -+ checkEndMarkNow = 0; -+ if (p->dicPos >= dicLimit) -+ { -+ if (p->remainLen == 0 && p->code == 0) -+ { -+ *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; -+ return SZ_OK; -+ } -+ if (finishMode == LZMA_FINISH_ANY) -+ { -+ *status = LZMA_STATUS_NOT_FINISHED; -+ return SZ_OK; -+ } -+ if (p->remainLen != 0) -+ { -+ *status = LZMA_STATUS_NOT_FINISHED; -+ return SZ_ERROR_DATA; -+ } -+ checkEndMarkNow = 1; -+ } -+ -+ if (p->needInitState) -+ LzmaDec_InitStateReal(p); -+ -+ if (p->tempBufSize == 0) -+ { -+ SizeT processed; -+ const Byte *bufLimit; -+ if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) -+ { -+ int dummyRes = LzmaDec_TryDummy(p, src, inSize); -+ if (dummyRes == DUMMY_ERROR) -+ { -+ memcpy(p->tempBuf, src, inSize); -+ p->tempBufSize = (unsigned)inSize; -+ (*srcLen) += inSize; -+ *status = LZMA_STATUS_NEEDS_MORE_INPUT; -+ return SZ_OK; -+ } -+ if (checkEndMarkNow && dummyRes != DUMMY_MATCH) -+ { -+ *status = LZMA_STATUS_NOT_FINISHED; -+ return SZ_ERROR_DATA; -+ } -+ bufLimit = src; -+ } -+ else -+ bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; -+ p->buf = src; -+ if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) -+ return SZ_ERROR_DATA; -+ processed = (SizeT)(p->buf - src); -+ (*srcLen) += processed; -+ src += processed; -+ inSize -= processed; -+ } -+ else -+ { -+ unsigned rem = p->tempBufSize, lookAhead = 0; -+ while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) -+ p->tempBuf[rem++] = src[lookAhead++]; -+ p->tempBufSize = rem; -+ if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) -+ { -+ int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); -+ if (dummyRes == DUMMY_ERROR) -+ { -+ (*srcLen) += lookAhead; -+ *status = LZMA_STATUS_NEEDS_MORE_INPUT; -+ return SZ_OK; -+ } -+ if (checkEndMarkNow && dummyRes != DUMMY_MATCH) -+ { -+ *status = LZMA_STATUS_NOT_FINISHED; -+ return SZ_ERROR_DATA; -+ } -+ } -+ p->buf = p->tempBuf; -+ if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) -+ return SZ_ERROR_DATA; -+ lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); -+ (*srcLen) += lookAhead; -+ src += lookAhead; -+ inSize -= lookAhead; -+ p->tempBufSize = 0; -+ } -+ } -+ if (p->code == 0) -+ *status = LZMA_STATUS_FINISHED_WITH_MARK; -+ return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; -+} -+ -+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) -+{ -+ SizeT outSize = *destLen; -+ SizeT inSize = *srcLen; -+ *srcLen = *destLen = 0; -+ for (;;) -+ { -+ SizeT inSizeCur = inSize, outSizeCur, dicPos; -+ ELzmaFinishMode curFinishMode; -+ SRes res; -+ if (p->dicPos == p->dicBufSize) -+ p->dicPos = 0; -+ dicPos = p->dicPos; -+ if (outSize > p->dicBufSize - dicPos) -+ { -+ outSizeCur = p->dicBufSize; -+ curFinishMode = LZMA_FINISH_ANY; -+ } -+ else -+ { -+ outSizeCur = dicPos + outSize; -+ curFinishMode = finishMode; -+ } -+ -+ res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); -+ src += inSizeCur; -+ inSize -= inSizeCur; -+ *srcLen += inSizeCur; -+ outSizeCur = p->dicPos - dicPos; -+ memcpy(dest, p->dic + dicPos, outSizeCur); -+ dest += outSizeCur; -+ outSize -= outSizeCur; -+ *destLen += outSizeCur; -+ if (res != 0) -+ return res; -+ if (outSizeCur == 0 || outSize == 0) -+ return SZ_OK; -+ } -+} -+ -+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) -+{ -+ alloc->Free(alloc, p->probs); -+ p->probs = 0; -+} -+ -+static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) -+{ -+ alloc->Free(alloc, p->dic); -+ p->dic = 0; -+} -+ -+void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) -+{ -+ LzmaDec_FreeProbs(p, alloc); -+ LzmaDec_FreeDict(p, alloc); -+} -+ -+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) -+{ -+ UInt32 dicSize; -+ Byte d; -+ -+ if (size < LZMA_PROPS_SIZE) -+ return SZ_ERROR_UNSUPPORTED; -+ else -+ dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); -+ -+ if (dicSize < LZMA_DIC_MIN) -+ dicSize = LZMA_DIC_MIN; -+ p->dicSize = dicSize; -+ -+ d = data[0]; -+ if (d >= (9 * 5 * 5)) -+ return SZ_ERROR_UNSUPPORTED; -+ -+ p->lc = d % 9; -+ d /= 9; -+ p->pb = d / 5; -+ p->lp = d % 5; -+ -+ return SZ_OK; -+} -+ -+static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) -+{ -+ UInt32 numProbs = LzmaProps_GetNumProbs(propNew); -+ if (p->probs == 0 || numProbs != p->numProbs) -+ { -+ LzmaDec_FreeProbs(p, alloc); -+ p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); -+ p->numProbs = numProbs; -+ if (p->probs == 0) -+ return SZ_ERROR_MEM; -+ } -+ return SZ_OK; -+} -+ -+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) -+{ -+ CLzmaProps propNew; -+ RINOK(LzmaProps_Decode(&propNew, props, propsSize)); -+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); -+ p->prop = propNew; -+ return SZ_OK; -+} -+ -+SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) -+{ -+ CLzmaProps propNew; -+ SizeT dicBufSize; -+ RINOK(LzmaProps_Decode(&propNew, props, propsSize)); -+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); -+ dicBufSize = propNew.dicSize; -+ if (p->dic == 0 || dicBufSize != p->dicBufSize) -+ { -+ LzmaDec_FreeDict(p, alloc); -+ p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); -+ if (p->dic == 0) -+ { -+ LzmaDec_FreeProbs(p, alloc); -+ return SZ_ERROR_MEM; -+ } -+ } -+ p->dicBufSize = dicBufSize; -+ p->prop = propNew; -+ return SZ_OK; -+} -+ -+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, -+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, -+ ELzmaStatus *status, ISzAlloc *alloc) -+{ -+ CLzmaDec p; -+ SRes res; -+ SizeT outSize = *destLen, inSize = *srcLen; -+ *destLen = *srcLen = 0; -+ *status = LZMA_STATUS_NOT_SPECIFIED; -+ if (inSize < RC_INIT_SIZE) -+ return SZ_ERROR_INPUT_EOF; -+ LzmaDec_Construct(&p); -+ RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc)); -+ p.dic = dest; -+ p.dicBufSize = outSize; -+ LzmaDec_Init(&p); -+ *srcLen = inSize; -+ res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); -+ *destLen = p.dicPos; -+ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) -+ res = SZ_ERROR_INPUT_EOF; -+ LzmaDec_FreeProbs(&p, alloc); -+ return res; -+} -diff --git a/cut-n-paste/unarr/lzmasdk/LzmaDec.h b/cut-n-paste/unarr/lzmasdk/LzmaDec.h -new file mode 100644 -index 00000000..cc44daef ---- /dev/null -+++ b/cut-n-paste/unarr/lzmasdk/LzmaDec.h -@@ -0,0 +1,227 @@ -+/* LzmaDec.h -- LZMA Decoder -+2013-01-18 : Igor Pavlov : Public domain */ -+ -+#ifndef __LZMA_DEC_H -+#define __LZMA_DEC_H -+ -+#include "7zTypes.h" -+ -+EXTERN_C_BEGIN -+ -+/* #define _LZMA_PROB32 */ -+/* _LZMA_PROB32 can increase the speed on some CPUs, -+ but memory usage for CLzmaDec::probs will be doubled in that case */ -+ -+#ifdef _LZMA_PROB32 -+#define CLzmaProb UInt32 -+#else -+#define CLzmaProb UInt16 -+#endif -+ -+ -+/* ---------- LZMA Properties ---------- */ -+ -+#define LZMA_PROPS_SIZE 5 -+ -+typedef struct _CLzmaProps -+{ -+ unsigned lc, lp, pb; -+ UInt32 dicSize; -+} CLzmaProps; -+ -+/* LzmaProps_Decode - decodes properties -+Returns: -+ SZ_OK -+ SZ_ERROR_UNSUPPORTED - Unsupported properties -+*/ -+ -+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); -+ -+ -+/* ---------- LZMA Decoder state ---------- */ -+ -+/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. -+ Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ -+ -+#define LZMA_REQUIRED_INPUT_MAX 20 -+ -+typedef struct -+{ -+ CLzmaProps prop; -+ CLzmaProb *probs; -+ Byte *dic; -+ const Byte *buf; -+ UInt32 range, code; -+ SizeT dicPos; -+ SizeT dicBufSize; -+ UInt32 processedPos; -+ UInt32 checkDicSize; -+ unsigned state; -+ UInt32 reps[4]; -+ unsigned remainLen; -+ int needFlush; -+ int needInitState; -+ UInt32 numProbs; -+ unsigned tempBufSize; -+ Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; -+} CLzmaDec; -+ -+#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } -+ -+void LzmaDec_Init(CLzmaDec *p); -+ -+/* There are two types of LZMA streams: -+ 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. -+ 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ -+ -+typedef enum -+{ -+ LZMA_FINISH_ANY, /* finish at any point */ -+ LZMA_FINISH_END /* block must be finished at the end */ -+} ELzmaFinishMode; -+ -+/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! -+ -+ You must use LZMA_FINISH_END, when you know that current output buffer -+ covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. -+ -+ If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, -+ and output value of destLen will be less than output buffer size limit. -+ You can check status result also. -+ -+ You can use multiple checks to test data integrity after full decompression: -+ 1) Check Result and "status" variable. -+ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. -+ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. -+ You must use correct finish mode in that case. */ -+ -+typedef enum -+{ -+ LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ -+ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ -+ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ -+ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ -+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ -+} ELzmaStatus; -+ -+/* ELzmaStatus is used only as output value for function call */ -+ -+ -+/* ---------- Interfaces ---------- */ -+ -+/* There are 3 levels of interfaces: -+ 1) Dictionary Interface -+ 2) Buffer Interface -+ 3) One Call Interface -+ You can select any of these interfaces, but don't mix functions from different -+ groups for same object. */ -+ -+ -+/* There are two variants to allocate state for Dictionary Interface: -+ 1) LzmaDec_Allocate / LzmaDec_Free -+ 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs -+ You can use variant 2, if you set dictionary buffer manually. -+ For Buffer Interface you must always use variant 1. -+ -+LzmaDec_Allocate* can return: -+ SZ_OK -+ SZ_ERROR_MEM - Memory allocation error -+ SZ_ERROR_UNSUPPORTED - Unsupported properties -+*/ -+ -+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); -+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); -+ -+SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); -+void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); -+ -+/* ---------- Dictionary Interface ---------- */ -+ -+/* You can use it, if you want to eliminate the overhead for data copying from -+ dictionary to some other external buffer. -+ You must work with CLzmaDec variables directly in this interface. -+ -+ STEPS: -+ LzmaDec_Constr() -+ LzmaDec_Allocate() -+ for (each new stream) -+ { -+ LzmaDec_Init() -+ while (it needs more decompression) -+ { -+ LzmaDec_DecodeToDic() -+ use data from CLzmaDec::dic and update CLzmaDec::dicPos -+ } -+ } -+ LzmaDec_Free() -+*/ -+ -+/* LzmaDec_DecodeToDic -+ -+ The decoding to internal dictionary buffer (CLzmaDec::dic). -+ You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! -+ -+finishMode: -+ It has meaning only if the decoding reaches output limit (dicLimit). -+ LZMA_FINISH_ANY - Decode just dicLimit bytes. -+ LZMA_FINISH_END - Stream must be finished after dicLimit. -+ -+Returns: -+ SZ_OK -+ status: -+ LZMA_STATUS_FINISHED_WITH_MARK -+ LZMA_STATUS_NOT_FINISHED -+ LZMA_STATUS_NEEDS_MORE_INPUT -+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK -+ SZ_ERROR_DATA - Data error -+*/ -+ -+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, -+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); -+ -+ -+/* ---------- Buffer Interface ---------- */ -+ -+/* It's zlib-like interface. -+ See LzmaDec_DecodeToDic description for information about STEPS and return results, -+ but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need -+ to work with CLzmaDec variables manually. -+ -+finishMode: -+ It has meaning only if the decoding reaches output limit (*destLen). -+ LZMA_FINISH_ANY - Decode just destLen bytes. -+ LZMA_FINISH_END - Stream must be finished after (*destLen). -+*/ -+ -+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, -+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); -+ -+ -+/* ---------- One Call Interface ---------- */ -+ -+/* LzmaDecode -+ -+finishMode: -+ It has meaning only if the decoding reaches output limit (*destLen). -+ LZMA_FINISH_ANY - Decode just destLen bytes. -+ LZMA_FINISH_END - Stream must be finished after (*destLen). -+ -+Returns: -+ SZ_OK -+ status: -+ LZMA_STATUS_FINISHED_WITH_MARK -+ LZMA_STATUS_NOT_FINISHED -+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK -+ SZ_ERROR_DATA - Data error -+ SZ_ERROR_MEM - Memory allocation error -+ SZ_ERROR_UNSUPPORTED - Unsupported properties -+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). -+*/ -+ -+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, -+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, -+ ELzmaStatus *status, ISzAlloc *alloc); -+ -+EXTERN_C_END -+ -+#endif -diff --git a/cut-n-paste/unarr/lzmasdk/Ppmd.h b/cut-n-paste/unarr/lzmasdk/Ppmd.h -new file mode 100644 -index 00000000..4356dd1d ---- /dev/null -+++ b/cut-n-paste/unarr/lzmasdk/Ppmd.h -@@ -0,0 +1,85 @@ -+/* Ppmd.h -- PPMD codec common code -+2013-01-18 : Igor Pavlov : Public domain -+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ -+ -+#ifndef __PPMD_H -+#define __PPMD_H -+ -+#include "CpuArch.h" -+ -+EXTERN_C_BEGIN -+ -+#ifdef MY_CPU_32BIT -+ #define PPMD_32BIT -+#endif -+ -+#define PPMD_INT_BITS 7 -+#define PPMD_PERIOD_BITS 7 -+#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS)) -+ -+#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift)) -+#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2) -+#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob)) -+#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob)) -+ -+#define PPMD_N1 4 -+#define PPMD_N2 4 -+#define PPMD_N3 4 -+#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4) -+#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4) -+ -+#pragma pack(push, 1) -+/* Most compilers works OK here even without #pragma pack(push, 1), but some GCC compilers need it. */ -+ -+/* SEE-contexts for PPM-contexts with masked symbols */ -+typedef struct -+{ -+ UInt16 Summ; /* Freq */ -+ Byte Shift; /* Speed of Freq change; low Shift is for fast change */ -+ Byte Count; /* Count to next change of Shift */ -+} CPpmd_See; -+ -+#define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \ -+ { (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); } -+ -+typedef struct -+{ -+ Byte Symbol; -+ Byte Freq; -+ UInt16 SuccessorLow; -+ UInt16 SuccessorHigh; -+} CPpmd_State; -+ -+#pragma pack(pop) -+ -+typedef -+ #ifdef PPMD_32BIT -+ CPpmd_State * -+ #else -+ UInt32 -+ #endif -+ CPpmd_State_Ref; -+ -+typedef -+ #ifdef PPMD_32BIT -+ void * -+ #else -+ UInt32 -+ #endif -+ CPpmd_Void_Ref; -+ -+typedef -+ #ifdef PPMD_32BIT -+ Byte * -+ #else -+ UInt32 -+ #endif -+ CPpmd_Byte_Ref; -+ -+#define PPMD_SetAllBitsIn256Bytes(p) \ -+ { unsigned i; for (i = 0; i < 256 / sizeof(p[0]); i += 8) { \ -+ p[i+7] = p[i+6] = p[i+5] = p[i+4] = p[i+3] = p[i+2] = p[i+1] = p[i+0] = ~(size_t)0; }} -+ -+EXTERN_C_END -+ -+#endif -diff --git a/cut-n-paste/unarr/lzmasdk/Ppmd7.c b/cut-n-paste/unarr/lzmasdk/Ppmd7.c -new file mode 100644 -index 00000000..bb5d175e ---- /dev/null -+++ b/cut-n-paste/unarr/lzmasdk/Ppmd7.c -@@ -0,0 +1,710 @@ -+/* Ppmd7.c -- PPMdH codec -+2010-03-12 : Igor Pavlov : Public domain -+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ -+ -+#include "Precomp.h" -+ -+#include -+ -+#include "Ppmd7.h" -+ -+const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; -+static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; -+ -+#define MAX_FREQ 124 -+#define UNIT_SIZE 12 -+ -+#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) -+#define U2I(nu) (p->Units2Indx[(nu) - 1]) -+#define I2U(indx) (p->Indx2Units[indx]) -+ -+#ifdef PPMD_32BIT -+ #define REF(ptr) (ptr) -+#else -+ #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) -+#endif -+ -+#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) -+ -+#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref)) -+#define STATS(ctx) Ppmd7_GetStats(p, ctx) -+#define ONE_STATE(ctx) Ppmd7Context_OneState(ctx) -+#define SUFFIX(ctx) CTX((ctx)->Suffix) -+ -+typedef CPpmd7_Context * CTX_PTR; -+ -+struct CPpmd7_Node_; -+ -+typedef -+ #ifdef PPMD_32BIT -+ struct CPpmd7_Node_ * -+ #else -+ UInt32 -+ #endif -+ CPpmd7_Node_Ref; -+ -+typedef struct CPpmd7_Node_ -+{ -+ UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */ -+ UInt16 NU; -+ CPpmd7_Node_Ref Next; /* must be at offset >= 4 */ -+ CPpmd7_Node_Ref Prev; -+} CPpmd7_Node; -+ -+#ifdef PPMD_32BIT -+ #define NODE(ptr) (ptr) -+#else -+ #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs))) -+#endif -+ -+void Ppmd7_Construct(CPpmd7 *p) -+{ -+ unsigned i, k, m; -+ -+ p->Base = 0; -+ -+ for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) -+ { -+ unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); -+ do { p->Units2Indx[k++] = (Byte)i; } while(--step); -+ p->Indx2Units[i] = (Byte)k; -+ } -+ -+ p->NS2BSIndx[0] = (0 << 1); -+ p->NS2BSIndx[1] = (1 << 1); -+ memset(p->NS2BSIndx + 2, (2 << 1), 9); -+ memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); -+ -+ for (i = 0; i < 3; i++) -+ p->NS2Indx[i] = (Byte)i; -+ for (m = i, k = 1; i < 256; i++) -+ { -+ p->NS2Indx[i] = (Byte)m; -+ if (--k == 0) -+ k = (++m) - 2; -+ } -+ -+ memset(p->HB2Flag, 0, 0x40); -+ memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40); -+} -+ -+void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc) -+{ -+ alloc->Free(alloc, p->Base); -+ p->Size = 0; -+ p->Base = 0; -+} -+ -+Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc) -+{ -+ if (p->Base == 0 || p->Size != size) -+ { -+ Ppmd7_Free(p, alloc); -+ p->AlignOffset = -+ #ifdef PPMD_32BIT -+ (4 - size) & 3; -+ #else -+ 4 - (size & 3); -+ #endif -+ if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size -+ #ifndef PPMD_32BIT -+ + UNIT_SIZE -+ #endif -+ )) == 0) -+ return False; -+ p->Size = size; -+ } -+ return True; -+} -+ -+static void InsertNode(CPpmd7 *p, void *node, unsigned indx) -+{ -+ *((CPpmd_Void_Ref *)node) = p->FreeList[indx]; -+ p->FreeList[indx] = REF(node); -+} -+ -+static void *RemoveNode(CPpmd7 *p, unsigned indx) -+{ -+ CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]); -+ p->FreeList[indx] = *node; -+ return node; -+} -+ -+static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx) -+{ -+ unsigned i, nu = I2U(oldIndx) - I2U(newIndx); -+ ptr = (Byte *)ptr + U2B(I2U(newIndx)); -+ if (I2U(i = U2I(nu)) != nu) -+ { -+ unsigned k = I2U(--i); -+ InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); -+ } -+ InsertNode(p, ptr, i); -+} -+ -+static void GlueFreeBlocks(CPpmd7 *p) -+{ -+ #ifdef PPMD_32BIT -+ CPpmd7_Node headItem; -+ CPpmd7_Node_Ref head = &headItem; -+ #else -+ CPpmd7_Node_Ref head = p->AlignOffset + p->Size; -+ #endif -+ -+ CPpmd7_Node_Ref n = head; -+ unsigned i; -+ -+ p->GlueCount = 255; -+ -+ /* create doubly-linked list of free blocks */ -+ for (i = 0; i < PPMD_NUM_INDEXES; i++) -+ { -+ UInt16 nu = I2U(i); -+ CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i]; -+ p->FreeList[i] = 0; -+ while (next != 0) -+ { -+ CPpmd7_Node *node = NODE(next); -+ node->Next = n; -+ n = NODE(n)->Prev = next; -+ next = *(const CPpmd7_Node_Ref *)node; -+ node->Stamp = 0; -+ node->NU = (UInt16)nu; -+ } -+ } -+ NODE(head)->Stamp = 1; -+ NODE(head)->Next = n; -+ NODE(n)->Prev = head; -+ if (p->LoUnit != p->HiUnit) -+ ((CPpmd7_Node *)p->LoUnit)->Stamp = 1; -+ -+ /* Glue free blocks */ -+ while (n != head) -+ { -+ CPpmd7_Node *node = NODE(n); -+ UInt32 nu = (UInt32)node->NU; -+ for (;;) -+ { -+ CPpmd7_Node *node2 = NODE(n) + nu; -+ nu += node2->NU; -+ if (node2->Stamp != 0 || nu >= 0x10000) -+ break; -+ NODE(node2->Prev)->Next = node2->Next; -+ NODE(node2->Next)->Prev = node2->Prev; -+ node->NU = (UInt16)nu; -+ } -+ n = node->Next; -+ } -+ -+ /* Fill lists of free blocks */ -+ for (n = NODE(head)->Next; n != head;) -+ { -+ CPpmd7_Node *node = NODE(n); -+ unsigned nu; -+ CPpmd7_Node_Ref next = node->Next; -+ for (nu = node->NU; nu > 128; nu -= 128, node += 128) -+ InsertNode(p, node, PPMD_NUM_INDEXES - 1); -+ if (I2U(i = U2I(nu)) != nu) -+ { -+ unsigned k = I2U(--i); -+ InsertNode(p, node + k, nu - k - 1); -+ } -+ InsertNode(p, node, i); -+ n = next; -+ } -+} -+ -+static void *AllocUnitsRare(CPpmd7 *p, unsigned indx) -+{ -+ unsigned i; -+ void *retVal; -+ if (p->GlueCount == 0) -+ { -+ GlueFreeBlocks(p); -+ if (p->FreeList[indx] != 0) -+ return RemoveNode(p, indx); -+ } -+ i = indx; -+ do -+ { -+ if (++i == PPMD_NUM_INDEXES) -+ { -+ UInt32 numBytes = U2B(I2U(indx)); -+ p->GlueCount--; -+ return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); -+ } -+ } -+ while (p->FreeList[i] == 0); -+ retVal = RemoveNode(p, i); -+ SplitBlock(p, retVal, i, indx); -+ return retVal; -+} -+ -+static void *AllocUnits(CPpmd7 *p, unsigned indx) -+{ -+ UInt32 numBytes; -+ if (p->FreeList[indx] != 0) -+ return RemoveNode(p, indx); -+ numBytes = U2B(I2U(indx)); -+ if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) -+ { -+ void *retVal = p->LoUnit; -+ p->LoUnit += numBytes; -+ return retVal; -+ } -+ return AllocUnitsRare(p, indx); -+} -+ -+#define MyMem12Cpy(dest, src, num) \ -+ { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \ -+ do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); } -+ -+static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU) -+{ -+ unsigned i0 = U2I(oldNU); -+ unsigned i1 = U2I(newNU); -+ if (i0 == i1) -+ return oldPtr; -+ if (p->FreeList[i1] != 0) -+ { -+ void *ptr = RemoveNode(p, i1); -+ MyMem12Cpy(ptr, oldPtr, newNU); -+ InsertNode(p, oldPtr, i0); -+ return ptr; -+ } -+ SplitBlock(p, oldPtr, i0, i1); -+ return oldPtr; -+} -+ -+#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) -+ -+static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) -+{ -+ (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); -+ (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); -+} -+ -+static void RestartModel(CPpmd7 *p) -+{ -+ unsigned i, k, m; -+ -+ memset(p->FreeList, 0, sizeof(p->FreeList)); -+ p->Text = p->Base + p->AlignOffset; -+ p->HiUnit = p->Text + p->Size; -+ p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; -+ p->GlueCount = 0; -+ -+ p->OrderFall = p->MaxOrder; -+ p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; -+ p->PrevSuccess = 0; -+ -+ p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ -+ p->MinContext->Suffix = 0; -+ p->MinContext->NumStats = 256; -+ p->MinContext->SummFreq = 256 + 1; -+ p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ -+ p->LoUnit += U2B(256 / 2); -+ p->MinContext->Stats = REF(p->FoundState); -+ for (i = 0; i < 256; i++) -+ { -+ CPpmd_State *s = &p->FoundState[i]; -+ s->Symbol = (Byte)i; -+ s->Freq = 1; -+ SetSuccessor(s, 0); -+ } -+ -+ for (i = 0; i < 128; i++) -+ for (k = 0; k < 8; k++) -+ { -+ UInt16 *dest = p->BinSumm[i] + k; -+ UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2)); -+ for (m = 0; m < 64; m += 8) -+ dest[m] = val; -+ } -+ -+ for (i = 0; i < 25; i++) -+ for (k = 0; k < 16; k++) -+ { -+ CPpmd_See *s = &p->See[i][k]; -+ s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4)); -+ s->Count = 4; -+ } -+} -+ -+void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder) -+{ -+ p->MaxOrder = maxOrder; -+ RestartModel(p); -+ p->DummySee.Shift = PPMD_PERIOD_BITS; -+ p->DummySee.Summ = 0; /* unused */ -+ p->DummySee.Count = 64; /* unused */ -+} -+ -+static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip) -+{ -+ CPpmd_State upState; -+ CTX_PTR c = p->MinContext; -+ CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); -+ CPpmd_State *ps[PPMD7_MAX_ORDER]; -+ unsigned numPs = 0; -+ -+ if (!skip) -+ ps[numPs++] = p->FoundState; -+ -+ while (c->Suffix) -+ { -+ CPpmd_Void_Ref successor; -+ CPpmd_State *s; -+ c = SUFFIX(c); -+ if (c->NumStats != 1) -+ { -+ for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); -+ } -+ else -+ s = ONE_STATE(c); -+ successor = SUCCESSOR(s); -+ if (successor != upBranch) -+ { -+ c = CTX(successor); -+ if (numPs == 0) -+ return c; -+ break; -+ } -+ ps[numPs++] = s; -+ } -+ -+ upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch); -+ SetSuccessor(&upState, upBranch + 1); -+ -+ if (c->NumStats == 1) -+ upState.Freq = ONE_STATE(c)->Freq; -+ else -+ { -+ UInt32 cf, s0; -+ CPpmd_State *s; -+ for (s = STATS(c); s->Symbol != upState.Symbol; s++); -+ cf = s->Freq - 1; -+ s0 = c->SummFreq - c->NumStats - cf; -+ upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0)))); -+ } -+ -+ do -+ { -+ /* Create Child */ -+ CTX_PTR c1; /* = AllocContext(p); */ -+ if (p->HiUnit != p->LoUnit) -+ c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); -+ else if (p->FreeList[0] != 0) -+ c1 = (CTX_PTR)RemoveNode(p, 0); -+ else -+ { -+ c1 = (CTX_PTR)AllocUnitsRare(p, 0); -+ if (!c1) -+ return NULL; -+ } -+ c1->NumStats = 1; -+ *ONE_STATE(c1) = upState; -+ c1->Suffix = REF(c); -+ SetSuccessor(ps[--numPs], REF(c1)); -+ c = c1; -+ } -+ while (numPs != 0); -+ -+ return c; -+} -+ -+static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) -+{ -+ CPpmd_State tmp = *t1; -+ *t1 = *t2; -+ *t2 = tmp; -+} -+ -+static void UpdateModel(CPpmd7 *p) -+{ -+ CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); -+ CTX_PTR c; -+ unsigned s0, ns; -+ -+ if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) -+ { -+ c = SUFFIX(p->MinContext); -+ -+ if (c->NumStats == 1) -+ { -+ CPpmd_State *s = ONE_STATE(c); -+ if (s->Freq < 32) -+ s->Freq++; -+ } -+ else -+ { -+ CPpmd_State *s = STATS(c); -+ if (s->Symbol != p->FoundState->Symbol) -+ { -+ do { s++; } while (s->Symbol != p->FoundState->Symbol); -+ if (s[0].Freq >= s[-1].Freq) -+ { -+ SwapStates(&s[0], &s[-1]); -+ s--; -+ } -+ } -+ if (s->Freq < MAX_FREQ - 9) -+ { -+ s->Freq += 2; -+ c->SummFreq += 2; -+ } -+ } -+ } -+ -+ if (p->OrderFall == 0) -+ { -+ p->MinContext = p->MaxContext = CreateSuccessors(p, True); -+ if (p->MinContext == 0) -+ { -+ RestartModel(p); -+ return; -+ } -+ SetSuccessor(p->FoundState, REF(p->MinContext)); -+ return; -+ } -+ -+ *p->Text++ = p->FoundState->Symbol; -+ successor = REF(p->Text); -+ if (p->Text >= p->UnitsStart) -+ { -+ RestartModel(p); -+ return; -+ } -+ -+ if (fSuccessor) -+ { -+ if (fSuccessor <= successor) -+ { -+ CTX_PTR cs = CreateSuccessors(p, False); -+ if (cs == NULL) -+ { -+ RestartModel(p); -+ return; -+ } -+ fSuccessor = REF(cs); -+ } -+ if (--p->OrderFall == 0) -+ { -+ successor = fSuccessor; -+ p->Text -= (p->MaxContext != p->MinContext); -+ } -+ } -+ else -+ { -+ SetSuccessor(p->FoundState, successor); -+ fSuccessor = REF(p->MinContext); -+ } -+ -+ s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1); -+ -+ for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c)) -+ { -+ unsigned ns1; -+ UInt32 cf, sf; -+ if ((ns1 = c->NumStats) != 1) -+ { -+ if ((ns1 & 1) == 0) -+ { -+ /* Expand for one UNIT */ -+ unsigned oldNU = ns1 >> 1; -+ unsigned i = U2I(oldNU); -+ if (i != U2I(oldNU + 1)) -+ { -+ void *ptr = AllocUnits(p, i + 1); -+ void *oldPtr; -+ if (!ptr) -+ { -+ RestartModel(p); -+ return; -+ } -+ oldPtr = STATS(c); -+ MyMem12Cpy(ptr, oldPtr, oldNU); -+ InsertNode(p, oldPtr, i); -+ c->Stats = STATS_REF(ptr); -+ } -+ } -+ c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1))); -+ } -+ else -+ { -+ CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0); -+ if (!s) -+ { -+ RestartModel(p); -+ return; -+ } -+ *s = *ONE_STATE(c); -+ c->Stats = REF(s); -+ if (s->Freq < MAX_FREQ / 4 - 1) -+ s->Freq <<= 1; -+ else -+ s->Freq = MAX_FREQ - 4; -+ c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3)); -+ } -+ cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6); -+ sf = (UInt32)s0 + c->SummFreq; -+ if (cf < 6 * sf) -+ { -+ cf = 1 + (cf > sf) + (cf >= 4 * sf); -+ c->SummFreq += 3; -+ } -+ else -+ { -+ cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf); -+ c->SummFreq = (UInt16)(c->SummFreq + cf); -+ } -+ { -+ CPpmd_State *s = STATS(c) + ns1; -+ SetSuccessor(s, successor); -+ s->Symbol = p->FoundState->Symbol; -+ s->Freq = (Byte)cf; -+ c->NumStats = (UInt16)(ns1 + 1); -+ } -+ } -+ p->MaxContext = p->MinContext = CTX(fSuccessor); -+} -+ -+static void Rescale(CPpmd7 *p) -+{ -+ unsigned i, adder, sumFreq, escFreq; -+ CPpmd_State *stats = STATS(p->MinContext); -+ CPpmd_State *s = p->FoundState; -+ { -+ CPpmd_State tmp = *s; -+ for (; s != stats; s--) -+ s[0] = s[-1]; -+ *s = tmp; -+ } -+ escFreq = p->MinContext->SummFreq - s->Freq; -+ s->Freq += 4; -+ adder = (p->OrderFall != 0); -+ s->Freq = (Byte)((s->Freq + adder) >> 1); -+ sumFreq = s->Freq; -+ -+ i = p->MinContext->NumStats - 1; -+ do -+ { -+ escFreq -= (++s)->Freq; -+ s->Freq = (Byte)((s->Freq + adder) >> 1); -+ sumFreq += s->Freq; -+ if (s[0].Freq > s[-1].Freq) -+ { -+ CPpmd_State *s1 = s; -+ CPpmd_State tmp = *s1; -+ do -+ s1[0] = s1[-1]; -+ while (--s1 != stats && tmp.Freq > s1[-1].Freq); -+ *s1 = tmp; -+ } -+ } -+ while (--i); -+ -+ if (s->Freq == 0) -+ { -+ unsigned numStats = p->MinContext->NumStats; -+ unsigned n0, n1; -+ do { i++; } while ((--s)->Freq == 0); -+ escFreq += i; -+ p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i); -+ if (p->MinContext->NumStats == 1) -+ { -+ CPpmd_State tmp = *stats; -+ do -+ { -+ tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1)); -+ escFreq >>= 1; -+ } -+ while (escFreq > 1); -+ InsertNode(p, stats, U2I(((numStats + 1) >> 1))); -+ *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; -+ return; -+ } -+ n0 = (numStats + 1) >> 1; -+ n1 = (p->MinContext->NumStats + 1) >> 1; -+ if (n0 != n1) -+ p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); -+ } -+ p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); -+ p->FoundState = STATS(p->MinContext); -+} -+ -+CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq) -+{ -+ CPpmd_See *see; -+ unsigned nonMasked = p->MinContext->NumStats - numMasked; -+ if (p->MinContext->NumStats != 256) -+ { -+ see = p->See[p->NS2Indx[nonMasked - 1]] + -+ (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) + -+ 2 * (p->MinContext->SummFreq < 11 * p->MinContext->NumStats) + -+ 4 * (numMasked > nonMasked) + -+ p->HiBitsFlag; -+ { -+ unsigned r = (see->Summ >> see->Shift); -+ see->Summ = (UInt16)(see->Summ - r); -+ *escFreq = r + (r == 0); -+ } -+ } -+ else -+ { -+ see = &p->DummySee; -+ *escFreq = 1; -+ } -+ return see; -+} -+ -+static void NextContext(CPpmd7 *p) -+{ -+ CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); -+ if (p->OrderFall == 0 && (Byte *)c > p->Text) -+ p->MinContext = p->MaxContext = c; -+ else -+ UpdateModel(p); -+} -+ -+void Ppmd7_Update1(CPpmd7 *p) -+{ -+ CPpmd_State *s = p->FoundState; -+ s->Freq += 4; -+ p->MinContext->SummFreq += 4; -+ if (s[0].Freq > s[-1].Freq) -+ { -+ SwapStates(&s[0], &s[-1]); -+ p->FoundState = --s; -+ if (s->Freq > MAX_FREQ) -+ Rescale(p); -+ } -+ NextContext(p); -+} -+ -+void Ppmd7_Update1_0(CPpmd7 *p) -+{ -+ p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq); -+ p->RunLength += p->PrevSuccess; -+ p->MinContext->SummFreq += 4; -+ if ((p->FoundState->Freq += 4) > MAX_FREQ) -+ Rescale(p); -+ NextContext(p); -+} -+ -+void Ppmd7_UpdateBin(CPpmd7 *p) -+{ -+ p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0)); -+ p->PrevSuccess = 1; -+ p->RunLength++; -+ NextContext(p); -+} -+ -+void Ppmd7_Update2(CPpmd7 *p) -+{ -+ p->MinContext->SummFreq += 4; -+ if ((p->FoundState->Freq += 4) > MAX_FREQ) -+ Rescale(p); -+ p->RunLength = p->InitRL; -+ UpdateModel(p); -+} -diff --git a/cut-n-paste/unarr/lzmasdk/Ppmd7.h b/cut-n-paste/unarr/lzmasdk/Ppmd7.h -new file mode 100644 -index 00000000..96521c31 ---- /dev/null -+++ b/cut-n-paste/unarr/lzmasdk/Ppmd7.h -@@ -0,0 +1,140 @@ -+/* Ppmd7.h -- PPMdH compression codec -+2010-03-12 : Igor Pavlov : Public domain -+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ -+ -+/* This code supports virtual RangeDecoder and includes the implementation -+of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H. -+If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */ -+ -+#ifndef __PPMD7_H -+#define __PPMD7_H -+ -+#include "Ppmd.h" -+ -+EXTERN_C_BEGIN -+ -+#define PPMD7_MIN_ORDER 2 -+#define PPMD7_MAX_ORDER 64 -+ -+#define PPMD7_MIN_MEM_SIZE (1 << 11) -+#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3) -+ -+struct CPpmd7_Context_; -+ -+typedef -+ #ifdef PPMD_32BIT -+ struct CPpmd7_Context_ * -+ #else -+ UInt32 -+ #endif -+ CPpmd7_Context_Ref; -+ -+typedef struct CPpmd7_Context_ -+{ -+ UInt16 NumStats; -+ UInt16 SummFreq; -+ CPpmd_State_Ref Stats; -+ CPpmd7_Context_Ref Suffix; -+} CPpmd7_Context; -+ -+#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq) -+ -+typedef struct -+{ -+ CPpmd7_Context *MinContext, *MaxContext; -+ CPpmd_State *FoundState; -+ unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag; -+ Int32 RunLength, InitRL; /* must be 32-bit at least */ -+ -+ UInt32 Size; -+ UInt32 GlueCount; -+ Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; -+ UInt32 AlignOffset; -+ -+ Byte Indx2Units[PPMD_NUM_INDEXES]; -+ Byte Units2Indx[128]; -+ CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; -+ Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256]; -+ CPpmd_See DummySee, See[25][16]; -+ UInt16 BinSumm[128][64]; -+} CPpmd7; -+ -+void Ppmd7_Construct(CPpmd7 *p); -+Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc); -+void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc); -+void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder); -+#define Ppmd7_WasAllocated(p) ((p)->Base != NULL) -+ -+ -+/* ---------- Internal Functions ---------- */ -+ -+extern const Byte PPMD7_kExpEscape[16]; -+ -+#ifdef PPMD_32BIT -+ #define Ppmd7_GetPtr(p, ptr) (ptr) -+ #define Ppmd7_GetContext(p, ptr) (ptr) -+ #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats) -+#else -+ #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs))) -+ #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs))) -+ #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats))) -+#endif -+ -+void Ppmd7_Update1(CPpmd7 *p); -+void Ppmd7_Update1_0(CPpmd7 *p); -+void Ppmd7_Update2(CPpmd7 *p); -+void Ppmd7_UpdateBin(CPpmd7 *p); -+ -+#define Ppmd7_GetBinSumm(p) \ -+ &p->BinSumm[Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \ -+ p->NS2BSIndx[Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \ -+ (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \ -+ 2 * p->HB2Flag[Ppmd7Context_OneState(p->MinContext)->Symbol] + \ -+ ((p->RunLength >> 26) & 0x20)] -+ -+CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale); -+ -+ -+/* ---------- Decode ---------- */ -+ -+typedef struct -+{ -+ UInt32 (*GetThreshold)(void *p, UInt32 total); -+ void (*Decode)(void *p, UInt32 start, UInt32 size); -+ UInt32 (*DecodeBit)(void *p, UInt32 size0); -+} IPpmd7_RangeDec; -+ -+typedef struct -+{ -+ IPpmd7_RangeDec p; -+ UInt32 Range; -+ UInt32 Code; -+ IByteIn *Stream; -+} CPpmd7z_RangeDec; -+ -+void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p); -+Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p); -+#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0) -+ -+int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc); -+ -+ -+/* ---------- Encode ---------- */ -+ -+typedef struct -+{ -+ UInt64 Low; -+ UInt32 Range; -+ Byte Cache; -+ UInt64 CacheSize; -+ IByteOut *Stream; -+} CPpmd7z_RangeEnc; -+ -+void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p); -+void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p); -+ -+void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol); -+ -+EXTERN_C_END -+ -+#endif -diff --git a/cut-n-paste/unarr/lzmasdk/Ppmd7Dec.c b/cut-n-paste/unarr/lzmasdk/Ppmd7Dec.c -new file mode 100644 -index 00000000..04b4b09e ---- /dev/null -+++ b/cut-n-paste/unarr/lzmasdk/Ppmd7Dec.c -@@ -0,0 +1,189 @@ -+/* Ppmd7Dec.c -- PPMdH Decoder -+2010-03-12 : Igor Pavlov : Public domain -+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */ -+ -+#include "Precomp.h" -+ -+#include "Ppmd7.h" -+ -+#define kTopValue (1 << 24) -+ -+Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p) -+{ -+ unsigned i; -+ p->Code = 0; -+ p->Range = 0xFFFFFFFF; -+ if (p->Stream->Read((void *)p->Stream) != 0) -+ return False; -+ for (i = 0; i < 4; i++) -+ p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); -+ return (p->Code < 0xFFFFFFFF); -+} -+ -+static UInt32 Range_GetThreshold(void *pp, UInt32 total) -+{ -+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; -+ return (p->Code) / (p->Range /= total); -+} -+ -+static void Range_Normalize(CPpmd7z_RangeDec *p) -+{ -+ if (p->Range < kTopValue) -+ { -+ p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); -+ p->Range <<= 8; -+ if (p->Range < kTopValue) -+ { -+ p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream); -+ p->Range <<= 8; -+ } -+ } -+} -+ -+static void Range_Decode(void *pp, UInt32 start, UInt32 size) -+{ -+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; -+ p->Code -= start * p->Range; -+ p->Range *= size; -+ Range_Normalize(p); -+} -+ -+static UInt32 Range_DecodeBit(void *pp, UInt32 size0) -+{ -+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp; -+ UInt32 newBound = (p->Range >> 14) * size0; -+ UInt32 symbol; -+ if (p->Code < newBound) -+ { -+ symbol = 0; -+ p->Range = newBound; -+ } -+ else -+ { -+ symbol = 1; -+ p->Code -= newBound; -+ p->Range -= newBound; -+ } -+ Range_Normalize(p); -+ return symbol; -+} -+ -+void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p) -+{ -+ p->p.GetThreshold = Range_GetThreshold; -+ p->p.Decode = Range_Decode; -+ p->p.DecodeBit = Range_DecodeBit; -+} -+ -+ -+#define MASK(sym) ((signed char *)charMask)[sym] -+ -+int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc) -+{ -+ size_t charMask[256 / sizeof(size_t)]; -+ if (p->MinContext->NumStats != 1) -+ { -+ CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext); -+ unsigned i; -+ UInt32 count, hiCnt; -+ if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) -+ { -+ Byte symbol; -+ rc->Decode(rc, 0, s->Freq); -+ p->FoundState = s; -+ symbol = s->Symbol; -+ Ppmd7_Update1_0(p); -+ return symbol; -+ } -+ p->PrevSuccess = 0; -+ i = p->MinContext->NumStats - 1; -+ do -+ { -+ if ((hiCnt += (++s)->Freq) > count) -+ { -+ Byte symbol; -+ rc->Decode(rc, hiCnt - s->Freq, s->Freq); -+ p->FoundState = s; -+ symbol = s->Symbol; -+ Ppmd7_Update1(p); -+ return symbol; -+ } -+ } -+ while (--i); -+ if (count >= p->MinContext->SummFreq) -+ return -2; -+ p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]; -+ rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt); -+ PPMD_SetAllBitsIn256Bytes(charMask); -+ MASK(s->Symbol) = 0; -+ i = p->MinContext->NumStats - 1; -+ do { MASK((--s)->Symbol) = 0; } while (--i); -+ } -+ else -+ { -+ UInt16 *prob = Ppmd7_GetBinSumm(p); -+ if (rc->DecodeBit(rc, *prob) == 0) -+ { -+ Byte symbol; -+ *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); -+ symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol; -+ Ppmd7_UpdateBin(p); -+ return symbol; -+ } -+ *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); -+ p->InitEsc = PPMD7_kExpEscape[*prob >> 10]; -+ PPMD_SetAllBitsIn256Bytes(charMask); -+ MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0; -+ p->PrevSuccess = 0; -+ } -+ for (;;) -+ { -+ CPpmd_State *ps[256], *s; -+ UInt32 freqSum, count, hiCnt; -+ CPpmd_See *see; -+ unsigned i, num, numMasked = p->MinContext->NumStats; -+ do -+ { -+ p->OrderFall++; -+ if (!p->MinContext->Suffix) -+ return -1; -+ p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix); -+ } -+ while (p->MinContext->NumStats == numMasked); -+ hiCnt = 0; -+ s = Ppmd7_GetStats(p, p->MinContext); -+ i = 0; -+ num = p->MinContext->NumStats - numMasked; -+ do -+ { -+ int k = (int)(MASK(s->Symbol)); -+ hiCnt += (s->Freq & k); -+ ps[i] = s++; -+ i -= k; -+ } -+ while (i != num); -+ -+ see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum); -+ freqSum += hiCnt; -+ count = rc->GetThreshold(rc, freqSum); -+ -+ if (count < hiCnt) -+ { -+ Byte symbol; -+ CPpmd_State **pps = ps; -+ for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); -+ s = *pps; -+ rc->Decode(rc, hiCnt - s->Freq, s->Freq); -+ Ppmd_See_Update(see); -+ p->FoundState = s; -+ symbol = s->Symbol; -+ Ppmd7_Update2(p); -+ return symbol; -+ } -+ if (count >= freqSum) -+ return -2; -+ rc->Decode(rc, hiCnt, freqSum - hiCnt); -+ see->Summ = (UInt16)(see->Summ + freqSum); -+ do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); -+ } -+} -diff --git a/cut-n-paste/unarr/lzmasdk/Ppmd8.c b/cut-n-paste/unarr/lzmasdk/Ppmd8.c -new file mode 100644 -index 00000000..8beef23b ---- /dev/null -+++ b/cut-n-paste/unarr/lzmasdk/Ppmd8.c -@@ -0,0 +1,1122 @@ -+/* Ppmd8.c -- PPMdI codec -+2010-03-24 : Igor Pavlov : Public domain -+This code is based on PPMd var.I (2002): Dmitry Shkarin : Public domain */ -+ -+#include "Precomp.h" -+ -+#include -+ -+#include "Ppmd8.h" -+ -+const Byte PPMD8_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; -+static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051}; -+ -+#define MAX_FREQ 124 -+#define UNIT_SIZE 12 -+ -+#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE) -+#define U2I(nu) (p->Units2Indx[(nu) - 1]) -+#define I2U(indx) (p->Indx2Units[indx]) -+ -+#ifdef PPMD_32BIT -+ #define REF(ptr) (ptr) -+#else -+ #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base)) -+#endif -+ -+#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr)) -+ -+#define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref)) -+#define STATS(ctx) Ppmd8_GetStats(p, ctx) -+#define ONE_STATE(ctx) Ppmd8Context_OneState(ctx) -+#define SUFFIX(ctx) CTX((ctx)->Suffix) -+ -+typedef CPpmd8_Context * CTX_PTR; -+ -+struct CPpmd8_Node_; -+ -+typedef -+ #ifdef PPMD_32BIT -+ struct CPpmd8_Node_ * -+ #else -+ UInt32 -+ #endif -+ CPpmd8_Node_Ref; -+ -+typedef struct CPpmd8_Node_ -+{ -+ UInt32 Stamp; -+ CPpmd8_Node_Ref Next; -+ UInt32 NU; -+} CPpmd8_Node; -+ -+#ifdef PPMD_32BIT -+ #define NODE(ptr) (ptr) -+#else -+ #define NODE(offs) ((CPpmd8_Node *)(p->Base + (offs))) -+#endif -+ -+#define EMPTY_NODE 0xFFFFFFFF -+ -+void Ppmd8_Construct(CPpmd8 *p) -+{ -+ unsigned i, k, m; -+ -+ p->Base = 0; -+ -+ for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++) -+ { -+ unsigned step = (i >= 12 ? 4 : (i >> 2) + 1); -+ do { p->Units2Indx[k++] = (Byte)i; } while(--step); -+ p->Indx2Units[i] = (Byte)k; -+ } -+ -+ p->NS2BSIndx[0] = (0 << 1); -+ p->NS2BSIndx[1] = (1 << 1); -+ memset(p->NS2BSIndx + 2, (2 << 1), 9); -+ memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11); -+ -+ for (i = 0; i < 5; i++) -+ p->NS2Indx[i] = (Byte)i; -+ for (m = i, k = 1; i < 260; i++) -+ { -+ p->NS2Indx[i] = (Byte)m; -+ if (--k == 0) -+ k = (++m) - 4; -+ } -+} -+ -+void Ppmd8_Free(CPpmd8 *p, ISzAlloc *alloc) -+{ -+ alloc->Free(alloc, p->Base); -+ p->Size = 0; -+ p->Base = 0; -+} -+ -+Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAlloc *alloc) -+{ -+ if (p->Base == 0 || p->Size != size) -+ { -+ Ppmd8_Free(p, alloc); -+ p->AlignOffset = -+ #ifdef PPMD_32BIT -+ (4 - size) & 3; -+ #else -+ 4 - (size & 3); -+ #endif -+ if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size)) == 0) -+ return False; -+ p->Size = size; -+ } -+ return True; -+} -+ -+static void InsertNode(CPpmd8 *p, void *node, unsigned indx) -+{ -+ ((CPpmd8_Node *)node)->Stamp = EMPTY_NODE; -+ ((CPpmd8_Node *)node)->Next = (CPpmd8_Node_Ref)p->FreeList[indx]; -+ ((CPpmd8_Node *)node)->NU = I2U(indx); -+ p->FreeList[indx] = REF(node); -+ p->Stamps[indx]++; -+} -+ -+static void *RemoveNode(CPpmd8 *p, unsigned indx) -+{ -+ CPpmd8_Node *node = NODE((CPpmd8_Node_Ref)p->FreeList[indx]); -+ p->FreeList[indx] = node->Next; -+ p->Stamps[indx]--; -+ return node; -+} -+ -+static void SplitBlock(CPpmd8 *p, void *ptr, unsigned oldIndx, unsigned newIndx) -+{ -+ unsigned i, nu = I2U(oldIndx) - I2U(newIndx); -+ ptr = (Byte *)ptr + U2B(I2U(newIndx)); -+ if (I2U(i = U2I(nu)) != nu) -+ { -+ unsigned k = I2U(--i); -+ InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1); -+ } -+ InsertNode(p, ptr, i); -+} -+ -+static void GlueFreeBlocks(CPpmd8 *p) -+{ -+ CPpmd8_Node_Ref head = 0; -+ CPpmd8_Node_Ref *prev = &head; -+ unsigned i; -+ -+ p->GlueCount = 1 << 13; -+ memset(p->Stamps, 0, sizeof(p->Stamps)); -+ -+ /* Order-0 context is always at top UNIT, so we don't need guard NODE at the end. -+ All blocks up to p->LoUnit can be free, so we need guard NODE at LoUnit. */ -+ if (p->LoUnit != p->HiUnit) -+ ((CPpmd8_Node *)p->LoUnit)->Stamp = 0; -+ -+ /* Glue free blocks */ -+ for (i = 0; i < PPMD_NUM_INDEXES; i++) -+ { -+ CPpmd8_Node_Ref next = (CPpmd8_Node_Ref)p->FreeList[i]; -+ p->FreeList[i] = 0; -+ while (next != 0) -+ { -+ CPpmd8_Node *node = NODE(next); -+ if (node->NU != 0) -+ { -+ CPpmd8_Node *node2; -+ *prev = next; -+ prev = &(node->Next); -+ while ((node2 = node + node->NU)->Stamp == EMPTY_NODE) -+ { -+ node->NU += node2->NU; -+ node2->NU = 0; -+ } -+ } -+ next = node->Next; -+ } -+ } -+ *prev = 0; -+ -+ /* Fill lists of free blocks */ -+ while (head != 0) -+ { -+ CPpmd8_Node *node = NODE(head); -+ unsigned nu; -+ head = node->Next; -+ nu = node->NU; -+ if (nu == 0) -+ continue; -+ for (; nu > 128; nu -= 128, node += 128) -+ InsertNode(p, node, PPMD_NUM_INDEXES - 1); -+ if (I2U(i = U2I(nu)) != nu) -+ { -+ unsigned k = I2U(--i); -+ InsertNode(p, node + k, nu - k - 1); -+ } -+ InsertNode(p, node, i); -+ } -+} -+ -+static void *AllocUnitsRare(CPpmd8 *p, unsigned indx) -+{ -+ unsigned i; -+ void *retVal; -+ if (p->GlueCount == 0) -+ { -+ GlueFreeBlocks(p); -+ if (p->FreeList[indx] != 0) -+ return RemoveNode(p, indx); -+ } -+ i = indx; -+ do -+ { -+ if (++i == PPMD_NUM_INDEXES) -+ { -+ UInt32 numBytes = U2B(I2U(indx)); -+ p->GlueCount--; -+ return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL); -+ } -+ } -+ while (p->FreeList[i] == 0); -+ retVal = RemoveNode(p, i); -+ SplitBlock(p, retVal, i, indx); -+ return retVal; -+} -+ -+static void *AllocUnits(CPpmd8 *p, unsigned indx) -+{ -+ UInt32 numBytes; -+ if (p->FreeList[indx] != 0) -+ return RemoveNode(p, indx); -+ numBytes = U2B(I2U(indx)); -+ if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit)) -+ { -+ void *retVal = p->LoUnit; -+ p->LoUnit += numBytes; -+ return retVal; -+ } -+ return AllocUnitsRare(p, indx); -+} -+ -+#define MyMem12Cpy(dest, src, num) \ -+ { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \ -+ do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); } -+ -+static void *ShrinkUnits(CPpmd8 *p, void *oldPtr, unsigned oldNU, unsigned newNU) -+{ -+ unsigned i0 = U2I(oldNU); -+ unsigned i1 = U2I(newNU); -+ if (i0 == i1) -+ return oldPtr; -+ if (p->FreeList[i1] != 0) -+ { -+ void *ptr = RemoveNode(p, i1); -+ MyMem12Cpy(ptr, oldPtr, newNU); -+ InsertNode(p, oldPtr, i0); -+ return ptr; -+ } -+ SplitBlock(p, oldPtr, i0, i1); -+ return oldPtr; -+} -+ -+static void FreeUnits(CPpmd8 *p, void *ptr, unsigned nu) -+{ -+ InsertNode(p, ptr, U2I(nu)); -+} -+ -+static void SpecialFreeUnit(CPpmd8 *p, void *ptr) -+{ -+ if ((Byte *)ptr != p->UnitsStart) -+ InsertNode(p, ptr, 0); -+ else -+ { -+ #ifdef PPMD8_FREEZE_SUPPORT -+ *(UInt32 *)ptr = EMPTY_NODE; /* it's used for (Flags == 0xFF) check in RemoveBinContexts */ -+ #endif -+ p->UnitsStart += UNIT_SIZE; -+ } -+} -+ -+static void *MoveUnitsUp(CPpmd8 *p, void *oldPtr, unsigned nu) -+{ -+ unsigned indx = U2I(nu); -+ void *ptr; -+ if ((Byte *)oldPtr > p->UnitsStart + 16 * 1024 || REF(oldPtr) > p->FreeList[indx]) -+ return oldPtr; -+ ptr = RemoveNode(p, indx); -+ MyMem12Cpy(ptr, oldPtr, nu); -+ if ((Byte*)oldPtr != p->UnitsStart) -+ InsertNode(p, oldPtr, indx); -+ else -+ p->UnitsStart += U2B(I2U(indx)); -+ return ptr; -+} -+ -+static void ExpandTextArea(CPpmd8 *p) -+{ -+ UInt32 count[PPMD_NUM_INDEXES]; -+ unsigned i; -+ memset(count, 0, sizeof(count)); -+ if (p->LoUnit != p->HiUnit) -+ ((CPpmd8_Node *)p->LoUnit)->Stamp = 0; -+ -+ { -+ CPpmd8_Node *node = (CPpmd8_Node *)p->UnitsStart; -+ for (; node->Stamp == EMPTY_NODE; node += node->NU) -+ { -+ node->Stamp = 0; -+ count[U2I(node->NU)]++; -+ } -+ p->UnitsStart = (Byte *)node; -+ } -+ -+ for (i = 0; i < PPMD_NUM_INDEXES; i++) -+ { -+ CPpmd8_Node_Ref *next = (CPpmd8_Node_Ref *)&p->FreeList[i]; -+ while (count[i] != 0) -+ { -+ CPpmd8_Node *node = NODE(*next); -+ while (node->Stamp == 0) -+ { -+ *next = node->Next; -+ node = NODE(*next); -+ p->Stamps[i]--; -+ if (--count[i] == 0) -+ break; -+ } -+ next = &node->Next; -+ } -+ } -+} -+ -+#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16))) -+ -+static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v) -+{ -+ (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF); -+ (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF); -+} -+ -+#define RESET_TEXT(offs) { p->Text = p->Base + p->AlignOffset + (offs); } -+ -+static void RestartModel(CPpmd8 *p) -+{ -+ unsigned i, k, m, r; -+ -+ memset(p->FreeList, 0, sizeof(p->FreeList)); -+ memset(p->Stamps, 0, sizeof(p->Stamps)); -+ RESET_TEXT(0); -+ p->HiUnit = p->Text + p->Size; -+ p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE; -+ p->GlueCount = 0; -+ -+ p->OrderFall = p->MaxOrder; -+ p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1; -+ p->PrevSuccess = 0; -+ -+ p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */ -+ p->MinContext->Suffix = 0; -+ p->MinContext->NumStats = 255; -+ p->MinContext->Flags = 0; -+ p->MinContext->SummFreq = 256 + 1; -+ p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */ -+ p->LoUnit += U2B(256 / 2); -+ p->MinContext->Stats = REF(p->FoundState); -+ for (i = 0; i < 256; i++) -+ { -+ CPpmd_State *s = &p->FoundState[i]; -+ s->Symbol = (Byte)i; -+ s->Freq = 1; -+ SetSuccessor(s, 0); -+ } -+ -+ for (i = m = 0; m < 25; m++) -+ { -+ while (p->NS2Indx[i] == m) -+ i++; -+ for (k = 0; k < 8; k++) -+ { -+ UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 1)); -+ UInt16 *dest = p->BinSumm[m] + k; -+ for (r = 0; r < 64; r += 8) -+ dest[r] = val; -+ } -+ } -+ -+ for (i = m = 0; m < 24; m++) -+ { -+ while (p->NS2Indx[i + 3] == m + 3) -+ i++; -+ for (k = 0; k < 32; k++) -+ { -+ CPpmd_See *s = &p->See[m][k]; -+ s->Summ = (UInt16)((2 * i + 5) << (s->Shift = PPMD_PERIOD_BITS - 4)); -+ s->Count = 7; -+ } -+ } -+} -+ -+void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod) -+{ -+ p->MaxOrder = maxOrder; -+ p->RestoreMethod = restoreMethod; -+ RestartModel(p); -+ p->DummySee.Shift = PPMD_PERIOD_BITS; -+ p->DummySee.Summ = 0; /* unused */ -+ p->DummySee.Count = 64; /* unused */ -+} -+ -+static void Refresh(CPpmd8 *p, CTX_PTR ctx, unsigned oldNU, unsigned scale) -+{ -+ unsigned i = ctx->NumStats, escFreq, sumFreq, flags; -+ CPpmd_State *s = (CPpmd_State *)ShrinkUnits(p, STATS(ctx), oldNU, (i + 2) >> 1); -+ ctx->Stats = REF(s); -+ #ifdef PPMD8_FREEZE_SUPPORT -+ /* fixed over Shkarin's code. Fixed code is not compatible with original code for some files in FREEZE mode. */ -+ scale |= (ctx->SummFreq >= ((UInt32)1 << 15)); -+ #endif -+ flags = (ctx->Flags & (0x10 + 0x04 * scale)) + 0x08 * (s->Symbol >= 0x40); -+ escFreq = ctx->SummFreq - s->Freq; -+ sumFreq = (s->Freq = (Byte)((s->Freq + scale) >> scale)); -+ do -+ { -+ escFreq -= (++s)->Freq; -+ sumFreq += (s->Freq = (Byte)((s->Freq + scale) >> scale)); -+ flags |= 0x08 * (s->Symbol >= 0x40); -+ } -+ while (--i); -+ ctx->SummFreq = (UInt16)(sumFreq + ((escFreq + scale) >> scale)); -+ ctx->Flags = (Byte)flags; -+} -+ -+static void SwapStates(CPpmd_State *t1, CPpmd_State *t2) -+{ -+ CPpmd_State tmp = *t1; -+ *t1 = *t2; -+ *t2 = tmp; -+} -+ -+static CPpmd_Void_Ref CutOff(CPpmd8 *p, CTX_PTR ctx, unsigned order) -+{ -+ int i; -+ unsigned tmp; -+ CPpmd_State *s; -+ -+ if (!ctx->NumStats) -+ { -+ s = ONE_STATE(ctx); -+ if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart) -+ { -+ if (order < p->MaxOrder) -+ SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1)); -+ else -+ SetSuccessor(s, 0); -+ if (SUCCESSOR(s) || order <= 9) /* O_BOUND */ -+ return REF(ctx); -+ } -+ SpecialFreeUnit(p, ctx); -+ return 0; -+ } -+ -+ ctx->Stats = STATS_REF(MoveUnitsUp(p, STATS(ctx), tmp = ((unsigned)ctx->NumStats + 2) >> 1)); -+ -+ for (s = STATS(ctx) + (i = ctx->NumStats); s >= STATS(ctx); s--) -+ if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) < p->UnitsStart) -+ { -+ CPpmd_State *s2 = STATS(ctx) + (i--); -+ SetSuccessor(s, 0); -+ SwapStates(s, s2); -+ } -+ else if (order < p->MaxOrder) -+ SetSuccessor(s, CutOff(p, CTX(SUCCESSOR(s)), order + 1)); -+ else -+ SetSuccessor(s, 0); -+ -+ if (i != ctx->NumStats && order) -+ { -+ ctx->NumStats = (Byte)i; -+ s = STATS(ctx); -+ if (i < 0) -+ { -+ FreeUnits(p, s, tmp); -+ SpecialFreeUnit(p, ctx); -+ return 0; -+ } -+ if (i == 0) -+ { -+ ctx->Flags = (ctx->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40); -+ *ONE_STATE(ctx) = *s; -+ FreeUnits(p, s, tmp); -+ ONE_STATE(ctx)->Freq = (Byte)((unsigned)ONE_STATE(ctx)->Freq + 11) >> 3; -+ } -+ else -+ Refresh(p, ctx, tmp, ctx->SummFreq > 16 * i); -+ } -+ return REF(ctx); -+} -+ -+#ifdef PPMD8_FREEZE_SUPPORT -+static CPpmd_Void_Ref RemoveBinContexts(CPpmd8 *p, CTX_PTR ctx, unsigned order) -+{ -+ CPpmd_State *s; -+ if (!ctx->NumStats) -+ { -+ s = ONE_STATE(ctx); -+ if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder) -+ SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1)); -+ else -+ SetSuccessor(s, 0); -+ /* Suffix context can be removed already, since different (high-order) -+ Successors may refer to same context. So we check Flags == 0xFF (Stamp == EMPTY_NODE) */ -+ if (!SUCCESSOR(s) && (!SUFFIX(ctx)->NumStats || SUFFIX(ctx)->Flags == 0xFF)) -+ { -+ FreeUnits(p, ctx, 1); -+ return 0; -+ } -+ else -+ return REF(ctx); -+ } -+ -+ for (s = STATS(ctx) + ctx->NumStats; s >= STATS(ctx); s--) -+ if ((Byte *)Ppmd8_GetPtr(p, SUCCESSOR(s)) >= p->UnitsStart && order < p->MaxOrder) -+ SetSuccessor(s, RemoveBinContexts(p, CTX(SUCCESSOR(s)), order + 1)); -+ else -+ SetSuccessor(s, 0); -+ -+ return REF(ctx); -+} -+#endif -+ -+static UInt32 GetUsedMemory(const CPpmd8 *p) -+{ -+ UInt32 v = 0; -+ unsigned i; -+ for (i = 0; i < PPMD_NUM_INDEXES; i++) -+ v += p->Stamps[i] * I2U(i); -+ return p->Size - (UInt32)(p->HiUnit - p->LoUnit) - (UInt32)(p->UnitsStart - p->Text) - U2B(v); -+} -+ -+#ifdef PPMD8_FREEZE_SUPPORT -+ #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1, fSuccessor) -+#else -+ #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1) -+#endif -+ -+static void RestoreModel(CPpmd8 *p, CTX_PTR c1 -+ #ifdef PPMD8_FREEZE_SUPPORT -+ , CTX_PTR fSuccessor -+ #endif -+ ) -+{ -+ CTX_PTR c; -+ CPpmd_State *s; -+ RESET_TEXT(0); -+ for (c = p->MaxContext; c != c1; c = SUFFIX(c)) -+ if (--(c->NumStats) == 0) -+ { -+ s = STATS(c); -+ c->Flags = (c->Flags & 0x10) + 0x08 * (s->Symbol >= 0x40); -+ *ONE_STATE(c) = *s; -+ SpecialFreeUnit(p, s); -+ ONE_STATE(c)->Freq = (ONE_STATE(c)->Freq + 11) >> 3; -+ } -+ else -+ Refresh(p, c, (c->NumStats+3) >> 1, 0); -+ -+ for (; c != p->MinContext; c = SUFFIX(c)) -+ if (!c->NumStats) -+ ONE_STATE(c)->Freq -= ONE_STATE(c)->Freq >> 1; -+ else if ((c->SummFreq += 4) > 128 + 4 * c->NumStats) -+ Refresh(p, c, (c->NumStats + 2) >> 1, 1); -+ -+ #ifdef PPMD8_FREEZE_SUPPORT -+ if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) -+ { -+ p->MaxContext = fSuccessor; -+ p->GlueCount += !(p->Stamps[1] & 1); -+ } -+ else if (p->RestoreMethod == PPMD8_RESTORE_METHOD_FREEZE) -+ { -+ while (p->MaxContext->Suffix) -+ p->MaxContext = SUFFIX(p->MaxContext); -+ RemoveBinContexts(p, p->MaxContext, 0); -+ p->RestoreMethod++; -+ p->GlueCount = 0; -+ p->OrderFall = p->MaxOrder; -+ } -+ else -+ #endif -+ if (p->RestoreMethod == PPMD8_RESTORE_METHOD_RESTART || GetUsedMemory(p) < (p->Size >> 1)) -+ RestartModel(p); -+ else -+ { -+ while (p->MaxContext->Suffix) -+ p->MaxContext = SUFFIX(p->MaxContext); -+ do -+ { -+ CutOff(p, p->MaxContext, 0); -+ ExpandTextArea(p); -+ } -+ while (GetUsedMemory(p) > 3 * (p->Size >> 2)); -+ p->GlueCount = 0; -+ p->OrderFall = p->MaxOrder; -+ } -+} -+ -+static CTX_PTR CreateSuccessors(CPpmd8 *p, Bool skip, CPpmd_State *s1, CTX_PTR c) -+{ -+ CPpmd_State upState; -+ Byte flags; -+ CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState); -+ /* fixed over Shkarin's code. Maybe it could work without + 1 too. */ -+ CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; -+ unsigned numPs = 0; -+ -+ if (!skip) -+ ps[numPs++] = p->FoundState; -+ -+ while (c->Suffix) -+ { -+ CPpmd_Void_Ref successor; -+ CPpmd_State *s; -+ c = SUFFIX(c); -+ if (s1) -+ { -+ s = s1; -+ s1 = NULL; -+ } -+ else if (c->NumStats != 0) -+ { -+ for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++); -+ if (s->Freq < MAX_FREQ - 9) -+ { -+ s->Freq++; -+ c->SummFreq++; -+ } -+ } -+ else -+ { -+ s = ONE_STATE(c); -+ s->Freq += (!SUFFIX(c)->NumStats & (s->Freq < 24)); -+ } -+ successor = SUCCESSOR(s); -+ if (successor != upBranch) -+ { -+ c = CTX(successor); -+ if (numPs == 0) -+ return c; -+ break; -+ } -+ ps[numPs++] = s; -+ } -+ -+ upState.Symbol = *(const Byte *)Ppmd8_GetPtr(p, upBranch); -+ SetSuccessor(&upState, upBranch + 1); -+ flags = 0x10 * (p->FoundState->Symbol >= 0x40) + 0x08 * (upState.Symbol >= 0x40); -+ -+ if (c->NumStats == 0) -+ upState.Freq = ONE_STATE(c)->Freq; -+ else -+ { -+ UInt32 cf, s0; -+ CPpmd_State *s; -+ for (s = STATS(c); s->Symbol != upState.Symbol; s++); -+ cf = s->Freq - 1; -+ s0 = c->SummFreq - c->NumStats - cf; -+ upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((cf + 2 * s0 - 3) / s0))); -+ } -+ -+ do -+ { -+ /* Create Child */ -+ CTX_PTR c1; /* = AllocContext(p); */ -+ if (p->HiUnit != p->LoUnit) -+ c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); -+ else if (p->FreeList[0] != 0) -+ c1 = (CTX_PTR)RemoveNode(p, 0); -+ else -+ { -+ c1 = (CTX_PTR)AllocUnitsRare(p, 0); -+ if (!c1) -+ return NULL; -+ } -+ c1->NumStats = 0; -+ c1->Flags = flags; -+ *ONE_STATE(c1) = upState; -+ c1->Suffix = REF(c); -+ SetSuccessor(ps[--numPs], REF(c1)); -+ c = c1; -+ } -+ while (numPs != 0); -+ -+ return c; -+} -+ -+static CTX_PTR ReduceOrder(CPpmd8 *p, CPpmd_State *s1, CTX_PTR c) -+{ -+ CPpmd_State *s = NULL; -+ CTX_PTR c1 = c; -+ CPpmd_Void_Ref upBranch = REF(p->Text); -+ -+ #ifdef PPMD8_FREEZE_SUPPORT -+ /* The BUG in Shkarin's code was fixed: ps could overflow in CUT_OFF mode. */ -+ CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; -+ unsigned numPs = 0; -+ ps[numPs++] = p->FoundState; -+ #endif -+ -+ SetSuccessor(p->FoundState, upBranch); -+ p->OrderFall++; -+ -+ for (;;) -+ { -+ if (s1) -+ { -+ c = SUFFIX(c); -+ s = s1; -+ s1 = NULL; -+ } -+ else -+ { -+ if (!c->Suffix) -+ { -+ #ifdef PPMD8_FREEZE_SUPPORT -+ if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) -+ { -+ do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs); -+ RESET_TEXT(1); -+ p->OrderFall = 1; -+ } -+ #endif -+ return c; -+ } -+ c = SUFFIX(c); -+ if (c->NumStats) -+ { -+ if ((s = STATS(c))->Symbol != p->FoundState->Symbol) -+ do { s++; } while (s->Symbol != p->FoundState->Symbol); -+ if (s->Freq < MAX_FREQ - 9) -+ { -+ s->Freq += 2; -+ c->SummFreq += 2; -+ } -+ } -+ else -+ { -+ s = ONE_STATE(c); -+ s->Freq += (s->Freq < 32); -+ } -+ } -+ if (SUCCESSOR(s)) -+ break; -+ #ifdef PPMD8_FREEZE_SUPPORT -+ ps[numPs++] = s; -+ #endif -+ SetSuccessor(s, upBranch); -+ p->OrderFall++; -+ } -+ -+ #ifdef PPMD8_FREEZE_SUPPORT -+ if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) -+ { -+ c = CTX(SUCCESSOR(s)); -+ do { SetSuccessor(ps[--numPs], REF(c)); } while (numPs); -+ RESET_TEXT(1); -+ p->OrderFall = 1; -+ return c; -+ } -+ else -+ #endif -+ if (SUCCESSOR(s) <= upBranch) -+ { -+ CTX_PTR successor; -+ CPpmd_State *s1 = p->FoundState; -+ p->FoundState = s; -+ -+ successor = CreateSuccessors(p, False, NULL, c); -+ if (successor == NULL) -+ SetSuccessor(s, 0); -+ else -+ SetSuccessor(s, REF(successor)); -+ p->FoundState = s1; -+ } -+ -+ if (p->OrderFall == 1 && c1 == p->MaxContext) -+ { -+ SetSuccessor(p->FoundState, SUCCESSOR(s)); -+ p->Text--; -+ } -+ if (SUCCESSOR(s) == 0) -+ return NULL; -+ return CTX(SUCCESSOR(s)); -+} -+ -+static void UpdateModel(CPpmd8 *p) -+{ -+ CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState); -+ CTX_PTR c; -+ unsigned s0, ns, fFreq = p->FoundState->Freq; -+ Byte flag, fSymbol = p->FoundState->Symbol; -+ CPpmd_State *s = NULL; -+ -+ if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0) -+ { -+ c = SUFFIX(p->MinContext); -+ -+ if (c->NumStats == 0) -+ { -+ s = ONE_STATE(c); -+ if (s->Freq < 32) -+ s->Freq++; -+ } -+ else -+ { -+ s = STATS(c); -+ if (s->Symbol != p->FoundState->Symbol) -+ { -+ do { s++; } while (s->Symbol != p->FoundState->Symbol); -+ if (s[0].Freq >= s[-1].Freq) -+ { -+ SwapStates(&s[0], &s[-1]); -+ s--; -+ } -+ } -+ if (s->Freq < MAX_FREQ - 9) -+ { -+ s->Freq += 2; -+ c->SummFreq += 2; -+ } -+ } -+ } -+ -+ c = p->MaxContext; -+ if (p->OrderFall == 0 && fSuccessor) -+ { -+ CTX_PTR cs = CreateSuccessors(p, True, s, p->MinContext); -+ if (cs == 0) -+ { -+ SetSuccessor(p->FoundState, 0); -+ RESTORE_MODEL(c, CTX(fSuccessor)); -+ } -+ else -+ { -+ SetSuccessor(p->FoundState, REF(cs)); -+ p->MaxContext = cs; -+ } -+ return; -+ } -+ -+ *p->Text++ = p->FoundState->Symbol; -+ successor = REF(p->Text); -+ if (p->Text >= p->UnitsStart) -+ { -+ RESTORE_MODEL(c, CTX(fSuccessor)); /* check it */ -+ return; -+ } -+ -+ if (!fSuccessor) -+ { -+ CTX_PTR cs = ReduceOrder(p, s, p->MinContext); -+ if (cs == NULL) -+ { -+ RESTORE_MODEL(c, 0); -+ return; -+ } -+ fSuccessor = REF(cs); -+ } -+ else if ((Byte *)Ppmd8_GetPtr(p, fSuccessor) < p->UnitsStart) -+ { -+ CTX_PTR cs = CreateSuccessors(p, False, s, p->MinContext); -+ if (cs == NULL) -+ { -+ RESTORE_MODEL(c, 0); -+ return; -+ } -+ fSuccessor = REF(cs); -+ } -+ -+ if (--p->OrderFall == 0) -+ { -+ successor = fSuccessor; -+ p->Text -= (p->MaxContext != p->MinContext); -+ } -+ #ifdef PPMD8_FREEZE_SUPPORT -+ else if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE) -+ { -+ successor = fSuccessor; -+ RESET_TEXT(0); -+ p->OrderFall = 0; -+ } -+ #endif -+ -+ s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - fFreq; -+ flag = 0x08 * (fSymbol >= 0x40); -+ -+ for (; c != p->MinContext; c = SUFFIX(c)) -+ { -+ unsigned ns1; -+ UInt32 cf, sf; -+ if ((ns1 = c->NumStats) != 0) -+ { -+ if ((ns1 & 1) != 0) -+ { -+ /* Expand for one UNIT */ -+ unsigned oldNU = (ns1 + 1) >> 1; -+ unsigned i = U2I(oldNU); -+ if (i != U2I(oldNU + 1)) -+ { -+ void *ptr = AllocUnits(p, i + 1); -+ void *oldPtr; -+ if (!ptr) -+ { -+ RESTORE_MODEL(c, CTX(fSuccessor)); -+ return; -+ } -+ oldPtr = STATS(c); -+ MyMem12Cpy(ptr, oldPtr, oldNU); -+ InsertNode(p, oldPtr, i); -+ c->Stats = STATS_REF(ptr); -+ } -+ } -+ c->SummFreq = (UInt16)(c->SummFreq + (3 * ns1 + 1 < ns)); -+ } -+ else -+ { -+ CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0); -+ if (!s) -+ { -+ RESTORE_MODEL(c, CTX(fSuccessor)); -+ return; -+ } -+ *s = *ONE_STATE(c); -+ c->Stats = REF(s); -+ if (s->Freq < MAX_FREQ / 4 - 1) -+ s->Freq <<= 1; -+ else -+ s->Freq = MAX_FREQ - 4; -+ c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 2)); -+ } -+ cf = 2 * fFreq * (c->SummFreq + 6); -+ sf = (UInt32)s0 + c->SummFreq; -+ if (cf < 6 * sf) -+ { -+ cf = 1 + (cf > sf) + (cf >= 4 * sf); -+ c->SummFreq += 4; -+ } -+ else -+ { -+ cf = 4 + (cf > 9 * sf) + (cf > 12 * sf) + (cf > 15 * sf); -+ c->SummFreq = (UInt16)(c->SummFreq + cf); -+ } -+ { -+ CPpmd_State *s = STATS(c) + ns1 + 1; -+ SetSuccessor(s, successor); -+ s->Symbol = fSymbol; -+ s->Freq = (Byte)cf; -+ c->Flags |= flag; -+ c->NumStats = (Byte)(ns1 + 1); -+ } -+ } -+ p->MaxContext = p->MinContext = CTX(fSuccessor); -+} -+ -+static void Rescale(CPpmd8 *p) -+{ -+ unsigned i, adder, sumFreq, escFreq; -+ CPpmd_State *stats = STATS(p->MinContext); -+ CPpmd_State *s = p->FoundState; -+ { -+ CPpmd_State tmp = *s; -+ for (; s != stats; s--) -+ s[0] = s[-1]; -+ *s = tmp; -+ } -+ escFreq = p->MinContext->SummFreq - s->Freq; -+ s->Freq += 4; -+ adder = (p->OrderFall != 0 -+ #ifdef PPMD8_FREEZE_SUPPORT -+ || p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE -+ #endif -+ ); -+ s->Freq = (Byte)((s->Freq + adder) >> 1); -+ sumFreq = s->Freq; -+ -+ i = p->MinContext->NumStats; -+ do -+ { -+ escFreq -= (++s)->Freq; -+ s->Freq = (Byte)((s->Freq + adder) >> 1); -+ sumFreq += s->Freq; -+ if (s[0].Freq > s[-1].Freq) -+ { -+ CPpmd_State *s1 = s; -+ CPpmd_State tmp = *s1; -+ do -+ s1[0] = s1[-1]; -+ while (--s1 != stats && tmp.Freq > s1[-1].Freq); -+ *s1 = tmp; -+ } -+ } -+ while (--i); -+ -+ if (s->Freq == 0) -+ { -+ unsigned numStats = p->MinContext->NumStats; -+ unsigned n0, n1; -+ do { i++; } while ((--s)->Freq == 0); -+ escFreq += i; -+ p->MinContext->NumStats = (Byte)(p->MinContext->NumStats - i); -+ if (p->MinContext->NumStats == 0) -+ { -+ CPpmd_State tmp = *stats; -+ tmp.Freq = (Byte)((2 * tmp.Freq + escFreq - 1) / escFreq); -+ if (tmp.Freq > MAX_FREQ / 3) -+ tmp.Freq = MAX_FREQ / 3; -+ InsertNode(p, stats, U2I((numStats + 2) >> 1)); -+ p->MinContext->Flags = (p->MinContext->Flags & 0x10) + 0x08 * (tmp.Symbol >= 0x40); -+ *(p->FoundState = ONE_STATE(p->MinContext)) = tmp; -+ return; -+ } -+ n0 = (numStats + 2) >> 1; -+ n1 = (p->MinContext->NumStats + 2) >> 1; -+ if (n0 != n1) -+ p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1)); -+ p->MinContext->Flags &= ~0x08; -+ p->MinContext->Flags |= 0x08 * ((s = STATS(p->MinContext))->Symbol >= 0x40); -+ i = p->MinContext->NumStats; -+ do { p->MinContext->Flags |= 0x08*((++s)->Symbol >= 0x40); } while (--i); -+ } -+ p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1)); -+ p->MinContext->Flags |= 0x4; -+ p->FoundState = STATS(p->MinContext); -+} -+ -+CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq) -+{ -+ CPpmd_See *see; -+ if (p->MinContext->NumStats != 0xFF) -+ { -+ see = p->See[p->NS2Indx[p->MinContext->NumStats + 2] - 3] + -+ (p->MinContext->SummFreq > 11 * ((unsigned)p->MinContext->NumStats + 1)) + -+ 2 * (2 * (unsigned)p->MinContext->NumStats < -+ ((unsigned)SUFFIX(p->MinContext)->NumStats + numMasked1)) + -+ p->MinContext->Flags; -+ { -+ unsigned r = (see->Summ >> see->Shift); -+ see->Summ = (UInt16)(see->Summ - r); -+ *escFreq = r + (r == 0); -+ } -+ } -+ else -+ { -+ see = &p->DummySee; -+ *escFreq = 1; -+ } -+ return see; -+} -+ -+static void NextContext(CPpmd8 *p) -+{ -+ CTX_PTR c = CTX(SUCCESSOR(p->FoundState)); -+ if (p->OrderFall == 0 && (Byte *)c >= p->UnitsStart) -+ p->MinContext = p->MaxContext = c; -+ else -+ { -+ UpdateModel(p); -+ p->MinContext = p->MaxContext; -+ } -+} -+ -+void Ppmd8_Update1(CPpmd8 *p) -+{ -+ CPpmd_State *s = p->FoundState; -+ s->Freq += 4; -+ p->MinContext->SummFreq += 4; -+ if (s[0].Freq > s[-1].Freq) -+ { -+ SwapStates(&s[0], &s[-1]); -+ p->FoundState = --s; -+ if (s->Freq > MAX_FREQ) -+ Rescale(p); -+ } -+ NextContext(p); -+} -+ -+void Ppmd8_Update1_0(CPpmd8 *p) -+{ -+ p->PrevSuccess = (2 * p->FoundState->Freq >= p->MinContext->SummFreq); -+ p->RunLength += p->PrevSuccess; -+ p->MinContext->SummFreq += 4; -+ if ((p->FoundState->Freq += 4) > MAX_FREQ) -+ Rescale(p); -+ NextContext(p); -+} -+ -+void Ppmd8_UpdateBin(CPpmd8 *p) -+{ -+ p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 196)); -+ p->PrevSuccess = 1; -+ p->RunLength++; -+ NextContext(p); -+} -+ -+void Ppmd8_Update2(CPpmd8 *p) -+{ -+ p->MinContext->SummFreq += 4; -+ if ((p->FoundState->Freq += 4) > MAX_FREQ) -+ Rescale(p); -+ p->RunLength = p->InitRL; -+ UpdateModel(p); -+ p->MinContext = p->MaxContext; -+} -+ -+/* H->I changes: -+ NS2Indx -+ GlewCount, and Glue method -+ BinSum -+ See / EscFreq -+ CreateSuccessors updates more suffix contexts -+ UpdateModel consts. -+ PrevSuccess Update -+*/ -diff --git a/cut-n-paste/unarr/lzmasdk/Ppmd8.h b/cut-n-paste/unarr/lzmasdk/Ppmd8.h -new file mode 100644 -index 00000000..7dcfc916 ---- /dev/null -+++ b/cut-n-paste/unarr/lzmasdk/Ppmd8.h -@@ -0,0 +1,137 @@ -+/* Ppmd8.h -- PPMdI codec -+2011-01-27 : Igor Pavlov : Public domain -+This code is based on: -+ PPMd var.I (2002): Dmitry Shkarin : Public domain -+ Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ -+ -+#ifndef __PPMD8_H -+#define __PPMD8_H -+ -+#include "Ppmd.h" -+ -+EXTERN_C_BEGIN -+ -+#define PPMD8_MIN_ORDER 2 -+#define PPMD8_MAX_ORDER 16 -+ -+struct CPpmd8_Context_; -+ -+typedef -+ #ifdef PPMD_32BIT -+ struct CPpmd8_Context_ * -+ #else -+ UInt32 -+ #endif -+ CPpmd8_Context_Ref; -+ -+#pragma pack(push, 1) -+ -+typedef struct CPpmd8_Context_ -+{ -+ Byte NumStats; -+ Byte Flags; -+ UInt16 SummFreq; -+ CPpmd_State_Ref Stats; -+ CPpmd8_Context_Ref Suffix; -+} CPpmd8_Context; -+ -+#pragma pack(pop) -+ -+#define Ppmd8Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq) -+ -+/* The BUG in Shkarin's code for FREEZE mode was fixed, but that fixed -+ code is not compatible with original code for some files compressed -+ in FREEZE mode. So we disable FREEZE mode support. */ -+ -+enum -+{ -+ PPMD8_RESTORE_METHOD_RESTART, -+ PPMD8_RESTORE_METHOD_CUT_OFF -+ #ifdef PPMD8_FREEZE_SUPPORT -+ , PPMD8_RESTORE_METHOD_FREEZE -+ #endif -+}; -+ -+typedef struct -+{ -+ CPpmd8_Context *MinContext, *MaxContext; -+ CPpmd_State *FoundState; -+ unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder; -+ Int32 RunLength, InitRL; /* must be 32-bit at least */ -+ -+ UInt32 Size; -+ UInt32 GlueCount; -+ Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart; -+ UInt32 AlignOffset; -+ unsigned RestoreMethod; -+ -+ /* Range Coder */ -+ UInt32 Range; -+ UInt32 Code; -+ UInt32 Low; -+ union -+ { -+ IByteIn *In; -+ IByteOut *Out; -+ } Stream; -+ -+ Byte Indx2Units[PPMD_NUM_INDEXES]; -+ Byte Units2Indx[128]; -+ CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES]; -+ UInt32 Stamps[PPMD_NUM_INDEXES]; -+ -+ Byte NS2BSIndx[256], NS2Indx[260]; -+ CPpmd_See DummySee, See[24][32]; -+ UInt16 BinSumm[25][64]; -+} CPpmd8; -+ -+void Ppmd8_Construct(CPpmd8 *p); -+Bool Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAlloc *alloc); -+void Ppmd8_Free(CPpmd8 *p, ISzAlloc *alloc); -+void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod); -+#define Ppmd8_WasAllocated(p) ((p)->Base != NULL) -+ -+ -+/* ---------- Internal Functions ---------- */ -+ -+extern const Byte PPMD8_kExpEscape[16]; -+ -+#ifdef PPMD_32BIT -+ #define Ppmd8_GetPtr(p, ptr) (ptr) -+ #define Ppmd8_GetContext(p, ptr) (ptr) -+ #define Ppmd8_GetStats(p, ctx) ((ctx)->Stats) -+#else -+ #define Ppmd8_GetPtr(p, offs) ((void *)((p)->Base + (offs))) -+ #define Ppmd8_GetContext(p, offs) ((CPpmd8_Context *)Ppmd8_GetPtr((p), (offs))) -+ #define Ppmd8_GetStats(p, ctx) ((CPpmd_State *)Ppmd8_GetPtr((p), ((ctx)->Stats))) -+#endif -+ -+void Ppmd8_Update1(CPpmd8 *p); -+void Ppmd8_Update1_0(CPpmd8 *p); -+void Ppmd8_Update2(CPpmd8 *p); -+void Ppmd8_UpdateBin(CPpmd8 *p); -+ -+#define Ppmd8_GetBinSumm(p) \ -+ &p->BinSumm[p->NS2Indx[Ppmd8Context_OneState(p->MinContext)->Freq - 1]][ \ -+ p->NS2BSIndx[Ppmd8_GetContext(p, p->MinContext->Suffix)->NumStats] + \ -+ p->PrevSuccess + p->MinContext->Flags + ((p->RunLength >> 26) & 0x20)] -+ -+CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked, UInt32 *scale); -+ -+ -+/* ---------- Decode ---------- */ -+ -+Bool Ppmd8_RangeDec_Init(CPpmd8 *p); -+#define Ppmd8_RangeDec_IsFinishedOK(p) ((p)->Code == 0) -+int Ppmd8_DecodeSymbol(CPpmd8 *p); /* returns: -1 as EndMarker, -2 as DataError */ -+ -+ -+/* ---------- Encode ---------- */ -+ -+#define Ppmd8_RangeEnc_Init(p) { (p)->Low = 0; (p)->Range = 0xFFFFFFFF; } -+void Ppmd8_RangeEnc_FlushData(CPpmd8 *p); -+void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol); /* symbol = -1 means EndMarker */ -+ -+EXTERN_C_END -+ -+#endif -diff --git a/cut-n-paste/unarr/lzmasdk/Ppmd8Dec.c b/cut-n-paste/unarr/lzmasdk/Ppmd8Dec.c -new file mode 100644 -index 00000000..317bd651 ---- /dev/null -+++ b/cut-n-paste/unarr/lzmasdk/Ppmd8Dec.c -@@ -0,0 +1,157 @@ -+/* Ppmd8Dec.c -- PPMdI Decoder -+2010-04-16 : Igor Pavlov : Public domain -+This code is based on: -+ PPMd var.I (2002): Dmitry Shkarin : Public domain -+ Carryless rangecoder (1999): Dmitry Subbotin : Public domain */ -+ -+#include "Precomp.h" -+ -+#include "Ppmd8.h" -+ -+#define kTop (1 << 24) -+#define kBot (1 << 15) -+ -+Bool Ppmd8_RangeDec_Init(CPpmd8 *p) -+{ -+ unsigned i; -+ p->Low = 0; -+ p->Range = 0xFFFFFFFF; -+ p->Code = 0; -+ for (i = 0; i < 4; i++) -+ p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In); -+ return (p->Code < 0xFFFFFFFF); -+} -+ -+static UInt32 RangeDec_GetThreshold(CPpmd8 *p, UInt32 total) -+{ -+ return p->Code / (p->Range /= total); -+} -+ -+static void RangeDec_Decode(CPpmd8 *p, UInt32 start, UInt32 size) -+{ -+ start *= p->Range; -+ p->Low += start; -+ p->Code -= start; -+ p->Range *= size; -+ -+ while ((p->Low ^ (p->Low + p->Range)) < kTop || -+ (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) -+ { -+ p->Code = (p->Code << 8) | p->Stream.In->Read(p->Stream.In); -+ p->Range <<= 8; -+ p->Low <<= 8; -+ } -+} -+ -+#define MASK(sym) ((signed char *)charMask)[sym] -+ -+int Ppmd8_DecodeSymbol(CPpmd8 *p) -+{ -+ size_t charMask[256 / sizeof(size_t)]; -+ if (p->MinContext->NumStats != 0) -+ { -+ CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext); -+ unsigned i; -+ UInt32 count, hiCnt; -+ if ((count = RangeDec_GetThreshold(p, p->MinContext->SummFreq)) < (hiCnt = s->Freq)) -+ { -+ Byte symbol; -+ RangeDec_Decode(p, 0, s->Freq); -+ p->FoundState = s; -+ symbol = s->Symbol; -+ Ppmd8_Update1_0(p); -+ return symbol; -+ } -+ p->PrevSuccess = 0; -+ i = p->MinContext->NumStats; -+ do -+ { -+ if ((hiCnt += (++s)->Freq) > count) -+ { -+ Byte symbol; -+ RangeDec_Decode(p, hiCnt - s->Freq, s->Freq); -+ p->FoundState = s; -+ symbol = s->Symbol; -+ Ppmd8_Update1(p); -+ return symbol; -+ } -+ } -+ while (--i); -+ if (count >= p->MinContext->SummFreq) -+ return -2; -+ RangeDec_Decode(p, hiCnt, p->MinContext->SummFreq - hiCnt); -+ PPMD_SetAllBitsIn256Bytes(charMask); -+ MASK(s->Symbol) = 0; -+ i = p->MinContext->NumStats; -+ do { MASK((--s)->Symbol) = 0; } while (--i); -+ } -+ else -+ { -+ UInt16 *prob = Ppmd8_GetBinSumm(p); -+ if (((p->Code / (p->Range >>= 14)) < *prob)) -+ { -+ Byte symbol; -+ RangeDec_Decode(p, 0, *prob); -+ *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob); -+ symbol = (p->FoundState = Ppmd8Context_OneState(p->MinContext))->Symbol; -+ Ppmd8_UpdateBin(p); -+ return symbol; -+ } -+ RangeDec_Decode(p, *prob, (1 << 14) - *prob); -+ *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob); -+ p->InitEsc = PPMD8_kExpEscape[*prob >> 10]; -+ PPMD_SetAllBitsIn256Bytes(charMask); -+ MASK(Ppmd8Context_OneState(p->MinContext)->Symbol) = 0; -+ p->PrevSuccess = 0; -+ } -+ for (;;) -+ { -+ CPpmd_State *ps[256], *s; -+ UInt32 freqSum, count, hiCnt; -+ CPpmd_See *see; -+ unsigned i, num, numMasked = p->MinContext->NumStats; -+ do -+ { -+ p->OrderFall++; -+ if (!p->MinContext->Suffix) -+ return -1; -+ p->MinContext = Ppmd8_GetContext(p, p->MinContext->Suffix); -+ } -+ while (p->MinContext->NumStats == numMasked); -+ hiCnt = 0; -+ s = Ppmd8_GetStats(p, p->MinContext); -+ i = 0; -+ num = p->MinContext->NumStats - numMasked; -+ do -+ { -+ int k = (int)(MASK(s->Symbol)); -+ hiCnt += (s->Freq & k); -+ ps[i] = s++; -+ i -= k; -+ } -+ while (i != num); -+ -+ see = Ppmd8_MakeEscFreq(p, numMasked, &freqSum); -+ freqSum += hiCnt; -+ count = RangeDec_GetThreshold(p, freqSum); -+ -+ if (count < hiCnt) -+ { -+ Byte symbol; -+ CPpmd_State **pps = ps; -+ for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++); -+ s = *pps; -+ RangeDec_Decode(p, hiCnt - s->Freq, s->Freq); -+ Ppmd_See_Update(see); -+ p->FoundState = s; -+ symbol = s->Symbol; -+ Ppmd8_Update2(p); -+ return symbol; -+ } -+ if (count >= freqSum) -+ return -2; -+ RangeDec_Decode(p, hiCnt, freqSum - hiCnt); -+ see->Summ = (UInt16)(see->Summ + freqSum); -+ do { MASK(ps[--i]->Symbol) = 0; } while (i != 0); -+ } -+} -diff --git a/cut-n-paste/unarr/lzmasdk/Precomp.h b/cut-n-paste/unarr/lzmasdk/Precomp.h -new file mode 100644 -index 00000000..895bc35e ---- /dev/null -+++ b/cut-n-paste/unarr/lzmasdk/Precomp.h -@@ -0,0 +1,15 @@ -+/* Precomp.h -- StdAfx -+2013-11-12 : Igor Pavlov : Public domain */ -+ -+#ifndef __7Z_PRECOMP_H -+#define __7Z_PRECOMP_H -+ -+/* #include "Compiler.h" */ -+#ifdef _MSC_VER -+#pragma warning(disable : 4456) // declaration of * hides previous local declaration -+#pragma warning(disable : 4457) // declaration of * hides function parameter -+#pragma warning(disable : 4996) // This function or variable may be unsafe -+#endif -+/* #include "7zTypes.h" */ -+ -+#endif -diff --git a/cut-n-paste/unarr/rar/filter-rar.c b/cut-n-paste/unarr/rar/filter-rar.c -new file mode 100644 -index 00000000..cbb2916d ---- /dev/null -+++ b/cut-n-paste/unarr/rar/filter-rar.c -@@ -0,0 +1,704 @@ -+/* Copyright 2015 the unarr project authors (see AUTHORS file). -+ License: LGPLv3 */ -+ -+#include "rar.h" -+#include "rarvm.h" -+ -+/* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/XADRARVirtualMachine.m */ -+/* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/XADRAR30Filter.m */ -+ -+struct MemBitReader { -+ const uint8_t *bytes; -+ size_t length; -+ size_t offset; -+ uint64_t bits; -+ int available; -+ bool at_eof; -+}; -+ -+struct RARProgramCode { -+ RARProgram *prog; -+ uint8_t *staticdata; -+ uint32_t staticdatalen; -+ uint8_t *globalbackup; -+ uint32_t globalbackuplen; -+ uint64_t fingerprint; -+ uint32_t usagecount; -+ uint32_t oldfilterlength; -+ struct RARProgramCode *next; -+}; -+ -+struct RARFilter { -+ struct RARProgramCode *prog; -+ uint32_t initialregisters[8]; -+ uint8_t *globaldata; -+ uint32_t globaldatalen; -+ size_t blockstartpos; -+ uint32_t blocklength; -+ uint32_t filteredblockaddress; -+ uint32_t filteredblocklength; -+ struct RARFilter *next; -+}; -+ -+static bool br_fill(struct MemBitReader *br, int bits) -+{ -+ while (br->available < bits && br->offset < br->length) { -+ br->bits = (br->bits << 8) | br->bytes[br->offset++]; -+ br->available += 8; -+ } -+ if (bits > br->available) { -+ br->at_eof = true; -+ return false; -+ } -+ return true; -+} -+ -+static inline uint32_t br_bits(struct MemBitReader *br, int bits) -+{ -+ if (bits > br->available && (br->at_eof || !br_fill(br, bits))) -+ return 0; -+ return (uint32_t)((br->bits >> (br->available -= bits)) & (((uint64_t)1 << bits) - 1)); -+} -+ -+static inline bool br_available(struct MemBitReader *br, int bits) -+{ -+ return !br->at_eof && (bits <= br->available || br_fill(br, bits)); -+} -+ -+static uint32_t br_next_rarvm_number(struct MemBitReader *br) -+{ -+ uint32_t val; -+ switch (br_bits(br, 2)) { -+ case 0: -+ return br_bits(br, 4); -+ case 1: -+ val = br_bits(br, 8); -+ if (val >= 16) -+ return val; -+ return 0xFFFFFF00 | (val << 4) | br_bits(br, 4); -+ case 2: -+ return br_bits(br, 16); -+ default: -+ return br_bits(br, 32); -+ } -+} -+ -+static void bw_write32le(uint8_t *dst, uint32_t value) -+{ -+ dst[0] = value & 0xFF; -+ dst[1] = (value >> 8) & 0xFF; -+ dst[2] = (value >> 16) & 0xFF; -+ dst[3] = (value >> 24) & 0xFF; -+} -+ -+static void rar_delete_program(struct RARProgramCode *prog) -+{ -+ while (prog) { -+ struct RARProgramCode *next = prog->next; -+ RARDeleteProgram(prog->prog); -+ free(prog->staticdata); -+ free(prog->globalbackup); -+ free(prog); -+ prog = next; -+ } -+} -+ -+static bool rar_parse_operand(struct MemBitReader *br, uint8_t instruction, bool bytemode, uint32_t instrcount, uint8_t *addressmode, uint32_t *value) -+{ -+ if (br_bits(br, 1)) { -+ *addressmode = RARRegisterAddressingMode((uint8_t)br_bits(br, 3)); -+ *value = 0; -+ } -+ else if (br_bits(br, 1)) { -+ if (br_bits(br, 1)) { -+ if (br_bits(br, 1)) -+ *addressmode = RARAbsoluteAddressingMode; -+ else -+ *addressmode = RARIndexedAbsoluteAddressingMode((uint8_t)br_bits(br, 3)); -+ *value = br_next_rarvm_number(br); -+ } -+ else { -+ *addressmode = RARRegisterIndirectAddressingMode((uint8_t)br_bits(br, 3)); -+ *value = 0; -+ } -+ } -+ else { -+ *addressmode = RARImmediateAddressingMode; -+ if (!bytemode) -+ *value = br_next_rarvm_number(br); -+ else -+ *value = br_bits(br, 8); -+ if (instrcount != (uint32_t)-1 && RARInstructionIsRelativeJump(instruction)) { -+ if (*value >= 256) /* absolute address */ -+ *value -= 256; -+ else { /* relative address */ -+ if (*value >= 136) -+ *value -= 264; -+ else if (*value >= 16) -+ *value -= 8; -+ else if (*value >= 8) -+ *value -= 16; -+ *value += instrcount; -+ } -+ } -+ } -+ return !br->at_eof; -+} -+ -+static struct RARProgramCode *rar_compile_program(const uint8_t *bytes, size_t length) -+{ -+ struct MemBitReader br = { 0 }; -+ struct RARProgramCode *prog; -+ uint32_t instrcount = 0; -+ uint8_t xor; -+ size_t i; -+ -+ xor = 0; -+ for (i = 1; i < length; i++) -+ xor ^= bytes[i]; -+ if (!length || xor != bytes[0]) -+ return NULL; -+ -+ br.bytes = bytes; -+ br.length = length; -+ br.offset = 1; -+ -+ prog = calloc(1, sizeof(*prog)); -+ if (!prog) -+ return NULL; -+ prog->prog = RARCreateProgram(); -+ if (!prog->prog) { -+ rar_delete_program(prog); -+ return NULL; -+ } -+ prog->fingerprint = ar_crc32(0, bytes, length) | ((uint64_t)length << 32); -+ -+ if (br_bits(&br, 1)) { -+ prog->staticdatalen = br_next_rarvm_number(&br) + 1; -+ prog->staticdata = malloc(prog->staticdatalen); -+ if (!prog->staticdata) { -+ rar_delete_program(prog); -+ return NULL; -+ } -+ for (i = 0; i < prog->staticdatalen; i++) -+ prog->staticdata[i] = (uint8_t)br_bits(&br, 8); -+ } -+ -+ while (br_available(&br, 8)) { -+ bool ok = true; -+ uint8_t instruction = (uint8_t)br_bits(&br, 4); -+ bool bytemode = false; -+ int numargs = 0; -+ uint8_t addrmode1 = 0, addrmode2 = 0; -+ uint32_t value1 = 0, value2 = 0; -+ -+ if ((instruction & 0x08)) -+ instruction = ((instruction << 2) | (uint8_t)br_bits(&br, 2)) - 24; -+ if (RARInstructionHasByteMode(instruction)) -+ bytemode = br_bits(&br, 1) != 0; -+ ok = RARProgramAddInstr(prog->prog, instruction, bytemode); -+ numargs = NumberOfRARInstructionOperands(instruction); -+ if (ok && numargs >= 1) -+ ok = rar_parse_operand(&br, instruction, bytemode, instrcount, &addrmode1, &value1); -+ if (ok && numargs == 2) -+ ok = rar_parse_operand(&br, instruction, bytemode, (uint32_t)-1, &addrmode2, &value2); -+ if (ok) -+ ok = RARSetLastInstrOperands(prog->prog, addrmode1, value1, addrmode2, value2); -+ if (!ok) { -+ warn("Invalid RAR program instruction"); -+ rar_delete_program(prog); -+ return NULL; -+ } -+ instrcount++; -+ } -+ -+ if (!RARIsProgramTerminated(prog->prog)) { -+ if (!RARProgramAddInstr(prog->prog, RARRetInstruction, false)) { -+ rar_delete_program(prog); -+ return NULL; -+ } -+ } -+ -+ return prog; -+} -+ -+static bool rar_execute_filter_prog(struct RARFilter *filter, RARVirtualMachine *vm) -+{ -+ uint32_t newgloballength; -+ uint32_t globallength = filter->globaldatalen; -+ if (globallength > RARProgramSystemGlobalSize) -+ globallength = RARProgramSystemGlobalSize; -+ memcpy(&vm->memory[RARProgramSystemGlobalAddress], filter->globaldata, globallength); -+ if (filter->prog->staticdata) { -+ uint32_t staticlength = filter->prog->staticdatalen; -+ if (staticlength > RARProgramUserGlobalSize - globallength) -+ staticlength = RARProgramUserGlobalSize - globallength; -+ memcpy(&vm->memory[RARProgramUserGlobalAddress], filter->prog->staticdata, staticlength); -+ } -+ RARSetVirtualMachineRegisters(vm, filter->initialregisters); -+ -+ if (!RARExecuteProgram(vm, filter->prog->prog)) { -+ warn("Error while executing program in RAR VM"); -+ return false; -+ } -+ -+ newgloballength = RARVirtualMachineRead32(vm, RARProgramSystemGlobalAddress + 0x30); -+ if (newgloballength > RARProgramUserGlobalSize) -+ newgloballength = RARProgramUserGlobalSize; -+ if (newgloballength > 0) { -+ uint32_t newglobaldatalength = RARProgramSystemGlobalSize + newgloballength; -+ if (newglobaldatalength > filter->globaldatalen) { -+ uint8_t *newglobaldata = malloc(newglobaldatalength); -+ if (!newglobaldata) -+ return false; -+ free(filter->globaldata); -+ filter->globaldata = newglobaldata; -+ } -+ filter->globaldatalen = newglobaldatalength; -+ memcpy(filter->globaldata, &vm->memory[RARProgramSystemGlobalAddress], filter->globaldatalen); -+ } -+ else -+ filter->globaldatalen = 0; -+ -+ return true; -+} -+ -+static struct RARFilter *rar_create_filter(struct RARProgramCode *prog, const uint8_t *globaldata, uint32_t globaldatalen, uint32_t registers[8], size_t startpos, uint32_t length) -+{ -+ struct RARFilter *filter; -+ -+ filter = calloc(1, sizeof(*filter)); -+ if (!filter) -+ return NULL; -+ filter->prog = prog; -+ filter->globaldatalen = globaldatalen > RARProgramSystemGlobalSize ? globaldatalen : RARProgramSystemGlobalSize; -+ filter->globaldata = calloc(1, filter->globaldatalen); -+ if (!filter->globaldata) -+ return NULL; -+ if (globaldata) -+ memcpy(filter->globaldata, globaldata, globaldatalen); -+ if (registers) -+ memcpy(filter->initialregisters, registers, sizeof(filter->initialregisters)); -+ filter->blockstartpos = startpos; -+ filter->blocklength = length; -+ -+ return filter; -+} -+ -+static void rar_delete_filter(struct RARFilter *filter) -+{ -+ while (filter) { -+ struct RARFilter *next = filter->next; -+ free(filter->globaldata); -+ free(filter); -+ filter = next; -+ } -+} -+ -+static bool rar_execute_filter_delta(struct RARFilter *filter, RARVirtualMachine *vm) -+{ -+ uint32_t length = filter->initialregisters[4]; -+ uint32_t numchannels = filter->initialregisters[0]; -+ uint8_t *src, *dst; -+ uint32_t i, idx; -+ -+ if (length > RARProgramWorkSize / 2) -+ return false; -+ -+ src = &vm->memory[0]; -+ dst = &vm->memory[length]; -+ for (i = 0; i < numchannels; i++) { -+ uint8_t lastbyte = 0; -+ for (idx = i; idx < length; idx += numchannels) -+ lastbyte = dst[idx] = lastbyte - *src++; -+ } -+ -+ filter->filteredblockaddress = length; -+ filter->filteredblocklength = length; -+ -+ return true; -+} -+ -+static bool rar_execute_filter_e8(struct RARFilter *filter, RARVirtualMachine *vm, size_t pos, bool e9also) -+{ -+ uint32_t length = filter->initialregisters[4]; -+ uint32_t filesize = 0x1000000; -+ uint32_t i; -+ -+ if (length > RARProgramWorkSize || length < 4) -+ return false; -+ -+ for (i = 0; i <= length - 5; i++) { -+ if (vm->memory[i] == 0xE8 || (e9also && vm->memory[i] == 0xE9)) { -+ uint32_t currpos = (uint32_t)pos + i + 1; -+ int32_t address = (int32_t)RARVirtualMachineRead32(vm, i + 1); -+ if (address < 0 && currpos >= (uint32_t)-address) -+ RARVirtualMachineWrite32(vm, i + 1, address + filesize); -+ else if (address >= 0 && (uint32_t)address < filesize) -+ RARVirtualMachineWrite32(vm, i + 1, address - currpos); -+ i += 4; -+ } -+ } -+ -+ filter->filteredblockaddress = 0; -+ filter->filteredblocklength = length; -+ -+ return true; -+} -+ -+static bool rar_execute_filter_rgb(struct RARFilter *filter, RARVirtualMachine *vm) -+{ -+ uint32_t stride = filter->initialregisters[0]; -+ uint32_t byteoffset = filter->initialregisters[1]; -+ uint32_t blocklength = filter->initialregisters[4]; -+ uint8_t *src, *dst; -+ uint32_t i, j; -+ -+ if (blocklength > RARProgramWorkSize / 2 || stride > blocklength) -+ return false; -+ -+ src = &vm->memory[0]; -+ dst = &vm->memory[blocklength]; -+ for (i = 0; i < 3; i++) { -+ uint8_t byte = 0; -+ uint8_t *prev = dst + i - stride; -+ for (j = i; j < blocklength; j += 3) { -+ if (prev >= dst) { -+ uint32_t delta1 = abs(prev[3] - prev[0]); -+ uint32_t delta2 = abs(byte - prev[0]); -+ uint32_t delta3 = abs(prev[3] - prev[0] + byte - prev[0]); -+ if (delta1 > delta2 || delta1 > delta3) -+ byte = delta2 <= delta3 ? prev[3] : prev[0]; -+ } -+ byte -= *src++; -+ dst[j] = byte; -+ prev += 3; -+ } -+ } -+ for (i = byteoffset; i < blocklength - 2; i += 3) { -+ dst[i] += dst[i + 1]; -+ dst[i + 2] += dst[i + 1]; -+ } -+ -+ filter->filteredblockaddress = blocklength; -+ filter->filteredblocklength = blocklength; -+ -+ return true; -+} -+ -+static bool rar_execute_filter_audio(struct RARFilter *filter, RARVirtualMachine *vm) -+{ -+ uint32_t length = filter->initialregisters[4]; -+ uint32_t numchannels = filter->initialregisters[0]; -+ uint8_t *src, *dst; -+ uint32_t i, j; -+ -+ if (length > RARProgramWorkSize / 2) -+ return false; -+ -+ src = &vm->memory[0]; -+ dst = &vm->memory[length]; -+ for (i = 0; i < numchannels; i++) { -+ struct AudioState state; -+ memset(&state, 0, sizeof(state)); -+ for (j = i; j < length; j += numchannels) { -+ int8_t delta = (int8_t)*src++; -+ uint8_t predbyte, byte; -+ int prederror; -+ state.delta[2] = state.delta[1]; -+ state.delta[1] = state.lastdelta - state.delta[0]; -+ state.delta[0] = state.lastdelta; -+ predbyte = ((8 * state.lastbyte + state.weight[0] * state.delta[0] + state.weight[1] * state.delta[1] + state.weight[2] * state.delta[2]) >> 3) & 0xFF; -+ byte = (predbyte - delta) & 0xFF; -+ prederror = delta << 3; -+ state.error[0] += abs(prederror); -+ state.error[1] += abs(prederror - state.delta[0]); state.error[2] += abs(prederror + state.delta[0]); -+ state.error[3] += abs(prederror - state.delta[1]); state.error[4] += abs(prederror + state.delta[1]); -+ state.error[5] += abs(prederror - state.delta[2]); state.error[6] += abs(prederror + state.delta[2]); -+ state.lastdelta = (int8_t)(byte - state.lastbyte); -+ dst[j] = state.lastbyte = byte; -+ if (!(state.count++ & 0x1F)) { -+ uint8_t k, idx = 0; -+ for (k = 1; k < 7; k++) { -+ if (state.error[k] < state.error[idx]) -+ idx = k; -+ } -+ memset(state.error, 0, sizeof(state.error)); -+ switch (idx) { -+ case 1: if (state.weight[0] >= -16) state.weight[0]--; break; -+ case 2: if (state.weight[0] < 16) state.weight[0]++; break; -+ case 3: if (state.weight[1] >= -16) state.weight[1]--; break; -+ case 4: if (state.weight[1] < 16) state.weight[1]++; break; -+ case 5: if (state.weight[2] >= -16) state.weight[2]--; break; -+ case 6: if (state.weight[2] < 16) state.weight[2]++; break; -+ } -+ } -+ } -+ } -+ -+ filter->filteredblockaddress = length; -+ filter->filteredblocklength = length; -+ -+ return true; -+} -+ -+static bool rar_execute_filter(struct RARFilter *filter, RARVirtualMachine *vm, size_t pos) -+{ -+ if (filter->prog->fingerprint == 0x1D0E06077D) -+ return rar_execute_filter_delta(filter, vm); -+ if (filter->prog->fingerprint == 0x35AD576887) -+ return rar_execute_filter_e8(filter, vm, pos, false); -+ if (filter->prog->fingerprint == 0x393CD7E57E) -+ return rar_execute_filter_e8(filter, vm, pos, true); -+ if (filter->prog->fingerprint == 0x951C2C5DC8) -+ return rar_execute_filter_rgb(filter, vm); -+ if (filter->prog->fingerprint == 0xD8BC85E701) -+ return rar_execute_filter_audio(filter, vm); -+ log("Unknown parsing filter 0x%x%08x", (uint32_t)(filter->prog->fingerprint >> 32), (uint32_t)filter->prog->fingerprint); -+ -+ /* XADRAR30Filter.m @executeOnVirtualMachine claims that this is required */ -+ if (filter->prog->globalbackuplen > RARProgramSystemGlobalSize) { -+ uint8_t *newglobaldata = malloc(filter->prog->globalbackuplen); -+ if (newglobaldata) { -+ free(filter->globaldata); -+ filter->globaldata = newglobaldata; -+ filter->globaldatalen = filter->prog->globalbackuplen; -+ memcpy(filter->globaldata, filter->prog->globalbackup, filter->prog->globalbackuplen); -+ } -+ } -+ -+ filter->initialregisters[6] = (uint32_t)pos; -+ bw_write32le(&filter->globaldata[0x24], (uint32_t)pos); -+ bw_write32le(&filter->globaldata[0x28], (uint32_t)((uint64_t)pos >> 32)); -+ -+ if (!rar_execute_filter_prog(filter, vm)) -+ return false; -+ -+ filter->filteredblockaddress = RARVirtualMachineRead32(vm, RARProgramSystemGlobalAddress + 0x20) & RARProgramMemoryMask; -+ filter->filteredblocklength = RARVirtualMachineRead32(vm, RARProgramSystemGlobalAddress + 0x1C) & RARProgramMemoryMask; -+ if (filter->filteredblockaddress + filter->filteredblocklength >= RARProgramMemorySize) { -+ filter->filteredblockaddress = filter->filteredblocklength = 0; -+ return false; -+ } -+ -+ if (filter->globaldatalen > RARProgramSystemGlobalSize) { -+ uint8_t *newglobalbackup = malloc(filter->globaldatalen); -+ if (newglobalbackup) { -+ free(filter->prog->globalbackup); -+ filter->prog->globalbackup = newglobalbackup; -+ filter->prog->globalbackuplen = filter->globaldatalen; -+ memcpy(filter->prog->globalbackup, filter->globaldata, filter->globaldatalen); -+ } -+ } -+ else -+ filter->prog->globalbackuplen = 0; -+ -+ return true; -+} -+ -+bool rar_parse_filter(ar_archive_rar *rar, const uint8_t *bytes, uint16_t length, uint8_t flags) -+{ -+ struct ar_archive_rar_uncomp_v3 *uncomp = &rar->uncomp.state.v3; -+ struct ar_archive_rar_filters *filters = &uncomp->filters; -+ -+ struct MemBitReader br = { 0 }; -+ struct RARProgramCode *prog; -+ struct RARFilter *filter, **nextfilter; -+ -+ uint32_t numprogs, num, blocklength, globaldatalen; -+ uint8_t *globaldata; -+ size_t blockstartpos; -+ uint32_t registers[8] = { 0 }; -+ uint32_t i; -+ -+ br.bytes = bytes; -+ br.length = length; -+ -+ numprogs = 0; -+ for (prog = filters->progs; prog; prog = prog->next) -+ numprogs++; -+ -+ if ((flags & 0x80)) { -+ num = br_next_rarvm_number(&br); -+ if (num == 0) { -+ rar_delete_filter(filters->stack); -+ filters->stack = NULL; -+ rar_delete_program(filters->progs); -+ filters->progs = NULL; -+ } -+ else -+ num--; -+ if (num > numprogs) { -+ warn("Invalid program number"); -+ return false; -+ } -+ filters->lastfilternum = num; -+ } -+ else -+ num = filters->lastfilternum; -+ -+ prog = filters->progs; -+ for (i = 0; i < num; i++) -+ prog = prog->next; -+ if (prog) -+ prog->usagecount++; -+ -+ blockstartpos = br_next_rarvm_number(&br) + (size_t)lzss_position(&rar->uncomp.lzss); -+ if ((flags & 0x40)) -+ blockstartpos += 258; -+ if ((flags & 0x20)) -+ blocklength = br_next_rarvm_number(&br); -+ else -+ blocklength = prog ? prog->oldfilterlength : 0; -+ -+ registers[3] = RARProgramSystemGlobalAddress; -+ registers[4] = blocklength; -+ registers[5] = prog ? prog->usagecount : 0; -+ registers[7] = RARProgramMemorySize; -+ -+ if ((flags & 0x10)) { -+ uint8_t mask = (uint8_t)br_bits(&br, 7); -+ for (i = 0; i < 7; i++) { -+ if ((mask & (1 << i))) -+ registers[i] = br_next_rarvm_number(&br); -+ } -+ } -+ -+ if (!prog) { -+ uint32_t len = br_next_rarvm_number(&br); -+ uint8_t *bytecode; -+ struct RARProgramCode **next; -+ -+ if (len == 0 || len > 0x10000) { -+ warn("Invalid RARVM bytecode length"); -+ return false; -+ } -+ bytecode = malloc(len); -+ if (!bytecode) -+ return false; -+ for (i = 0; i < len; i++) -+ bytecode[i] = (uint8_t)br_bits(&br, 8); -+ prog = rar_compile_program(bytecode, len); -+ if (!prog) { -+ free(bytecode); -+ return false; -+ } -+ free(bytecode); -+ next = &filters->progs; -+ while (*next) -+ next = &(*next)->next; -+ *next = prog; -+ } -+ prog->oldfilterlength = blocklength; -+ -+ globaldata = NULL; -+ globaldatalen = 0; -+ if ((flags & 0x08)) { -+ globaldatalen = br_next_rarvm_number(&br); -+ if (globaldatalen > RARProgramUserGlobalSize) { -+ warn("Invalid RARVM data length"); -+ return false; -+ } -+ globaldata = malloc(globaldatalen + RARProgramSystemGlobalSize); -+ if (!globaldata) -+ return false; -+ for (i = 0; i < globaldatalen; i++) -+ globaldata[i + RARProgramSystemGlobalSize] = (uint8_t)br_bits(&br, 8); -+ } -+ -+ if (br.at_eof) { -+ free(globaldata); -+ return false; -+ } -+ -+ filter = rar_create_filter(prog, globaldata, globaldatalen, registers, blockstartpos, blocklength); -+ free(globaldata); -+ if (!filter) -+ return false; -+ -+ for (i = 0; i < 7; i++) -+ bw_write32le(&filter->globaldata[i * 4], registers[i]); -+ bw_write32le(&filter->globaldata[0x1C], blocklength); -+ bw_write32le(&filter->globaldata[0x20], 0); -+ bw_write32le(&filter->globaldata[0x2C], prog->usagecount); -+ -+ nextfilter = &filters->stack; -+ while (*nextfilter) -+ nextfilter = &(*nextfilter)->next; -+ *nextfilter = filter; -+ -+ if (!filters->stack->next) -+ filters->filterstart = blockstartpos; -+ -+ return true; -+} -+ -+bool rar_run_filters(ar_archive_rar *rar) -+{ -+ struct ar_archive_rar_filters *filters = &rar->uncomp.state.v3.filters; -+ struct RARFilter *filter = filters->stack; -+ size_t start = filters->filterstart; -+ size_t end = start + filter->blocklength; -+ uint32_t lastfilteraddress; -+ uint32_t lastfilterlength; -+ -+ filters->filterstart = SIZE_MAX; -+ end = (size_t)rar_expand(rar, end); -+ if (end != start + filter->blocklength) { -+ warn("Failed to expand the expected amout of bytes"); -+ return false; -+ } -+ -+ if (!filters->vm) { -+ filters->vm = calloc(1, sizeof(*filters->vm)); -+ if (!filters->vm) -+ return false; -+ } -+ -+ lzss_copy_bytes_from_window(&rar->uncomp.lzss, filters->vm->memory, start, filter->blocklength); -+ if (!rar_execute_filter(filter, filters->vm, rar->progress.bytes_done)) { -+ warn("Failed to execute parsing filter"); -+ return false; -+ } -+ -+ lastfilteraddress = filter->filteredblockaddress; -+ lastfilterlength = filter->filteredblocklength; -+ filters->stack = filter->next; -+ filter->next = NULL; -+ rar_delete_filter(filter); -+ -+ while ((filter = filters->stack) != NULL && filter->blockstartpos == filters->filterstart && filter->blocklength == lastfilterlength) { -+ memmove(&filters->vm->memory[0], &filters->vm->memory[lastfilteraddress], lastfilterlength); -+ if (!rar_execute_filter(filter, filters->vm, rar->progress.bytes_done)) { -+ warn("Failed to execute parsing filter"); -+ return false; -+ } -+ -+ lastfilteraddress = filter->filteredblockaddress; -+ lastfilterlength = filter->filteredblocklength; -+ filters->stack = filter->next; -+ filter->next = NULL; -+ rar_delete_filter(filter); -+ } -+ -+ if (filters->stack) { -+ if (filters->stack->blockstartpos < end) { -+ warn("Bad filter order"); -+ return false; -+ } -+ filters->filterstart = filters->stack->blockstartpos; -+ } -+ -+ filters->lastend = end; -+ filters->bytes = &filters->vm->memory[lastfilteraddress]; -+ filters->bytes_ready = lastfilterlength; -+ -+ return true; -+} -+ -+void rar_clear_filters(struct ar_archive_rar_filters *filters) -+{ -+ rar_delete_filter(filters->stack); -+ rar_delete_program(filters->progs); -+ free(filters->vm); -+} -diff --git a/cut-n-paste/unarr/rar/huffman-rar.c b/cut-n-paste/unarr/rar/huffman-rar.c -new file mode 100644 -index 00000000..c77eed93 ---- /dev/null -+++ b/cut-n-paste/unarr/rar/huffman-rar.c -@@ -0,0 +1,142 @@ -+/* Copyright 2015 the unarr project authors (see AUTHORS file). -+ License: LGPLv3 */ -+ -+/* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/XADPrefixCode.m */ -+ -+#include "rar.h" -+ -+bool rar_new_node(struct huffman_code *code) -+{ -+ if (!code->tree) { -+ code->minlength = INT_MAX; -+ code->maxlength = INT_MIN; -+ } -+ if (code->numentries + 1 >= code->capacity) { -+ /* in my small file sample, 1024 is the value needed most often */ -+ int new_capacity = code->capacity ? code->capacity * 2 : 1024; -+ void *new_tree = calloc(new_capacity, sizeof(*code->tree)); -+ if (!new_tree) { -+ warn("OOM during decompression"); -+ return false; -+ } -+ memcpy(new_tree, code->tree, code->capacity * sizeof(*code->tree)); -+ free(code->tree); -+ code->tree = new_tree; -+ code->capacity = new_capacity; -+ } -+ code->tree[code->numentries].branches[0] = -1; -+ code->tree[code->numentries].branches[1] = -2; -+ code->numentries++; -+ return true; -+} -+ -+bool rar_add_value(struct huffman_code *code, int value, int codebits, int length) -+{ -+ int lastnode, bitpos, bit; -+ -+ free(code->table); -+ code->table = NULL; -+ -+ if (length > code->maxlength) -+ code->maxlength = length; -+ if (length < code->minlength) -+ code->minlength = length; -+ -+ lastnode = 0; -+ for (bitpos = length - 1; bitpos >= 0; bitpos--) { -+ bit = (codebits >> bitpos) & 1; -+ if (rar_is_leaf_node(code, lastnode)) { -+ warn("Invalid data in bitstream"); /* prefix found */ -+ return false; -+ } -+ if (code->tree[lastnode].branches[bit] < 0) { -+ if (!rar_new_node(code)) -+ return false; -+ code->tree[lastnode].branches[bit] = code->numentries - 1; -+ } -+ lastnode = code->tree[lastnode].branches[bit]; -+ } -+ -+ if (code->tree[lastnode].branches[0] != -1 || code->tree[lastnode].branches[1] != -2) { -+ warn("Invalid data in bitstream"); /* prefix found */ -+ return false; -+ } -+ code->tree[lastnode].branches[0] = code->tree[lastnode].branches[1] = value; -+ return true; -+} -+ -+bool rar_create_code(struct huffman_code *code, uint8_t *lengths, int numsymbols) -+{ -+ int symbolsleft = numsymbols; -+ int codebits = 0; -+ int i, j; -+ -+ if (!rar_new_node(code)) -+ return false; -+ -+ for (i = 1; i <= 0x0F; i++) { -+ for (j = 0; j < numsymbols; j++) { -+ if (lengths[j] != i) -+ continue; -+ if (!rar_add_value(code, j, codebits, i)) -+ return false; -+ if (--symbolsleft <= 0) -+ return true; -+ codebits++; -+ } -+ codebits <<= 1; -+ } -+ return true; -+} -+ -+static bool rar_make_table_rec(struct huffman_code *code, int node, int offset, int depth, int maxdepth) -+{ -+ int currtablesize = 1 << (maxdepth - depth); -+ -+ if (node < 0 || code->numentries <= node) { -+ warn("Invalid data in bitstream"); /* invalid location to Huffman tree specified */ -+ return false; -+ } -+ -+ if (rar_is_leaf_node(code, node)) { -+ int i; -+ for (i = 0; i < currtablesize; i++) { -+ code->table[offset + i].length = depth; -+ code->table[offset + i].value = code->tree[node].branches[0]; -+ } -+ } -+ else if (depth == maxdepth) { -+ code->table[offset].length = maxdepth + 1; -+ code->table[offset].value = node; -+ } -+ else { -+ if (!rar_make_table_rec(code, code->tree[node].branches[0], offset, depth + 1, maxdepth)) -+ return false; -+ if (!rar_make_table_rec(code, code->tree[node].branches[1], offset + currtablesize / 2, depth + 1, maxdepth)) -+ return false; -+ } -+ return true; -+} -+ -+bool rar_make_table(struct huffman_code *code) -+{ -+ if (code->minlength <= code->maxlength && code->maxlength <= 10) -+ code->tablesize = code->maxlength; -+ else -+ code->tablesize = 10; -+ -+ code->table = calloc(1ULL << code->tablesize, sizeof(*code->table)); -+ if (!code->table) { -+ warn("OOM during decompression"); -+ return false; -+ } -+ -+ return rar_make_table_rec(code, 0, 0, 0, code->tablesize); -+} -+ -+void rar_free_code(struct huffman_code *code) -+{ -+ free(code->tree); -+ free(code->table); -+ memset(code, 0, sizeof(*code)); -+} -diff --git a/cut-n-paste/unarr/rar/lzss.h b/cut-n-paste/unarr/rar/lzss.h -new file mode 100644 -index 00000000..580fe4c5 ---- /dev/null -+++ b/cut-n-paste/unarr/rar/lzss.h -@@ -0,0 +1,88 @@ -+/* Copyright 2015 the unarr project authors (see AUTHORS file). -+ License: LGPLv3 */ -+ -+/* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/LZSS.h */ -+ -+#ifndef rar_lzss_h -+#define rar_lzss_h -+ -+#include -+#include -+#include -+#include -+ -+#if defined(_MSC_VER) && !defined(inline) -+#define inline __inline -+#endif -+ -+typedef struct { -+ uint8_t *window; -+ int mask; -+ int64_t position; -+} LZSS; -+ -+static inline int64_t lzss_position(LZSS *self) { return self->position; } -+ -+static inline int lzss_mask(LZSS *self) { return self->mask; } -+ -+static inline int lzss_size(LZSS *self) { return self->mask + 1; } -+ -+static inline uint8_t *lzss_window_pointer(LZSS *self) { return self->window; } -+ -+static inline int lzss_offset_for_position(LZSS *self, int64_t pos) { return (int)(pos & self->mask); } -+ -+static inline uint8_t *lzss_window_pointer_for_position(LZSS *self, int64_t pos) { return &self->window[lzss_offset_for_position(self, pos)]; } -+ -+static inline int lzss_current_window_offset(LZSS *self) { return lzss_offset_for_position(self, self->position); } -+ -+static inline uint8_t *lzss_current_window_pointer(LZSS *self) { return lzss_window_pointer_for_position(self, self->position); } -+ -+static inline int64_t lzss_next_window_edge_after_position(LZSS *self, int64_t pos) { return (pos + lzss_size(self)) & ~(int64_t)lzss_mask(self); } -+ -+static inline int64_t lzss_next_window_edge(LZSS *self) { return lzss_next_window_edge_after_position(self, self->position); } -+ -+static inline uint8_t lzss_get_byte_from_window(LZSS *self, int64_t pos) { return *lzss_window_pointer_for_position(self, pos); } -+ -+static inline void lzss_emit_literal(LZSS *self, uint8_t literal) { -+ /* self->window[(self->position & self->mask)] = literal; */ -+ *lzss_current_window_pointer(self) = literal; -+ self->position++; -+} -+ -+static inline void lzss_emit_match(LZSS *self, int offset, int length) { -+ int windowoffs = lzss_current_window_offset(self); -+ int i; -+ for (i = 0; i < length; i++) { -+ self->window[(windowoffs + i) & lzss_mask(self)] = self->window[(windowoffs + i - offset) & lzss_mask(self)]; -+ } -+ self->position += length; -+} -+ -+static inline void lzss_copy_bytes_from_window(LZSS *self, uint8_t *buffer, int64_t startpos, int length) { -+ int windowoffs = lzss_offset_for_position(self, startpos); -+ int firstpart = lzss_size(self) - windowoffs; -+ if (length <= firstpart) { -+ /* Request fits inside window */ -+ memcpy(buffer, &self->window[windowoffs], length); -+ } -+ else { -+ /* Request wraps around window */ -+ memcpy(buffer, &self->window[windowoffs], firstpart); -+ memcpy(buffer + firstpart, &self->window[0], length - firstpart); -+ } -+} -+ -+static inline bool lzss_initialize(LZSS *self, int windowsize) { -+ self->window = malloc(windowsize); -+ if (!self->window) -+ return false; -+ -+ self->mask = windowsize - 1; /* Assume windows are power-of-two sized! */ -+ memset(self->window, 0, lzss_size(self)); -+ self->position = 0; -+ return true; -+} -+ -+static inline void lzss_cleanup(LZSS *self) { free(self->window); } -+ -+#endif -diff --git a/cut-n-paste/unarr/rar/parse-rar.c b/cut-n-paste/unarr/rar/parse-rar.c -new file mode 100644 -index 00000000..f41534c6 ---- /dev/null -+++ b/cut-n-paste/unarr/rar/parse-rar.c -@@ -0,0 +1,236 @@ -+/* Copyright 2015 the unarr project authors (see AUTHORS file). -+ License: LGPLv3 */ -+ -+/* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/XADRARParser.m */ -+ -+#include "rar.h" -+ -+static inline uint8_t uint8le(unsigned char *data) { return data[0]; } -+static inline uint16_t uint16le(unsigned char *data) { return data[0] | data[1] << 8; } -+static inline uint32_t uint32le(unsigned char *data) { return data[0] | data[1] << 8 | data[2] << 16 | data[3] << 24; } -+ -+bool rar_parse_header(ar_archive *ar, struct rar_header *header) -+{ -+ unsigned char header_data[7]; -+ size_t read = ar_read(ar->stream, header_data, sizeof(header_data)); -+ if (read == 0) { -+ ar->at_eof = true; -+ return false; -+ } -+ if (read < sizeof(header_data)) -+ return false; -+ -+ header->crc = uint16le(header_data + 0); -+ header->type = uint8le(header_data + 2); -+ header->flags = uint16le(header_data + 3); -+ header->size = uint16le(header_data + 5); -+ -+ header->datasize = 0; -+ if ((header->flags & LHD_LONG_BLOCK) || header->type == 0x74) { -+ unsigned char size_data[4]; -+ if (!(header->flags & LHD_LONG_BLOCK)) -+ log("File header without LHD_LONG_BLOCK set"); -+ read += ar_read(ar->stream, size_data, sizeof(size_data)); -+ if (read < sizeof(header_data) + sizeof(size_data)) -+ return false; -+ header->datasize = uint32le(size_data); -+ } -+ -+ if (header->size < read) { -+ warn("Invalid header size %d", header->size); -+ return false; -+ } -+ -+ return true; -+} -+ -+bool rar_check_header_crc(ar_archive *ar) -+{ -+ unsigned char buffer[256]; -+ uint16_t crc16, size; -+ uint32_t crc32; -+ -+ if (!ar_seek(ar->stream, ar->entry_offset, SEEK_SET)) -+ return false; -+ if (ar_read(ar->stream, buffer, 7) != 7) -+ return false; -+ -+ crc16 = uint16le(buffer + 0); -+ size = uint16le(buffer + 5); -+ if (size < 7) -+ return false; -+ size -= 7; -+ -+ crc32 = ar_crc32(0, buffer + 2, 5); -+ while (size > 0) { -+ if (ar_read(ar->stream, buffer, smin(size, sizeof(buffer))) != smin(size, sizeof(buffer))) -+ return false; -+ crc32 = ar_crc32(crc32, buffer, smin(size, sizeof(buffer))); -+ size -= (uint16_t)smin(size, sizeof(buffer)); -+ } -+ return (crc32 & 0xFFFF) == crc16; -+} -+ -+bool rar_parse_header_entry(ar_archive_rar *rar, struct rar_header *header, struct rar_entry *entry) -+{ -+ unsigned char data[21]; -+ if (ar_read(rar->super.stream, data, sizeof(data)) != sizeof(data)) -+ return false; -+ -+ entry->size = uint32le(data + 0); -+ entry->os = uint8le(data + 4); -+ entry->crc = uint32le(data + 5); -+ entry->dosdate = uint32le(data + 9); -+ entry->version = uint8le(data + 13); -+ entry->method = uint8le(data + 14); -+ entry->namelen = uint16le(data + 15); -+ entry->attrs = uint32le(data + 17); -+ if ((header->flags & LHD_LARGE)) { -+ unsigned char more_data[8]; -+ if (ar_read(rar->super.stream, more_data, sizeof(more_data)) != sizeof(more_data)) -+ return false; -+ header->datasize += (uint64_t)uint32le(more_data + 0); -+ entry->size += (uint64_t)uint32le(more_data + 4); -+ } -+ if (!ar_skip(rar->super.stream, entry->namelen)) -+ return false; -+ if ((header->flags & LHD_SALT)) { -+ log("Skipping LHD_SALT"); -+ ar_skip(rar->super.stream, 8); -+ } -+ -+ rar->entry.version = entry->version; -+ rar->entry.method = entry->method; -+ rar->entry.crc = entry->crc; -+ rar->entry.header_size = header->size; -+ rar->entry.solid = entry->version < 20 ? (rar->archive_flags & MHD_SOLID) : (header->flags & LHD_SOLID); -+ free(rar->entry.name); -+ rar->entry.name = NULL; -+ -+ return true; -+} -+ -+/* this seems to be what RAR considers "Unicode" */ -+static char *rar_conv_unicode_to_utf8(const char *data, uint16_t len) -+{ -+#define Check(cond) if (!(cond)) { free(str); return NULL; } else ((void)0) -+ -+ uint8_t highbyte, flagbyte, flagbits, size, length, i; -+ const uint8_t *in = (uint8_t *)data + strlen(data) + 1; -+ const uint8_t *end_in = (uint8_t *)data + len; -+ char *str = calloc(len + 1, 3); -+ char *out = str; -+ char *end_out = str + len * 3; -+ -+ if (!str) -+ return NULL; -+ if (end_in - in <= 1) { -+ memcpy(str, data, len); -+ return str; -+ } -+ -+ highbyte = *in++; -+ flagbyte = 0; -+ flagbits = 0; -+ size = 0; -+ -+ while (in < end_in && out < end_out) { -+ if (flagbits == 0) { -+ flagbyte = *in++; -+ flagbits = 8; -+ } -+ flagbits -= 2; -+ switch ((flagbyte >> flagbits) & 3) { -+ case 0: -+ Check(in + 1 <= end_in); -+ out += ar_conv_rune_to_utf8(*in++, out, end_out - out); -+ size++; -+ break; -+ case 1: -+ Check(in + 1 <= end_in); -+ out += ar_conv_rune_to_utf8(((uint16_t)highbyte << 8) | *in++, out, end_out - out); -+ size++; -+ break; -+ case 2: -+ Check(in + 2 <= end_in); -+ out += ar_conv_rune_to_utf8(((uint16_t)*(in + 1) << 8) | *in, out, end_out - out); -+ in += 2; -+ size++; -+ break; -+ case 3: -+ Check(in + 1 <= end_in); -+ length = *in++; -+ if ((length & 0x80)) { -+ uint8_t correction = *in++; -+ for (i = 0; i < (length & 0x7F) + 2; i++) { -+ Check(size < len); -+ out += ar_conv_rune_to_utf8(((uint16_t)highbyte << 8) | (data[size] + (correction & 0xFF)), out, end_out - out); -+ size++; -+ } -+ } -+ else { -+ for (i = 0; i < (length & 0x7F) + 2; i++) { -+ Check(size < len); -+ out += ar_conv_rune_to_utf8(data[size], out, end_out - out); -+ size++; -+ } -+ } -+ break; -+ } -+ } -+ -+ return str; -+ -+#undef Check -+} -+ -+const char *rar_get_name(ar_archive *ar) -+{ -+ ar_archive_rar *rar = (ar_archive_rar *)ar; -+ if (!rar->entry.name) { -+ unsigned char data[21]; -+ uint16_t namelen; -+ char *name; -+ -+ struct rar_header header; -+ if (!ar_seek(ar->stream, ar->entry_offset, SEEK_SET)) -+ return NULL; -+ if (!rar_parse_header(ar, &header)) -+ return NULL; -+ if (ar_read(ar->stream, data, sizeof(data)) != sizeof(data)) -+ return NULL; -+ if ((header.flags & LHD_LARGE) && !ar_skip(ar->stream, 8)) -+ return NULL; -+ -+ namelen = uint16le(data + 15); -+ name = malloc(namelen + 1); -+ if (!name || ar_read(ar->stream, name, namelen) != namelen) { -+ free(name); -+ return NULL; -+ } -+ name[namelen] = '\0'; -+ -+ if (!(header.flags & LHD_UNICODE)) { -+ rar->entry.name = ar_conv_dos_to_utf8(name); -+ free(name); -+ } -+ else if (namelen == strlen(name)) { -+ rar->entry.name = name; -+ } -+ else { -+ rar->entry.name = rar_conv_unicode_to_utf8(name, namelen); -+ free(name); -+ } -+ /* normalize path separators */ -+ if (rar->entry.name) { -+ char *p = rar->entry.name; -+ while ((p = strchr(p, '\\')) != NULL) { -+ *p = '/'; -+ } -+ } -+ -+ if (!ar_seek(ar->stream, ar->entry_offset + rar->entry.header_size, SEEK_SET)) -+ warn("Couldn't seek back to the end of the entry header"); -+ } -+ return rar->entry.name; -+} -diff --git a/cut-n-paste/unarr/rar/rar.c b/cut-n-paste/unarr/rar/rar.c -new file mode 100644 -index 00000000..40cafcfc ---- /dev/null -+++ b/cut-n-paste/unarr/rar/rar.c -@@ -0,0 +1,223 @@ -+/* Copyright 2015 the unarr project authors (see AUTHORS file). -+ License: LGPLv3 */ -+ -+#include "rar.h" -+ -+static void rar_close(ar_archive *ar) -+{ -+ ar_archive_rar *rar = (ar_archive_rar *)ar; -+ free(rar->entry.name); -+ rar_clear_uncompress(&rar->uncomp); -+} -+ -+static bool rar_parse_entry(ar_archive *ar, off64_t offset) -+{ -+ ar_archive_rar *rar = (ar_archive_rar *)ar; -+ struct rar_header header; -+ struct rar_entry entry; -+ bool out_of_order = offset != ar->entry_offset_next; -+ -+ if (!ar_seek(ar->stream, offset, SEEK_SET)) { -+ warn("Couldn't seek to offset %" PRIi64, offset); -+ return false; -+ } -+ -+ for (;;) { -+ ar->entry_offset = ar_tell(ar->stream); -+ ar->entry_size_uncompressed = 0; -+ -+ if (!rar_parse_header(ar, &header)) -+ return false; -+ -+ ar->entry_offset_next = ar->entry_offset + header.size + header.datasize; -+ if (ar->entry_offset_next < ar->entry_offset + header.size) { -+ warn("Integer overflow due to overly large data size"); -+ return false; -+ } -+ -+ switch (header.type) { -+ case TYPE_MAIN_HEADER: -+ if ((header.flags & MHD_PASSWORD)) { -+ warn("Encrypted archives aren't supported"); -+ return false; -+ } -+ ar_skip(ar->stream, 6 /* reserved data */); -+ if ((header.flags & MHD_ENCRYPTVER)) { -+ log("MHD_ENCRYPTVER is set"); -+ ar_skip(ar->stream, 1); -+ } -+ if ((header.flags & MHD_COMMENT)) -+ log("MHD_COMMENT is set"); -+ if (ar_tell(ar->stream) - ar->entry_offset > header.size) { -+ warn("Invalid RAR header size: %d", header.size); -+ return false; -+ } -+ rar->archive_flags = header.flags; -+ break; -+ -+ case TYPE_FILE_ENTRY: -+ if (!rar_parse_header_entry(rar, &header, &entry)) -+ return false; -+ if ((header.flags & LHD_PASSWORD)) -+ warn("Encrypted entries will fail to uncompress"); -+ if ((header.flags & LHD_DIRECTORY) == LHD_DIRECTORY) { -+ if (header.datasize == 0) { -+ log("Skipping directory entry \"%s\"", rar_get_name(ar)); -+ break; -+ } -+ warn("Can't skip directory entries containing data"); -+ } -+ if ((header.flags & (LHD_SPLIT_BEFORE | LHD_SPLIT_AFTER))) -+ warn("Splitting files isn't really supported"); -+ ar->entry_size_uncompressed = (size_t)entry.size; -+ ar->entry_filetime = ar_conv_dosdate_to_filetime(entry.dosdate); -+ if (!rar->entry.solid || rar->entry.method == METHOD_STORE || out_of_order) { -+ rar_clear_uncompress(&rar->uncomp); -+ memset(&rar->solid, 0, sizeof(rar->solid)); -+ } -+ else { -+ br_clear_leftover_bits(&rar->uncomp); -+ } -+ -+ rar->solid.restart = rar->entry.solid && (out_of_order || !rar->solid.part_done); -+ rar->solid.part_done = !ar->entry_size_uncompressed; -+ rar->progress.data_left = (size_t)header.datasize; -+ rar->progress.bytes_done = 0; -+ rar->progress.crc = 0; -+ -+ /* TODO: CRC checks don't always hold (claim in XADRARParser.m @readBlockHeader) */ -+ if (!rar_check_header_crc(ar)) -+ warn("Invalid header checksum @%" PRIi64, ar->entry_offset); -+ if (ar_tell(ar->stream) != ar->entry_offset + rar->entry.header_size) { -+ warn("Couldn't seek to offset %" PRIi64, ar->entry_offset + rar->entry.header_size); -+ return false; -+ } -+ return true; -+ -+ case TYPE_NEWSUB: -+ log("Skipping newsub header @%" PRIi64, ar->entry_offset); -+ break; -+ -+ case TYPE_END_OF_ARCHIVE: -+ ar->at_eof = true; -+ return false; -+ -+ default: -+ log("Unknown RAR header type %02x", header.type); -+ break; -+ } -+ -+ /* TODO: CRC checks don't always hold (claim in XADRARParser.m @readBlockHeader) */ -+ if (!rar_check_header_crc(ar)) -+ warn("Invalid header checksum @%" PRIi64, ar->entry_offset); -+ if (!ar_seek(ar->stream, ar->entry_offset_next, SEEK_SET)) { -+ warn("Couldn't seek to offset %" PRIi64, ar->entry_offset_next); -+ return false; -+ } -+ } -+} -+ -+static bool rar_copy_stored(ar_archive_rar *rar, void *buffer, size_t count) -+{ -+ if (count > rar->progress.data_left) { -+ warn("Unexpected EOS in stored data"); -+ return false; -+ } -+ if (ar_read(rar->super.stream, buffer, count) != count) { -+ warn("Unexpected EOF in stored data"); -+ return false; -+ } -+ rar->progress.data_left -= count; -+ rar->progress.bytes_done += count; -+ return true; -+} -+ -+static bool rar_restart_solid(ar_archive *ar) -+{ -+ ar_archive_rar *rar = (ar_archive_rar *)ar; -+ off64_t current_offset = ar->entry_offset; -+ log("Restarting decompression for solid entry"); -+ if (!ar_parse_entry_at(ar, ar->entry_offset_first)) { -+ ar_parse_entry_at(ar, current_offset); -+ return false; -+ } -+ while (ar->entry_offset < current_offset) { -+ size_t size = ar->entry_size_uncompressed; -+ rar->solid.restart = false; -+ while (size > 0) { -+ unsigned char buffer[1024]; -+ size_t count = smin(size, sizeof(buffer)); -+ if (!ar_entry_uncompress(ar, buffer, count)) { -+ ar_parse_entry_at(ar, current_offset); -+ return false; -+ } -+ size -= count; -+ } -+ if (!ar_parse_entry(ar)) { -+ ar_parse_entry_at(ar, current_offset); -+ return false; -+ } -+ } -+ rar->solid.restart = false; -+ return true; -+} -+ -+static bool rar_uncompress(ar_archive *ar, void *buffer, size_t count) -+{ -+ ar_archive_rar *rar = (ar_archive_rar *)ar; -+ if (count > ar->entry_size_uncompressed - rar->progress.bytes_done) { -+ warn("Requesting too much data (%" PRIuPTR " < %" PRIuPTR ")", ar->entry_size_uncompressed - rar->progress.bytes_done, count); -+ return false; -+ } -+ if (rar->entry.method == METHOD_STORE) { -+ if (!rar_copy_stored(rar, buffer, count)) -+ return false; -+ } -+ else if (rar->entry.method == METHOD_FASTEST || rar->entry.method == METHOD_FAST || -+ rar->entry.method == METHOD_NORMAL || rar->entry.method == METHOD_GOOD || -+ rar->entry.method == METHOD_BEST) { -+ if (rar->solid.restart && !rar_restart_solid(ar)) { -+ warn("Failed to produce the required solid decompression state"); -+ return false; -+ } -+ if (!rar_uncompress_part(rar, buffer, count)) -+ return false; -+ } -+ else { -+ warn("Unknown compression method %#02x", rar->entry.method); -+ return false; -+ } -+ -+ rar->progress.crc = ar_crc32(rar->progress.crc, buffer, count); -+ if (rar->progress.bytes_done < ar->entry_size_uncompressed) -+ return true; -+ if (rar->progress.data_left) -+ log("Compressed block has more data than required"); -+ rar->solid.part_done = true; -+ rar->solid.size_total += rar->progress.bytes_done; -+ if (rar->progress.crc != rar->entry.crc) { -+ warn("Checksum of extracted data doesn't match"); -+ return false; -+ } -+ return true; -+} -+ -+ar_archive *ar_open_rar_archive(ar_stream *stream) -+{ -+ char signature[FILE_SIGNATURE_SIZE]; -+ if (!ar_seek(stream, 0, SEEK_SET)) -+ return NULL; -+ if (ar_read(stream, signature, sizeof(signature)) != sizeof(signature)) -+ return NULL; -+ if (memcmp(signature, "Rar!\x1A\x07\x00", sizeof(signature)) != 0) { -+ if (memcmp(signature, "Rar!\x1A\x07\x01", sizeof(signature)) == 0) -+ warn("RAR 5 format isn't supported"); -+ else if (memcmp(signature, "RE~^", 4) == 0) -+ warn("Ancient RAR format isn't supported"); -+ else if (memcmp(signature, "MZ", 2) == 0 || memcmp(signature, "\x7F\x45LF", 4) == 0) -+ warn("SFX archives aren't supported"); -+ return NULL; -+ } -+ -+ return ar_open_archive(stream, sizeof(ar_archive_rar), rar_close, rar_parse_entry, rar_get_name, rar_uncompress, NULL, FILE_SIGNATURE_SIZE); -+} -diff --git a/cut-n-paste/unarr/rar/rar.h b/cut-n-paste/unarr/rar/rar.h -new file mode 100644 -index 00000000..0e112224 ---- /dev/null -+++ b/cut-n-paste/unarr/rar/rar.h -@@ -0,0 +1,252 @@ -+/* Copyright 2015 the unarr project authors (see AUTHORS file). -+ License: LGPLv3 */ -+ -+#ifndef rar_rar_h -+#define rar_rar_h -+ -+#include "../common/unarr-imp.h" -+ -+#include "lzss.h" -+#include "../lzmasdk/Ppmd7.h" -+#include -+ -+static inline size_t smin(size_t a, size_t b) { return a < b ? a : b; } -+ -+typedef struct ar_archive_rar_s ar_archive_rar; -+ -+/***** parse-rar *****/ -+ -+#define FILE_SIGNATURE_SIZE 7 -+ -+enum block_types { -+ TYPE_FILE_SIGNATURE = 0x72, TYPE_MAIN_HEADER = 0x73, TYPE_FILE_ENTRY = 0x74, -+ TYPE_NEWSUB = 0x7A, TYPE_END_OF_ARCHIVE = 0x7B, -+}; -+ -+enum archive_flags { -+ MHD_VOLUME = 1 << 0, MHD_COMMENT = 1 << 1, MHD_LOCK = 1 << 2, -+ MHD_SOLID = 1 << 3, MHD_PACK_COMMENT = 1 << 4, MHD_AV = 1 << 5, -+ MHD_PROTECT = 1 << 6, MHD_PASSWORD = 1 << 7, MHD_FIRSTVOLUME = 1 << 8, -+ MHD_ENCRYPTVER = 1 << 9, -+ MHD_LONG_BLOCK = 1 << 15, -+}; -+ -+enum entry_flags { -+ LHD_SPLIT_BEFORE = 1 << 0, LHD_SPLIT_AFTER = 1 << 1, LHD_PASSWORD = 1 << 2, -+ LHD_COMMENT = 1 << 3, LHD_SOLID = 1 << 4, -+ LHD_DIRECTORY = (1 << 5) | (1 << 6) | (1 << 7), -+ LHD_LARGE = 1 << 8, LHD_UNICODE = 1 << 9, LHD_SALT = 1 << 10, -+ LHD_VERSION = 1 << 11, LHD_EXTTIME = 1 << 12, LHD_EXTFLAGS = 1 << 13, -+ LHD_LONG_BLOCK = 1 << 15, -+}; -+ -+enum compression_method { -+ METHOD_STORE = 0x30, -+ METHOD_FASTEST = 0x31, METHOD_FAST = 0x32, METHOD_NORMAL = 0x33, -+ METHOD_GOOD = 0x34, METHOD_BEST = 0x35, -+}; -+ -+struct rar_header { -+ uint16_t crc; -+ uint8_t type; -+ uint16_t flags; -+ uint16_t size; -+ uint64_t datasize; -+}; -+ -+struct rar_entry { -+ uint64_t size; -+ uint8_t os; -+ uint32_t crc; -+ uint32_t dosdate; -+ uint8_t version; -+ uint8_t method; -+ uint16_t namelen; -+ uint32_t attrs; -+}; -+ -+struct ar_archive_rar_entry { -+ uint8_t version; -+ uint8_t method; -+ uint32_t crc; -+ uint16_t header_size; -+ bool solid; -+ char *name; -+}; -+ -+bool rar_parse_header(ar_archive *ar, struct rar_header *header); -+bool rar_check_header_crc(ar_archive *ar); -+bool rar_parse_header_entry(ar_archive_rar *rar, struct rar_header *header, struct rar_entry *entry); -+const char *rar_get_name(ar_archive *ar); -+ -+/***** filter-rar *****/ -+ -+struct RARVirtualMachine; -+struct RARProgramCode; -+struct RARFilter; -+ -+struct ar_archive_rar_filters { -+ struct RARVirtualMachine *vm; -+ struct RARProgramCode *progs; -+ struct RARFilter *stack; -+ size_t filterstart; -+ uint32_t lastfilternum; -+ size_t lastend; -+ uint8_t *bytes; -+ size_t bytes_ready; -+}; -+ -+bool rar_parse_filter(ar_archive_rar *rar, const uint8_t *bytes, uint16_t length, uint8_t flags); -+bool rar_run_filters(ar_archive_rar *rar); -+void rar_clear_filters(struct ar_archive_rar_filters *filters); -+ -+/***** huffman-rar *****/ -+ -+struct huffman_code { -+ struct { -+ int branches[2]; -+ } *tree; -+ int numentries; -+ int capacity; -+ int minlength; -+ int maxlength; -+ struct { -+ int length; -+ int value; -+ } *table; -+ int tablesize; -+}; -+ -+bool rar_new_node(struct huffman_code *code); -+bool rar_add_value(struct huffman_code *code, int value, int codebits, int length); -+bool rar_create_code(struct huffman_code *code, uint8_t *lengths, int numsymbols); -+bool rar_make_table(struct huffman_code *code); -+void rar_free_code(struct huffman_code *code); -+ -+static inline bool rar_is_leaf_node(struct huffman_code *code, int node) { return code->tree[node].branches[0] == code->tree[node].branches[1]; } -+ -+/***** uncompress-rar *****/ -+ -+#define LZSS_WINDOW_SIZE 0x400000 -+#define LZSS_OVERFLOW_SIZE 288 -+ -+#define MAINCODE_SIZE 299 -+#define OFFSETCODE_SIZE 60 -+#define LOWOFFSETCODE_SIZE 17 -+#define LENGTHCODE_SIZE 28 -+#define HUFFMAN_TABLE_SIZE MAINCODE_SIZE + OFFSETCODE_SIZE + LOWOFFSETCODE_SIZE + LENGTHCODE_SIZE -+ -+struct ByteReader { -+ IByteIn super; -+ ar_archive_rar *rar; -+}; -+ -+struct CPpmdRAR_RangeDec { -+ IPpmd7_RangeDec super; -+ UInt32 Range; -+ UInt32 Code; -+ UInt32 Low; -+ IByteIn *Stream; -+}; -+ -+struct ar_archive_rar_uncomp_v3 { -+ struct huffman_code maincode; -+ struct huffman_code offsetcode; -+ struct huffman_code lowoffsetcode; -+ struct huffman_code lengthcode; -+ uint8_t lengthtable[HUFFMAN_TABLE_SIZE]; -+ uint32_t lastlength; -+ uint32_t lastoffset; -+ uint32_t oldoffset[4]; -+ uint32_t lastlowoffset; -+ uint32_t numlowoffsetrepeats; -+ -+ bool is_ppmd_block; -+ int ppmd_escape; -+ CPpmd7 ppmd7_context; -+ struct CPpmdRAR_RangeDec range_dec; -+ struct ByteReader bytein; -+ -+ struct ar_archive_rar_filters filters; -+}; -+ -+#define MAINCODE_SIZE_20 298 -+#define OFFSETCODE_SIZE_20 48 -+#define LENGTHCODE_SIZE_20 28 -+#define HUFFMAN_TABLE_SIZE_20 4 * 257 -+ -+struct AudioState { -+ int8_t weight[5]; -+ int16_t delta[4]; -+ int8_t lastdelta; -+ int error[11]; -+ int count; -+ uint8_t lastbyte; -+}; -+ -+struct ar_archive_rar_uncomp_v2 { -+ struct huffman_code maincode; -+ struct huffman_code offsetcode; -+ struct huffman_code lengthcode; -+ struct huffman_code audiocode[4]; -+ uint8_t lengthtable[HUFFMAN_TABLE_SIZE_20]; -+ uint32_t lastoffset; -+ uint32_t lastlength; -+ uint32_t oldoffset[4]; -+ uint32_t oldoffsetindex; -+ -+ bool audioblock; -+ uint8_t channel; -+ uint8_t numchannels; -+ struct AudioState audiostate[4]; -+ int8_t channeldelta; -+}; -+ -+struct ar_archive_rar_uncomp { -+ uint8_t version; -+ -+ LZSS lzss; -+ size_t bytes_ready; -+ bool start_new_table; -+ -+ union { -+ struct ar_archive_rar_uncomp_v3 v3; -+ struct ar_archive_rar_uncomp_v2 v2; -+ } state; -+ -+ struct StreamBitReader { -+ uint64_t bits; -+ int available; -+ bool at_eof; -+ } br; -+}; -+ -+bool rar_uncompress_part(ar_archive_rar *rar, void *buffer, size_t buffer_size); -+int64_t rar_expand(ar_archive_rar *rar, int64_t end); -+void rar_clear_uncompress(struct ar_archive_rar_uncomp *uncomp); -+static inline void br_clear_leftover_bits(struct ar_archive_rar_uncomp *uncomp) { uncomp->br.available &= ~0x07; } -+ -+/***** rar *****/ -+ -+struct ar_archive_rar_progress { -+ size_t data_left; -+ size_t bytes_done; -+ uint32_t crc; -+}; -+ -+struct ar_archive_rar_solid { -+ size_t size_total; -+ bool part_done; -+ bool restart; -+}; -+ -+struct ar_archive_rar_s { -+ ar_archive super; -+ uint16_t archive_flags; -+ struct ar_archive_rar_entry entry; -+ struct ar_archive_rar_uncomp uncomp; -+ struct ar_archive_rar_progress progress; -+ struct ar_archive_rar_solid solid; -+}; -+ -+#endif -diff --git a/cut-n-paste/unarr/rar/rarvm.c b/cut-n-paste/unarr/rar/rarvm.c -new file mode 100644 -index 00000000..6f738ec3 ---- /dev/null -+++ b/cut-n-paste/unarr/rar/rarvm.c -@@ -0,0 +1,616 @@ -+/* Copyright 2015 the unarr project authors (see AUTHORS file). -+ License: LGPLv3 */ -+ -+/* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/RARVirtualMachine.c */ -+ -+#include "rarvm.h" -+#include "../common/allocator.h" -+ -+#include -+#include -+ -+typedef struct RAROpcode_s RAROpcode; -+ -+struct RAROpcode_s { -+ uint8_t instruction; -+ uint8_t bytemode; -+ uint8_t addressingmode1; -+ uint8_t addressingmode2; -+ uint32_t value1; -+ uint32_t value2; -+}; -+ -+struct RARProgram_s { -+ RAROpcode *opcodes; -+ uint32_t length; -+ uint32_t capacity; -+}; -+ -+/* Program building */ -+ -+RARProgram *RARCreateProgram() -+{ -+ return calloc(1, sizeof(RARProgram)); -+} -+ -+void RARDeleteProgram(RARProgram *prog) -+{ -+ if (prog) -+ free(prog->opcodes); -+ free(prog); -+} -+ -+bool RARProgramAddInstr(RARProgram *prog, uint8_t instruction, bool bytemode) -+{ -+ if (instruction >= RARNumberOfInstructions) -+ return false; -+ if (bytemode && !RARInstructionHasByteMode(instruction)) -+ return false; -+ if (prog->length + 1 >= prog->capacity) { -+ /* in my small file sample, 16 is the value needed most often */ -+ uint32_t newCapacity = prog->capacity ? prog->capacity * 4 : 32; -+ RAROpcode *newCodes = calloc(newCapacity, sizeof(*prog->opcodes)); -+ if (!newCodes) -+ return false; -+ memcpy(newCodes, prog->opcodes, prog->capacity * sizeof(*prog->opcodes)); -+ free(prog->opcodes); -+ prog->opcodes = newCodes; -+ prog->capacity = newCapacity; -+ } -+ memset(&prog->opcodes[prog->length], 0, sizeof(prog->opcodes[prog->length])); -+ prog->opcodes[prog->length].instruction = instruction; -+ if (instruction == RARMovzxInstruction || instruction == RARMovsxInstruction) -+ prog->opcodes[prog->length].bytemode = 2; /* second argument only */ -+ else if (bytemode) -+ prog->opcodes[prog->length].bytemode = (1 | 2); -+ else -+ prog->opcodes[prog->length].bytemode = 0; -+ prog->length++; -+ return true; -+} -+ -+bool RARSetLastInstrOperands(RARProgram *prog, uint8_t addressingmode1, uint32_t value1, uint8_t addressingmode2, uint32_t value2) -+{ -+ RAROpcode *opcode = &prog->opcodes[prog->length - 1]; -+ int numoperands; -+ -+ if (addressingmode1 >= RARNumberOfAddressingModes || addressingmode2 >= RARNumberOfAddressingModes) -+ return false; -+ if (!prog->length || opcode->addressingmode1 || opcode->value1 || opcode->addressingmode2 || opcode->value2) -+ return false; -+ -+ numoperands = NumberOfRARInstructionOperands(opcode->instruction); -+ if (numoperands == 0) -+ return true; -+ -+ if (addressingmode1 == RARImmediateAddressingMode && RARInstructionWritesFirstOperand(opcode->instruction)) -+ return false; -+ opcode->addressingmode1 = addressingmode1; -+ opcode->value1 = value1; -+ -+ if (numoperands == 2) { -+ if (addressingmode2 == RARImmediateAddressingMode && RARInstructionWritesSecondOperand(opcode->instruction)) -+ return false; -+ opcode->addressingmode2 = addressingmode2; -+ opcode->value2 = value2; -+ } -+ -+ return true; -+} -+ -+bool RARIsProgramTerminated(RARProgram *prog) -+{ -+ return prog->length > 0 && RARInstructionIsUnconditionalJump(prog->opcodes[prog->length - 1].instruction); -+} -+ -+/* Execution */ -+ -+#define EXTMACRO_BEGIN do { -+#ifdef _MSC_VER -+#define EXTMACRO_END } __pragma(warning(push)) __pragma(warning(disable:4127)) while (0) __pragma(warning(pop)) -+#else -+#define EXTMACRO_END } while (0) -+#endif -+ -+#define CarryFlag 1 -+#define ZeroFlag 2 -+#define SignFlag 0x80000000 -+ -+#define SignExtend(a) ((uint32_t)((int8_t)(a))) -+ -+static uint32_t _RARGetOperand(RARVirtualMachine *vm, uint8_t addressingmode, uint32_t value, bool bytemode); -+static void _RARSetOperand(RARVirtualMachine *vm, uint8_t addressingmode, uint32_t value, bool bytemode, uint32_t data); -+ -+#define GetOperand1() _RARGetOperand(vm, opcode->addressingmode1, opcode->value1, opcode->bytemode & 1) -+#define GetOperand2() _RARGetOperand(vm, opcode->addressingmode2, opcode->value2, opcode->bytemode & 2) -+#define SetOperand1(data) _RARSetOperand(vm, opcode->addressingmode1, opcode->value1, opcode->bytemode & 1, data) -+#define SetOperand2(data) _RARSetOperand(vm, opcode->addressingmode2, opcode->value2, opcode->bytemode & 2, data) -+ -+#define SetFlagsWithCarry(res, carry) EXTMACRO_BEGIN uint32_t result = (res); flags = (result == 0 ? ZeroFlag : (result & SignFlag)) | ((carry) ? CarryFlag : 0); EXTMACRO_END -+#define SetByteFlagsWithCarry(res, carry) EXTMACRO_BEGIN uint8_t result = (res); flags = (result == 0 ? ZeroFlag : (SignExtend(result) & SignFlag)) | ((carry) ? CarryFlag : 0); EXTMACRO_END -+#define SetFlags(res) SetFlagsWithCarry(res, 0) -+ -+#define SetOperand1AndFlagsWithCarry(res, carry) EXTMACRO_BEGIN uint32_t r = (res); SetFlagsWithCarry(r, carry); SetOperand1(r); EXTMACRO_END -+#define SetOperand1AndByteFlagsWithCarry(res, carry) EXTMACRO_BEGIN uint8_t r = (res); SetByteFlagsWithCarry(r, carry); SetOperand1(r); EXTMACRO_END -+#define SetOperand1AndFlags(res) EXTMACRO_BEGIN uint32_t r = (res); SetFlags(r); SetOperand1(r); EXTMACRO_END -+ -+#define NextInstruction() { opcode++; continue; } -+#define Jump(offs) { uint32_t o = (offs); if (o >= prog->length) return false; opcode = &prog->opcodes[o]; continue; } -+ -+bool RARExecuteProgram(RARVirtualMachine *vm, RARProgram *prog) -+{ -+ RAROpcode *opcode = prog->opcodes; -+ uint32_t flags = 0; -+ uint32_t op1, op2, carry, i; -+ uint32_t counter = 0; -+ -+ if (!RARIsProgramTerminated(prog)) -+ return false; -+ -+ while ((uint32_t)(opcode - prog->opcodes) < prog->length && counter++ < RARRuntimeMaxInstructions) { -+ switch (opcode->instruction) { -+ case RARMovInstruction: -+ SetOperand1(GetOperand2()); -+ NextInstruction(); -+ -+ case RARCmpInstruction: -+ op1 = GetOperand1(); -+ SetFlagsWithCarry(op1 - GetOperand2(), result > op1); -+ NextInstruction(); -+ -+ case RARAddInstruction: -+ op1 = GetOperand1(); -+ if (opcode->bytemode) -+ SetOperand1AndByteFlagsWithCarry((op1 + GetOperand2()) & 0xFF, result < op1); -+ else -+ SetOperand1AndFlagsWithCarry(op1 + GetOperand2(), result < op1); -+ NextInstruction(); -+ -+ case RARSubInstruction: -+ op1 = GetOperand1(); -+#if 0 /* apparently not correctly implemented in the RAR VM */ -+ if (opcode->bytemode) -+ SetOperand1AndByteFlagsWithCarry((op1 - GetOperand2()) & 0xFF, result > op1); -+ else -+#endif -+ SetOperand1AndFlagsWithCarry(op1 - GetOperand2(), result > op1); -+ NextInstruction(); -+ -+ case RARJzInstruction: -+ if ((flags & ZeroFlag)) -+ Jump(GetOperand1()); -+ NextInstruction(); -+ -+ case RARJnzInstruction: -+ if (!(flags & ZeroFlag)) -+ Jump(GetOperand1()); -+ NextInstruction(); -+ -+ case RARIncInstruction: -+ if (opcode->bytemode) -+ SetOperand1AndFlags((GetOperand1() + 1) & 0xFF); -+ else -+ SetOperand1AndFlags(GetOperand1() + 1); -+ NextInstruction(); -+ -+ case RARDecInstruction: -+ if (opcode->bytemode) -+ SetOperand1AndFlags((GetOperand1() - 1) & 0xFF); -+ else -+ SetOperand1AndFlags(GetOperand1() - 1); -+ NextInstruction(); -+ -+ case RARJmpInstruction: -+ Jump(GetOperand1()); -+ -+ case RARXorInstruction: -+ SetOperand1AndFlags(GetOperand1() ^ GetOperand2()); -+ NextInstruction(); -+ -+ case RARAndInstruction: -+ SetOperand1AndFlags(GetOperand1() & GetOperand2()); -+ NextInstruction(); -+ -+ case RAROrInstruction: -+ SetOperand1AndFlags(GetOperand1() | GetOperand2()); -+ NextInstruction(); -+ -+ case RARTestInstruction: -+ SetFlags(GetOperand1() & GetOperand2()); -+ NextInstruction(); -+ -+ case RARJsInstruction: -+ if ((flags & SignFlag)) -+ Jump(GetOperand1()); -+ NextInstruction(); -+ -+ case RARJnsInstruction: -+ if (!(flags & SignFlag)) -+ Jump(GetOperand1()); -+ NextInstruction(); -+ -+ case RARJbInstruction: -+ if ((flags & CarryFlag)) -+ Jump(GetOperand1()); -+ NextInstruction(); -+ -+ case RARJbeInstruction: -+ if ((flags & (CarryFlag | ZeroFlag))) -+ Jump(GetOperand1()); -+ NextInstruction(); -+ -+ case RARJaInstruction: -+ if (!(flags & (CarryFlag | ZeroFlag))) -+ Jump(GetOperand1()); -+ NextInstruction(); -+ -+ case RARJaeInstruction: -+ if (!(flags & CarryFlag)) -+ Jump(GetOperand1()); -+ NextInstruction(); -+ -+ case RARPushInstruction: -+ vm->registers[7] -= 4; -+ RARVirtualMachineWrite32(vm, vm->registers[7], GetOperand1()); -+ NextInstruction(); -+ -+ case RARPopInstruction: -+ SetOperand1(RARVirtualMachineRead32(vm, vm->registers[7])); -+ vm->registers[7] += 4; -+ NextInstruction(); -+ -+ case RARCallInstruction: -+ vm->registers[7] -= 4; -+ RARVirtualMachineWrite32(vm, vm->registers[7], (uint32_t)(opcode - prog->opcodes + 1)); -+ Jump(GetOperand1()); -+ -+ case RARRetInstruction: -+ if (vm->registers[7] >= RARProgramMemorySize) -+ return true; -+ i = RARVirtualMachineRead32(vm, vm->registers[7]); -+ vm->registers[7] += 4; -+ Jump(i); -+ -+ case RARNotInstruction: -+ SetOperand1(~GetOperand1()); -+ NextInstruction(); -+ -+ case RARShlInstruction: -+ op1 = GetOperand1(); -+ op2 = GetOperand2(); -+ SetOperand1AndFlagsWithCarry(op1 << op2, ((op1 << (op2 - 1)) & 0x80000000) != 0); -+ NextInstruction(); -+ -+ case RARShrInstruction: -+ op1 = GetOperand1(); -+ op2 = GetOperand2(); -+ SetOperand1AndFlagsWithCarry(op1 >> op2, ((op1 >> (op2 - 1)) & 1) != 0); -+ NextInstruction(); -+ -+ case RARSarInstruction: -+ op1 = GetOperand1(); -+ op2 = GetOperand2(); -+ SetOperand1AndFlagsWithCarry(((int32_t)op1) >> op2, ((op1 >> (op2 - 1)) & 1) != 0); -+ NextInstruction(); -+ -+ case RARNegInstruction: -+ SetOperand1AndFlagsWithCarry(-(int32_t)GetOperand1(), result != 0); -+ NextInstruction(); -+ -+ case RARPushaInstruction: -+ vm->registers[7] -= 32; -+ for (i = 0; i < 8; i++) -+ RARVirtualMachineWrite32(vm, vm->registers[7] + (7 - i) * 4, vm->registers[i]); -+ NextInstruction(); -+ -+ case RARPopaInstruction: -+ for (i = 0; i < 8; i++) -+ vm->registers[i] = RARVirtualMachineRead32(vm, vm->registers[7] + (7 - i) * 4); -+ vm->registers[7] += 32; -+ NextInstruction(); -+ -+ case RARPushfInstruction: -+ vm->registers[7] -= 4; -+ RARVirtualMachineWrite32(vm, vm->registers[7], flags); -+ NextInstruction(); -+ -+ case RARPopfInstruction: -+ flags = RARVirtualMachineRead32(vm, vm->registers[7]); -+ vm->registers[7] += 4; -+ NextInstruction(); -+ -+ case RARMovzxInstruction: -+ SetOperand1(GetOperand2()); -+ NextInstruction(); -+ -+ case RARMovsxInstruction: -+ SetOperand1(SignExtend(GetOperand2())); -+ NextInstruction(); -+ -+ case RARXchgInstruction: -+ op1 = GetOperand1(); -+ op2 = GetOperand2(); -+ SetOperand1(op2); -+ SetOperand2(op1); -+ NextInstruction(); -+ -+ case RARMulInstruction: -+ SetOperand1(GetOperand1() * GetOperand2()); -+ NextInstruction(); -+ -+ case RARDivInstruction: -+ op2 = GetOperand2(); -+ if (op2 != 0) -+ SetOperand1(GetOperand1() / op2); -+ NextInstruction(); -+ -+ case RARAdcInstruction: -+ op1 = GetOperand1(); -+ carry = (flags & CarryFlag); -+ if (opcode->bytemode) -+ SetOperand1AndFlagsWithCarry((op1 + GetOperand2() + carry) & 0xFF, result < op1 || (result == op1 && carry)); /* does not correctly set sign bit */ -+ else -+ SetOperand1AndFlagsWithCarry(op1 + GetOperand2() + carry, result < op1 || (result == op1 && carry)); -+ NextInstruction(); -+ -+ case RARSbbInstruction: -+ op1 = GetOperand1(); -+ carry = (flags & CarryFlag); -+ if (opcode->bytemode) -+ SetOperand1AndFlagsWithCarry((op1 - GetOperand2() - carry) & 0xFF, result > op1 || (result == op1 && carry)); /* does not correctly set sign bit */ -+ else -+ SetOperand1AndFlagsWithCarry(op1 - GetOperand2() - carry, result > op1 || (result == op1 && carry)); -+ NextInstruction(); -+ -+ case RARPrintInstruction: -+ /* TODO: ??? */ -+ NextInstruction(); -+ } -+ } -+ -+ return false; -+} -+ -+/* Memory and register access */ -+ -+static uint32_t _RARRead32(const uint8_t *b) -+{ -+ return ((uint32_t)b[3] << 24) | ((uint32_t)b[2] << 16) | ((uint32_t)b[1] << 8) | (uint32_t)b[0]; -+} -+ -+static void _RARWrite32(uint8_t *b, uint32_t n) -+{ -+ b[3] = (n >> 24) & 0xFF; -+ b[2] = (n >> 16) & 0xFF; -+ b[1] = (n >> 8) & 0xFF; -+ b[0] = n & 0xFF; -+} -+ -+void RARSetVirtualMachineRegisters(RARVirtualMachine *vm, uint32_t registers[8]) -+{ -+ if (registers) -+ memcpy(vm->registers, registers, sizeof(vm->registers)); -+ else -+ memset(vm->registers, 0, sizeof(vm->registers)); -+} -+ -+uint32_t RARVirtualMachineRead32(RARVirtualMachine *vm, uint32_t address) -+{ -+ return _RARRead32(&vm->memory[address & RARProgramMemoryMask]); -+} -+ -+void RARVirtualMachineWrite32(RARVirtualMachine *vm, uint32_t address, uint32_t val) -+{ -+ _RARWrite32(&vm->memory[address & RARProgramMemoryMask], val); -+} -+ -+uint8_t RARVirtualMachineRead8(RARVirtualMachine *vm, uint32_t address) -+{ -+ return vm->memory[address & RARProgramMemoryMask]; -+} -+ -+void RARVirtualMachineWrite8(RARVirtualMachine *vm, uint32_t address, uint8_t val) -+{ -+ vm->memory[address & RARProgramMemoryMask] = val; -+} -+ -+static uint32_t _RARGetOperand(RARVirtualMachine *vm, uint8_t addressingmode, uint32_t value, bool bytemode) -+{ -+ if (RARRegisterAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterAddressingMode(7)) { -+ uint32_t result = vm->registers[addressingmode % 8]; -+ if (bytemode) -+ result = result & 0xFF; -+ return result; -+ } -+ if (RARRegisterIndirectAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterIndirectAddressingMode(7)) { -+ if (bytemode) -+ return RARVirtualMachineRead8(vm, vm->registers[addressingmode % 8]); -+ return RARVirtualMachineRead32(vm, vm->registers[addressingmode % 8]); -+ } -+ if (RARIndexedAbsoluteAddressingMode(0) <= addressingmode && addressingmode <= RARIndexedAbsoluteAddressingMode(7)) { -+ if (bytemode) -+ return RARVirtualMachineRead8(vm, value + vm->registers[addressingmode % 8]); -+ return RARVirtualMachineRead32(vm, value + vm->registers[addressingmode % 8]); -+ } -+ if (addressingmode == RARAbsoluteAddressingMode) { -+ if (bytemode) -+ return RARVirtualMachineRead8(vm, value); -+ return RARVirtualMachineRead32(vm, value); -+ } -+ /* if (addressingmode == RARImmediateAddressingMode) */ -+ return value; -+} -+ -+static void _RARSetOperand(RARVirtualMachine *vm, uint8_t addressingmode, uint32_t value, bool bytemode, uint32_t data) -+{ -+ if (RARRegisterAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterAddressingMode(7)) { -+ if (bytemode) -+ data = data & 0xFF; -+ vm->registers[addressingmode % 8] = data; -+ } -+ else if (RARRegisterIndirectAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterIndirectAddressingMode(7)) { -+ if (bytemode) -+ RARVirtualMachineWrite8(vm, vm->registers[addressingmode % 8], (uint8_t)data); -+ else -+ RARVirtualMachineWrite32(vm, vm->registers[addressingmode % 8], data); -+ } -+ else if (RARIndexedAbsoluteAddressingMode(0) <= addressingmode && addressingmode <= RARIndexedAbsoluteAddressingMode(7)) { -+ if (bytemode) -+ RARVirtualMachineWrite8(vm, value + vm->registers[addressingmode % 8], (uint8_t)data); -+ else -+ RARVirtualMachineWrite32(vm, value + vm->registers[addressingmode % 8], data); -+ } -+ else if (addressingmode == RARAbsoluteAddressingMode) { -+ if (bytemode) -+ RARVirtualMachineWrite8(vm, value, (uint8_t)data); -+ else -+ RARVirtualMachineWrite32(vm, value, data); -+ } -+} -+ -+/* Instruction properties */ -+ -+#define RAR0OperandsFlag 0 -+#define RAR1OperandFlag 1 -+#define RAR2OperandsFlag 2 -+#define RAROperandsFlag 3 -+#define RARHasByteModeFlag 4 -+#define RARIsUnconditionalJumpFlag 8 -+#define RARIsRelativeJumpFlag 16 -+#define RARWritesFirstOperandFlag 32 -+#define RARWritesSecondOperandFlag 64 -+#define RARReadsStatusFlag 128 -+#define RARWritesStatusFlag 256 -+ -+static const int InstructionFlags[RARNumberOfInstructions] = { -+ /*RARMovInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag, -+ /*RARCmpInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesStatusFlag, -+ /*RARAddInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, -+ /*RARSubInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, -+ /*RARJzInstruction*/ RAR1OperandFlag | RARIsUnconditionalJumpFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag, -+ /*RARJnzInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag, -+ /*RARIncInstruction*/ RAR1OperandFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, -+ /*RARDecInstruction*/ RAR1OperandFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, -+ /*RARJmpInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag, -+ /*RARXorInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, -+ /*RARAndInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, -+ /*RAROrInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, -+ /*RARTestInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesStatusFlag, -+ /*RARJsInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag, -+ /*RARJnsInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag, -+ /*RARJbInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag, -+ /*RARJbeInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag, -+ /*RARJaInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag, -+ /*RARJaeInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag | RARReadsStatusFlag, -+ /*RARPushInstruction*/ RAR1OperandFlag, -+ /*RARPopInstruction*/ RAR1OperandFlag, -+ /*RARCallInstruction*/ RAR1OperandFlag | RARIsRelativeJumpFlag, -+ /*RARRetInstruction*/ RAR0OperandsFlag | RARIsUnconditionalJumpFlag, -+ /*RARNotInstruction*/ RAR1OperandFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag, -+ /*RARShlInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, -+ /*RARShrInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, -+ /*RARSarInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, -+ /*RARNegInstruction*/ RAR1OperandFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARWritesStatusFlag, -+ /*RARPushaInstruction*/ RAR0OperandsFlag, -+ /*RARPopaInstruction*/ RAR0OperandsFlag, -+ /*RARPushfInstruction*/ RAR0OperandsFlag | RARReadsStatusFlag, -+ /*RARPopfInstruction*/ RAR0OperandsFlag | RARWritesStatusFlag, -+ /*RARMovzxInstruction*/ RAR2OperandsFlag | RARWritesFirstOperandFlag, -+ /*RARMovsxInstruction*/ RAR2OperandsFlag | RARWritesFirstOperandFlag, -+ /*RARXchgInstruction*/ RAR2OperandsFlag | RARWritesFirstOperandFlag | RARWritesSecondOperandFlag | RARHasByteModeFlag, -+ /*RARMulInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag, -+ /*RARDivInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag, -+ /*RARAdcInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARReadsStatusFlag | RARWritesStatusFlag, -+ /*RARSbbInstruction*/ RAR2OperandsFlag | RARHasByteModeFlag | RARWritesFirstOperandFlag | RARReadsStatusFlag | RARWritesStatusFlag, -+ /*RARPrintInstruction*/ RAR0OperandsFlag -+}; -+ -+int NumberOfRARInstructionOperands(uint8_t instruction) -+{ -+ if (instruction >= RARNumberOfInstructions) -+ return 0; -+ return InstructionFlags[instruction] & RAROperandsFlag; -+} -+ -+bool RARInstructionHasByteMode(uint8_t instruction) -+{ -+ if (instruction >= RARNumberOfInstructions) -+ return false; -+ return (InstructionFlags[instruction] & RARHasByteModeFlag)!=0; -+} -+ -+bool RARInstructionIsUnconditionalJump(uint8_t instruction) -+{ -+ if (instruction >= RARNumberOfInstructions) -+ return false; -+ return (InstructionFlags[instruction] & RARIsUnconditionalJumpFlag) != 0; -+} -+ -+bool RARInstructionIsRelativeJump(uint8_t instruction) -+{ -+ if (instruction >= RARNumberOfInstructions) -+ return false; -+ return (InstructionFlags[instruction] & RARIsRelativeJumpFlag) != 0; -+} -+ -+bool RARInstructionWritesFirstOperand(uint8_t instruction) -+{ -+ if (instruction >= RARNumberOfInstructions) -+ return false; -+ return (InstructionFlags[instruction] & RARWritesFirstOperandFlag) != 0; -+} -+ -+bool RARInstructionWritesSecondOperand(uint8_t instruction) -+{ -+ if (instruction >= RARNumberOfInstructions) -+ return false; -+ return (InstructionFlags[instruction] & RARWritesSecondOperandFlag) != 0; -+} -+ -+/* Program debugging */ -+ -+#ifndef NDEBUG -+#include -+ -+static void RARPrintOperand(uint8_t addressingmode, uint32_t value) -+{ -+ if (RARRegisterAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterAddressingMode(7)) -+ printf("r%d", addressingmode % 8); -+ else if (RARRegisterIndirectAddressingMode(0) <= addressingmode && addressingmode <= RARRegisterIndirectAddressingMode(7)) -+ printf("@(r%d)", addressingmode % 8); -+ else if (RARIndexedAbsoluteAddressingMode(0) <= addressingmode && addressingmode <= RARIndexedAbsoluteAddressingMode(7)) -+ printf("@(r%d+$%02x)", addressingmode % 8, value); -+ else if (addressingmode == RARAbsoluteAddressingMode) -+ printf("@($%02x)", value); -+ else if (addressingmode == RARImmediateAddressingMode) -+ printf("$%02x", value); -+} -+ -+void RARPrintProgram(RARProgram *prog) -+{ -+ static const char *instructionNames[RARNumberOfInstructions] = { -+ "Mov", "Cmp", "Add", "Sub", "Jz", "Jnz", "Inc", "Dec", "Jmp", "Xor", -+ "And", "Or", "Test", "Js", "Jns", "Jb", "Jbe", "Ja", "Jae", "Push", -+ "Pop", "Call", "Ret", "Not", "Shl", "Shr", "Sar", "Neg", "Pusha", "Popa", -+ "Pushf", "Popf", "Movzx", "Movsx", "Xchg", "Mul", "Div", "Adc", "Sbb", "Print", -+ }; -+ -+ uint32_t i; -+ for (i = 0; i < prog->length; i++) { -+ RAROpcode *opcode = &prog->opcodes[i]; -+ int numoperands = NumberOfRARInstructionOperands(opcode->instruction); -+ printf(" %02x: %s", i, instructionNames[opcode->instruction]); -+ if (opcode->bytemode) -+ printf("B"); -+ if (numoperands >= 1) { -+ printf(" "); -+ RARPrintOperand(opcode->addressingmode1, opcode->value1); -+ } -+ if (numoperands == 2) { -+ printf(", "); -+ RARPrintOperand(opcode->addressingmode2, opcode->value2); -+ } -+ printf("\n"); -+ } -+} -+#endif -diff --git a/cut-n-paste/unarr/rar/rarvm.h b/cut-n-paste/unarr/rar/rarvm.h -new file mode 100644 -index 00000000..4fb0b47f ---- /dev/null -+++ b/cut-n-paste/unarr/rar/rarvm.h -@@ -0,0 +1,117 @@ -+/* Copyright 2015 the unarr project authors (see AUTHORS file). -+ License: LGPLv3 */ -+ -+/* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/RARVirtualMachine.h */ -+ -+#ifndef rar_vm_h -+#define rar_vm_h -+ -+#include -+#include -+ -+#define RARProgramMemorySize 0x40000 -+#define RARProgramMemoryMask (RARProgramMemorySize - 1) -+#define RARProgramWorkSize 0x3c000 -+#define RARProgramGlobalSize 0x2000 -+#define RARProgramSystemGlobalAddress RARProgramWorkSize -+#define RARProgramSystemGlobalSize 64 -+#define RARProgramUserGlobalAddress (RARProgramSystemGlobalAddress + RARProgramSystemGlobalSize) -+#define RARProgramUserGlobalSize (RARProgramGlobalSize - RARProgramSystemGlobalSize) -+#define RARRuntimeMaxInstructions 250000000 -+ -+#define RARRegisterAddressingMode(n) (0 + (n)) -+#define RARRegisterIndirectAddressingMode(n) (8 + (n)) -+#define RARIndexedAbsoluteAddressingMode(n) (16 + (n)) -+#define RARAbsoluteAddressingMode 24 -+#define RARImmediateAddressingMode 25 -+#define RARNumberOfAddressingModes 26 -+ -+typedef struct RARVirtualMachine RARVirtualMachine; -+ -+struct RARVirtualMachine { -+ uint32_t registers[8]; -+ uint8_t memory[RARProgramMemorySize + sizeof(uint32_t) /* overflow sentinel */]; -+}; -+ -+typedef struct RARProgram_s RARProgram; -+ -+/* Program building */ -+ -+enum { -+ RARMovInstruction = 0, -+ RARCmpInstruction = 1, -+ RARAddInstruction = 2, -+ RARSubInstruction = 3, -+ RARJzInstruction = 4, -+ RARJnzInstruction = 5, -+ RARIncInstruction = 6, -+ RARDecInstruction = 7, -+ RARJmpInstruction = 8, -+ RARXorInstruction = 9, -+ RARAndInstruction = 10, -+ RAROrInstruction = 11, -+ RARTestInstruction = 12, -+ RARJsInstruction = 13, -+ RARJnsInstruction = 14, -+ RARJbInstruction = 15, -+ RARJbeInstruction = 16, -+ RARJaInstruction = 17, -+ RARJaeInstruction = 18, -+ RARPushInstruction = 19, -+ RARPopInstruction = 20, -+ RARCallInstruction = 21, -+ RARRetInstruction = 22, -+ RARNotInstruction = 23, -+ RARShlInstruction = 24, -+ RARShrInstruction = 25, -+ RARSarInstruction = 26, -+ RARNegInstruction = 27, -+ RARPushaInstruction = 28, -+ RARPopaInstruction = 29, -+ RARPushfInstruction = 30, -+ RARPopfInstruction = 31, -+ RARMovzxInstruction = 32, -+ RARMovsxInstruction = 33, -+ RARXchgInstruction = 34, -+ RARMulInstruction = 35, -+ RARDivInstruction = 36, -+ RARAdcInstruction = 37, -+ RARSbbInstruction = 38, -+ RARPrintInstruction = 39, -+ RARNumberOfInstructions = 40, -+}; -+ -+RARProgram *RARCreateProgram(); -+void RARDeleteProgram(RARProgram *prog); -+bool RARProgramAddInstr(RARProgram *prog, uint8_t instruction, bool bytemode); -+bool RARSetLastInstrOperands(RARProgram *prog, uint8_t addressingmode1, uint32_t value1, uint8_t addressingmode2, uint32_t value2); -+bool RARIsProgramTerminated(RARProgram *prog); -+ -+/* Execution */ -+ -+bool RARExecuteProgram(RARVirtualMachine *vm, RARProgram *prog); -+ -+/* Memory and register access (convenience) */ -+ -+void RARSetVirtualMachineRegisters(RARVirtualMachine *vm, uint32_t registers[8]); -+uint32_t RARVirtualMachineRead32(RARVirtualMachine *vm, uint32_t address); -+void RARVirtualMachineWrite32(RARVirtualMachine *vm, uint32_t address, uint32_t val); -+uint8_t RARVirtualMachineRead8(RARVirtualMachine *vm, uint32_t address); -+void RARVirtualMachineWrite8(RARVirtualMachine *vm, uint32_t address, uint8_t val); -+ -+/* Instruction properties */ -+ -+int NumberOfRARInstructionOperands(uint8_t instruction); -+bool RARInstructionHasByteMode(uint8_t instruction); -+bool RARInstructionIsUnconditionalJump(uint8_t instruction); -+bool RARInstructionIsRelativeJump(uint8_t instruction); -+bool RARInstructionWritesFirstOperand(uint8_t instruction); -+bool RARInstructionWritesSecondOperand(uint8_t instruction); -+ -+/* Program debugging */ -+ -+#ifndef NDEBUG -+void RARPrintProgram(RARProgram *prog); -+#endif -+ -+#endif -diff --git a/cut-n-paste/unarr/rar/uncompress-rar.c b/cut-n-paste/unarr/rar/uncompress-rar.c -new file mode 100644 -index 00000000..74c2ea61 ---- /dev/null -+++ b/cut-n-paste/unarr/rar/uncompress-rar.c -@@ -0,0 +1,1038 @@ -+/* Copyright 2015 the unarr project authors (see AUTHORS file). -+ License: LGPLv3 */ -+ -+/* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/XADRAR30Handle.m */ -+/* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/XADRAR20Handle.m */ -+ -+#include "rar.h" -+ -+static void *gSzAlloc_Alloc(void *self, size_t size) { (void)self; return malloc(size); } -+static void gSzAlloc_Free(void *self, void *ptr) { (void)self; free(ptr); } -+static ISzAlloc gSzAlloc = { gSzAlloc_Alloc, gSzAlloc_Free }; -+ -+static bool br_fill(ar_archive_rar *rar, int bits) -+{ -+ uint8_t bytes[8]; -+ int count, i; -+ /* read as many bits as possible */ -+ count = (64 - rar->uncomp.br.available) / 8; -+ if (rar->progress.data_left < (size_t)count) -+ count = (int)rar->progress.data_left; -+ -+ if (bits > rar->uncomp.br.available + 8 * count || ar_read(rar->super.stream, bytes, count) != (size_t)count) { -+ if (!rar->uncomp.br.at_eof) { -+ warn("Unexpected EOF during decompression (truncated file?)"); -+ rar->uncomp.br.at_eof = true; -+ } -+ return false; -+ } -+ rar->progress.data_left -= count; -+ for (i = 0; i < count; i++) { -+ rar->uncomp.br.bits = (rar->uncomp.br.bits << 8) | bytes[i]; -+ } -+ rar->uncomp.br.available += 8 * count; -+ return true; -+} -+ -+static inline bool br_check(ar_archive_rar *rar, int bits) -+{ -+ return bits <= rar->uncomp.br.available || br_fill(rar, bits); -+} -+ -+static inline uint64_t br_bits(ar_archive_rar *rar, int bits) -+{ -+ return (rar->uncomp.br.bits >> (rar->uncomp.br.available -= bits)) & (((uint64_t)1 << bits) - 1); -+} -+ -+static Byte ByteIn_Read(void *p) -+{ -+ struct ByteReader *self = p; -+ return br_check(self->rar, 8) ? (Byte)br_bits(self->rar, 8) : 0xFF; -+} -+ -+static void ByteIn_CreateVTable(struct ByteReader *br, ar_archive_rar *rar) -+{ -+ br->super.Read = ByteIn_Read; -+ br->rar = rar; -+} -+ -+/* Ppmd7 range decoder differs between 7z and RAR */ -+static void PpmdRAR_RangeDec_Init(struct CPpmdRAR_RangeDec *p) -+{ -+ int i; -+ p->Code = 0; -+ p->Low = 0; -+ p->Range = 0xFFFFFFFF; -+ for (i = 0; i < 4; i++) { -+ p->Code = (p->Code << 8) | p->Stream->Read(p->Stream); -+ } -+} -+ -+static UInt32 Range_GetThreshold(void *p, UInt32 total) -+{ -+ struct CPpmdRAR_RangeDec *self = p; -+ return self->Code / (self->Range /= total); -+} -+ -+static void Range_Decode_RAR(void *p, UInt32 start, UInt32 size) -+{ -+ struct CPpmdRAR_RangeDec *self = p; -+ self->Low += start * self->Range; -+ self->Code -= start * self->Range; -+ self->Range *= size; -+ for (;;) { -+ if ((self->Low ^ (self->Low + self->Range)) >= (1 << 24)) { -+ if (self->Range >= (1 << 15)) -+ break; -+ self->Range = ((uint32_t)(-(int32_t)self->Low)) & ((1 << 15) - 1); -+ } -+ self->Code = (self->Code << 8) | self->Stream->Read(self->Stream); -+ self->Range <<= 8; -+ self->Low <<= 8; -+ } -+} -+ -+static UInt32 Range_DecodeBit_RAR(void *p, UInt32 size0) -+{ -+ UInt32 value = Range_GetThreshold(p, PPMD_BIN_SCALE); -+ UInt32 bit = value < size0 ? 0 : 1; -+ if (!bit) -+ Range_Decode_RAR(p, 0, size0); -+ else -+ Range_Decode_RAR(p, size0, PPMD_BIN_SCALE - size0); -+ return bit; -+} -+ -+static void PpmdRAR_RangeDec_CreateVTable(struct CPpmdRAR_RangeDec *p, IByteIn *stream) -+{ -+ p->super.GetThreshold = Range_GetThreshold; -+ p->super.Decode = Range_Decode_RAR; -+ p->super.DecodeBit = Range_DecodeBit_RAR; -+ p->Stream = stream; -+} -+ -+static bool rar_init_uncompress(struct ar_archive_rar_uncomp *uncomp, uint8_t version) -+{ -+ /* per XADRARParser.m @handleForSolidStreamWithObject these versions are identical */ -+ if (version == 29 || version == 36) -+ version = 3; -+ else if (version == 20 || version == 26) -+ version = 2; -+ else { -+ warn("Unsupported compression version: %d", version); -+ return false; -+ } -+ if (uncomp->version) { -+ if (uncomp->version != version) { -+ warn("Compression version mismatch: %d != %d", version, uncomp->version); -+ return false; -+ } -+ return true; -+ } -+ memset(uncomp, 0, sizeof(*uncomp)); -+ uncomp->start_new_table = true; -+ if (!lzss_initialize(&uncomp->lzss, LZSS_WINDOW_SIZE)) { -+ warn("OOM during decompression"); -+ return false; -+ } -+ if (version == 3) { -+ uncomp->state.v3.ppmd_escape = 2; -+ uncomp->state.v3.filters.filterstart = SIZE_MAX; -+ } -+ uncomp->version = version; -+ return true; -+} -+ -+static void rar_free_codes(struct ar_archive_rar_uncomp *uncomp); -+ -+void rar_clear_uncompress(struct ar_archive_rar_uncomp *uncomp) -+{ -+ if (!uncomp->version) -+ return; -+ rar_free_codes(uncomp); -+ lzss_cleanup(&uncomp->lzss); -+ if (uncomp->version == 3) { -+ Ppmd7_Free(&uncomp->state.v3.ppmd7_context, &gSzAlloc); -+ rar_clear_filters(&uncomp->state.v3.filters); -+ } -+ uncomp->version = 0; -+} -+ -+static int rar_read_next_symbol(ar_archive_rar *rar, struct huffman_code *code) -+{ -+ int node = 0; -+ -+ if (!code->table && !rar_make_table(code)) -+ return -1; -+ -+ /* performance optimization */ -+ if (code->tablesize <= rar->uncomp.br.available) { -+ uint16_t bits = (uint16_t)br_bits(rar, code->tablesize); -+ int length = code->table[bits].length; -+ int value = code->table[bits].value; -+ -+ if (length < 0) { -+ warn("Invalid data in bitstream"); /* invalid prefix code in bitstream */ -+ return -1; -+ } -+ if (length <= code->tablesize) { -+ /* Skip only length bits */ -+ rar->uncomp.br.available += code->tablesize - length; -+ return value; -+ } -+ -+ node = value; -+ } -+ -+ while (!rar_is_leaf_node(code, node)) { -+ uint8_t bit; -+ if (!br_check(rar, 1)) -+ return -1; -+ bit = (uint8_t)br_bits(rar, 1); -+ if (code->tree[node].branches[bit] < 0) { -+ warn("Invalid data in bitstream"); /* invalid prefix code in bitstream */ -+ return -1; -+ } -+ node = code->tree[node].branches[bit]; -+ } -+ -+ return code->tree[node].branches[0]; -+} -+ -+/***** RAR version 2 decompression *****/ -+ -+static void rar_free_codes_v2(struct ar_archive_rar_uncomp_v2 *uncomp_v2) -+{ -+ int i; -+ rar_free_code(&uncomp_v2->maincode); -+ rar_free_code(&uncomp_v2->offsetcode); -+ rar_free_code(&uncomp_v2->lengthcode); -+ for (i = 0; i < 4; i++) -+ rar_free_code(&uncomp_v2->audiocode[i]); -+} -+ -+static bool rar_parse_codes_v2(ar_archive_rar *rar) -+{ -+ struct ar_archive_rar_uncomp_v2 *uncomp_v2 = &rar->uncomp.state.v2; -+ struct huffman_code precode; -+ uint8_t prelengths[19]; -+ uint16_t i, count; -+ int j, val, n; -+ bool ok = false; -+ -+ rar_free_codes_v2(uncomp_v2); -+ -+ if (!br_check(rar, 2)) -+ return false; -+ uncomp_v2->audioblock = br_bits(rar, 1) != 0; -+ if (!br_bits(rar, 1)) -+ memset(uncomp_v2->lengthtable, 0, sizeof(uncomp_v2->lengthtable)); -+ -+ if (uncomp_v2->audioblock) { -+ if (!br_check(rar, 2)) -+ return false; -+ uncomp_v2->numchannels = (uint8_t)br_bits(rar, 2) + 1; -+ count = uncomp_v2->numchannels * 257; -+ if (uncomp_v2->channel > uncomp_v2->numchannels) -+ uncomp_v2->channel = 0; -+ } -+ else -+ count = MAINCODE_SIZE_20 + OFFSETCODE_SIZE_20 + LENGTHCODE_SIZE_20; -+ -+ for (i = 0; i < 19; i++) { -+ if (!br_check(rar, 4)) -+ return false; -+ prelengths[i] = (uint8_t)br_bits(rar, 4); -+ } -+ -+ memset(&precode, 0, sizeof(precode)); -+ if (!rar_create_code(&precode, prelengths, 19)) -+ goto PrecodeError; -+ for (i = 0; i < count; ) { -+ val = rar_read_next_symbol(rar, &precode); -+ if (val < 0) -+ goto PrecodeError; -+ if (val < 16) { -+ uncomp_v2->lengthtable[i] = (uncomp_v2->lengthtable[i] + val) & 0x0F; -+ i++; -+ } -+ else if (val == 16) { -+ if (i == 0) { -+ warn("Invalid data in bitstream"); -+ goto PrecodeError; -+ } -+ if (!br_check(rar, 2)) -+ goto PrecodeError; -+ n = (uint8_t)br_bits(rar, 2) + 3; -+ for (j = 0; j < n && i < count; i++, j++) { -+ uncomp_v2->lengthtable[i] = uncomp_v2->lengthtable[i - 1]; -+ } -+ } -+ else { -+ if (val == 17) { -+ if (!br_check(rar, 3)) -+ goto PrecodeError; -+ n = (uint8_t)br_bits(rar, 3) + 3; -+ } -+ else { -+ if (!br_check(rar, 7)) -+ goto PrecodeError; -+ n = (uint8_t)br_bits(rar, 7) + 11; -+ } -+ for (j = 0; j < n && i < count; i++, j++) { -+ uncomp_v2->lengthtable[i] = 0; -+ } -+ } -+ } -+ ok = true; -+PrecodeError: -+ rar_free_code(&precode); -+ if (!ok) -+ return false; -+ -+ if (uncomp_v2->audioblock) { -+ for (i = 0; i < uncomp_v2->numchannels; i++) { -+ if (!rar_create_code(&uncomp_v2->audiocode[i], uncomp_v2->lengthtable + i * 257, 257)) -+ return false; -+ } -+ } -+ else { -+ if (!rar_create_code(&uncomp_v2->maincode, uncomp_v2->lengthtable, MAINCODE_SIZE_20)) -+ return false; -+ if (!rar_create_code(&uncomp_v2->offsetcode, uncomp_v2->lengthtable + MAINCODE_SIZE_20, OFFSETCODE_SIZE_20)) -+ return false; -+ if (!rar_create_code(&uncomp_v2->lengthcode, uncomp_v2->lengthtable + MAINCODE_SIZE_20 + OFFSETCODE_SIZE_20, LENGTHCODE_SIZE_20)) -+ return false; -+ } -+ -+ rar->uncomp.start_new_table = false; -+ return true; -+} -+ -+static uint8_t rar_decode_audio(struct AudioState *state, int8_t *channeldelta, int8_t delta) -+{ -+ uint8_t predbyte, byte; -+ int prederror; -+ -+ state->delta[3] = state->delta[2]; -+ state->delta[2] = state->delta[1]; -+ state->delta[1] = state->lastdelta - state->delta[0]; -+ state->delta[0] = state->lastdelta; -+ -+ predbyte = ((8 * state->lastbyte + state->weight[0] * state->delta[0] + state->weight[1] * state->delta[1] + state->weight[2] * state->delta[2] + state->weight[3] * state->delta[3] + state->weight[4] * *channeldelta) >> 3) & 0xFF; -+ byte = (predbyte - delta) & 0xFF; -+ -+ prederror = delta << 3; -+ state->error[0] += abs(prederror); -+ state->error[1] += abs(prederror - state->delta[0]); state->error[2] += abs(prederror + state->delta[0]); -+ state->error[3] += abs(prederror - state->delta[1]); state->error[4] += abs(prederror + state->delta[1]); -+ state->error[5] += abs(prederror - state->delta[2]); state->error[6] += abs(prederror + state->delta[2]); -+ state->error[7] += abs(prederror - state->delta[3]); state->error[8] += abs(prederror + state->delta[3]); -+ state->error[9] += abs(prederror - *channeldelta); state->error[10] += abs(prederror + *channeldelta); -+ -+ *channeldelta = state->lastdelta = (int8_t)(byte - state->lastbyte); -+ state->lastbyte = byte; -+ -+ if (!(++state->count & 0x1F)) { -+ uint8_t i, idx = 0; -+ for (i = 1; i < 11; i++) { -+ if (state->error[i] < state->error[idx]) -+ idx = i; -+ } -+ memset(state->error, 0, sizeof(state->error)); -+ -+ switch (idx) { -+ case 1: if (state->weight[0] >= -16) state->weight[0]--; break; -+ case 2: if (state->weight[0] < 16) state->weight[0]++; break; -+ case 3: if (state->weight[1] >= -16) state->weight[1]--; break; -+ case 4: if (state->weight[1] < 16) state->weight[1]++; break; -+ case 5: if (state->weight[2] >= -16) state->weight[2]--; break; -+ case 6: if (state->weight[2] < 16) state->weight[2]++; break; -+ case 7: if (state->weight[3] >= -16) state->weight[3]--; break; -+ case 8: if (state->weight[3] < 16) state->weight[3]++; break; -+ case 9: if (state->weight[4] >= -16) state->weight[4]--; break; -+ case 10: if (state->weight[4] < 16) state->weight[4]++; break; -+ } -+ } -+ -+ return byte; -+} -+ -+int64_t rar_expand_v2(ar_archive_rar *rar, int64_t end) -+{ -+ static const uint8_t lengthbases[] = -+ { 0, 1, 2, 3, 4, 5, 6, -+ 7, 8, 10, 12, 14, 16, 20, -+ 24, 28, 32, 40, 48, 56, 64, -+ 80, 96, 112, 128, 160, 192, 224 }; -+ static const uint8_t lengthbits[] = -+ { 0, 0, 0, 0, 0, 0, 0, -+ 0, 1, 1, 1, 1, 2, 2, -+ 2, 2, 3, 3, 3, 3, 4, -+ 4, 4, 4, 5, 5, 5, 5 }; -+ static const int32_t offsetbases[] = -+ { 0, 1, 2, 3, 4, 6, -+ 8, 12, 16, 24, 32, 48, -+ 64, 96, 128, 192, 256, 384, -+ 512, 768, 1024, 1536, 2048, 3072, -+ 4096, 6144, 8192, 12288, 16384, 24576, -+ 32768, 49152, 65536, 98304, 131072, 196608, -+ 262144, 327680, 393216, 458752, 524288, 589824, -+ 655360, 720896, 786432, 851968, 917504, 983040 }; -+ static const uint8_t offsetbits[] = -+ { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, -+ 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, -+ 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, -+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 }; -+ static const uint8_t shortbases[] = -+ { 0, 4, 8, 16, 32, 64, 128, 192 }; -+ static const uint8_t shortbits[] = -+ { 2, 2, 3, 4, 5, 6, 6, 6 }; -+ -+ struct ar_archive_rar_uncomp_v2 *uncomp_v2 = &rar->uncomp.state.v2; -+ LZSS *lzss = &rar->uncomp.lzss; -+ int symbol, offs, len; -+ -+ if ((uint64_t)end > rar->super.entry_size_uncompressed + rar->solid.size_total) -+ end = rar->super.entry_size_uncompressed + rar->solid.size_total; -+ -+ for (;;) { -+ if (lzss_position(lzss) >= end) -+ return end; -+ -+ if (uncomp_v2->audioblock) { -+ uint8_t byte; -+ symbol = rar_read_next_symbol(rar, &uncomp_v2->audiocode[uncomp_v2->channel]); -+ if (symbol < 0) -+ return -1; -+ if (symbol == 256) { -+ rar->uncomp.start_new_table = true; -+ return lzss_position(lzss); -+ } -+ byte = rar_decode_audio(&uncomp_v2->audiostate[uncomp_v2->channel], &uncomp_v2->channeldelta, (int8_t)(uint8_t)symbol); -+ uncomp_v2->channel++; -+ if (uncomp_v2->channel == uncomp_v2->numchannels) -+ uncomp_v2->channel = 0; -+ lzss_emit_literal(lzss, byte); -+ continue; -+ } -+ -+ symbol = rar_read_next_symbol(rar, &uncomp_v2->maincode); -+ if (symbol < 0) -+ return -1; -+ if (symbol < 256) { -+ lzss_emit_literal(lzss, (uint8_t)symbol); -+ continue; -+ } -+ if (symbol == 256) { -+ offs = uncomp_v2->lastoffset; -+ len = uncomp_v2->lastlength; -+ } -+ else if (symbol <= 260) { -+ int idx = symbol - 256; -+ int lensymbol = rar_read_next_symbol(rar, &uncomp_v2->lengthcode); -+ offs = uncomp_v2->oldoffset[(uncomp_v2->oldoffsetindex - idx) & 0x03]; -+ if (lensymbol < 0 || lensymbol > (int)(sizeof(lengthbases) / sizeof(lengthbases[0])) || lensymbol > (int)(sizeof(lengthbits) / sizeof(lengthbits[0]))) { -+ warn("Invalid data in bitstream"); -+ return -1; -+ } -+ len = lengthbases[lensymbol] + 2; -+ if (lengthbits[lensymbol] > 0) { -+ if (!br_check(rar, lengthbits[lensymbol])) -+ return -1; -+ len += (uint8_t)br_bits(rar, lengthbits[lensymbol]); -+ } -+ if (offs >= 0x40000) -+ len++; -+ if (offs >= 0x2000) -+ len++; -+ if (offs >= 0x101) -+ len++; -+ } -+ else if (symbol <= 268) { -+ int idx = symbol - 261; -+ offs = shortbases[idx] + 1; -+ if (shortbits[idx] > 0) { -+ if (!br_check(rar, shortbits[idx])) -+ return -1; -+ offs += (uint8_t)br_bits(rar, shortbits[idx]); -+ } -+ len = 2; -+ } -+ else if (symbol == 269) { -+ rar->uncomp.start_new_table = true; -+ return lzss_position(lzss); -+ } -+ else { -+ int idx = symbol - 270; -+ int offssymbol; -+ if (idx > (int)(sizeof(lengthbases) / sizeof(lengthbases[0])) || idx > (int)(sizeof(lengthbits) / sizeof(lengthbits[0]))) { -+ warn("Invalid data in bitstream"); -+ return -1; -+ } -+ len = lengthbases[idx] + 3; -+ if (lengthbits[idx] > 0) { -+ if (!br_check(rar, lengthbits[idx])) -+ return -1; -+ len += (uint8_t)br_bits(rar, lengthbits[idx]); -+ } -+ offssymbol = rar_read_next_symbol(rar, &uncomp_v2->offsetcode); -+ if (offssymbol < 0 || offssymbol > (int)(sizeof(offsetbases) / sizeof(offsetbases[0])) || offssymbol > (int)(sizeof(offsetbits) / sizeof(offsetbits[0]))) { -+ warn("Invalid data in bitstream"); -+ return -1; -+ } -+ offs = offsetbases[offssymbol] + 1; -+ if (offsetbits[offssymbol] > 0) { -+ if (!br_check(rar, offsetbits[offssymbol])) -+ return -1; -+ offs += (int)br_bits(rar, offsetbits[offssymbol]); -+ } -+ if (offs >= 0x40000) -+ len++; -+ if (offs >= 0x2000) -+ len++; -+ } -+ -+ uncomp_v2->lastoffset = uncomp_v2->oldoffset[uncomp_v2->oldoffsetindex++ & 0x03] = offs; -+ uncomp_v2->lastlength = len; -+ -+ lzss_emit_match(lzss, offs, len); -+ } -+} -+ -+/***** RAR version 3 decompression *****/ -+ -+static void rar_free_codes(struct ar_archive_rar_uncomp *uncomp) -+{ -+ struct ar_archive_rar_uncomp_v3 *uncomp_v3 = &uncomp->state.v3; -+ -+ if (uncomp->version == 2) { -+ rar_free_codes_v2(&uncomp->state.v2); -+ return; -+ } -+ -+ rar_free_code(&uncomp_v3->maincode); -+ rar_free_code(&uncomp_v3->offsetcode); -+ rar_free_code(&uncomp_v3->lowoffsetcode); -+ rar_free_code(&uncomp_v3->lengthcode); -+} -+ -+static bool rar_parse_codes(ar_archive_rar *rar) -+{ -+ struct ar_archive_rar_uncomp_v3 *uncomp_v3 = &rar->uncomp.state.v3; -+ -+ if (rar->uncomp.version == 2) -+ return rar_parse_codes_v2(rar); -+ -+ rar_free_codes(&rar->uncomp); -+ -+ br_clear_leftover_bits(&rar->uncomp); -+ -+ if (!br_check(rar, 1)) -+ return false; -+ uncomp_v3->is_ppmd_block = br_bits(rar, 1) != 0; -+ if (uncomp_v3->is_ppmd_block) { -+ uint8_t ppmd_flags; -+ uint32_t max_alloc = 0; -+ -+ if (!br_check(rar, 7)) -+ return false; -+ ppmd_flags = (uint8_t)br_bits(rar, 7); -+ if ((ppmd_flags & 0x20)) { -+ if (!br_check(rar, 8)) -+ return false; -+ max_alloc = ((uint8_t)br_bits(rar, 8) + 1) << 20; -+ } -+ if ((ppmd_flags & 0x40)) { -+ if (!br_check(rar, 8)) -+ return false; -+ uncomp_v3->ppmd_escape = (uint8_t)br_bits(rar, 8); -+ } -+ if ((ppmd_flags & 0x20)) { -+ uint32_t maxorder = (ppmd_flags & 0x1F) + 1; -+ if (maxorder == 1) -+ return false; -+ if (maxorder > 16) -+ maxorder = 16 + (maxorder - 16) * 3; -+ -+ Ppmd7_Free(&uncomp_v3->ppmd7_context, &gSzAlloc); -+ Ppmd7_Construct(&uncomp_v3->ppmd7_context); -+ if (!Ppmd7_Alloc(&uncomp_v3->ppmd7_context, max_alloc, &gSzAlloc)) { -+ warn("OOM during decompression"); -+ return false; -+ } -+ ByteIn_CreateVTable(&uncomp_v3->bytein, rar); -+ PpmdRAR_RangeDec_CreateVTable(&uncomp_v3->range_dec, &uncomp_v3->bytein.super); -+ PpmdRAR_RangeDec_Init(&uncomp_v3->range_dec); -+ Ppmd7_Init(&uncomp_v3->ppmd7_context, maxorder); -+ } -+ else { -+ if (!Ppmd7_WasAllocated(&uncomp_v3->ppmd7_context)) { -+ warn("Invalid data in bitstream"); /* invalid PPMd sequence */ -+ return false; -+ } -+ PpmdRAR_RangeDec_Init(&uncomp_v3->range_dec); -+ } -+ } -+ else { -+ struct huffman_code precode; -+ uint8_t bitlengths[20]; -+ uint8_t zerocount; -+ int i, j, val, n; -+ bool ok = false; -+ -+ if (!br_check(rar, 1)) -+ return false; -+ if (!br_bits(rar, 1)) -+ memset(uncomp_v3->lengthtable, 0, sizeof(uncomp_v3->lengthtable)); -+ memset(&bitlengths, 0, sizeof(bitlengths)); -+ for (i = 0; i < sizeof(bitlengths); i++) { -+ if (!br_check(rar, 4)) -+ return false; -+ bitlengths[i] = (uint8_t)br_bits(rar, 4); -+ if (bitlengths[i] == 0x0F) { -+ if (!br_check(rar, 4)) -+ return false; -+ zerocount = (uint8_t)br_bits(rar, 4); -+ if (zerocount) { -+ for (j = 0; j < zerocount + 2 && i < sizeof(bitlengths); j++) { -+ bitlengths[i++] = 0; -+ } -+ i--; -+ } -+ } -+ } -+ -+ memset(&precode, 0, sizeof(precode)); -+ if (!rar_create_code(&precode, bitlengths, sizeof(bitlengths))) -+ goto PrecodeError; -+ for (i = 0; i < HUFFMAN_TABLE_SIZE; ) { -+ val = rar_read_next_symbol(rar, &precode); -+ if (val < 0) -+ goto PrecodeError; -+ if (val < 16) { -+ uncomp_v3->lengthtable[i] = (uncomp_v3->lengthtable[i] + val) & 0x0F; -+ i++; -+ } -+ else if (val < 18) { -+ if (i == 0) { -+ warn("Invalid data in bitstream"); -+ goto PrecodeError; -+ } -+ if (val == 16) { -+ if (!br_check(rar, 3)) -+ goto PrecodeError; -+ n = (uint8_t)br_bits(rar, 3) + 3; -+ } -+ else { -+ if (!br_check(rar, 7)) -+ goto PrecodeError; -+ n = (uint8_t)br_bits(rar, 7) + 11; -+ } -+ for (j = 0; j < n && i < HUFFMAN_TABLE_SIZE; i++, j++) { -+ uncomp_v3->lengthtable[i] = uncomp_v3->lengthtable[i - 1]; -+ } -+ } -+ else { -+ if (val == 18) { -+ if (!br_check(rar, 3)) -+ goto PrecodeError; -+ n = (uint8_t)br_bits(rar, 3) + 3; -+ } -+ else { -+ if (!br_check(rar, 7)) -+ goto PrecodeError; -+ n = (uint8_t)br_bits(rar, 7) + 11; -+ } -+ for (j = 0; j < n && i < HUFFMAN_TABLE_SIZE; i++, j++) { -+ uncomp_v3->lengthtable[i] = 0; -+ } -+ } -+ } -+ ok = true; -+PrecodeError: -+ rar_free_code(&precode); -+ if (!ok) -+ return false; -+ -+ if (!rar_create_code(&uncomp_v3->maincode, uncomp_v3->lengthtable, MAINCODE_SIZE)) -+ return false; -+ if (!rar_create_code(&uncomp_v3->offsetcode, uncomp_v3->lengthtable + MAINCODE_SIZE, OFFSETCODE_SIZE)) -+ return false; -+ if (!rar_create_code(&uncomp_v3->lowoffsetcode, uncomp_v3->lengthtable + MAINCODE_SIZE + OFFSETCODE_SIZE, LOWOFFSETCODE_SIZE)) -+ return false; -+ if (!rar_create_code(&uncomp_v3->lengthcode, uncomp_v3->lengthtable + MAINCODE_SIZE + OFFSETCODE_SIZE + LOWOFFSETCODE_SIZE, LENGTHCODE_SIZE)) -+ return false; -+ } -+ -+ rar->uncomp.start_new_table = false; -+ return true; -+} -+ -+static bool rar_read_filter(ar_archive_rar *rar, bool (* decode_byte)(ar_archive_rar *rar, uint8_t *byte), int64_t *end) -+{ -+ uint8_t flags, val, *code; -+ uint16_t length, i; -+ -+ if (!decode_byte(rar, &flags)) -+ return false; -+ length = (flags & 0x07) + 1; -+ if (length == 7) { -+ if (!decode_byte(rar, &val)) -+ return false; -+ length = val + 7; -+ } -+ else if (length == 8) { -+ if (!decode_byte(rar, &val)) -+ return false; -+ length = val << 8; -+ if (!decode_byte(rar, &val)) -+ return false; -+ length |= val; -+ } -+ -+ code = malloc(length); -+ if (!code) { -+ warn("OOM during decompression"); -+ return false; -+ } -+ for (i = 0; i < length; i++) { -+ if (!decode_byte(rar, &code[i])) { -+ free(code); -+ return false; -+ } -+ } -+ if (!rar_parse_filter(rar, code, length, flags)) { -+ free(code); -+ return false; -+ } -+ free(code); -+ -+ if (rar->uncomp.state.v3.filters.filterstart < (size_t)*end) -+ *end = rar->uncomp.state.v3.filters.filterstart; -+ -+ return true; -+} -+ -+static inline bool rar_decode_ppmd7_symbol(struct ar_archive_rar_uncomp_v3 *uncomp_v3, Byte *symbol) -+{ -+ int value = Ppmd7_DecodeSymbol(&uncomp_v3->ppmd7_context, &uncomp_v3->range_dec.super); -+ if (value < 0) { -+ warn("Invalid data in bitstream"); /* invalid PPMd symbol */ -+ return false; -+ } -+ *symbol = (Byte)value; -+ return true; -+} -+ -+static bool rar_decode_byte(ar_archive_rar *rar, uint8_t *byte) -+{ -+ if (!br_check(rar, 8)) -+ return false; -+ *byte = (uint8_t)br_bits(rar, 8); -+ return true; -+} -+ -+static bool rar_decode_ppmd7_byte(ar_archive_rar *rar, uint8_t *byte) -+{ -+ return rar_decode_ppmd7_symbol(&rar->uncomp.state.v3, byte); -+} -+ -+static bool rar_handle_ppmd_sequence(ar_archive_rar *rar, int64_t *end) -+{ -+ struct ar_archive_rar_uncomp_v3 *uncomp_v3 = &rar->uncomp.state.v3; -+ LZSS *lzss = &rar->uncomp.lzss; -+ Byte sym, code, length; -+ int lzss_offset; -+ -+ if (!rar_decode_ppmd7_symbol(uncomp_v3, &sym)) -+ return false; -+ if (sym != uncomp_v3->ppmd_escape) { -+ lzss_emit_literal(lzss, sym); -+ return true; -+ } -+ -+ if (!rar_decode_ppmd7_symbol(uncomp_v3, &code)) -+ return false; -+ switch (code) { -+ case 0: -+ return rar_parse_codes(rar); -+ -+ case 2: -+ rar->uncomp.start_new_table = true; -+ return true; -+ -+ case 3: -+ return rar_read_filter(rar, rar_decode_ppmd7_byte, end); -+ -+ case 4: -+ if (!rar_decode_ppmd7_symbol(uncomp_v3, &code)) -+ return false; -+ lzss_offset = code << 16; -+ if (!rar_decode_ppmd7_symbol(uncomp_v3, &code)) -+ return false; -+ lzss_offset |= code << 8; -+ if (!rar_decode_ppmd7_symbol(uncomp_v3, &code)) -+ return false; -+ lzss_offset |= code; -+ if (!rar_decode_ppmd7_symbol(uncomp_v3, &length)) -+ return false; -+ lzss_emit_match(lzss, lzss_offset + 2, length + 32); -+ return true; -+ -+ case 5: -+ if (!rar_decode_ppmd7_symbol(uncomp_v3, &length)) -+ return false; -+ lzss_emit_match(lzss, 1, length + 4); -+ return true; -+ -+ default: -+ lzss_emit_literal(lzss, sym); -+ return true; -+ } -+} -+ -+int64_t rar_expand(ar_archive_rar *rar, int64_t end) -+{ -+ static const uint8_t lengthbases[] = -+ { 0, 1, 2, 3, 4, 5, 6, -+ 7, 8, 10, 12, 14, 16, 20, -+ 24, 28, 32, 40, 48, 56, 64, -+ 80, 96, 112, 128, 160, 192, 224 }; -+ static const uint8_t lengthbits[] = -+ { 0, 0, 0, 0, 0, 0, 0, -+ 0, 1, 1, 1, 1, 2, 2, -+ 2, 2, 3, 3, 3, 3, 4, -+ 4, 4, 4, 5, 5, 5, 5 }; -+ static const int32_t offsetbases[] = -+ { 0, 1, 2, 3, 4, 6, -+ 8, 12, 16, 24, 32, 48, -+ 64, 96, 128, 192, 256, 384, -+ 512, 768, 1024, 1536, 2048, 3072, -+ 4096, 6144, 8192, 12288, 16384, 24576, -+ 32768, 49152, 65536, 98304, 131072, 196608, -+ 262144, 327680, 393216, 458752, 524288, 589824, -+ 655360, 720896, 786432, 851968, 917504, 983040, -+ 1048576, 1310720, 1572864, 1835008, 2097152, 2359296, -+ 2621440, 2883584, 3145728, 3407872, 3670016, 3932160 }; -+ static const uint8_t offsetbits[] = -+ { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, -+ 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, -+ 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, -+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, -+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18 }; -+ static const uint8_t shortbases[] = -+ { 0, 4, 8, 16, 32, 64, 128, 192 }; -+ static const uint8_t shortbits[] = -+ { 2, 2, 3, 4, 5, 6, 6, 6 }; -+ -+ struct ar_archive_rar_uncomp_v3 *uncomp_v3 = &rar->uncomp.state.v3; -+ LZSS *lzss = &rar->uncomp.lzss; -+ int symbol, offs, len, i; -+ -+ if (rar->uncomp.version == 2) -+ return rar_expand_v2(rar, end); -+ -+ for (;;) { -+ if (lzss_position(lzss) >= end) -+ return end; -+ -+ if (uncomp_v3->is_ppmd_block) { -+ if (!rar_handle_ppmd_sequence(rar, &end)) -+ return -1; -+ if (rar->uncomp.start_new_table) -+ return lzss_position(lzss); -+ continue; -+ } -+ -+ symbol = rar_read_next_symbol(rar, &uncomp_v3->maincode); -+ if (symbol < 0) -+ return -1; -+ if (symbol < 256) { -+ lzss_emit_literal(lzss, (uint8_t)symbol); -+ continue; -+ } -+ if (symbol == 256) { -+ if (!br_check(rar, 1)) -+ return -1; -+ if (!br_bits(rar, 1)) { -+ if (!br_check(rar, 1)) -+ return -1; -+ rar->uncomp.start_new_table = br_bits(rar, 1) != 0; -+ return lzss_position(lzss); -+ } -+ if (!rar_parse_codes(rar)) -+ return -1; -+ continue; -+ } -+ if (symbol == 257) { -+ if (!rar_read_filter(rar, rar_decode_byte, &end)) -+ return -1; -+ continue; -+ } -+ if (symbol == 258) { -+ if (uncomp_v3->lastlength == 0) -+ continue; -+ offs = uncomp_v3->lastoffset; -+ len = uncomp_v3->lastlength; -+ } -+ else if (symbol <= 262) { -+ int idx = symbol - 259; -+ int lensymbol = rar_read_next_symbol(rar, &uncomp_v3->lengthcode); -+ offs = uncomp_v3->oldoffset[idx]; -+ if (lensymbol < 0 || lensymbol > (int)(sizeof(lengthbases) / sizeof(lengthbases[0])) || lensymbol > (int)(sizeof(lengthbits) / sizeof(lengthbits[0]))) { -+ warn("Invalid data in bitstream"); -+ return -1; -+ } -+ len = lengthbases[lensymbol] + 2; -+ if (lengthbits[lensymbol] > 0) { -+ if (!br_check(rar, lengthbits[lensymbol])) -+ return -1; -+ len += (uint8_t)br_bits(rar, lengthbits[lensymbol]); -+ } -+ for (i = idx; i > 0; i--) -+ uncomp_v3->oldoffset[i] = uncomp_v3->oldoffset[i - 1]; -+ uncomp_v3->oldoffset[0] = offs; -+ } -+ else if (symbol <= 270) { -+ int idx = symbol - 263; -+ offs = shortbases[idx] + 1; -+ if (shortbits[idx] > 0) { -+ if (!br_check(rar, shortbits[idx])) -+ return -1; -+ offs += (uint8_t)br_bits(rar, shortbits[idx]); -+ } -+ len = 2; -+ for (i = 3; i > 0; i--) -+ uncomp_v3->oldoffset[i] = uncomp_v3->oldoffset[i - 1]; -+ uncomp_v3->oldoffset[0] = offs; -+ } -+ else { -+ int idx = symbol - 271; -+ int offssymbol; -+ if (idx > (int)(sizeof(lengthbases) / sizeof(lengthbases[0])) || idx > (int)(sizeof(lengthbits) / sizeof(lengthbits[0]))) { -+ warn("Invalid data in bitstream"); -+ return -1; -+ } -+ len = lengthbases[idx] + 3; -+ if (lengthbits[idx] > 0) { -+ if (!br_check(rar, lengthbits[idx])) -+ return -1; -+ len += (uint8_t)br_bits(rar, lengthbits[idx]); -+ } -+ offssymbol = rar_read_next_symbol(rar, &uncomp_v3->offsetcode); -+ if (offssymbol < 0 || offssymbol > (int)(sizeof(offsetbases) / sizeof(offsetbases[0])) || offssymbol > (int)(sizeof(offsetbits) / sizeof(offsetbits[0]))) { -+ warn("Invalid data in bitstream"); -+ return -1; -+ } -+ offs = offsetbases[offssymbol] + 1; -+ if (offsetbits[offssymbol] > 0) { -+ if (offssymbol > 9) { -+ if (offsetbits[offssymbol] > 4) { -+ if (!br_check(rar, offsetbits[offssymbol] - 4)) -+ return -1; -+ offs += (int)br_bits(rar, offsetbits[offssymbol] - 4) << 4; -+ } -+ if (uncomp_v3->numlowoffsetrepeats > 0) { -+ uncomp_v3->numlowoffsetrepeats--; -+ offs += uncomp_v3->lastlowoffset; -+ } -+ else { -+ int lowoffsetsymbol = rar_read_next_symbol(rar, &uncomp_v3->lowoffsetcode); -+ if (lowoffsetsymbol < 0) -+ return -1; -+ if (lowoffsetsymbol == 16) { -+ uncomp_v3->numlowoffsetrepeats = 15; -+ offs += uncomp_v3->lastlowoffset; -+ } -+ else { -+ offs += lowoffsetsymbol; -+ uncomp_v3->lastlowoffset = lowoffsetsymbol; -+ } -+ } -+ } -+ else { -+ if (!br_check(rar, offsetbits[offssymbol])) -+ return -1; -+ offs += (int)br_bits(rar, offsetbits[offssymbol]); -+ } -+ } -+ -+ if (offs >= 0x40000) -+ len++; -+ if (offs >= 0x2000) -+ len++; -+ -+ for (i = 3; i > 0; i--) -+ uncomp_v3->oldoffset[i] = uncomp_v3->oldoffset[i - 1]; -+ uncomp_v3->oldoffset[0] = offs; -+ } -+ -+ uncomp_v3->lastoffset = offs; -+ uncomp_v3->lastlength = len; -+ -+ lzss_emit_match(lzss, offs, len); -+ } -+} -+ -+bool rar_uncompress_part(ar_archive_rar *rar, void *buffer, size_t buffer_size) -+{ -+ struct ar_archive_rar_uncomp *uncomp = &rar->uncomp; -+ struct ar_archive_rar_uncomp_v3 *uncomp_v3 = NULL; -+ size_t end; -+ -+ if (!rar_init_uncompress(uncomp, rar->entry.version)) -+ return false; -+ if (uncomp->version == 3) -+ uncomp_v3 = &uncomp->state.v3; -+ -+ for (;;) { -+ if (uncomp_v3 && uncomp_v3->filters.bytes_ready > 0) { -+ size_t count = smin(uncomp_v3->filters.bytes_ready, buffer_size); -+ memcpy(buffer, uncomp_v3->filters.bytes, count); -+ uncomp_v3->filters.bytes_ready -= count; -+ uncomp_v3->filters.bytes += count; -+ rar->progress.bytes_done += count; -+ buffer_size -= count; -+ buffer = (uint8_t *)buffer + count; -+ if (rar->progress.bytes_done == rar->super.entry_size_uncompressed) -+ goto FinishBlock; -+ } -+ else if (uncomp->bytes_ready > 0) { -+ int count = (int)smin(uncomp->bytes_ready, buffer_size); -+ lzss_copy_bytes_from_window(&uncomp->lzss, buffer, rar->progress.bytes_done + rar->solid.size_total, count); -+ uncomp->bytes_ready -= count; -+ rar->progress.bytes_done += count; -+ buffer_size -= count; -+ buffer = (uint8_t *)buffer + count; -+ } -+ if (buffer_size == 0) -+ return true; -+ -+ if (uncomp->br.at_eof) -+ return false; -+ -+ if (uncomp_v3 && uncomp_v3->filters.lastend == uncomp_v3->filters.filterstart) { -+ if (!rar_run_filters(rar)) -+ return false; -+ continue; -+ } -+ -+FinishBlock: -+ if (uncomp->start_new_table && !rar_parse_codes(rar)) -+ return false; -+ -+ end = rar->progress.bytes_done + rar->solid.size_total + LZSS_WINDOW_SIZE - LZSS_OVERFLOW_SIZE; -+ if (uncomp_v3 && uncomp_v3->filters.filterstart < end) -+ end = uncomp_v3->filters.filterstart; -+ end = (size_t)rar_expand(rar, end); -+ if (end == (size_t)-1 || end < rar->progress.bytes_done + rar->solid.size_total) -+ return false; -+ uncomp->bytes_ready = end - rar->progress.bytes_done - rar->solid.size_total; -+ if (uncomp_v3) -+ uncomp_v3->filters.lastend = end; -+ -+ if (uncomp_v3 && uncomp_v3->is_ppmd_block && uncomp->start_new_table) -+ goto FinishBlock; -+ } -+} -diff --git a/cut-n-paste/unarr/unarr.h b/cut-n-paste/unarr/unarr.h -new file mode 100644 -index 00000000..5ef7447c ---- /dev/null -+++ b/cut-n-paste/unarr/unarr.h -@@ -0,0 +1,94 @@ -+/* Copyright 2015 the unarr project authors (see AUTHORS file). -+ License: LGPLv3 */ -+ -+#ifndef unarr_h -+#define unarr_h -+ -+#include -+#include -+#include -+typedef int64_t off64_t; -+typedef int64_t time64_t; -+ -+#define UNARR_API_VERSION 100 -+ -+/***** common/stream *****/ -+ -+typedef struct ar_stream_s ar_stream; -+ -+/* opens a read-only stream for the given file path; returns NULL on error */ -+ar_stream *ar_open_file(const char *path); -+#ifdef _WIN32 -+ar_stream *ar_open_file_w(const wchar_t *path); -+#endif -+/* opens a read-only stream for the given chunk of memory; the pointer must be valid until ar_close is called */ -+ar_stream *ar_open_memory(const void *data, size_t datalen); -+#ifdef _WIN32 -+typedef struct IStream IStream; -+/* opens a read-only stream based on the given IStream */ -+ar_stream *ar_open_istream(IStream *stream); -+#endif -+ -+/* closes the stream and releases underlying resources */ -+void ar_close(ar_stream *stream); -+/* tries to read 'count' bytes into buffer, advancing the read offset pointer; returns the actual number of bytes read */ -+size_t ar_read(ar_stream *stream, void *buffer, size_t count); -+/* moves the read offset pointer (same as fseek); returns false on failure */ -+bool ar_seek(ar_stream *stream, off64_t offset, int origin); -+/* shortcut for ar_seek(stream, count, SEEK_CUR); returns false on failure */ -+bool ar_skip(ar_stream *stream, off64_t count); -+/* returns the current read offset (or 0 on error) */ -+off64_t ar_tell(ar_stream *stream); -+ -+/***** common/unarr *****/ -+ -+typedef struct ar_archive_s ar_archive; -+ -+/* frees all data stored for the given archive; does not close the underlying stream */ -+void ar_close_archive(ar_archive *ar); -+/* reads the next archive entry; returns false on error or at the end of the file (use ar_at_eof to distinguish the two cases) */ -+bool ar_parse_entry(ar_archive *ar); -+/* reads the archive entry at the given offset as returned by ar_entry_get_offset (offset 0 always restarts at the first entry); should always succeed */ -+bool ar_parse_entry_at(ar_archive *ar, off64_t offset); -+/* reads the (first) archive entry associated with the given name; returns false if the entry couldn't be found */ -+bool ar_parse_entry_for(ar_archive *ar, const char *entry_name); -+/* returns whether the last ar_parse_entry call has reached the file's expected end */ -+bool ar_at_eof(ar_archive *ar); -+ -+/* returns the name of the current entry as UTF-8 string; this pointer is only valid until the next call to ar_parse_entry; returns NULL on failure */ -+const char *ar_entry_get_name(ar_archive *ar); -+/* returns the stream offset of the current entry for use with ar_parse_entry_at */ -+off64_t ar_entry_get_offset(ar_archive *ar); -+/* returns the total size of uncompressed data of the current entry; read exactly that many bytes using ar_entry_uncompress */ -+size_t ar_entry_get_size(ar_archive *ar); -+/* returns the stored modification date of the current entry in 100ns since 1601/01/01 */ -+time64_t ar_entry_get_filetime(ar_archive *ar); -+/* WARNING: don't manually seek in the stream between ar_parse_entry and the last corresponding ar_entry_uncompress call! */ -+/* uncompresses the next 'count' bytes of the current entry into buffer; returns false on error */ -+bool ar_entry_uncompress(ar_archive *ar, void *buffer, size_t count); -+ -+/* copies at most 'count' bytes of the archive's global comment (if any) into buffer; returns the actual amout of bytes copied (or, if 'buffer' is NULL, the required buffer size) */ -+size_t ar_get_global_comment(ar_archive *ar, void *buffer, size_t count); -+ -+/***** rar/rar *****/ -+ -+/* checks whether 'stream' could contain RAR data and prepares for archive listing/extraction; returns NULL on failure */ -+ar_archive *ar_open_rar_archive(ar_stream *stream); -+ -+/***** tar/tar *****/ -+ -+/* checks whether 'stream' could contain TAR data and prepares for archive listing/extraction; returns NULL on failure */ -+ar_archive *ar_open_tar_archive(ar_stream *stream); -+ -+/***** zip/zip *****/ -+ -+/* checks whether 'stream' could contain ZIP data and prepares for archive listing/extraction; returns NULL on failure */ -+/* set deflatedonly for extracting XPS, EPUB, etc. documents where non-Deflate compression methods are not supported by specification */ -+ar_archive *ar_open_zip_archive(ar_stream *stream, bool deflatedonly); -+ -+/***** _7z/_7z *****/ -+ -+/* checks whether 'stream' could contain 7Z data and prepares for archive listing/extraction; returns NULL on failure */ -+ar_archive *ar_open_7z_archive(ar_stream *stream); -+ -+#endif --- -2.13.0 - - -From 9ec025b3d17edebc0bbdd466f789c4740bbb1268 Mon Sep 17 00:00:00 2001 -From: Bastien Nocera -Date: Wed, 15 Mar 2017 18:28:42 +0100 -Subject: [PATCH 04/10] comics: Fix "no previous prototype for..." errors - -Functions that aren't used outside the C file should be marked as -static. - -https://bugzilla.gnome.org/show_bug.cgi?id=720742 ---- - cut-n-paste/unarr/lzmasdk/LzmaDec.c | 2 +- - cut-n-paste/unarr/rar/uncompress-rar.c | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/cut-n-paste/unarr/lzmasdk/LzmaDec.c b/cut-n-paste/unarr/lzmasdk/LzmaDec.c -index bbf650de..038b000a 100644 ---- a/cut-n-paste/unarr/lzmasdk/LzmaDec.c -+++ b/cut-n-paste/unarr/lzmasdk/LzmaDec.c -@@ -715,7 +715,7 @@ static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) - p->needFlush = 0; - } - --void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) -+static void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) - { - p->needFlush = 1; - p->remainLen = 0; -diff --git a/cut-n-paste/unarr/rar/uncompress-rar.c b/cut-n-paste/unarr/rar/uncompress-rar.c -index 74c2ea61..3df490d4 100644 ---- a/cut-n-paste/unarr/rar/uncompress-rar.c -+++ b/cut-n-paste/unarr/rar/uncompress-rar.c -@@ -358,7 +358,7 @@ static uint8_t rar_decode_audio(struct AudioState *state, int8_t *channeldelta, - return byte; - } - --int64_t rar_expand_v2(ar_archive_rar *rar, int64_t end) -+static int64_t rar_expand_v2(ar_archive_rar *rar, int64_t end) - { - static const uint8_t lengthbases[] = - { 0, 1, 2, 3, 4, 5, 6, --- -2.13.0 - - -From 5ab715e60cad52ed1a71e3269e6120851bd8d221 Mon Sep 17 00:00:00 2001 -From: Bastien Nocera -Date: Wed, 15 Mar 2017 18:28:34 +0100 -Subject: [PATCH 05/10] =?UTF-8?q?comics:=20Fix=20"function=20declaration?= - =?UTF-8?q?=20isn=E2=80=99t=20a=20prototype"=20errors?= -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Need to use "void" as the arguments when declaring. - -FIXME: Should be upstreamed! - -https://bugzilla.gnome.org/show_bug.cgi?id=720742 ---- - cut-n-paste/unarr/lzmasdk/CpuArch.h | 4 ++-- - cut-n-paste/unarr/rar/rarvm.h | 2 +- - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/cut-n-paste/unarr/lzmasdk/CpuArch.h b/cut-n-paste/unarr/lzmasdk/CpuArch.h -index 4fee0093..e3c95257 100644 ---- a/cut-n-paste/unarr/lzmasdk/CpuArch.h -+++ b/cut-n-paste/unarr/lzmasdk/CpuArch.h -@@ -147,8 +147,8 @@ int x86cpuid_GetFirm(const Cx86cpuid *p); - #define x86cpuid_GetModel(p) (((p)->ver >> 4) & 0xF00F) - #define x86cpuid_GetStepping(p) ((p)->ver & 0xF) - --Bool CPU_Is_InOrder(); --Bool CPU_Is_Aes_Supported(); -+Bool CPU_Is_InOrder(void); -+Bool CPU_Is_Aes_Supported(void); - - #endif - -diff --git a/cut-n-paste/unarr/rar/rarvm.h b/cut-n-paste/unarr/rar/rarvm.h -index 4fb0b47f..51567a9a 100644 ---- a/cut-n-paste/unarr/rar/rarvm.h -+++ b/cut-n-paste/unarr/rar/rarvm.h -@@ -81,7 +81,7 @@ enum { - RARNumberOfInstructions = 40, - }; - --RARProgram *RARCreateProgram(); -+RARProgram *RARCreateProgram(void); - void RARDeleteProgram(RARProgram *prog); - bool RARProgramAddInstr(RARProgram *prog, uint8_t instruction, bool bytemode); - bool RARSetLastInstrOperands(RARProgram *prog, uint8_t addressingmode1, uint32_t value1, uint8_t addressingmode2, uint32_t value2); --- -2.13.0 - - -From 283c897b5e4bb935014ab6ebd3d424bdead49c8c Mon Sep 17 00:00:00 2001 -From: Bastien Nocera -Date: Wed, 15 Mar 2017 19:00:50 +0100 -Subject: [PATCH 06/10] comics: Add unarr support - -We support all the type of RAR archives now! - -https://bugzilla.gnome.org/show_bug.cgi?id=720742 ---- - backend/comics/Makefile.am | 2 ++ - backend/comics/ev-archive.c | 50 ++++++++++++++++++++++++++++++++++----------- - 2 files changed, 40 insertions(+), 12 deletions(-) - -diff --git a/backend/comics/Makefile.am b/backend/comics/Makefile.am -index 856f469c..1e87d049 100644 ---- a/backend/comics/Makefile.am -+++ b/backend/comics/Makefile.am -@@ -9,6 +9,7 @@ libcomicsdocument_la_SOURCES = \ - libcomicsdocument_la_CPPFLAGS = \ - -I$(top_srcdir) \ - -I$(top_srcdir)/libdocument \ -+ -I$(top_srcdir)/cut-n-paste \ - -DGNOMELOCALEDIR=\"$(datadir)/locale\" \ - -DEVINCE_COMPILATION \ - $(AM_CPPFLAGS) -@@ -22,6 +23,7 @@ libcomicsdocument_la_CFLAGS = \ - libcomicsdocument_la_LDFLAGS = $(BACKEND_LIBTOOL_FLAGS) - libcomicsdocument_la_LIBADD = \ - $(top_builddir)/libdocument/libevdocument3.la \ -+ $(top_builddir)/cut-n-paste/unarr/libunarr.la \ - $(LIBARCHIVE_LIBS) \ - $(BACKEND_LIBS) \ - $(LIB_LIBS) -diff --git a/backend/comics/ev-archive.c b/backend/comics/ev-archive.c -index 333db470..4c423ef2 100644 ---- a/backend/comics/ev-archive.c -+++ b/backend/comics/ev-archive.c -@@ -22,6 +22,7 @@ - - #include - #include -+#include - #include - - #define BUFFER_SIZE (64 * 1024) -@@ -33,6 +34,10 @@ struct _EvArchive { - /* libarchive */ - struct archive *libar; - struct archive_entry *libar_entry; -+ -+ /* unarr */ -+ ar_stream *unarr_s; -+ ar_archive *unarr; - }; - - G_DEFINE_TYPE(EvArchive, ev_archive, G_TYPE_OBJECT); -@@ -44,6 +49,8 @@ ev_archive_finalize (GObject *object) - - switch (archive->type) { - case EV_ARCHIVE_TYPE_RAR: -+ g_clear_pointer (&archive->unarr, ar_close_archive); -+ g_clear_pointer (&archive->unarr_s, ar_close); - break; - case EV_ARCHIVE_TYPE_ZIP: - case EV_ARCHIVE_TYPE_7Z: -@@ -103,9 +110,8 @@ ev_archive_set_archive_type (EvArchive *archive, - - switch (archive_type) { - case EV_ARCHIVE_TYPE_RAR: -- /* Disabled until this is fixed: -- * https://github.com/libarchive/libarchive/issues/373 */ -- return FALSE; -+ archive->type = archive_type; -+ break; - case EV_ARCHIVE_TYPE_ZIP: - case EV_ARCHIVE_TYPE_7Z: - case EV_ARCHIVE_TYPE_TAR: -@@ -133,9 +139,19 @@ ev_archive_open_filename (EvArchive *archive, - case EV_ARCHIVE_TYPE_NONE: - g_assert_not_reached (); - case EV_ARCHIVE_TYPE_RAR: -- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, -- "Archive type 'RAR' not supported"); -- return FALSE; -+ archive->unarr_s = ar_open_file (path); -+ if (archive->unarr_s == NULL) { -+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, -+ "Error opening archive"); -+ return FALSE; -+ } -+ archive->unarr = ar_open_rar_archive (archive->unarr_s); -+ if (archive->unarr == NULL) { -+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, -+ "Error opening RAR archive"); -+ return FALSE; -+ } -+ return TRUE; - case EV_ARCHIVE_TYPE_ZIP: - case EV_ARCHIVE_TYPE_7Z: - case EV_ARCHIVE_TYPE_TAR: -@@ -190,7 +206,7 @@ ev_archive_read_next_header (EvArchive *archive, - switch (archive->type) { - case EV_ARCHIVE_TYPE_NONE: - case EV_ARCHIVE_TYPE_RAR: -- g_assert_not_reached (); -+ return ar_parse_entry (archive->unarr); - case EV_ARCHIVE_TYPE_ZIP: - case EV_ARCHIVE_TYPE_7Z: - case EV_ARCHIVE_TYPE_TAR: -@@ -205,16 +221,17 @@ ev_archive_get_entry_pathname (EvArchive *archive) - { - g_return_val_if_fail (EV_IS_ARCHIVE (archive), NULL); - g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, NULL); -- g_return_val_if_fail (archive->libar_entry != NULL, NULL); - - switch (archive->type) { - case EV_ARCHIVE_TYPE_NONE: - g_assert_not_reached (); - case EV_ARCHIVE_TYPE_RAR: -- return NULL; -+ g_return_val_if_fail (archive->unarr != NULL, NULL); -+ return ar_entry_get_name (archive->unarr); - case EV_ARCHIVE_TYPE_ZIP: - case EV_ARCHIVE_TYPE_7Z: - case EV_ARCHIVE_TYPE_TAR: -+ g_return_val_if_fail (archive->libar_entry != NULL, NULL); - return archive_entry_pathname (archive->libar_entry); - } - -@@ -226,15 +243,17 @@ ev_archive_get_entry_size (EvArchive *archive) - { - g_return_val_if_fail (EV_IS_ARCHIVE (archive), -1); - g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, -1); -- g_return_val_if_fail (archive->libar_entry != NULL, -1); - - switch (archive->type) { - case EV_ARCHIVE_TYPE_RAR: -+ g_return_val_if_fail (archive->unarr != NULL, -1); -+ return ar_entry_get_size (archive->unarr); - case EV_ARCHIVE_TYPE_NONE: - g_assert_not_reached (); - case EV_ARCHIVE_TYPE_ZIP: - case EV_ARCHIVE_TYPE_7Z: - case EV_ARCHIVE_TYPE_TAR: -+ g_return_val_if_fail (archive->libar_entry != NULL, -1); - return archive_entry_size (archive->libar_entry); - } - -@@ -251,15 +270,22 @@ ev_archive_read_data (EvArchive *archive, - - g_return_val_if_fail (EV_IS_ARCHIVE (archive), -1); - g_return_val_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE, -1); -- g_return_val_if_fail (archive->libar_entry != NULL, -1); - - switch (archive->type) { - case EV_ARCHIVE_TYPE_RAR: - case EV_ARCHIVE_TYPE_NONE: -- g_assert_not_reached (); -+ g_return_val_if_fail (archive->unarr != NULL, -1); -+ if (!ar_entry_uncompress (archive->unarr, buf, count)) { -+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, -+ "Failed to decompress RAR data"); -+ return -1; -+ } -+ r = count; -+ break; - case EV_ARCHIVE_TYPE_ZIP: - case EV_ARCHIVE_TYPE_7Z: - case EV_ARCHIVE_TYPE_TAR: -+ g_return_val_if_fail (archive->libar_entry != NULL, -1); - r = archive_read_data (archive->libar, buf, count); - if (r < 0) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, --- -2.13.0 - - -From adcd3dff47d20e657c5b825ed5192a3e8cdda444 Mon Sep 17 00:00:00 2001 -From: Carlos Garcia Campos -Date: Sat, 25 Mar 2017 12:34:38 +0100 -Subject: [PATCH 07/10] comics: Add ev_archive_reset() - -And use it instead of destroying and re-creating the EvArchive. This way -we don't need to keep the archive type in the document either. ---- - backend/comics/comics-document.c | 17 +++-------------- - backend/comics/ev-archive.c | 32 +++++++++++++++++++++++++++----- - backend/comics/ev-archive.h | 1 + - 3 files changed, 31 insertions(+), 19 deletions(-) - -diff --git a/backend/comics/comics-document.c b/backend/comics/comics-document.c -index 87c25270..5e07df4d 100644 ---- a/backend/comics/comics-document.c -+++ b/backend/comics/comics-document.c -@@ -49,7 +49,6 @@ struct _ComicsDocument - { - EvDocument parent_instance; - EvArchive *archive; -- EvArchiveType archive_type; - gchar *archive_path; - gchar *archive_uri; - GPtrArray *page_names; -@@ -59,14 +58,6 @@ static GSList* get_supported_image_extensions (void); - - EV_BACKEND_REGISTER (ComicsDocument, comics_document) - --static void --comics_document_reset_archive (ComicsDocument *comics_document) --{ -- g_clear_object (&comics_document->archive); -- comics_document->archive = ev_archive_new (); -- ev_archive_set_archive_type (comics_document->archive, comics_document->archive_type); --} -- - static char ** - comics_document_list (ComicsDocument *comics_document) - { -@@ -104,7 +95,7 @@ comics_document_list (ComicsDocument *comics_document) - } - - out: -- comics_document_reset_archive (comics_document); -+ ev_archive_reset (comics_document->archive); - return ret; - } - -@@ -202,8 +193,6 @@ comics_document_load (EvDocument *document, - } - g_free (mime_type); - -- comics_document->archive_type = ev_archive_get_archive_type (comics_document->archive); -- - /* Get list of files in archive */ - cb_files = comics_document_list (comics_document); - if (!cb_files) { -@@ -354,7 +343,7 @@ comics_document_get_page_size (EvDocument *document, - } - - out: -- comics_document_reset_archive (comics_document); -+ ev_archive_reset (comics_document->archive); - } - - static void -@@ -439,7 +428,7 @@ comics_document_render_pixbuf (EvDocument *document, - g_object_unref (loader); - - out: -- comics_document_reset_archive (comics_document); -+ ev_archive_reset (comics_document->archive); - return rotated_pixbuf; - } - -diff --git a/backend/comics/ev-archive.c b/backend/comics/ev-archive.c -index 4c423ef2..e8a93682 100644 ---- a/backend/comics/ev-archive.c -+++ b/backend/comics/ev-archive.c -@@ -36,7 +36,7 @@ struct _EvArchive { - struct archive_entry *libar_entry; - - /* unarr */ -- ar_stream *unarr_s; -+ ar_stream *unarr_stream; - ar_archive *unarr; - }; - -@@ -50,7 +50,7 @@ ev_archive_finalize (GObject *object) - switch (archive->type) { - case EV_ARCHIVE_TYPE_RAR: - g_clear_pointer (&archive->unarr, ar_close_archive); -- g_clear_pointer (&archive->unarr_s, ar_close); -+ g_clear_pointer (&archive->unarr_stream, ar_close); - break; - case EV_ARCHIVE_TYPE_ZIP: - case EV_ARCHIVE_TYPE_7Z: -@@ -139,13 +139,13 @@ ev_archive_open_filename (EvArchive *archive, - case EV_ARCHIVE_TYPE_NONE: - g_assert_not_reached (); - case EV_ARCHIVE_TYPE_RAR: -- archive->unarr_s = ar_open_file (path); -- if (archive->unarr_s == NULL) { -+ archive->unarr_stream = ar_open_file (path); -+ if (archive->unarr_stream == NULL) { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Error opening archive"); - return FALSE; - } -- archive->unarr = ar_open_rar_archive (archive->unarr_s); -+ archive->unarr = ar_open_rar_archive (archive->unarr_stream); - if (archive->unarr == NULL) { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Error opening RAR archive"); -@@ -297,6 +297,28 @@ ev_archive_read_data (EvArchive *archive, - return r; - } - -+void -+ev_archive_reset (EvArchive *archive) -+{ -+ g_return_if_fail (EV_IS_ARCHIVE (archive)); -+ g_return_if_fail (archive->type != EV_ARCHIVE_TYPE_NONE); -+ -+ switch (archive->type) { -+ case EV_ARCHIVE_TYPE_RAR: -+ g_clear_pointer (&archive->unarr, ar_close_archive); -+ g_clear_pointer (&archive->unarr_stream, ar_close); -+ break; -+ case EV_ARCHIVE_TYPE_ZIP: -+ case EV_ARCHIVE_TYPE_7Z: -+ case EV_ARCHIVE_TYPE_TAR: -+ g_clear_pointer (&archive->libar, archive_free); -+ libarchive_set_archive_type (archive, archive->type); -+ break; -+ default: -+ g_assert_not_reached (); -+ } -+} -+ - static void - ev_archive_init (EvArchive *archive) - { -diff --git a/backend/comics/ev-archive.h b/backend/comics/ev-archive.h -index 3e206939..cb526698 100644 ---- a/backend/comics/ev-archive.h -+++ b/backend/comics/ev-archive.h -@@ -50,6 +50,7 @@ gssize ev_archive_read_data (EvArchive *archive, - void *buf, - gsize count, - GError **error); -+void ev_archive_reset (EvArchive *archive); - - G_END_DECLS - --- -2.13.0 - - -From 5a81953bb79d3398bf143e8499cde3c6b527ba05 Mon Sep 17 00:00:00 2001 -From: Carlos Garcia Campos -Date: Sat, 25 Mar 2017 12:38:07 +0100 -Subject: [PATCH 08/10] comic: correctly handle NONE archive type in several - methods - ---- - backend/comics/ev-archive.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/backend/comics/ev-archive.c b/backend/comics/ev-archive.c -index e8a93682..7556a49c 100644 ---- a/backend/comics/ev-archive.c -+++ b/backend/comics/ev-archive.c -@@ -205,6 +205,7 @@ ev_archive_read_next_header (EvArchive *archive, - - switch (archive->type) { - case EV_ARCHIVE_TYPE_NONE: -+ g_assert_not_reached (); - case EV_ARCHIVE_TYPE_RAR: - return ar_parse_entry (archive->unarr); - case EV_ARCHIVE_TYPE_ZIP: -@@ -273,7 +274,6 @@ ev_archive_read_data (EvArchive *archive, - - switch (archive->type) { - case EV_ARCHIVE_TYPE_RAR: -- case EV_ARCHIVE_TYPE_NONE: - g_return_val_if_fail (archive->unarr != NULL, -1); - if (!ar_entry_uncompress (archive->unarr, buf, count)) { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, -@@ -282,6 +282,8 @@ ev_archive_read_data (EvArchive *archive, - } - r = count; - break; -+ case EV_ARCHIVE_TYPE_NONE: -+ g_assert_not_reached (); - case EV_ARCHIVE_TYPE_ZIP: - case EV_ARCHIVE_TYPE_7Z: - case EV_ARCHIVE_TYPE_TAR: --- -2.13.0 - - -From f919d85005d0573c92eb2df231855704c90a8602 Mon Sep 17 00:00:00 2001 -From: Bastien Nocera -Date: Tue, 11 Jul 2017 13:41:09 +0200 -Subject: [PATCH 09/10] comics: Don't throw errors in a loop if image is not - readable - -If the file inside the comics archive isn't a readable image file, then -the loader would get closed but we'd keep trying to feed it data, -leading to tons of warnings. - -Exit early with the gdk-pixbuf loader error instead. - -https://bugzilla.gnome.org/show_bug.cgi?id=784790 ---- - backend/comics/comics-document.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/backend/comics/comics-document.c b/backend/comics/comics-document.c -index 5e07df4d..ee060091 100644 ---- a/backend/comics/comics-document.c -+++ b/backend/comics/comics-document.c -@@ -321,7 +321,10 @@ comics_document_get_page_size (EvDocument *document, - - read = ev_archive_read_data (comics_document->archive, buf, sizeof(buf), &error); - while (read > 0 && !info.got_info) { -- gdk_pixbuf_loader_write (loader, (guchar *) buf, read, NULL); -+ if (!gdk_pixbuf_loader_write (loader, (guchar *) buf, read, &error)) { -+ read = -1; -+ break; -+ } - read = ev_archive_read_data (comics_document->archive, buf, BLOCK_SIZE, &error); - } - if (read < 0) { --- -2.13.0 - - -From 42dbbf4f8236c83c9c7101b34b97ea3face872d4 Mon Sep 17 00:00:00 2001 -From: Bastien Nocera -Date: Wed, 12 Jul 2017 12:53:19 +0200 -Subject: [PATCH 10/10] comics: Fix decoding some files in RAR archives - -The unarr RAR decoder doesn't like it when we request more data than is -available: -! rar.c:169: Requesting too much data (3563 < 10240) - -Clamp the size of the read request to the data left to read. - -https://bugzilla.gnome.org/show_bug.cgi?id=784842 ---- - backend/comics/comics-document.c | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - -diff --git a/backend/comics/comics-document.c b/backend/comics/comics-document.c -index ee060091..a913641d 100644 ---- a/backend/comics/comics-document.c -+++ b/backend/comics/comics-document.c -@@ -318,14 +318,19 @@ comics_document_get_page_size (EvDocument *document, - if (g_strcmp0 (name, page_path) == 0) { - char buf[BLOCK_SIZE]; - gssize read; -+ gint64 left; - -- read = ev_archive_read_data (comics_document->archive, buf, sizeof(buf), &error); -+ left = ev_archive_get_entry_size (comics_document->archive); -+ read = ev_archive_read_data (comics_document->archive, buf, -+ MIN(BLOCK_SIZE, left), &error); - while (read > 0 && !info.got_info) { - if (!gdk_pixbuf_loader_write (loader, (guchar *) buf, read, &error)) { - read = -1; - break; - } -- read = ev_archive_read_data (comics_document->archive, buf, BLOCK_SIZE, &error); -+ left -= read; -+ read = ev_archive_read_data (comics_document->archive, buf, -+ MIN(BLOCK_SIZE, left), &error); - } - if (read < 0) { - g_warning ("Fatal error reading '%s' in archive: %s", name, error->message); --- -2.13.0 - diff --git a/evince.spec b/evince.spec index 3e4122e..d770c83 100644 --- a/evince.spec +++ b/evince.spec @@ -4,24 +4,20 @@ %global gxps_version 0.2.1 Name: evince -Version: 3.24.0 -Release: 4%{?dist} +Version: 3.25.4 +Release: 1%{?dist} Summary: Document viewer License: GPLv2+ and GPLv3+ and LGPLv2+ and MIT and Afmparse URL: https://wiki.gnome.org/Apps/Evince -Source0: https://download.gnome.org/sources/%{name}/3.24/%{name}-%{version}.tar.xz +Source0: https://download.gnome.org/sources/%{name}/3.25/%{name}-%{version}.tar.xz Patch0: evince-3.21.4-NPNVToolKit.patch -#https://bugzilla.gnome.org/show_bug.cgi?id=777082 -Patch2: 0001-Resolves-rhbz-1404656-crash-on-opening-second-evince.patch #https://bugzilla.gnome.org/show_bug.cgi?id=766749 Patch3: 0001-Resolves-deb-762530-rhbz-1061177-add-man-pages.patch Patch4: 0001-Resolves-rhbz-1358249-page-up-down.patch -Patch5: 0001-sidebar-thumbnails-fix-clunky-scrolling.patch Patch6: 0001-Revert-Bump-poppler-requirements-to-0.33.0.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1468488 -Patch7: evince-libarchive-gnome-3-24.patch BuildRequires: pkgconfig(adwaita-icon-theme) BuildRequires: pkgconfig(gio-unix-2.0) >= %{glib2_version} @@ -269,6 +265,9 @@ glib-compile-schemas %{_datadir}/glib-2.0/schemas >&/dev/null ||: %{_libdir}/mozilla/plugins/libevbrowserplugin.so %changelog +* Thu Jul 27 2017 Kalev Lember - 3.25.4-1 +- Update to 3.25.4 + * Wed Jul 26 2017 Fedora Release Engineering - 3.24.0-4 - Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild diff --git a/sources b/sources index 166cfce..be042dd 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (evince-3.24.0.tar.xz) = b793c44b2976abe58461adfdb0b1874af8d6bafaf9b80a851d94b776f9d50f6a81774bcb5b35cd59a9ad3afeea9a8b88018aa85d670373c7c2fa9617407a09c4 +SHA512 (evince-3.25.4.tar.xz) = d0d72eeeb935c36ce9185c2ecff763c20926ce12b10565108ff927bd973758754a48ceda99ee1d4e6f27d5abd42e7224a3cce3721263c35e2fc135ea4b026fc9