aboutsummaryrefslogtreecommitdiff
path: root/subversion/libsvn_subr/compress_lz4.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_subr/compress_lz4.c')
-rw-r--r--subversion/libsvn_subr/compress_lz4.c144
1 files changed, 144 insertions, 0 deletions
diff --git a/subversion/libsvn_subr/compress_lz4.c b/subversion/libsvn_subr/compress_lz4.c
new file mode 100644
index 000000000000..d700b3215566
--- /dev/null
+++ b/subversion/libsvn_subr/compress_lz4.c
@@ -0,0 +1,144 @@
+/*
+ * compress_lz4.c: LZ4 data compression routines
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+#include <assert.h>
+
+#include "private/svn_subr_private.h"
+
+#include "svn_private_config.h"
+
+#if SVN_INTERNAL_LZ4
+#include "lz4/lz4internal.h"
+#else
+#include <lz4.h>
+#endif
+
+svn_error_t *
+svn__compress_lz4(const void *data, apr_size_t len,
+ svn_stringbuf_t *out)
+{
+ apr_size_t hdrlen;
+ unsigned char buf[SVN__MAX_ENCODED_UINT_LEN];
+ unsigned char *p;
+ int compressed_data_len;
+ int max_compressed_data_len;
+
+ assert(len <= LZ4_MAX_INPUT_SIZE);
+
+ p = svn__encode_uint(buf, (apr_uint64_t)len);
+ hdrlen = p - buf;
+ max_compressed_data_len = LZ4_compressBound((int)len);
+ svn_stringbuf_setempty(out);
+ svn_stringbuf_ensure(out, max_compressed_data_len + hdrlen);
+ svn_stringbuf_appendbytes(out, (const char *)buf, hdrlen);
+ compressed_data_len = LZ4_compress_default(data, out->data + out->len,
+ (int)len, max_compressed_data_len);
+ if (!compressed_data_len)
+ return svn_error_create(SVN_ERR_LZ4_COMPRESSION_FAILED, NULL, NULL);
+
+ if (compressed_data_len >= (int)len)
+ {
+ /* Compression didn't help :(, just append the original text */
+ svn_stringbuf_appendbytes(out, data, len);
+ }
+ else
+ {
+ out->len += compressed_data_len;
+ out->data[out->len] = 0;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn__decompress_lz4(const void *data, apr_size_t len,
+ svn_stringbuf_t *out,
+ apr_size_t limit)
+{
+ apr_size_t hdrlen;
+ int compressed_data_len;
+ int decompressed_data_len;
+ apr_uint64_t u64;
+ const unsigned char *p = data;
+ int rv;
+
+ assert(len <= INT_MAX);
+ assert(limit <= INT_MAX);
+
+ /* First thing in the string is the original length. */
+ p = svn__decode_uint(&u64, p, p + len);
+ if (p == NULL)
+ return svn_error_create(SVN_ERR_SVNDIFF_INVALID_COMPRESSED_DATA, NULL,
+ _("Decompression of compressed data failed: "
+ "no size"));
+ if (u64 > limit)
+ return svn_error_create(SVN_ERR_SVNDIFF_INVALID_COMPRESSED_DATA, NULL,
+ _("Decompression of compressed data failed: "
+ "size too large"));
+ decompressed_data_len = (int)u64;
+ hdrlen = p - (const unsigned char *)data;
+ compressed_data_len = (int)(len - hdrlen);
+
+ svn_stringbuf_setempty(out);
+ svn_stringbuf_ensure(out, decompressed_data_len);
+
+ if (compressed_data_len == decompressed_data_len)
+ {
+ /* Data is in the original, uncompressed form. */
+ memcpy(out->data, p, decompressed_data_len);
+ }
+ else
+ {
+ rv = LZ4_decompress_safe((const char *)p, out->data, compressed_data_len,
+ decompressed_data_len);
+ if (rv < 0)
+ return svn_error_create(SVN_ERR_LZ4_DECOMPRESSION_FAILED, NULL, NULL);
+
+ if (rv != decompressed_data_len)
+ return svn_error_create(SVN_ERR_SVNDIFF_INVALID_COMPRESSED_DATA,
+ NULL,
+ _("Size of uncompressed data "
+ "does not match stored original length"));
+ }
+
+ out->data[decompressed_data_len] = 0;
+ out->len = decompressed_data_len;
+
+ return SVN_NO_ERROR;
+}
+
+const char *
+svn_lz4__compiled_version(void)
+{
+ static const char lz4_version_str[] = APR_STRINGIFY(LZ4_VERSION_MAJOR) "." \
+ APR_STRINGIFY(LZ4_VERSION_MINOR) "." \
+ APR_STRINGIFY(LZ4_VERSION_RELEASE);
+
+ return lz4_version_str;
+}
+
+int
+svn_lz4__runtime_version(void)
+{
+ return LZ4_versionNumber();
+}