-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Windows API plugin #54
Comments
This is completely untested; it probably won't even compile. However, most of the work should be done, so if someone wants to pick it up and finish it it should be pretty straightforward. AFAIK the only thing that really needs to be done is to fix the max_compressed_size functions to better match whatever RtlCompressBuffer actually does. See #54
I've added a Windows plugin to the wip/windows branch. There is still some work to be done (which is hard for me to do without a Windows development environment), but it should be pretty straightforward. Basically, someone just needs to get it to compile, then provide more realistic implementations of the Just in case I end up deleting the branch, here is the diff: diff --git a/docs/index.md b/docs/index.md
index efe7167..ef38773 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -60,6 +60,7 @@ Squash currently contains plugins for the following libraries:
- [QuickLZ](@ref md_plugins_quicklz_quicklz)
- [Snappy](@ref md_plugins_snappy_snappy)
- [wfLZ](@ref md_plugins_wflz_wflz)
+- [Windows](@ref md_plugins_windows_windows)
- [yalz77](@ref md_plugins_yalz77_yalz77)
- [zlib](@ref md_plugins_zlib_zlib)
- [zlib-ng](@ref md_plugins_zlib-ng_zlib-ng)
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
index f4a4a4e..21443fa 100644
--- a/plugins/CMakeLists.txt
+++ b/plugins/CMakeLists.txt
@@ -27,6 +27,7 @@ set (plugins_available
quicklz
snappy
wflz
+ windows
yalz77
zlib
zlib-ng
diff --git a/plugins/windows/CMakeLists.txt b/plugins/windows/CMakeLists.txt
new file mode 100644
index 0000000..b35ba3c
--- /dev/null
+++ b/plugins/windows/CMakeLists.txt
@@ -0,0 +1,13 @@
+include (SquashPlugin)
+
+check_include_file("Ntifs.h" HAVE_NTIFS_H)
+if(HAVE_NTIFS_H)
+ set(SQUASH_WINDOWS_ENABLED_DEFAULT "")
+else()
+ set(SQUASH_WINDOWS_ENABLED_DEFAULT "DEFAULT_DISABLED")
+endif(HAVE_NTIFS_H)
+
+squash_plugin (
+ NAME windows
+ ${SQUASH_WINDOWS_ENABLED_DEFAULT}
+ SOURCES squash-windows.c)
diff --git a/plugins/windows/squash-windows.c b/plugins/windows/squash-windows.c
new file mode 100644
index 0000000..03280e7
--- /dev/null
+++ b/plugins/windows/squash-windows.c
@@ -0,0 +1,194 @@
+/* Copyright (c) 2016 The Squash Authors
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Evan Nemerson <evan@nemerson.com>
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <Ntifs.h>
+
+#include <squash/squash.h>
+
+SQUASH_PLUGIN_EXPORT
+SquashStatus squash_plugin_init_codec (SquashCodec* codec, SquashCodecImpl* impl);
+
+static size_t
+squash_windows_lznt1_get_max_compressed_size (SquashCodec* codec, size_t uncompressed_size) {
+ return uncompressed_size * 2 + 256;
+}
+
+static size_t
+squash_windows_xpress_get_max_compressed_size (SquashCodec* codec, size_t uncompressed_size) {
+ return uncompressed_size * 2 + 256;
+}
+
+static size_t
+squash_windows_xpress_huffman_get_max_compressed_size (SquashCodec* codec, size_t uncompressed_size) {
+ return uncompressed_size * 2 + 256;
+}
+
+enum SquashWindowsOptIndex {
+ SQUASH_WINDOWS_OPT_LEVEL = 0
+};
+
+static SquashOptionInfo squash_windows_options[] = {
+ { "level",
+ SQUASH_OPTION_TYPE_RANGE_INT,
+ .info.range_int = {
+ .min = 1,
+ .max = 2 },
+ .default_value.int_value = 1 },
+};
+
+static USHORT squash_windows_get_format_from_codec (SquashCodec* codec) {
+ const char* name = squash_codec_get_name (codec);
+
+ if (name[0] == 'l')
+ return COMPRESSION_FORMAT_LZNT1;
+ else if (name[6] == '-')
+ return COMPRESSION_FORMAT_XPRESS_HUFF;
+ else
+ return COMPRESSION_FORMAT_XPRESS;
+}
+
+static SquashStatus
+squash_windows_compress_buffer (SquashCodec* codec,
+ size_t* compressed_size,
+ uint8_t compressed[SQUASH_ARRAY_PARAM(*compressed_size)],
+ size_t uncompressed_size,
+ const uint8_t uncompressed[SQUASH_ARRAY_PARAM(uncompressed_size)],
+ SquashOptions* options) {
+ const USHORT engine = squash_options_get_int_at (options, codec, SQUASH_ZLIB_OPT_LEVEL) == 1 ?
+ COMPRESSION_ENGINE_STANDARD : COMPRESSION_ENGINE_MAXIMUM;
+ const USHORT format = squash_windows_get_format_from_codec (codec);
+ const USHORT format_and_engine = format | engine;
+ uint8_t* workmem = NULL;
+ ULONG workmem_size;
+ NTSTATUS r;
+ ULONG out_size;
+
+#if ULONG_MAX < SIZE_MAX
+ if (SQUASH_UNLIKELY(ULONG_MAX < *compressed_size) ||
+ SQUASH_UNLIKELY(ULONG_MAX < decompressed_size))
+ return squash_error (SQUASH_RANGE);
+#endif
+
+ r = RtlGetCompressionWorkSpaceSize (format_and_engine, &workmem_size, NULL);
+ if (SQUASH_UNLIKELY(r != STATUS_SUCCESS))
+ return squash_error (SQUASH_FAILED);
+
+ workmem = squash_malloc(workmem_size);
+ if (SQUASH_UNLIKELY(workmem == NULL))
+ return squash_error (SQUASH_MEMORY);
+
+ r = RtlCompressBuffer (format_and_engine,
+ (PUCHAR) uncompressed, (ULONG) uncompressed_size,
+ (PUCHAR) compressed, (ULONG) *compressed_size,
+ 4096, &out_size, workmem);
+
+ squash_free (workmem);
+
+ if (SQUASH_UNLIKELY(r != STATUS_SUCCCESS)) {
+ switch (r) {
+ case STATUS_BUFFER_ALL_ZEROS:
+ break;
+ case STATUS_BUFFER_TOO_SMALL:
+ return squash_error (SQUASH_BUFFER_FULL);
+ default:
+ return squash_error (SQUASH_FAILED);
+ }
+ }
+
+#if SIZE_MAX < ULONG_MAX
+ if (SQUASH_UNLIKELY(SIZE_MAX < out_size))
+ return squash_error (SQUASH_RANGE);
+#endif
+
+ *compressed_size = (size_t) out_size;
+
+ return SQUASH_OK;
+}
+
+static SquashStatus
+squash_windows_decompress_buffer (SquashCodec* codec,
+ size_t* decompressed_size,
+ uint8_t decompressed[SQUASH_ARRAY_PARAM(*decompressed_size)],
+ size_t compressed_size,
+ const uint8_t compressed[SQUASH_ARRAY_PARAM(compressed_size)],
+ SquashOptions* options) {
+ const USHORT format = squash_windows_get_format_from_codec (codec);
+ ULONG out_size;
+ NTSTATUS r;
+
+#if ULONG_MAX < SIZE_MAX
+ if (SQUASH_UNLIKELY(ULONG_MAX < compressed_size) ||
+ SQUASH_UNLIKELY(ULONG_MAX < *decompressed_size))
+ return squash_error (SQUASH_RANGE);
+#endif
+
+ r = RtlDecompressBuffer(format,
+ (PUCHAR) decompressed, (ULONG) *decompressed_size,
+ (PUCHAR) compressed, (ULONG) compressed_size,
+ &out_size);
+
+#if SIZE_MAX < ULONG_MAX
+ if (SQUASH_UNLIKELY(SIZE_MAX < out_size))
+ return squash_error (SQUASH_RANGE);
+#endif
+
+ if (SQUASH_UNLIKELY(r != STATUS_SUCCESS)) {
+ switch (r) {
+ case STATUS_BAD_COMPRESSION_BUFFER:
+ return squash_error (SQUASH_BUFFER_FULL);
+ default:
+ return squash_error (SQUASH_FAILED);
+ }
+ }
+
+ *decompressed_size = (size_t) out_size;
+
+ return SQUASH_OK;
+}
+
+SquashStatus
+squash_plugin_init_codec (SquashCodec* codec, SquashCodecImpl* impl) {
+ const char* name = squash_codec_get_name (codec);
+
+ if (strcmp ("lznt1", name) == 0)
+ impl->get_max_compressed_size = squash_windows_lznt1_get_max_compressed_size;
+ else if (strcmp ("xpress", name) == 0)
+ impl->get_max_compressed_size = squash_windows_xpress_get_max_compressed_size;
+ else if (strcmp ("xpress-huffman", name) == 0)
+ impl->get_max_compressed_size = squash_windows_xpress_huffman_get_max_compressed_size;
+ else
+ return squash_error (SQUASH_UNABLE_TO_LOAD);
+
+ impl->options = squash_windows_options;
+ impl->decompress_buffer = squash_windows_decompress_buffer;
+ impl->compress_buffer = squash_windows_compress_buffer;
+
+ return SQUASH_OK;
+}
diff --git a/plugins/windows/squash.ini b/plugins/windows/squash.ini
new file mode 100644
index 0000000..7ebb826
--- /dev/null
+++ b/plugins/windows/squash.ini
@@ -0,0 +1,5 @@
+license=Proprietary
+
+[lznt1]
+[xpress]
+[xpress-huffman]
diff --git a/plugins/windows/windows.md b/plugins/windows/windows.md
new file mode 100644
index 0000000..10715df
--- /dev/null
+++ b/plugins/windows/windows.md
@@ -0,0 +1,29 @@
+# windows Plugin #
+
+This plugin uses the Windows compression API (RtlCompressBuffer et. al.).
+
+For more information about this API, see the
+[RtlCompressBuffer documentation](https://msdn.microsoft.com/en-us/library/windows/hardware/ff552127(v=vs.85).aspx)
+
+Note: this plugin is only available on Windows. For a cross-platform
+implementation of LZNT1 and Xpress-huffman, see the ms-compress
+plugin.
+
+## Codecs ##
+
+- **lznt1** — LZNT1 data.
+- **xpress** — Xpress data.
+- **xpress-huffman** — Xpress-huffman data.
+
+## Options ##
+
+### Compression Only ###
+
+- **level** (integer, 1 or 2, default 1): whether to use the standard
+ or maximume compression engine.
+
+## License ##
+
+The windows plugin is licensed under the
+[MIT License](http://opensource.org/licenses/MIT). The Windows API is
+proprietary. |
Note that the random-data test provides a convenient way to figure out those
Where $codec is lznt1, xpress, and xpress-huffman. |
http://msdn.microsoft.com/en-us/library/windows/hardware/ff552127%28v=vs.85%29.aspx (RtlCompressBuffer)
Depends on #38.
The text was updated successfully, but these errors were encountered: