[open-ils-commits] [GIT] Evergreen ILS branch master updated. 78e19fd3f4c8baa6d003ee230d18bf0c34e9f00b

Evergreen Git git at git.evergreen-ils.org
Wed May 29 17:41:28 EDT 2013


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Evergreen ILS".

The branch, master has been updated
       via  78e19fd3f4c8baa6d003ee230d18bf0c34e9f00b (commit)
       via  fc5182a90f625a21ce5a4668dcd3c6130477e202 (commit)
       via  8819aa61378fee8c58d2b307f802d24cc7a8acc9 (commit)
       via  a698dc48c5d3a01515127b131e9506dda6c74137 (commit)
      from  77c9886c809b407653b8b6580899ea7ad328b457 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 78e19fd3f4c8baa6d003ee230d18bf0c34e9f00b
Author: Jason Stephenson <jstephenson at mvlc.org>
Date:   Tue Mar 26 11:01:50 2013 -0400

    Add new dependency on libbz2-dev(el).
    
    Our own mar tools add a build dependency on libbz2.  The easiest way to
    make sure this is there seems to be to install libbz2-dev(el).
    
    Also, update the release notes to reflect the new dependency.
    
    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>
    Signed-off-by: Ben Shum <bshum at biblio.org>

diff --git a/Open-ILS/src/extras/Makefile.install b/Open-ILS/src/extras/Makefile.install
index a49ea6a..fc46d62 100644
--- a/Open-ILS/src/extras/Makefile.install
+++ b/Open-ILS/src/extras/Makefile.install
@@ -87,7 +87,8 @@ DEBS =  \
 	libuniversal-require-perl\
 	libnet-ip-perl\
 	liblocale-maketext-lexicon-perl\
-	libunix-syslog-perl
+	libunix-syslog-perl\
+	libbz2-dev
 
 # Debian Lenny and Ubuntu Intrepid bundle recent versions of yaz
 EXTRA_DEBS = \
@@ -159,7 +160,8 @@ FEDORA_RPMS = \
 	readline-devel \
 	tcp_wrappers-devel \
 	wget \
-	yaz
+	yaz \
+	libbz2-devel
 
 # Note: B:O:AuthorizeNet 3.21 fails with https://rt.cpan.org/Public/Bug/Display.html?id=55172
 # Should be fixed in 3.22
diff --git a/docs/RELEASE_NOTES_NEXT/Administration/new-updates-tools.txt b/docs/RELEASE_NOTES_NEXT/Administration/new-updates-tools.txt
index a65b488..7c94024 100644
--- a/docs/RELEASE_NOTES_NEXT/Administration/new-updates-tools.txt
+++ b/docs/RELEASE_NOTES_NEXT/Administration/new-updates-tools.txt
@@ -14,12 +14,15 @@ Evergreen during the installation or upgrade process.
 The make_updates.sh script that is run when you tell Evergreen to make
 the staff client updates has been modified to use the new tools.
 
-These tools introduce no new dependencies on building or running
-Evergreen.
+These tools introduce a dependency on libbz2.  This is often only
+available when installing the libbz2-dev or libbz2-devel packages.
+Thus this branch introduces a new depency on the development packages
+for libbz2 in Evergreen.
 
 Nothing in the user facing behavior of building updates changes with
 these tools.  They are drop-in replacements for the previous tools and
-you don't even need to know that they are there.
+other than the new dependency on libbz2, you don't even need to know
+that they are there.
 
 These tools were added to Evergreen to be an aid in portability to
 operating systems other than Linux.  They also remove a dependency on

commit fc5182a90f625a21ce5a4668dcd3c6130477e202
Author: Jason Stephenson <jstephenson at mvlc.org>
Date:   Wed Mar 20 10:45:03 2013 -0400

    Add release notes for the new updates tools.
    
    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>
    Signed-off-by: Ben Shum <bshum at biblio.org>

diff --git a/docs/RELEASE_NOTES_NEXT/Administration/new-updates-tools.txt b/docs/RELEASE_NOTES_NEXT/Administration/new-updates-tools.txt
new file mode 100644
index 0000000..a65b488
--- /dev/null
+++ b/docs/RELEASE_NOTES_NEXT/Administration/new-updates-tools.txt
@@ -0,0 +1,26 @@
+New Updates Tools
+^^^^^^^^^^^^^^^^^
+
+Source code for tools to generate the staff clients updates tools were
+added to Open-ILS/xul/staff_client/external/libmar.  These tools
+replace the downloadable tools from Mozilla.org that were previously
+used to generate the staff client updates files.
+
+They come with their own configuration script and are condfigured
+automatically as a subpackage when you configure Evergreen for
+installation.  They are also built and ready for use when you make
+Evergreen during the installation or upgrade process.
+
+The make_updates.sh script that is run when you tell Evergreen to make
+the staff client updates has been modified to use the new tools.
+
+These tools introduce no new dependencies on building or running
+Evergreen.
+
+Nothing in the user facing behavior of building updates changes with
+these tools.  They are drop-in replacements for the previous tools and
+you don't even need to know that they are there.
+
+These tools were added to Evergreen to be an aid in portability to
+operating systems other than Linux.  They also remove a dependency on
+a third-party tool, that is typically downloaded as a binary.

commit 8819aa61378fee8c58d2b307f802d24cc7a8acc9
Author: Jason Stephenson <jason at sigio.com>
Date:   Tue Mar 19 08:38:31 2013 -0400

    Fix segmentation fault in mbsdiff and fix crc by linking with libbz2.
    
    Doh! I typed memcpy when I really wanted memset.
    
    This does not actually introduce any new dependencies.  Evergreen
    updates/installation already requires bzip2.  If bzip2 is present,
    then libbz2 is present.  We don't need libbz2 headers, just the
    library itself for a single data structure used in crc32 calculation.
    
    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>
    Signed-off-by: Ben Shum <bshum at biblio.org>

diff --git a/Open-ILS/xul/staff_client/external/libmar/configure.ac b/Open-ILS/xul/staff_client/external/libmar/configure.ac
index e7715cd..0cfba6e 100644
--- a/Open-ILS/xul/staff_client/external/libmar/configure.ac
+++ b/Open-ILS/xul/staff_client/external/libmar/configure.ac
@@ -27,6 +27,7 @@ AC_PROG_CC
 AC_PROG_RANLIB
 
 # Checks for libraries.
+AC_CHECK_LIB([bz2],[BZ2_bzCompressInit],,AC_MSG_ERROR(*** OpenILS requires libbz2))
 
 # Checks for header files.
 AC_CHECK_HEADERS([err.h fcntl.h netinet/in.h stdint.h stdio.h stdlib.h string.h sys/stat.h sys/types.h unistd.h])
diff --git a/Open-ILS/xul/staff_client/external/libmar/tool/bsdiff.c b/Open-ILS/xul/staff_client/external/libmar/tool/bsdiff.c
index ea384bb..9aacd83 100644
--- a/Open-ILS/xul/staff_client/external/libmar/tool/bsdiff.c
+++ b/Open-ILS/xul/staff_client/external/libmar/tool/bsdiff.c
@@ -267,7 +267,7 @@ int main(int argc,char *argv[])
 	memcpy(header + 12, &outVal, 4);
 	outVal = htonl(newsize);
 	memcpy(header + 16, &outVal, 4);
-	memcpy(header + 20, 0, 12);
+	memset(header + 20, 0, 12);
 	if (fwrite(header, 32, 1, pf) != 1)
 		err(1, "fwrite(%s)", argv[3]);
 
diff --git a/Open-ILS/xul/staff_client/external/libmar/tool/crc32.c b/Open-ILS/xul/staff_client/external/libmar/tool/crc32.c
index d249076..3bba38f 100644
--- a/Open-ILS/xul/staff_client/external/libmar/tool/crc32.c
+++ b/Open-ILS/xul/staff_client/external/libmar/tool/crc32.c
@@ -6,7 +6,7 @@
 #include <stdint.h>
 
 /* This guy lives in libbz2, and is the only reason we need libbz2. */
- extern uint32_t BZ2_crc32Table[256];
+extern uint32_t BZ2_crc32Table[256];
 
 uint32_t
 crc32(const unsigned char *buf, uint32_t len)
@@ -15,7 +15,7 @@ crc32(const unsigned char *buf, uint32_t len)
 
   const unsigned char *end = buf + len;
   for (; buf != end; ++buf)
-    crc = (crc << 8) ^ crc32Table[(crc >> 24) ^ *buf];
+    crc = (crc << 8) ^ BZ2_crc32Table[(crc >> 24) ^ *buf];
 
   crc = ~crc;
   return crc;

commit a698dc48c5d3a01515127b131e9506dda6c74137
Author: Jason Stephenson <jason at sigio.com>
Date:   Mon Mar 18 20:03:42 2013 -0400

    Add libmar to build update tools to the repo.
    
    This adds code from Mozilla to build a command line mar program and the
    libmar library that it uses.  This code is now dual-licensed under the
    MPL 2.0 and GPL v2 or later.
    
    We also add our own version of mbsdiff using a modified version of Colin
    Percival's FreeBSD-licensed bsdiff program.  We also copy the crc32 code
    from Mozilla's updater.
    
    Add libmar as "subpackage" in cofigure.ac.
    
    Add AC_CONFIG_SUBDIRS macro call for Open-ILS/xul/staff_client/external/
    libmar so that our update tools will get configured and built when
    Evergreen is built.
    
    Modify make_updates.sh for our update tools.
    
    Instead of downloading mar and mbsdiff from Mozilla.org's servers,
    we check if they exist in Open-ILS/xul/staff_client/external/libmar/tool
    and if not we build them.  They should be there already.
    
    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>
    Signed-off-by: Ben Shum <bshum at biblio.org>

diff --git a/Open-ILS/xul/staff_client/external/libmar/Makefile.am b/Open-ILS/xul/staff_client/external/libmar/Makefile.am
new file mode 100644
index 0000000..518638b
--- /dev/null
+++ b/Open-ILS/xul/staff_client/external/libmar/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = src tool
diff --git a/Open-ILS/xul/staff_client/external/libmar/README b/Open-ILS/xul/staff_client/external/libmar/README
new file mode 100644
index 0000000..7513ded
--- /dev/null
+++ b/Open-ILS/xul/staff_client/external/libmar/README
@@ -0,0 +1,11 @@
+This directory contains code for a simple archive file format, which
+is documented at http://wiki.mozilla.org/Software_Update:MAR
+
+The src directory builds a small static library used to create, read,
+and extract an archive file.  The tool directory builds a command line
+utility around the library, mar.
+
+The tool directory also builds a modified version of bsdiff used by
+the Mozilla update mechanism to generate patches.  This version was
+modified from a recent copy of Colin Percival's, FreeBSD-licensed
+bsdiff sources with the crc32 code taken from the Mozilla updater.
diff --git a/Open-ILS/xul/staff_client/external/libmar/configure.ac b/Open-ILS/xul/staff_client/external/libmar/configure.ac
new file mode 100644
index 0000000..e7715cd
--- /dev/null
+++ b/Open-ILS/xul/staff_client/external/libmar/configure.ac
@@ -0,0 +1,49 @@
+#                                               -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ([2.68])
+AC_INIT([libmar], [1.0], [jason at sigio.com])
+AM_INIT_AUTOMAKE([foreign])
+AC_CONFIG_SRCDIR([tool/mar.c])
+AC_CONFIG_HEADER([config.h])
+
+# Check for MAR_CHANNEL_ID:
+AC_ARG_WITH([marchannelid],
+[  --with-marchannelid=channelname    default name for MAR channel (default is blank)],
+[mar_channel_id=${withval}],
+[mar_channel_id=])
+AC_DEFINE_UNQUOTED([MAR_CHANNEL_ID], ["${mar_channel_id}"], [Default MAR_CHANNEL_ID])
+
+# Check for MOZ_APP_VERSION
+AC_ARG_WITH([mozappversion],
+[  --with-mozappversion=appversion    default version for app (default is 19.0.1)],
+[moz_app_version=${withval}],
+[moz_app_version="19.0.1"])
+AC_DEFINE_UNQUOTED([MOZ_APP_VERSION], ["${moz_app_version}"], [Default MOZ_APP_VERSION])
+
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_RANLIB
+
+# Checks for libraries.
+
+# Checks for header files.
+AC_CHECK_HEADERS([err.h fcntl.h netinet/in.h stdint.h stdio.h stdlib.h string.h sys/stat.h sys/types.h unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_TYPE_INT64_T
+AC_TYPE_SIZE_T
+AC_TYPE_UINT32_T
+AC_TYPE_UINT64_T
+
+# Checks for library functions.
+AC_FUNC_FSEEKO
+AC_FUNC_MALLOC
+AC_FUNC_REALLOC
+AC_CHECK_FUNCS([memset mkdir strdup strrchr])
+
+AC_CONFIG_FILES([Makefile
+                 src/Makefile
+                 tool/Makefile])
+AC_OUTPUT
diff --git a/Open-ILS/xul/staff_client/external/libmar/src/Makefile.am b/Open-ILS/xul/staff_client/external/libmar/src/Makefile.am
new file mode 100644
index 0000000..c586505
--- /dev/null
+++ b/Open-ILS/xul/staff_client/external/libmar/src/Makefile.am
@@ -0,0 +1,2 @@
+noinst_LIBRARIES = libmar.a
+libmar_a_SOURCES = mar_cmdline.h mar.h mar_private.h mar_create.c mar_extract.c mar_read.c
diff --git a/Open-ILS/xul/staff_client/external/libmar/src/mar.h b/Open-ILS/xul/staff_client/external/libmar/src/mar.h
new file mode 100644
index 0000000..8f4cb61
--- /dev/null
+++ b/Open-ILS/xul/staff_client/external/libmar/src/mar.h
@@ -0,0 +1,169 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/*
+ * This file is part of Evergreen.
+ *
+ * Evergreen 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 of the License,
+ * or (at your option) any later version.
+ *
+ * Evergreen 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 Evergreen.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * This Source Code Form is derived from code that was originally
+ * subject to the terms of the Mozilla Public License, v. 2.0 and
+ * included in Evergreen.  You may, therefore, use this Source Code
+ * Form under the terms of the Mozilla Public License 2.0.  This
+ * licensing option does not affect the larger Evergreen project, only
+ * the Source Code Forms bearing this exception are affected.  If a
+ * copy of the MPL was not distributed with this file, You can obtain
+ * one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef MAR_H__
+#define MAR_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* We have a MAX_SIGNATURES limit so that an invalid MAR will never
+ * waste too much of either updater's or signmar's time.
+ * It is also used at various places internally and will affect memory usage.
+ * If you want to increase this value above 9 then you need to adjust parsing
+ * code in tool/mar.c.
+*/
+#define MAX_SIGNATURES 8
+
+struct ProductInformationBlock {
+  const char *MARChannelID;
+  const char *productVersion;
+};
+
+/**
+ * The MAR item data structure.
+ */
+typedef struct MarItem_ {
+  struct MarItem_ *next;  /* private field */
+  uint32_t offset;        /* offset into archive */
+  uint32_t length;        /* length of data in bytes */
+  uint32_t flags;         /* contains file mode bits */
+  char name[1];           /* file path */
+} MarItem;
+
+#define TABLESIZE 256
+
+struct MarFile_ {
+  FILE *fp;
+  MarItem *item_table[TABLESIZE];
+};
+
+typedef struct MarFile_ MarFile;
+
+/**
+ * Signature of callback function passed to mar_enum_items.
+ * @param mar       The MAR file being visited.
+ * @param item      The MAR item being visited.
+ * @param data      The data parameter passed by the caller of mar_enum_items.
+ * @return          A non-zero value to stop enumerating.
+ */
+typedef int (* MarItemCallback)(MarFile *mar, const MarItem *item, void *data);
+
+/**
+ * Open a MAR file for reading.
+ * @param path      Specifies the path to the MAR file to open.  This path must
+ *                  be compatible with fopen.
+ * @return          NULL if an error occurs.
+ */
+MarFile *mar_open(const char *path);
+
+#ifdef XP_WIN
+MarFile *mar_wopen(const PRUnichar *path);
+#endif
+
+/**
+ * Close a MAR file that was opened using mar_open.
+ * @param mar       The MarFile object to close.
+ */
+void mar_close(MarFile *mar);
+
+/**
+ * Find an item in the MAR file by name.
+ * @param mar       The MarFile object to query.
+ * @param item      The name of the item to query.
+ * @return          A const reference to a MAR item or NULL if not found.
+ */
+const MarItem *mar_find_item(MarFile *mar, const char *item);
+
+/**
+ * Enumerate all MAR items via callback function.
+ * @param mar       The MAR file to enumerate.
+ * @param callback  The function to call for each MAR item.
+ * @param data      A caller specified value that is passed along to the
+ *                  callback function.
+ * @return          0 if the enumeration ran to completion.  Otherwise, any
+ *                  non-zero return value from the callback is returned.
+ */
+int mar_enum_items(MarFile *mar, MarItemCallback callback, void *data);
+
+/**
+ * Read from MAR item at given offset up to bufsize bytes.
+ * @param mar       The MAR file to read.
+ * @param item      The MAR item to read.
+ * @param offset    The byte offset relative to the start of the item.
+ * @param buf       A pointer to a buffer to copy the data into.
+ * @param bufsize   The length of the buffer to copy the data into.
+ * @return          The number of bytes written or a negative value if an
+ *                  error occurs.
+ */
+int mar_read(MarFile *mar, const MarItem *item, int offset, char *buf,
+             int bufsize);
+
+/**
+ * Create a MAR file from a set of files.
+ * @param dest      The path to the file to create.  This path must be
+ *                  compatible with fopen.
+ * @param numfiles  The number of files to store in the archive.
+ * @param files     The list of null-terminated file paths.  Each file
+ *                  path must be compatible with fopen.
+ * @param infoBlock The information to store in the product information block.
+ * @return          A non-zero value if an error occurs.
+ */
+int mar_create(const char *dest, 
+               int numfiles, 
+               char **files, 
+               struct ProductInformationBlock *infoBlock);
+
+/**
+ * Extract a MAR file to the current working directory.
+ * @param path      The path to the MAR file to extract.  This path must be
+ *                  compatible with fopen.
+ * @return          A non-zero value if an error occurs.
+ */
+int mar_extract(const char *path);
+
+/** 
+ * Reads the product info block from the MAR file's additional block section.
+ * The caller is responsible for freeing the fields in infoBlock
+ * if the return is successful.
+ *
+ * @param infoBlock Out parameter for where to store the result to
+ * @return 0 on success, -1 on failure
+*/
+int
+mar_read_product_info_block(MarFile *mar, 
+                            struct ProductInformationBlock *infoBlock);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* MAR_H__ */
diff --git a/Open-ILS/xul/staff_client/external/libmar/src/mar_cmdline.h b/Open-ILS/xul/staff_client/external/libmar/src/mar_cmdline.h
new file mode 100644
index 0000000..3f79148
--- /dev/null
+++ b/Open-ILS/xul/staff_client/external/libmar/src/mar_cmdline.h
@@ -0,0 +1,94 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/*
+ * This file is part of Evergreen.
+ *
+ * Evergreen 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 of the License,
+ * or (at your option) any later version.
+ *
+ * Evergreen 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 Evergreen.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * This Source Code Form is derived from code that was originally
+ * subject to the terms of the Mozilla Public License, v. 2.0 and
+ * included in Evergreen.  You may, therefore, use this Source Code
+ * Form under the terms of the Mozilla Public License 2.0.  This
+ * licensing option does not affect the larger Evergreen project, only
+ * the Source Code Forms bearing this exception are affected.  If a
+ * copy of the MPL was not distributed with this file, You can obtain
+ * one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef MAR_CMDLINE_H__
+#define MAR_CMDLINE_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ProductInformationBlock;
+
+/**
+ * Determines MAR file information.
+ *
+ * @param path                   The path of the MAR file to check.
+ * @param hasSignatureBlock      Optional out parameter specifying if the MAR
+ *                               file has a signature block or not.
+ * @param numSignatures          Optional out parameter for storing the number
+ *                               of signatures in the MAR file.
+ * @param hasAdditionalBlocks    Optional out parameter specifying if the MAR
+ *                               file has additional blocks or not.
+ * @param offsetAdditionalBlocks Optional out parameter for the offset to the 
+ *                               first additional block. Value is only valid if
+ *                               hasAdditionalBlocks is not equal to 0.
+ * @param numAdditionalBlocks    Optional out parameter for the number of
+ *                               additional blocks.  Value is only valid if
+ *                               has_additional_blocks is not equal to 0.
+ * @return 0 on success and non-zero on failure.
+ */
+int get_mar_file_info(const char *path, 
+                      int *hasSignatureBlock,
+                      uint32_t *numSignatures,
+                      int *hasAdditionalBlocks,
+                      uint32_t *offsetAdditionalBlocks,
+                      uint32_t *numAdditionalBlocks);
+
+/** 
+ * Reads the product info block from the MAR file's additional block section.
+ * The caller is responsible for freeing the fields in infoBlock
+ * if the return is successful.
+ *
+ * @param infoBlock Out parameter for where to store the result to
+ * @return 0 on success, -1 on failure
+*/
+int
+read_product_info_block(char *path, 
+                        struct ProductInformationBlock *infoBlock);
+
+/** 
+ * Refreshes the product information block with the new information.
+ * The input MAR must not be signed or the function call will fail.
+ * 
+ * @param path             The path to the MAR file whose product info block
+ *                         should be refreshed.
+ * @param infoBlock        Out parameter for where to store the result to
+ * @return 0 on success, -1 on failure
+*/
+int
+refresh_product_info_block(const char *path,
+                           struct ProductInformationBlock *infoBlock);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* MAR_CMDLINE_H__ */
diff --git a/Open-ILS/xul/staff_client/external/libmar/src/mar_create.c b/Open-ILS/xul/staff_client/external/libmar/src/mar_create.c
new file mode 100644
index 0000000..d540c37
--- /dev/null
+++ b/Open-ILS/xul/staff_client/external/libmar/src/mar_create.c
@@ -0,0 +1,416 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/*
+ * This file is part of Evergreen.
+ *
+ * Evergreen 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 of the License,
+ * or (at your option) any later version.
+ *
+ * Evergreen 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 Evergreen.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * This Source Code Form is derived from code that was originally
+ * subject to the terms of the Mozilla Public License, v. 2.0 and
+ * included in Evergreen.  You may, therefore, use this Source Code
+ * Form under the terms of the Mozilla Public License 2.0.  This
+ * licensing option does not affect the larger Evergreen project, only
+ * the Source Code Forms bearing this exception are affected.  If a
+ * copy of the MPL was not distributed with this file, You can obtain
+ * one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include "mar_private.h"
+#include "mar_cmdline.h"
+#include "mar.h"
+
+#ifdef XP_WIN
+#include <winsock2.h>
+#else
+#include <netinet/in.h>
+#include <unistd.h>
+#endif
+
+struct MarItemStack {
+  void *head;
+  uint32_t size_used;
+  uint32_t size_allocated;
+  uint32_t last_offset;
+};
+
+/**
+ * Push a new item onto the stack of items.  The stack is a single block
+ * of memory.
+ */
+static int mar_push(struct MarItemStack *stack, uint32_t length, uint32_t flags,
+                    const char *name) {
+  int namelen;
+  uint32_t n_offset, n_length, n_flags;
+  uint32_t size;
+  char *data;
+  
+  namelen = strlen(name);
+  size = MAR_ITEM_SIZE(namelen);
+
+  if (stack->size_allocated - stack->size_used < size) {
+    /* increase size of stack */
+    size_t size_needed = ROUND_UP(stack->size_used + size, BLOCKSIZE);
+    stack->head = realloc(stack->head, size_needed);
+    if (!stack->head)
+      return -1;
+    stack->size_allocated = size_needed;
+  }
+
+  data = (((char *) stack->head) + stack->size_used);
+
+  n_offset = htonl(stack->last_offset);
+  n_length = htonl(length);
+  n_flags = htonl(flags);
+
+  memcpy(data, &n_offset, sizeof(n_offset));
+  data += sizeof(n_offset);
+
+  memcpy(data, &n_length, sizeof(n_length));
+  data += sizeof(n_length);
+
+  memcpy(data, &n_flags, sizeof(n_flags));
+  data += sizeof(n_flags);
+
+  memcpy(data, name, namelen + 1);
+  
+  stack->size_used += size;
+  stack->last_offset += length;
+  return 0;
+}
+
+static int mar_concat_file(FILE *fp, const char *path) {
+  FILE *in;
+  char buf[BLOCKSIZE];
+  size_t len;
+  int rv = 0;
+
+  in = fopen(path, "rb");
+  if (!in)
+    return -1;
+
+  while ((len = fread(buf, 1, BLOCKSIZE, in)) > 0) {
+    if (fwrite(buf, len, 1, fp) != 1) {
+      rv = -1;
+      break;
+    }
+  }
+
+  fclose(in);
+  return rv;
+}
+
+/**
+ * Writes out the product information block to the specified file.
+ *
+ * @param fp           The opened MAR file being created.
+ * @param stack        A pointer to the MAR item stack being used to create 
+ *                     the MAR
+ * @param infoBlock    The product info block to store in the file.
+ * @return 0 on success.
+*/
+static int
+mar_concat_product_info_block(FILE *fp, 
+                              struct MarItemStack *stack,
+                              struct ProductInformationBlock *infoBlock)
+{
+  char buf[PIB_MAX_MAR_CHANNEL_ID_SIZE + PIB_MAX_PRODUCT_VERSION_SIZE];
+  uint32_t additionalBlockID = 1, infoBlockSize, unused;
+  if (!fp || !infoBlock || 
+      !infoBlock->MARChannelID ||
+      !infoBlock->productVersion) {
+    return -1;
+  }
+ 
+  /* The MAR channel name must be < 64 bytes per the spec */
+  if (strlen(infoBlock->MARChannelID) > PIB_MAX_MAR_CHANNEL_ID_SIZE) {
+    return -1;
+  }
+
+  /* The product version must be < 32 bytes per the spec */
+  if (strlen(infoBlock->productVersion) > PIB_MAX_PRODUCT_VERSION_SIZE) {
+    return -1;
+  }
+
+  /* Although we don't need the product information block size to include the
+     maximum MAR channel name and product version, we allocate the maximum
+     amount to make it easier to modify the MAR file for repurposing MAR files
+     to different MAR channels. + 2 is for the NULL terminators. */
+  infoBlockSize = sizeof(infoBlockSize) +
+                  sizeof(additionalBlockID) +
+                  PIB_MAX_MAR_CHANNEL_ID_SIZE +
+                  PIB_MAX_PRODUCT_VERSION_SIZE + 2;
+  if (stack) {
+    stack->last_offset += infoBlockSize;
+  }
+
+  /* Write out the product info block size */
+  infoBlockSize = htonl(infoBlockSize);
+  if (fwrite(&infoBlockSize, 
+      sizeof(infoBlockSize), 1, fp) != 1) {
+    return -1;
+  }
+  infoBlockSize = ntohl(infoBlockSize);
+
+  /* Write out the product info block ID */
+  additionalBlockID = htonl(additionalBlockID);
+  if (fwrite(&additionalBlockID, 
+      sizeof(additionalBlockID), 1, fp) != 1) {
+    return -1;
+  }
+  additionalBlockID = ntohl(additionalBlockID);
+
+  /* Write out the channel name and NULL terminator */
+  if (fwrite(infoBlock->MARChannelID, 
+      strlen(infoBlock->MARChannelID) + 1, 1, fp) != 1) {
+    return -1;
+  }
+
+  /* Write out the product version string and NULL terminator */
+  if (fwrite(infoBlock->productVersion, 
+      strlen(infoBlock->productVersion) + 1, 1, fp) != 1) {
+    return -1;
+  }
+
+  /* Write out the rest of the block that is unused */
+  unused = infoBlockSize - (sizeof(infoBlockSize) +
+                            sizeof(additionalBlockID) +
+                            strlen(infoBlock->MARChannelID) + 
+                            strlen(infoBlock->productVersion) + 2);
+  memset(buf, 0, sizeof(buf));
+  if (fwrite(buf, unused, 1, fp) != 1) {
+    return -1;
+  }
+  return 0;
+}
+
+/** 
+ * Refreshes the product information block with the new information.
+ * The input MAR must not be signed or the function call will fail.
+ * 
+ * @param path             The path to the MAR file whose product info block
+ *                         should be refreshed.
+ * @param infoBlock        Out parameter for where to store the result to
+ * @return 0 on success, -1 on failure
+*/
+int
+refresh_product_info_block(const char *path,
+                           struct ProductInformationBlock *infoBlock)
+{
+  FILE *fp ;
+  int rv;
+  uint32_t numSignatures, additionalBlockSize, additionalBlockID,
+    offsetAdditionalBlocks, numAdditionalBlocks, i;
+  int additionalBlocks, hasSignatureBlock;
+  int64_t oldPos;
+
+  rv = get_mar_file_info(path, 
+                         &hasSignatureBlock,
+                         &numSignatures,
+                         &additionalBlocks,
+                         &offsetAdditionalBlocks,
+                         &numAdditionalBlocks);
+  if (rv) {
+    fprintf(stderr, "ERROR: Could not obtain MAR information.\n");
+    return -1;
+  }
+
+  if (hasSignatureBlock && numSignatures) {
+    fprintf(stderr, "ERROR: Cannot refresh a signed MAR\n");
+    return -1;
+  }
+
+  fp = fopen(path, "r+b");
+  if (!fp) {
+    fprintf(stderr, "ERROR: could not open target file: %s\n", path);
+    return -1;
+  }
+
+  if (fseeko(fp, offsetAdditionalBlocks, SEEK_SET)) {
+    fprintf(stderr, "ERROR: could not seek to additional blocks\n");
+    fclose(fp);
+    return -1;
+  }
+
+  for (i = 0; i < numAdditionalBlocks; ++i) {
+    /* Get the position of the start of this block */
+    oldPos = ftello(fp);
+
+    /* Read the additional block size */
+    if (fread(&additionalBlockSize, 
+              sizeof(additionalBlockSize), 
+              1, fp) != 1) {
+      return -1;
+    }
+    additionalBlockSize = ntohl(additionalBlockSize);
+
+    /* Read the additional block ID */
+    if (fread(&additionalBlockID, 
+              sizeof(additionalBlockID), 
+              1, fp) != 1) {
+      return -1;
+    }
+    additionalBlockID = ntohl(additionalBlockID);
+
+    if (PRODUCT_INFO_BLOCK_ID == additionalBlockID) {
+      if (fseeko(fp, oldPos, SEEK_SET)) {
+        fprintf(stderr, "Could not seek back to Product Information Block\n");
+        fclose(fp);
+        return -1;
+      }
+
+      if (mar_concat_product_info_block(fp, NULL, infoBlock)) {
+        fprintf(stderr, "Could not concat Product Information Block\n");
+        fclose(fp);
+        return -1;
+      }
+
+      fclose(fp);
+      return 0;
+    } else {
+      /* This is not the additional block you're looking for. Move along. */
+      if (fseek(fp, additionalBlockSize, SEEK_CUR)) {
+        fprintf(stderr, "ERROR: Could not seek past current block.\n");
+        fclose(fp);
+        return -1;
+      }
+    }
+  }
+
+  /* If we had a product info block we would have already returned */
+  fclose(fp);
+  fprintf(stderr, "ERROR: Could not refresh because block does not exist\n");
+  return -1;
+}
+
+/**
+ * Create a MAR file from a set of files.
+ * @param dest      The path to the file to create.  This path must be
+ *                  compatible with fopen.
+ * @param numfiles  The number of files to store in the archive.
+ * @param files     The list of null-terminated file paths.  Each file
+ *                  path must be compatible with fopen.
+ * @param infoBlock The information to store in the product information block.
+ * @return A non-zero value if an error occurs.
+ */
+int mar_create(const char *dest, int 
+               num_files, char **files, 
+               struct ProductInformationBlock *infoBlock) {
+  struct MarItemStack stack;
+  uint32_t offset_to_index = 0, size_of_index, 
+    numSignatures, numAdditionalSections;
+  uint64_t sizeOfEntireMAR = 0;
+  struct stat st;
+  FILE *fp;
+  int i, rv = -1;
+
+  memset(&stack, 0, sizeof(stack));
+
+  fp = fopen(dest, "wb");
+  if (!fp) {
+    fprintf(stderr, "ERROR: could not create target file: %s\n", dest);
+    return -1;
+  }
+
+  if (fwrite(MAR_ID, MAR_ID_SIZE, 1, fp) != 1)
+    goto failure;
+  if (fwrite(&offset_to_index, sizeof(uint32_t), 1, fp) != 1)
+    goto failure;
+
+  stack.last_offset = MAR_ID_SIZE + 
+                      sizeof(offset_to_index) +
+                      sizeof(numSignatures) + 
+                      sizeof(numAdditionalSections) +
+                      sizeof(sizeOfEntireMAR);
+
+  /* We will circle back on this at the end of the MAR creation to fill it */
+  if (fwrite(&sizeOfEntireMAR, sizeof(sizeOfEntireMAR), 1, fp) != 1) {
+    goto failure;
+  }
+
+  /* Write out the number of signatures, for now only at most 1 is supported */
+  numSignatures = 0;
+  if (fwrite(&numSignatures, sizeof(numSignatures), 1, fp) != 1) {
+    goto failure;
+  }
+
+  /* Write out the number of additional sections, for now just 1 
+     for the product info block */
+  numAdditionalSections = htonl(1);
+  if (fwrite(&numAdditionalSections, 
+             sizeof(numAdditionalSections), 1, fp) != 1) {
+    goto failure;
+  }
+  numAdditionalSections = ntohl(numAdditionalSections);
+
+  if (mar_concat_product_info_block(fp, &stack, infoBlock)) {
+    goto failure;
+  }
+
+  for (i = 0; i < num_files; ++i) {
+    if (stat(files[i], &st)) {
+      fprintf(stderr, "ERROR: file not found: %s\n", files[i]);
+      goto failure;
+    }
+
+    if (mar_push(&stack, st.st_size, st.st_mode & 0777, files[i]))
+      goto failure;
+
+    /* concatenate input file to archive */
+    if (mar_concat_file(fp, files[i]))
+      goto failure;
+  }
+
+  /* write out the index (prefixed with length of index) */
+  size_of_index = htonl(stack.size_used);
+  if (fwrite(&size_of_index, sizeof(size_of_index), 1, fp) != 1)
+    goto failure;
+  if (fwrite(stack.head, stack.size_used, 1, fp) != 1)
+    goto failure;
+
+  /* To protect against invalid MAR files, we assumes that the MAR file 
+     size is less than or equal to MAX_SIZE_OF_MAR_FILE. */
+  if (ftell(fp) > MAX_SIZE_OF_MAR_FILE) {
+    goto failure;
+  }
+
+  /* write out offset to index file in network byte order */
+  offset_to_index = htonl(stack.last_offset);
+  if (fseek(fp, MAR_ID_SIZE, SEEK_SET))
+    goto failure;
+  if (fwrite(&offset_to_index, sizeof(offset_to_index), 1, fp) != 1)
+    goto failure;
+  offset_to_index = ntohl(stack.last_offset);
+  
+  sizeOfEntireMAR = ((uint64_t)stack.last_offset) +
+                    stack.size_used +
+                    sizeof(size_of_index);
+  sizeOfEntireMAR = HOST_TO_NETWORK64(sizeOfEntireMAR);
+  if (fwrite(&sizeOfEntireMAR, sizeof(sizeOfEntireMAR), 1, fp) != 1)
+    goto failure;
+  sizeOfEntireMAR = NETWORK_TO_HOST64(sizeOfEntireMAR);
+
+  rv = 0;
+failure: 
+  if (stack.head)
+    free(stack.head);
+  fclose(fp);
+  if (rv)
+    remove(dest);
+  return rv;
+}
diff --git a/Open-ILS/xul/staff_client/external/libmar/src/mar_extract.c b/Open-ILS/xul/staff_client/external/libmar/src/mar_extract.c
new file mode 100644
index 0000000..404a535
--- /dev/null
+++ b/Open-ILS/xul/staff_client/external/libmar/src/mar_extract.c
@@ -0,0 +1,102 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/*
+ * This file is part of Evergreen.
+ *
+ * Evergreen 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 of the License,
+ * or (at your option) any later version.
+ *
+ * Evergreen 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 Evergreen.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * This Source Code Form is derived from code that was originally
+ * subject to the terms of the Mozilla Public License, v. 2.0 and
+ * included in Evergreen.  You may, therefore, use this Source Code
+ * Form under the terms of the Mozilla Public License 2.0.  This
+ * licensing option does not affect the larger Evergreen project, only
+ * the Source Code Forms bearing this exception are affected.  If a
+ * copy of the MPL was not distributed with this file, You can obtain
+ * one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include "mar_private.h"
+#include "mar.h"
+
+#ifdef XP_WIN
+#include <io.h>
+#include <direct.h>
+#endif
+
+/* Ensure that the directory containing this file exists */
+static int mar_ensure_parent_dir(const char *path)
+{
+  char *slash = strrchr(path, '/');
+  if (slash)
+  {
+    *slash = '\0';
+    mar_ensure_parent_dir(path);
+#ifdef XP_WIN
+    _mkdir(path);
+#else
+    mkdir(path, 0755);
+#endif
+    *slash = '/';
+  }
+  return 0;
+}
+
+static int mar_test_callback(MarFile *mar, const MarItem *item, void *unused) {
+  FILE *fp;
+  char buf[BLOCKSIZE];
+  int fd, len, offset = 0;
+
+  if (mar_ensure_parent_dir(item->name))
+    return -1;
+
+#ifdef XP_WIN
+  fd = _open(item->name, _O_BINARY|_O_CREAT|_O_TRUNC|_O_WRONLY, item->flags);
+#else
+  fd = creat(item->name, item->flags);
+#endif
+  if (fd == -1)
+    return -1;
+
+  fp = fdopen(fd, "wb");
+  if (!fp)
+    return -1;
+
+  while ((len = mar_read(mar, item, offset, buf, sizeof(buf))) > 0) {
+    if (fwrite(buf, len, 1, fp) != 1)
+      break;
+    offset += len;
+  }
+
+  fclose(fp);
+  return len == 0 ? 0 : -1;
+}
+
+int mar_extract(const char *path) {
+  MarFile *mar;
+  int rv;
+
+  mar = mar_open(path);
+  if (!mar)
+    return -1;
+
+  rv = mar_enum_items(mar, mar_test_callback, NULL);
+
+  mar_close(mar);
+  return rv;
+}
diff --git a/Open-ILS/xul/staff_client/external/libmar/src/mar_private.h b/Open-ILS/xul/staff_client/external/libmar/src/mar_private.h
new file mode 100644
index 0000000..adcd251
--- /dev/null
+++ b/Open-ILS/xul/staff_client/external/libmar/src/mar_private.h
@@ -0,0 +1,88 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/*
+ * This file is part of Evergreen.
+ *
+ * Evergreen 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 of the License,
+ * or (at your option) any later version.
+ *
+ * Evergreen 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 Evergreen.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * This Source Code Form is derived from code that was originally
+ * subject to the terms of the Mozilla Public License, v. 2.0 and
+ * included in Evergreen.  You may, therefore, use this Source Code
+ * Form under the terms of the Mozilla Public License 2.0.  This
+ * licensing option does not affect the larger Evergreen project, only
+ * the Source Code Forms bearing this exception are affected.  If a
+ * copy of the MPL was not distributed with this file, You can obtain
+ * one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef MAR_PRIVATE_H__
+#define MAR_PRIVATE_H__
+
+#include <stdint.h>
+
+#define BLOCKSIZE 4096
+#define ROUND_UP(n, incr) (((n) / (incr) + 1) * (incr))
+
+#define MAR_ID "MAR1"
+#define MAR_ID_SIZE 4
+
+/* The signature block comes directly after the header block 
+   which is 16 bytes */
+#define SIGNATURE_BLOCK_OFFSET 16
+
+/* Make sure the file is less than 500MB.  We do this to protect against
+   invalid MAR files. */
+#define MAX_SIZE_OF_MAR_FILE ((int64_t)524288000)
+
+/* The maximum size of any signature supported by current and future
+   implementations of the signmar program. */
+#define MAX_SIGNATURE_LENGTH 2048
+
+/* Each additional block has a unique ID.  
+   The product information block has an ID of 1. */
+#define PRODUCT_INFO_BLOCK_ID 1
+
+#define MAR_ITEM_SIZE(namelen) (3*sizeof(uint32_t) + (namelen) + 1)
+
+/* Product Information Block (PIB) constants */
+#define PIB_MAX_MAR_CHANNEL_ID_SIZE 63
+#define PIB_MAX_PRODUCT_VERSION_SIZE 31
+
+/* The mar program is compiled as a host bin so we don't have access to NSPR at
+   runtime.  For that reason we use ntohl, htonl, and define HOST_TO_NETWORK64 
+   instead of the NSPR equivalents. */
+#ifdef XP_WIN
+#include <winsock2.h>
+#define ftello _ftelli64
+#define fseeko _fseeki64
+#else
+#define _FILE_OFFSET_BITS 64
+#include <netinet/in.h>
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+
+#define HOST_TO_NETWORK64(x) ( \
+  ((((uint64_t) x) & 0xFF) << 56) | \
+  ((((uint64_t) x) >> 8) & 0xFF) << 48) | \
+  (((((uint64_t) x) >> 16) & 0xFF) << 40) | \
+  (((((uint64_t) x) >> 24) & 0xFF) << 32) | \
+  (((((uint64_t) x) >> 32) & 0xFF) << 24) | \
+  (((((uint64_t) x) >> 40) & 0xFF) << 16) | \
+  (((((uint64_t) x) >> 48) & 0xFF) << 8) | \
+  (((uint64_t) x) >> 56)
+#define NETWORK_TO_HOST64 HOST_TO_NETWORK64
+
+#endif  /* MAR_PRIVATE_H__ */
diff --git a/Open-ILS/xul/staff_client/external/libmar/src/mar_read.c b/Open-ILS/xul/staff_client/external/libmar/src/mar_read.c
new file mode 100644
index 0000000..8c14fd0
--- /dev/null
+++ b/Open-ILS/xul/staff_client/external/libmar/src/mar_read.c
@@ -0,0 +1,581 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/*
+ * This file is part of Evergreen.
+ *
+ * Evergreen 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 of the License,
+ * or (at your option) any later version.
+ *
+ * Evergreen 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 Evergreen.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * This Source Code Form is derived from code that was originally
+ * subject to the terms of the Mozilla Public License, v. 2.0 and
+ * included in Evergreen.  You may, therefore, use this Source Code
+ * Form under the terms of the Mozilla Public License 2.0.  This
+ * licensing option does not affect the larger Evergreen project, only
+ * the Source Code Forms bearing this exception are affected.  If a
+ * copy of the MPL was not distributed with this file, You can obtain
+ * one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include "mar_private.h"
+#include "mar.h"
+
+#ifdef XP_WIN
+#include <winsock2.h>
+#else
+#include <netinet/in.h>
+#endif
+
+
+/* this is the same hash algorithm used by nsZipArchive.cpp */
+static uint32_t mar_hash_name(const char *name) {
+  uint32_t val = 0;
+  unsigned char* c;
+
+  for (c = (unsigned char *) name; *c; ++c)
+    val = val*37 + *c;
+
+  return val % TABLESIZE;
+}
+
+static int mar_insert_item(MarFile *mar, const char *name, int namelen,
+                           uint32_t offset, uint32_t length, uint32_t flags) {
+  MarItem *item, *root;
+  uint32_t hash;
+  
+  item = (MarItem *) malloc(sizeof(MarItem) + namelen);
+  if (!item)
+    return -1;
+  item->next = NULL;
+  item->offset = offset;
+  item->length = length;
+  item->flags = flags;
+  memcpy(item->name, name, namelen + 1);
+
+  hash = mar_hash_name(name);
+
+  root = mar->item_table[hash];
+  if (!root) {
+    mar->item_table[hash] = item;
+  } else {
+    /* append item */
+    while (root->next)
+      root = root->next;
+    root->next = item;
+  }
+  return 0;
+}
+
+static int mar_consume_index(MarFile *mar, char **buf, const char *buf_end) {
+  /*
+   * Each item has the following structure:
+   *   uint32_t offset      (network byte order)
+   *   uint32_t length      (network byte order)
+   *   uint32_t flags       (network byte order)
+   *   char     name[N]     (where N >= 1)
+   *   char     null_byte;
+   */
+  uint32_t offset;
+  uint32_t length;
+  uint32_t flags;
+  const char *name;
+  int namelen;
+
+  if ((buf_end - *buf) < (int)(3*sizeof(uint32_t) + 2))
+    return -1;
+
+  memcpy(&offset, *buf, sizeof(offset));
+  *buf += sizeof(offset);
+
+  memcpy(&length, *buf, sizeof(length));
+  *buf += sizeof(length);
+
+  memcpy(&flags, *buf, sizeof(flags));
+  *buf += sizeof(flags);
+
+  offset = ntohl(offset);
+  length = ntohl(length);
+  flags = ntohl(flags);
+
+  name = *buf;
+  /* find namelen; must take care not to read beyond buf_end */
+  while (**buf) {
+    if (*buf == buf_end)
+      return -1;
+    ++(*buf);
+  }
+  namelen = (*buf - name);
+  /* consume null byte */
+  if (*buf == buf_end)
+    return -1;
+  ++(*buf);
+
+  return mar_insert_item(mar, name, namelen, offset, length, flags);
+}
+
+static int mar_read_index(MarFile *mar) {
+  char id[MAR_ID_SIZE], *buf, *bufptr, *bufend;
+  uint32_t offset_to_index, size_of_index;
+
+  /* verify MAR ID */
+  if (fread(id, MAR_ID_SIZE, 1, mar->fp) != 1)
+    return -1;
+  if (memcmp(id, MAR_ID, MAR_ID_SIZE) != 0)
+    return -1;
+
+  if (fread(&offset_to_index, sizeof(uint32_t), 1, mar->fp) != 1)
+    return -1;
+  offset_to_index = ntohl(offset_to_index);
+
+  if (fseek(mar->fp, offset_to_index, SEEK_SET))
+    return -1;
+  if (fread(&size_of_index, sizeof(uint32_t), 1, mar->fp) != 1)
+    return -1;
+  size_of_index = ntohl(size_of_index);
+
+  buf = (char *) malloc(size_of_index);
+  if (!buf)
+    return -1;
+  if (fread(buf, size_of_index, 1, mar->fp) != 1) {
+    free(buf);
+    return -1;
+  }
+
+  bufptr = buf;
+  bufend = buf + size_of_index;
+  while (bufptr < bufend && mar_consume_index(mar, &bufptr, bufend) == 0);
+
+  free(buf);
+  return (bufptr == bufend) ? 0 : -1;
+}
+
+/**
+ * Internal shared code for mar_open and mar_wopen.
+ * On failure, will fclose(fp).
+ */
+static MarFile *mar_fpopen(FILE *fp)
+{
+  MarFile *mar;
+
+  mar = (MarFile *) malloc(sizeof(*mar));
+  if (!mar) {
+    fclose(fp);
+    return NULL;
+  }
+
+  mar->fp = fp;
+  memset(mar->item_table, 0, sizeof(mar->item_table));
+  if (mar_read_index(mar)) {
+    mar_close(mar);
+    return NULL;
+  }
+
+  return mar;
+}
+
+MarFile *mar_open(const char *path) {
+  FILE *fp;
+
+  fp = fopen(path, "rb");
+  if (!fp)
+    return NULL;
+
+  return mar_fpopen(fp);
+}
+
+#ifdef XP_WIN
+MarFile *mar_wopen(const PRUnichar *path) {
+  FILE *fp;
+
+  fp = _wfopen(path, L"rb");
+  if (!fp)
+    return NULL;
+
+  return mar_fpopen(fp);
+}
+#endif
+
+void mar_close(MarFile *mar) {
+  MarItem *item;
+  int i;
+
+  fclose(mar->fp);
+
+  for (i = 0; i < TABLESIZE; ++i) {
+    item = mar->item_table[i];
+    while (item) {
+      MarItem *temp = item;
+      item = item->next;
+      free(temp);
+    }
+  }
+
+  free(mar);
+}
+
+/**
+ * Determines the MAR file information.
+ *
+ * @param fp                     An opened MAR file in read mode.
+ * @param hasSignatureBlock      Optional out parameter specifying if the MAR
+ *                               file has a signature block or not.
+ * @param numSignatures          Optional out parameter for storing the number
+ *                               of signatures in the MAR file.
+ * @param hasAdditionalBlocks    Optional out parameter specifying if the MAR
+ *                               file has additional blocks or not.
+ * @param offsetAdditionalBlocks Optional out parameter for the offset to the 
+ *                               first additional block. Value is only valid if
+ *                               hasAdditionalBlocks is not equal to 0.
+ * @param numAdditionalBlocks    Optional out parameter for the number of
+ *                               additional blocks.  Value is only valid if
+ *                               hasAdditionalBlocks is not equal to 0.
+ * @return 0 on success and non-zero on failure.
+ */
+int get_mar_file_info_fp(FILE *fp, 
+                         int *hasSignatureBlock,
+                         int *numSignatures,
+                         int *hasAdditionalBlocks,
+                         int *offsetAdditionalBlocks,
+                         int *numAdditionalBlocks)
+{
+  uint32_t offsetToIndex, offsetToContent, signatureCount, signatureLen, i;
+  
+  /* One of hasSignatureBlock or hasAdditionalBlocks must be non NULL */
+  if (!hasSignatureBlock && !hasAdditionalBlocks) {
+    return -1;
+  }
+
+
+  /* Skip to the start of the offset index */
+  if (fseek(fp, MAR_ID_SIZE, SEEK_SET)) {
+    return -1;
+  }
+
+  /* Read the offset to the index. */
+  if (fread(&offsetToIndex, sizeof(offsetToIndex), 1, fp) != 1) {
+    return -1;
+  }
+  offsetToIndex = ntohl(offsetToIndex);
+
+  if (numSignatures) {
+     /* Skip past the MAR file size field */
+    if (fseek(fp, sizeof(uint64_t), SEEK_CUR)) {
+      return -1;
+    }
+
+    /* Read the number of signatures field */
+    if (fread(numSignatures, sizeof(*numSignatures), 1, fp) != 1) {
+      return -1;
+    }
+    *numSignatures = ntohl(*numSignatures);
+  }
+
+  /* Skip to the first index entry past the index size field 
+     We do it in 2 calls because offsetToIndex + sizeof(uint32_t) 
+     could oerflow in theory. */
+  if (fseek(fp, offsetToIndex, SEEK_SET)) {
+    return -1;
+  }
+
+  if (fseek(fp, sizeof(uint32_t), SEEK_CUR)) {
+    return -1;
+  }
+
+  /* Read the first offset to content field. */
+  if (fread(&offsetToContent, sizeof(offsetToContent), 1, fp) != 1) {
+    return -1;
+  }
+  offsetToContent = ntohl(offsetToContent);
+
+  /* Check if we have a new or old MAR file */
+  if (hasSignatureBlock) {
+    if (offsetToContent == MAR_ID_SIZE + sizeof(uint32_t)) {
+      *hasSignatureBlock = 0;
+    } else {
+      *hasSignatureBlock = 1;
+    }
+  }
+
+  /* If the caller doesn't care about the product info block 
+     value, then just return */
+  if (!hasAdditionalBlocks) {
+    return 0;
+  }
+
+   /* Skip to the start of the signature block */
+  if (fseeko(fp, SIGNATURE_BLOCK_OFFSET, SEEK_SET)) {
+    return -1;
+  }
+
+  /* Get the number of signatures */
+  if (fread(&signatureCount, sizeof(signatureCount), 1, fp) != 1) {
+    return -1;
+  }
+  signatureCount = ntohl(signatureCount);
+
+  /* Check that we have less than the max amount of signatures so we don't
+     waste too much of either updater's or signmar's time. */
+  if (signatureCount > MAX_SIGNATURES) {
+    return -1;
+  }
+
+  /* Skip past the whole signature block */
+  for (i = 0; i < signatureCount; i++) {
+    /* Skip past the signature algorithm ID */
+    if (fseek(fp, sizeof(uint32_t), SEEK_CUR)) {
+      return -1;
+    }
+
+    /* Read the signature length and skip past the signature */
+    if (fread(&signatureLen, sizeof(uint32_t), 1, fp) != 1) {
+      return -1;
+    }
+    signatureLen = ntohl(signatureLen);
+    if (fseek(fp, signatureLen, SEEK_CUR)) {
+      return -1;
+    }
+  }
+
+  if (ftell(fp) == offsetToContent) {
+    *hasAdditionalBlocks = 0;
+  } else {
+    if (numAdditionalBlocks) {
+      /* We have an additional block, so read in the number of additional blocks
+         and set the offset. */
+      *hasAdditionalBlocks = 1;
+      if (fread(numAdditionalBlocks, sizeof(uint32_t), 1, fp) != 1) {
+        return -1;
+      }
+      *numAdditionalBlocks = ntohl(*numAdditionalBlocks);
+      if (offsetAdditionalBlocks) {
+        *offsetAdditionalBlocks = ftell(fp);
+      }
+    } else if (offsetAdditionalBlocks) {
+      /* numAdditionalBlocks is not specified but offsetAdditionalBlocks 
+         is, so fill it! */
+      *offsetAdditionalBlocks = ftell(fp) + sizeof(uint32_t);
+    }
+  }
+
+  return 0;
+}
+
+/** 
+ * Reads the product info block from the MAR file's additional block section.
+ * The caller is responsible for freeing the fields in infoBlock
+ * if the return is successful.
+ *
+ * @param infoBlock Out parameter for where to store the result to
+ * @return 0 on success, -1 on failure
+*/
+int
+read_product_info_block(char *path, 
+                        struct ProductInformationBlock *infoBlock)
+{
+  int rv;
+  MarFile mar;
+  mar.fp = fopen(path, "rb");
+  if (!mar.fp) {
+    return -1;
+  }
+  rv = mar_read_product_info_block(&mar, infoBlock);
+  fclose(mar.fp);
+  return rv;
+}
+
+/** 
+ * Reads the product info block from the MAR file's additional block section.
+ * The caller is responsible for freeing the fields in infoBlock
+ * if the return is successful.
+ *
+ * @param infoBlock Out parameter for where to store the result to
+ * @return 0 on success, -1 on failure
+*/
+int
+mar_read_product_info_block(MarFile *mar, 
+                            struct ProductInformationBlock *infoBlock)
+{
+  int i, hasAdditionalBlocks, offset, 
+    offsetAdditionalBlocks, numAdditionalBlocks,
+    additionalBlockSize, additionalBlockID;
+  /* The buffer size is 97 bytes because the MAR channel name < 64 bytes, and 
+     product version < 32 bytes + 3 NULL terminator bytes. */
+  char buf[97] = { '\0' };
+  int ret = get_mar_file_info_fp(mar->fp, NULL, NULL,
+                                 &hasAdditionalBlocks, 
+                                 &offsetAdditionalBlocks, 
+                                 &numAdditionalBlocks);
+  for (i = 0; i < numAdditionalBlocks; ++i) {
+    /* Read the additional block size */
+    if (fread(&additionalBlockSize, 
+              sizeof(additionalBlockSize), 
+              1, mar->fp) != 1) {
+      return -1;
+    }
+    additionalBlockSize = ntohl(additionalBlockSize) - 
+                          sizeof(additionalBlockSize) - 
+                          sizeof(additionalBlockID);
+
+    /* Read the additional block ID */
+    if (fread(&additionalBlockID, 
+              sizeof(additionalBlockID), 
+              1, mar->fp) != 1) {
+      return -1;
+    }
+    additionalBlockID = ntohl(additionalBlockID);
+
+    if (PRODUCT_INFO_BLOCK_ID == additionalBlockID) {
+      const char *location;
+      int len;
+
+      /* This block must be at most 104 bytes.
+         MAR channel name < 64 bytes, and product version < 32 bytes + 3 NULL 
+         terminator bytes. We only check for 96 though because we remove 8 
+         bytes above from the additionalBlockSize: We subtract 
+         sizeof(additionalBlockSize) and sizeof(additionalBlockID) */
+      if (additionalBlockSize > 96) {
+        return -1;
+      }
+
+    if (fread(buf, additionalBlockSize, 1, mar->fp) != 1) {
+        return -1;
+      }
+
+      /* Extract the MAR channel name from the buffer.  For now we
+         point to the stack allocated buffer but we strdup this
+         if we are within bounds of each field's max length. */
+      location = buf;
+      len = strlen(location);
+      infoBlock->MARChannelID = location;
+      location += len + 1;
+      if (len >= 64) {
+        infoBlock->MARChannelID = NULL;
+        return -1;
+      }
+
+      /* Extract the version from the buffer */
+      len = strlen(location);
+      infoBlock->productVersion = location;
+      location += len + 1;
+      if (len >= 32) {
+        infoBlock->MARChannelID = NULL;
+        infoBlock->productVersion = NULL;
+        return -1;
+      }
+      infoBlock->MARChannelID = 
+        strdup(infoBlock->MARChannelID);
+      infoBlock->productVersion = 
+        strdup(infoBlock->productVersion);
+      return 0;
+    } else {
+      /* This is not the additional block you're looking for. Move along. */
+      if (fseek(mar->fp, additionalBlockSize, SEEK_CUR)) {
+        return -1;
+      }
+    }
+  }
+
+  /* If we had a product info block we would have already returned */
+  return -1;
+}
+
+const MarItem *mar_find_item(MarFile *mar, const char *name) {
+  uint32_t hash;
+  const MarItem *item;
+
+  hash = mar_hash_name(name);
+
+  item = mar->item_table[hash];
+  while (item && strcmp(item->name, name) != 0)
+    item = item->next;
+
+  return item;
+}
+
+int mar_enum_items(MarFile *mar, MarItemCallback callback, void *closure) {
+  MarItem *item;
+  int i;
+
+  for (i = 0; i < TABLESIZE; ++i) {
+    item = mar->item_table[i];
+    while (item) {
+      int rv = callback(mar, item, closure);
+      if (rv)
+        return rv;
+      item = item->next;
+    }
+  }
+
+  return 0;
+}
+
+int mar_read(MarFile *mar, const MarItem *item, int offset, char *buf,
+             int bufsize) {
+  int nr;
+
+  if (offset == (int) item->length)
+    return 0;
+  if (offset > (int) item->length)
+    return -1;
+
+  nr = item->length - offset;
+  if (nr > bufsize)
+    nr = bufsize;
+
+  if (fseek(mar->fp, item->offset + offset, SEEK_SET))
+    return -1;
+
+  return fread(buf, 1, nr, mar->fp);
+}
+
+/**
+ * Determines the MAR file information.
+ *
+ * @param path                   The path of the MAR file to check.
+ * @param hasSignatureBlock      Optional out parameter specifying if the MAR
+ *                               file has a signature block or not.
+ * @param numSignatures          Optional out parameter for storing the number
+ *                               of signatures in the MAR file.
+ * @param hasAdditionalBlocks    Optional out parameter specifying if the MAR
+ *                               file has additional blocks or not.
+ * @param offsetAdditionalBlocks Optional out parameter for the offset to the 
+ *                               first additional block. Value is only valid if
+ *                               hasAdditionalBlocks is not equal to 0.
+ * @param numAdditionalBlocks    Optional out parameter for the number of
+ *                               additional blocks.  Value is only valid if
+ *                               has_additional_blocks is not equal to 0.
+ * @return 0 on success and non-zero on failure.
+ */
+int get_mar_file_info(const char *path, 
+                      int *hasSignatureBlock,
+                      int *numSignatures,
+                      int *hasAdditionalBlocks,
+                      int *offsetAdditionalBlocks,
+                      int *numAdditionalBlocks)
+{
+  int rv;
+  FILE *fp = fopen(path, "rb");
+  if (!fp) {
+    return -1;
+  }
+
+  rv = get_mar_file_info_fp(fp, hasSignatureBlock, 
+                            numSignatures, hasAdditionalBlocks,
+                            offsetAdditionalBlocks, numAdditionalBlocks);
+
+  fclose(fp);
+  return rv;
+}
diff --git a/Open-ILS/xul/staff_client/external/libmar/tool/Makefile.am b/Open-ILS/xul/staff_client/external/libmar/tool/Makefile.am
new file mode 100644
index 0000000..a84243e
--- /dev/null
+++ b/Open-ILS/xul/staff_client/external/libmar/tool/Makefile.am
@@ -0,0 +1,5 @@
+AM_CPPFLAGS = -I../src/
+noinst_PROGRAMS = mar mbsdiff
+mar_SOURCES = mar.c
+mar_LDADD = ../src/libmar.a
+mbsdiff_SOURCES = bsdiff.c crc32.c
diff --git a/Open-ILS/xul/staff_client/external/libmar/tool/bsdiff.c b/Open-ILS/xul/staff_client/external/libmar/tool/bsdiff.c
new file mode 100644
index 0000000..ea384bb
--- /dev/null
+++ b/Open-ILS/xul/staff_client/external/libmar/tool/bsdiff.c
@@ -0,0 +1,393 @@
+/*-
+ * Copyright 2003-2005 Colin Percival
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted providing that the following conditions 
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Modified 18 March 2013 by Jason Stephenson <jason at sigio.com>.
+ *
+ * Modifications to make it compatible with the output of Mozilla's mbsdiff:
+ *
+ * Switch from 64 bit off_t to 32 bit int32_t.
+ * Don't bzip2 the output blocks.
+ * Use the modified header that Mozilla's bspatch expects.
+ * Add crc32 of the original file to the header.
+ * Use 32-bit ftell and fseek instead of ftello and fseeko.
+ */
+
+#include <sys/types.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <unistd.h>
+
+/* Calculate the crc32. */
+extern uint32_t
+crc32(const unsigned char *buf, uint32_t len);
+
+#define MIN(x,y) (((x)<(y)) ? (x) : (y))
+
+static void split(int32_t *I,int32_t *V,int32_t start,int32_t len,int32_t h)
+{
+	int32_t i,j,k,x,tmp,jj,kk;
+
+	if(len<16) {
+		for(k=start;k<start+len;k+=j) {
+			j=1;x=V[I[k]+h];
+			for(i=1;k+i<start+len;i++) {
+				if(V[I[k+i]+h]<x) {
+					x=V[I[k+i]+h];
+					j=0;
+				};
+				if(V[I[k+i]+h]==x) {
+					tmp=I[k+j];I[k+j]=I[k+i];I[k+i]=tmp;
+					j++;
+				};
+			};
+			for(i=0;i<j;i++) V[I[k+i]]=k+j-1;
+			if(j==1) I[k]=-1;
+		};
+		return;
+	};
+
+	x=V[I[start+len/2]+h];
+	jj=0;kk=0;
+	for(i=start;i<start+len;i++) {
+		if(V[I[i]+h]<x) jj++;
+		if(V[I[i]+h]==x) kk++;
+	};
+	jj+=start;kk+=jj;
+
+	i=start;j=0;k=0;
+	while(i<jj) {
+		if(V[I[i]+h]<x) {
+			i++;
+		} else if(V[I[i]+h]==x) {
+			tmp=I[i];I[i]=I[jj+j];I[jj+j]=tmp;
+			j++;
+		} else {
+			tmp=I[i];I[i]=I[kk+k];I[kk+k]=tmp;
+			k++;
+		};
+	};
+
+	while(jj+j<kk) {
+		if(V[I[jj+j]+h]==x) {
+			j++;
+		} else {
+			tmp=I[jj+j];I[jj+j]=I[kk+k];I[kk+k]=tmp;
+			k++;
+		};
+	};
+
+	if(jj>start) split(I,V,start,jj-start,h);
+
+	for(i=0;i<kk-jj;i++) V[I[jj+i]]=kk-1;
+	if(jj==kk-1) I[jj]=-1;
+
+	if(start+len>kk) split(I,V,kk,start+len-kk,h);
+}
+
+static void qsufsort(int32_t *I,int32_t *V,u_char *old,int32_t oldsize)
+{
+	int32_t buckets[256];
+	int32_t i,h,len;
+
+	for(i=0;i<256;i++) buckets[i]=0;
+	for(i=0;i<oldsize;i++) buckets[old[i]]++;
+	for(i=1;i<256;i++) buckets[i]+=buckets[i-1];
+	for(i=255;i>0;i--) buckets[i]=buckets[i-1];
+	buckets[0]=0;
+
+	for(i=0;i<oldsize;i++) I[++buckets[old[i]]]=i;
+	I[0]=oldsize;
+	for(i=0;i<oldsize;i++) V[i]=buckets[old[i]];
+	V[oldsize]=0;
+	for(i=1;i<256;i++) if(buckets[i]==buckets[i-1]+1) I[buckets[i]]=-1;
+	I[0]=-1;
+
+	for(h=1;I[0]!=-(oldsize+1);h+=h) {
+		len=0;
+		for(i=0;i<oldsize+1;) {
+			if(I[i]<0) {
+				len-=I[i];
+				i-=I[i];
+			} else {
+				if(len) I[i-len]=-len;
+				len=V[I[i]]+1-i;
+				split(I,V,i,len,h);
+				i+=len;
+				len=0;
+			};
+		};
+		if(len) I[i-len]=-len;
+	};
+
+	for(i=0;i<oldsize+1;i++) I[V[i]]=i;
+}
+
+static int32_t matchlen(u_char *old,int32_t oldsize,u_char *new,int32_t newsize)
+{
+	int32_t i;
+
+	for(i=0;(i<oldsize)&&(i<newsize);i++)
+		if(old[i]!=new[i]) break;
+
+	return i;
+}
+
+static int32_t search(int32_t *I,u_char *old,int32_t oldsize,
+		u_char *new,int32_t newsize,int32_t st,int32_t en,int32_t *pos)
+{
+	int32_t x,y;
+
+	if(en-st<2) {
+		x=matchlen(old+I[st],oldsize-I[st],new,newsize);
+		y=matchlen(old+I[en],oldsize-I[en],new,newsize);
+
+		if(x>y) {
+			*pos=I[st];
+			return x;
+		} else {
+			*pos=I[en];
+			return y;
+		}
+	};
+
+	x=st+(en-st)/2;
+	if(memcmp(old+I[x],new,MIN(oldsize-I[x],newsize))<0) {
+		return search(I,old,oldsize,new,newsize,x,en,pos);
+	} else {
+		return search(I,old,oldsize,new,newsize,st,x,pos);
+	};
+}
+
+int main(int argc,char *argv[])
+{
+	int fd;
+	u_char *old,*new;
+	int32_t oldsize,newsize;
+	int32_t *I,*V;
+	int32_t scan,pos,len;
+	int32_t lastscan,lastpos,lastoffset;
+	int32_t oldscore,scsc;
+	int32_t s,Sf,lenf,Sb,lenb;
+	int32_t overlap,Ss,lens;
+	int32_t i;
+	int32_t dblen,eblen;
+	u_char *db,*eb;
+	u_char header[32];
+	FILE * pf;
+	uint32_t crcVal;
+	int32_t outVal; /* place holder for result of htonl */
+
+	if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]);
+
+	/* Allocate oldsize+1 bytes instead of oldsize bytes to ensure
+		that we never try to malloc(0) and get a NULL pointer */
+	if(((fd=open(argv[1],O_RDONLY,0))<0) ||
+		((oldsize=lseek(fd,0,SEEK_END))==-1) ||
+		((old=malloc(oldsize+1))==NULL) ||
+		(lseek(fd,0,SEEK_SET)!=0) ||
+		(read(fd,old,oldsize)!=oldsize) ||
+		(close(fd)==-1)) err(1,"%s",argv[1]);
+
+	if(((I=malloc((oldsize+1)*sizeof(int32_t)))==NULL) ||
+		((V=malloc((oldsize+1)*sizeof(int32_t)))==NULL)) err(1,NULL);
+
+	/* Calculate the old file's crc32 value. */
+	crcVal = crc32(old, oldsize);
+
+	qsufsort(I,V,old,oldsize);
+
+	free(V);
+
+	/* Allocate newsize+1 bytes instead of newsize bytes to ensure
+		that we never try to malloc(0) and get a NULL pointer */
+	if(((fd=open(argv[2],O_RDONLY,0))<0) ||
+		((newsize=lseek(fd,0,SEEK_END))==-1) ||
+		((new=malloc(newsize+1))==NULL) ||
+		(lseek(fd,0,SEEK_SET)!=0) ||
+		(read(fd,new,newsize)!=newsize) ||
+		(close(fd)==-1)) err(1,"%s",argv[2]);
+
+	if(((db=malloc(newsize+1))==NULL) ||
+		((eb=malloc(newsize+1))==NULL)) err(1,NULL);
+	dblen=0;
+	eblen=0;
+
+	/* Create the patch file */
+	if ((pf = fopen(argv[3], "w")) == NULL)
+		err(1, "%s", argv[3]);
+
+	/* This is the modified header used by Mozilla's hacked bspatch. It
+	 * doesn't actually bzip2 anything despite what the documentation on
+	 * the wiki implies. */
+	/* Header is
+		0	8	 "MBDIFF10"
+    8 4  length of the file to be patched
+    12 4 crc32 of file to be patched
+    16 4 length of the new file
+		20 4 length of ctrl block
+		24 4 length of diff block
+    28 4 length of extra block
+	/* File is
+		0	32	Header
+		32	??	ctrl block
+		??	??	diff block
+		??	??	extra block */
+	memcpy(header, "MBDIFF10", 8);
+	outVal = htonl(oldsize);
+	memcpy(header + 8, &outVal, 4);
+	outVal = htonl(crcVal);
+	memcpy(header + 12, &outVal, 4);
+	outVal = htonl(newsize);
+	memcpy(header + 16, &outVal, 4);
+	memcpy(header + 20, 0, 12);
+	if (fwrite(header, 32, 1, pf) != 1)
+		err(1, "fwrite(%s)", argv[3]);
+
+	/* Compute the differences, writing ctrl as we go */
+	scan=0;len=0;
+	lastscan=0;lastpos=0;lastoffset=0;
+	while(scan<newsize) {
+		oldscore=0;
+
+		for(scsc=scan+=len;scan<newsize;scan++) {
+			len=search(I,old,oldsize,new+scan,newsize-scan,
+					0,oldsize,&pos);
+
+			for(;scsc<scan+len;scsc++)
+			if((scsc+lastoffset<oldsize) &&
+				(old[scsc+lastoffset] == new[scsc]))
+				oldscore++;
+
+			if(((len==oldscore) && (len!=0)) || 
+				(len>oldscore+8)) break;
+
+			if((scan+lastoffset<oldsize) &&
+				(old[scan+lastoffset] == new[scan]))
+				oldscore--;
+		};
+
+		if((len!=oldscore) || (scan==newsize)) {
+			s=0;Sf=0;lenf=0;
+			for(i=0;(lastscan+i<scan)&&(lastpos+i<oldsize);) {
+				if(old[lastpos+i]==new[lastscan+i]) s++;
+				i++;
+				if(s*2-i>Sf*2-lenf) { Sf=s; lenf=i; };
+			};
+
+			lenb=0;
+			if(scan<newsize) {
+				s=0;Sb=0;
+				for(i=1;(scan>=lastscan+i)&&(pos>=i);i++) {
+					if(old[pos-i]==new[scan-i]) s++;
+					if(s*2-i>Sb*2-lenb) { Sb=s; lenb=i; };
+				};
+			};
+
+			if(lastscan+lenf>scan-lenb) {
+				overlap=(lastscan+lenf)-(scan-lenb);
+				s=0;Ss=0;lens=0;
+				for(i=0;i<overlap;i++) {
+					if(new[lastscan+lenf-overlap+i]==
+					   old[lastpos+lenf-overlap+i]) s++;
+					if(new[scan-lenb+i]==
+					   old[pos-lenb+i]) s--;
+					if(s>Ss) { Ss=s; lens=i+1; };
+				};
+
+				lenf+=lens-overlap;
+				lenb-=lens;
+			};
+
+			for(i=0;i<lenf;i++)
+				db[dblen+i]=new[lastscan+i]-old[lastpos+i];
+			for(i=0;i<(scan-lenb)-(lastscan+lenf);i++)
+				eb[eblen+i]=new[lastscan+lenf+i];
+
+			dblen+=lenf;
+			eblen+=(scan-lenb)-(lastscan+lenf);
+
+			outVal = htonl(lenf);
+			if (fwrite(&outVal, 4, 1, pf) != 1)
+				err(1, "fwrite(%s)", argv[3]);
+
+			outVal = htonl((scan-lenb)-(lastscan+lenf));
+			if (fwrite(&outVal, 4, 1, pf) != 1)
+				err(1, "fwrite(%s)", argv[3]);
+
+			outVal = htonl((pos-lenb)-(lastpos+lenf));
+			if (fwrite(&outVal, 4, 1, pf) != 1)
+				err(1, "fwrite(%s)", argv[3]);
+
+			lastscan=scan-lenb;
+			lastpos=pos-lenb;
+			lastoffset=pos-scan;
+		};
+	};
+
+	/* Compute size of ctrl data */
+	if ((len = ftell(pf)) == -1)
+		err(1, "ftell");
+	outVal = htonl(len - 32);
+	memcpy(header + 20, &outVal, 4);
+
+	/* Write the diff data */
+	if (fwrite(db, 1, dblen, pf) != dblen)
+		err(1, "fwrite(%s)", argv[3]);
+
+	/* Size of diff data */
+	outVal = htonl(dblen);
+	memcpy(header + 24, &outVal, 4);
+
+	/* Write extra data */
+	if (fwrite(eb, 1, eblen, pf) != eblen)
+		err(1, "fwrite(%s)", argv[3]);
+
+	/* Size of extra data */
+	outVal = htonl(eblen);
+	memcpy(header + 28, &outVal, 4);
+
+	/* Seek to the beginning, write the header, and close the file */
+	if (fseek(pf, 0, SEEK_SET))
+		err(1, "fseek");
+	if (fwrite(header, 32, 1, pf) != 1)
+		err(1, "fwrite(%s)", argv[3]);
+	if (fclose(pf))
+		err(1, "fclose");
+
+	/* Free the memory we used */
+	free(db);
+	free(eb);
+	free(I);
+	free(old);
+	free(new);
+
+	return 0;
+}
diff --git a/Open-ILS/xul/staff_client/external/libmar/tool/crc32.c b/Open-ILS/xul/staff_client/external/libmar/tool/crc32.c
new file mode 100644
index 0000000..d249076
--- /dev/null
+++ b/Open-ILS/xul/staff_client/external/libmar/tool/crc32.c
@@ -0,0 +1,22 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include <stdint.h>
+
+/* This guy lives in libbz2, and is the only reason we need libbz2. */
+ extern uint32_t BZ2_crc32Table[256];
+
+uint32_t
+crc32(const unsigned char *buf, uint32_t len)
+{
+  uint32_t crc = 0xffffffffL;
+
+  const unsigned char *end = buf + len;
+  for (; buf != end; ++buf)
+    crc = (crc << 8) ^ crc32Table[(crc >> 24) ^ *buf];
+
+  crc = ~crc;
+  return crc;
+}
diff --git a/Open-ILS/xul/staff_client/external/libmar/tool/mar.c b/Open-ILS/xul/staff_client/external/libmar/tool/mar.c
new file mode 100644
index 0000000..1e4db33
--- /dev/null
+++ b/Open-ILS/xul/staff_client/external/libmar/tool/mar.c
@@ -0,0 +1,179 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/*
+ * This file is part of Evergreen.
+ *
+ * Evergreen 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 of the License,
+ * or (at your option) any later version.
+ *
+ * Evergreen 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 Evergreen.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * This Source Code Form is derived from code that was originally
+ * subject to the terms of the Mozilla Public License, v. 2.0 and
+ * included in Evergreen.  You may, therefore, use this Source Code
+ * Form under the terms of the Mozilla Public License 2.0.  This
+ * licensing option does not affect the larger Evergreen project, only
+ * the Source Code Forms bearing this exception are affected.  If a
+ * copy of the MPL was not distributed with this file, You can obtain
+ * one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <config.h>
+#include "mar.h"
+#include "mar_cmdline.h"
+
+#ifdef XP_WIN
+#include <windows.h>
+#include <direct.h>
+#define chdir _chdir
+#else
+#include <unistd.h>
+#endif
+
+static void print_usage() {
+  printf("usage:\n");
+  printf("Create a MAR file:\n");
+  printf("  mar [-H MARChannelID] [-V ProductVersion] [-C workingDir] "
+         "{-c|-x|-t|-T} archive.mar [files...]\n");
+  printf("Print information on a MAR file:\n");
+  printf("  mar [-H MARChannelID] [-V ProductVersion] [-C workingDir] "
+         "-i unsigned_archive_to_refresh.mar\n");
+  printf("This program does not handle unicode file paths properly\n");
+}
+
+static int mar_test_callback(MarFile *mar, 
+                             const MarItem *item, 
+                             void *unused) {
+  printf("%u\t0%o\t%s\n", item->length, item->flags, item->name);
+  return 0;
+}
+
+static int mar_test(const char *path) {
+  MarFile *mar;
+
+  mar = mar_open(path);
+  if (!mar)
+    return -1;
+
+  printf("SIZE\tMODE\tNAME\n");
+  mar_enum_items(mar, mar_test_callback, NULL);
+
+  mar_close(mar);
+  return 0;
+}
+
+int main(int argc, char **argv) {
+  char *MARChannelID = MAR_CHANNEL_ID;
+  char *productVersion = MOZ_APP_VERSION;
+  uint32_t i, k;
+  int rv = -1;
+
+  if (argc < 3) {
+    print_usage();
+    return -1;
+  }
+
+  while (argc > 0) {
+    if (argv[1][0] == '-' && (argv[1][1] == 'c' || 
+        argv[1][1] == 't' || argv[1][1] == 'x' || 
+        argv[1][1] == 'i' || argv[1][1] == 'T')) {
+      break;
+    /* -C workingdirectory */
+    } else if (argv[1][0] == '-' && argv[1][1] == 'C') {
+      chdir(argv[2]);
+      argv += 2;
+      argc -= 2;
+    /* MAR channel ID */
+    } else if (argv[1][0] == '-' && argv[1][1] == 'H') {
+      MARChannelID = argv[2];
+      argv += 2;
+      argc -= 2;
+    /* Product Version */
+    } else if (argv[1][0] == '-' && argv[1][1] == 'V') {
+      productVersion = argv[2];
+      argv += 2;
+      argc -= 2;
+    }
+    else {
+      print_usage();
+      return -1;
+    }
+  }
+
+  if (argv[1][0] != '-') {
+    print_usage();
+    return -1;
+  }
+
+  switch (argv[1][1]) {
+  case 'c': {
+    struct ProductInformationBlock infoBlock;
+    infoBlock.MARChannelID = MARChannelID;
+    infoBlock.productVersion = productVersion;
+    return mar_create(argv[2], argc - 3, argv + 3, &infoBlock);
+  }
+  case 'i': {
+    struct ProductInformationBlock infoBlock;
+    infoBlock.MARChannelID = MARChannelID;
+    infoBlock.productVersion = productVersion;
+    return refresh_product_info_block(argv[2], &infoBlock);
+  }
+  case 'T': {
+    struct ProductInformationBlock infoBlock;
+    uint32_t numSignatures, numAdditionalBlocks;
+    int hasSignatureBlock, hasAdditionalBlock;
+    if (!get_mar_file_info(argv[2], 
+                           &hasSignatureBlock,
+                           &numSignatures,
+                           &hasAdditionalBlock, 
+                           NULL, &numAdditionalBlocks)) {
+      if (hasSignatureBlock) {
+        printf("Signature block found with %d signature%s\n", 
+               numSignatures, 
+               numSignatures != 1 ? "s" : "");
+      }
+      if (hasAdditionalBlock) {
+        printf("%d additional block%s found:\n", 
+               numAdditionalBlocks,
+               numAdditionalBlocks != 1 ? "s" : "");
+      }
+
+      rv = read_product_info_block(argv[2], &infoBlock);
+      if (!rv) {
+        printf("  - Product Information Block:\n");
+        printf("    - MAR channel name: %s\n"
+               "    - Product version: %s\n",
+               infoBlock.MARChannelID,
+               infoBlock.productVersion);
+        free((void *)infoBlock.MARChannelID);
+        free((void *)infoBlock.productVersion);
+      }
+     }
+    printf("\n");
+    /* The fall through from 'T' to 't' is intentional */
+  }
+  case 't':
+    return mar_test(argv[2]);
+
+  /* Extract a MAR file */
+  case 'x':
+    return mar_extract(argv[2]);
+
+  default:
+    print_usage();
+    return -1;
+  }
+
+  return 0;
+}
diff --git a/Open-ILS/xul/staff_client/external/make_updates.sh b/Open-ILS/xul/staff_client/external/make_updates.sh
index d708e91..db7006f 100755
--- a/Open-ILS/xul/staff_client/external/make_updates.sh
+++ b/Open-ILS/xul/staff_client/external/make_updates.sh
@@ -193,12 +193,13 @@ function check_mar
 		MBSDIFF=${MBSDIFF:-mbsdiff}
 	fi
 	if [ ! -x "$MAR" -o ! -x "$MBSDIFF" ]; then
-		if [ ! -f "external/mar" -o ! -f "external/mbsdiff" ]; then
-			wget ftp://ftp.mozilla.org/pub/mozilla.org/xulrunner/mar-generation-tools/mar-generation-tools-linux.zip
-			unzip mar-generation-tools-linux.zip -d external
+		if [ ! -f "external/limbar/tool/mar" -o ! -f "external/libmar/tool/mbsdiff" ]; then
+		    cd external/libmar
+		    make
+		    cd -
 		fi
-		MAR="$PWD/external/mar"
-		MBSDIFF="$PWD/external/mbsdiff"
+		MAR="$PWD/external/libmar/tool/mar"
+		MBSDIFF="$PWD/external/libmar/tool/mbsdiff"
 	fi
 }
 
diff --git a/configure.ac b/configure.ac
index fab6180..d8ac271 100644
--- a/configure.ac
+++ b/configure.ac
@@ -24,6 +24,7 @@ AC_INIT(Open-ILS, trunk, open-ils-dev at list.georgialibraries.org)
 AM_INIT_AUTOMAKE([OpenILS], [trunk])
 AC_REVISION($Revision: 0.1 $)
 AC_CONFIG_SRCDIR([configure.ac])
+AC_CONFIG_SUBDIRS([Open-ILS/xul/staff_client/external/libmar])
 AC_SUBST(prefix)
 AC_SUBST([abs_top_builddir])
 #-----------------------------------

-----------------------------------------------------------------------

Summary of changes:
 Open-ILS/src/extras/Makefile.install               |    6 +-
 .../xul/staff_client/external/libmar/Makefile.am   |    1 +
 Open-ILS/xul/staff_client/external/libmar/README   |   11 +
 .../xul/staff_client/external/libmar/configure.ac  |   50 ++
 .../staff_client/external/libmar/src/Makefile.am   |    2 +
 .../xul/staff_client/external/libmar/src/mar.h     |  169 ++++++
 .../staff_client/external/libmar/src/mar_cmdline.h |   94 ++++
 .../staff_client/external/libmar/src/mar_create.c  |  416 ++++++++++++++
 .../staff_client/external/libmar/src/mar_extract.c |  102 ++++
 .../staff_client/external/libmar/src/mar_private.h |   88 +++
 .../staff_client/external/libmar/src/mar_read.c    |  581 ++++++++++++++++++++
 .../staff_client/external/libmar/tool/Makefile.am  |    5 +
 .../xul/staff_client/external/libmar/tool/bsdiff.c |  393 +++++++++++++
 .../xul/staff_client/external/libmar/tool/crc32.c  |   22 +
 .../xul/staff_client/external/libmar/tool/mar.c    |  179 ++++++
 Open-ILS/xul/staff_client/external/make_updates.sh |   11 +-
 configure.ac                                       |    1 +
 .../Administration/new-updates-tools.txt           |   29 +
 18 files changed, 2153 insertions(+), 7 deletions(-)
 create mode 100644 Open-ILS/xul/staff_client/external/libmar/Makefile.am
 create mode 100644 Open-ILS/xul/staff_client/external/libmar/README
 create mode 100644 Open-ILS/xul/staff_client/external/libmar/configure.ac
 create mode 100644 Open-ILS/xul/staff_client/external/libmar/src/Makefile.am
 create mode 100644 Open-ILS/xul/staff_client/external/libmar/src/mar.h
 create mode 100644 Open-ILS/xul/staff_client/external/libmar/src/mar_cmdline.h
 create mode 100644 Open-ILS/xul/staff_client/external/libmar/src/mar_create.c
 create mode 100644 Open-ILS/xul/staff_client/external/libmar/src/mar_extract.c
 create mode 100644 Open-ILS/xul/staff_client/external/libmar/src/mar_private.h
 create mode 100644 Open-ILS/xul/staff_client/external/libmar/src/mar_read.c
 create mode 100644 Open-ILS/xul/staff_client/external/libmar/tool/Makefile.am
 create mode 100644 Open-ILS/xul/staff_client/external/libmar/tool/bsdiff.c
 create mode 100644 Open-ILS/xul/staff_client/external/libmar/tool/crc32.c
 create mode 100644 Open-ILS/xul/staff_client/external/libmar/tool/mar.c
 create mode 100644 docs/RELEASE_NOTES_NEXT/Administration/new-updates-tools.txt


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list