summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYann Collet <Cyan4973@users.noreply.github.com>2022-03-21 23:36:46 (GMT)
committerGitHub <noreply@github.com>2022-03-21 23:36:46 (GMT)
commitf14be20f5d21e074211daa2b15beeedb714736df (patch)
treef77c1129fa31a4a3d70a2a8fef4663513e5de3d6
parent5b138c01b4644c133e556d96ad6105d24c401cac (diff)
parentf5625f260e746ae97a68120cd5e46c1a8ac53505 (diff)
downloadlz4-f14be20f5d21e074211daa2b15beeedb714736df.zip
lz4-f14be20f5d21e074211daa2b15beeedb714736df.tar.gz
lz4-f14be20f5d21e074211daa2b15beeedb714736df.tar.bz2
Merge pull request #1068 from anjiahao1/dev
add file operation
-rw-r--r--examples/.gitignore1
-rw-r--r--examples/Makefile10
-rw-r--r--examples/fileCompress.c232
-rw-r--r--lib/lz4file.c311
-rw-r--r--lib/lz4file.h93
5 files changed, 645 insertions, 2 deletions
diff --git a/examples/.gitignore b/examples/.gitignore
index 5abeef6..ddc8e21 100644
--- a/examples/.gitignore
+++ b/examples/.gitignore
@@ -6,5 +6,6 @@
/ringBufferHC
/lineCompress
/frameCompress
+/fileCompress
/simpleBuffer
/*.exe
diff --git a/examples/Makefile b/examples/Makefile
index a5af0c1..8be5c81 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -41,7 +41,7 @@ include ../Makefile.inc
default: all
all: printVersion doubleBuffer dictionaryRandomAccess ringBuffer ringBufferHC \
- lineCompress frameCompress simpleBuffer
+ lineCompress frameCompress fileCompress simpleBuffer
$(LZ4DIR)/liblz4.a: $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c $(LZ4DIR)/lz4frame.c $(LZ4DIR)/lz4.h $(LZ4DIR)/lz4hc.h $(LZ4DIR)/lz4frame.h $(LZ4DIR)/lz4frame_static.h
$(MAKE) -C $(LZ4DIR) liblz4.a
@@ -67,6 +67,9 @@ lineCompress: blockStreaming_lineByLine.c $(LZ4DIR)/liblz4.a
frameCompress: frameCompress.c $(LZ4DIR)/liblz4.a
$(CC) $(FLAGS) $^ -o $@$(EXT)
+fileCompress: fileCompress.c $(LZ4DIR)/liblz4.a
+ $(CC) $(FLAGS) $^ -o $@$(EXT)
+
compressFunctions: compress_functions.c $(LZ4DIR)/liblz4.a
$(CC) $(FLAGS) $^ -o $@$(EXT) -lrt
@@ -94,6 +97,9 @@ test : all $(LZ4)
@echo "\n=== Frame compression ==="
./frameCompress$(EXT) $(TESTFILE)
$(LZ4) -vt $(TESTFILE).lz4
+ @echo "\n=== file compression ==="
+ ./fileCompress$(EXT) $(TESTFILE)
+ $(LZ4) -vt $(TESTFILE).lz4
.PHONY: cxxtest
cxxtest: CFLAGS := -O3 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror
@@ -104,5 +110,5 @@ clean:
@rm -f core *.o *.dec *-0 *-9 *-8192 *.lz4s *.lz4 \
printVersion$(EXT) doubleBuffer$(EXT) dictionaryRandomAccess$(EXT) \
ringBuffer$(EXT) ringBufferHC$(EXT) lineCompress$(EXT) frameCompress$(EXT) \
- compressFunctions$(EXT) simpleBuffer$(EXT)
+ fileCompress$(EXT) compressFunctions$(EXT) simpleBuffer$(EXT)
@echo Cleaning completed
diff --git a/examples/fileCompress.c b/examples/fileCompress.c
new file mode 100644
index 0000000..4486ea8
--- /dev/null
+++ b/examples/fileCompress.c
@@ -0,0 +1,232 @@
+/* LZ4file API example : compress a file
+ * Modified from an example code by anjiahao
+ *
+ * This example will demonstrate how
+ * to manipulate lz4 compressed files like
+ * normal files */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <lz4file.h>
+
+
+#define CHUNK_SIZE (16*1024)
+
+static size_t get_file_size(char *filename)
+{
+ struct stat statbuf;
+
+ if (filename == NULL) {
+ return 0;
+ }
+
+ if(stat(filename,&statbuf)) {
+ return 0;
+ }
+
+ return statbuf.st_size;
+}
+
+static int compress_file(FILE* f_in, FILE* f_out)
+{
+ assert(f_in != NULL); assert(f_out != NULL);
+
+ LZ4F_errorCode_t ret = LZ4F_OK_NoError;
+ size_t len;
+ LZ4_writeFile_t* lz4fWrite;
+ void* const buf = malloc(CHUNK_SIZE);
+ if (!buf) {
+ printf("error: memory allocation failed \n");
+ }
+
+ /* Of course, you can also use prefsPtr to
+ * set the parameters of the compressed file
+ * NULL is use default
+ */
+ ret = LZ4F_writeOpen(&lz4fWrite, f_out, NULL);
+ if (LZ4F_isError(ret)) {
+ printf("LZ4F_writeOpen error: %s\n", LZ4F_getErrorName(ret));
+ free(buf);
+ return 1;
+ }
+
+ while (1) {
+ len = fread(buf, 1, CHUNK_SIZE, f_in);
+
+ if (ferror(f_in)) {
+ printf("fread error\n");
+ goto out;
+ }
+
+ /* nothing to read */
+ if (len == 0) {
+ break;
+ }
+
+ ret = LZ4F_write(lz4fWrite, buf, len);
+ if (LZ4F_isError(ret)) {
+ printf("LZ4F_write: %s\n", LZ4F_getErrorName(ret));
+ goto out;
+ }
+ }
+
+out:
+ free(buf);
+ if (LZ4F_isError(LZ4F_writeClose(lz4fWrite))) {
+ printf("LZ4F_writeClose: %s\n", LZ4F_getErrorName(ret));
+ return 1;
+ }
+
+ return 0;
+}
+
+static int decompress_file(FILE* f_in, FILE* f_out)
+{
+ assert(f_in != NULL); assert(f_out != NULL);
+
+ LZ4F_errorCode_t ret = LZ4F_OK_NoError;
+ LZ4_readFile_t* lz4fRead;
+ void* const buf= malloc(CHUNK_SIZE);
+ if (!buf) {
+ printf("error: memory allocation failed \n");
+ }
+
+ ret = LZ4F_readOpen(&lz4fRead, f_in);
+ if (LZ4F_isError(ret)) {
+ printf("LZ4F_readOpen error: %s\n", LZ4F_getErrorName(ret));
+ free(buf);
+ return 1;
+ }
+
+ while (1) {
+ ret = LZ4F_read(lz4fRead, buf, CHUNK_SIZE);
+ if (LZ4F_isError(ret)) {
+ printf("LZ4F_read error: %s\n", LZ4F_getErrorName(ret));
+ goto out;
+ }
+
+ /* nothing to read */
+ if (ret == 0) {
+ break;
+ }
+
+ if(fwrite(buf, 1, ret, f_out) != ret) {
+ printf("write error!\n");
+ goto out;
+ }
+ }
+
+out:
+ free(buf);
+ if (LZ4F_isError(LZ4F_readClose(lz4fRead))) {
+ printf("LZ4F_readClose: %s\n", LZ4F_getErrorName(ret));
+ return 1;
+ }
+
+ if (ret) {
+ return 1;
+ }
+
+ return 0;
+}
+
+int compareFiles(FILE* fp0, FILE* fp1)
+{
+ int result = 0;
+
+ while (result==0) {
+ char b0[1024];
+ char b1[1024];
+ size_t const r0 = fread(b0, 1, sizeof(b0), fp0);
+ size_t const r1 = fread(b1, 1, sizeof(b1), fp1);
+
+ result = (r0 != r1);
+ if (!r0 || !r1) break;
+ if (!result) result = memcmp(b0, b1, r0);
+ }
+
+ return result;
+}
+
+int main(int argc, const char **argv) {
+ char inpFilename[256] = { 0 };
+ char lz4Filename[256] = { 0 };
+ char decFilename[256] = { 0 };
+
+ if (argc < 2) {
+ printf("Please specify input filename\n");
+ return 0;
+ }
+
+ snprintf(inpFilename, 256, "%s", argv[1]);
+ snprintf(lz4Filename, 256, "%s.lz4", argv[1]);
+ snprintf(decFilename, 256, "%s.lz4.dec", argv[1]);
+
+ printf("inp = [%s]\n", inpFilename);
+ printf("lz4 = [%s]\n", lz4Filename);
+ printf("dec = [%s]\n", decFilename);
+
+ /* compress */
+ { FILE* const inpFp = fopen(inpFilename, "rb");
+ FILE* const outFp = fopen(lz4Filename, "wb");
+ printf("compress : %s -> %s\n", inpFilename, lz4Filename);
+ LZ4F_errorCode_t ret = compress_file(inpFp, outFp);
+ fclose(inpFp);
+ fclose(outFp);
+
+ if (ret) {
+ printf("compression error: %s\n", LZ4F_getErrorName(ret));
+ return 1;
+ }
+
+ printf("%s: %zu → %zu bytes, %.1f%%\n",
+ inpFilename,
+ get_file_size(inpFilename),
+ get_file_size(lz4Filename), /* might overflow is size_t is 32 bits and size_{in,out} > 4 GB */
+ (double)get_file_size(lz4Filename) / get_file_size(inpFilename) * 100);
+
+ printf("compress : done\n");
+ }
+
+ /* decompress */
+ {
+ FILE* const inpFp = fopen(lz4Filename, "rb");
+ FILE* const outFp = fopen(decFilename, "wb");
+
+ printf("decompress : %s -> %s\n", lz4Filename, decFilename);
+ LZ4F_errorCode_t ret = decompress_file(inpFp, outFp);
+
+ fclose(outFp);
+ fclose(inpFp);
+
+ if (ret) {
+ printf("compression error: %s\n", LZ4F_getErrorName(ret));
+ return 1;
+ }
+
+ printf("decompress : done\n");
+ }
+
+ /* verify */
+ { FILE* const inpFp = fopen(inpFilename, "rb");
+ FILE* const decFp = fopen(decFilename, "rb");
+
+ printf("verify : %s <-> %s\n", inpFilename, decFilename);
+ int const cmp = compareFiles(inpFp, decFp);
+
+ fclose(decFp);
+ fclose(inpFp);
+
+ if (cmp) {
+ printf("corruption detected : decompressed file differs from original\n");
+ return cmp;
+ }
+
+ printf("verify : OK\n");
+ }
+
+}
diff --git a/lib/lz4file.c b/lib/lz4file.c
new file mode 100644
index 0000000..eaf9b17
--- /dev/null
+++ b/lib/lz4file.c
@@ -0,0 +1,311 @@
+/*
+ * LZ4 file library
+ * Copyright (C) 2022, Xiaomi Inc.
+ *
+ * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT
+ * OWNER OR CONTRIBUTORS 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.
+ *
+ * You can contact the author at :
+ * - LZ4 homepage : http://www.lz4.org
+ * - LZ4 source repository : https://github.com/lz4/lz4
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "lz4.h"
+#include "lz4file.h"
+
+struct LZ4_readFile_s {
+ LZ4F_dctx* dctxPtr;
+ FILE* fp;
+ LZ4_byte* srcBuf;
+ size_t srcBufNext;
+ size_t srcBufSize;
+ size_t srcBufMaxSize;
+};
+
+struct LZ4_writeFile_s {
+ LZ4F_cctx* cctxPtr;
+ FILE* fp;
+ LZ4_byte* dstBuf;
+ size_t maxWriteSize;
+ size_t dstBufMaxSize;
+ LZ4F_errorCode_t errCode;
+};
+
+LZ4F_errorCode_t LZ4F_readOpen(LZ4_readFile_t** lz4fRead, FILE* fp)
+{
+ char buf[LZ4F_HEADER_SIZE_MAX];
+ size_t consumedSize;
+ LZ4F_errorCode_t ret;
+ LZ4F_frameInfo_t info;
+
+ if (fp == NULL || lz4fRead == NULL) {
+ return -LZ4F_ERROR_GENERIC;
+ }
+
+ *lz4fRead = (LZ4_readFile_t*)calloc(1, sizeof(LZ4_readFile_t));
+ if (*lz4fRead == NULL) {
+ return -LZ4F_ERROR_allocation_failed;
+ }
+
+ ret = LZ4F_createDecompressionContext(&(*lz4fRead)->dctxPtr, LZ4F_getVersion());
+ if (LZ4F_isError(ret)) {
+ free(*lz4fRead);
+ return ret;
+ }
+
+ (*lz4fRead)->fp = fp;
+ consumedSize = fread(buf, 1, sizeof(buf), (*lz4fRead)->fp);
+ if (consumedSize != sizeof(buf)) {
+ free(*lz4fRead);
+ return -LZ4F_ERROR_GENERIC;
+ }
+
+ ret = LZ4F_getFrameInfo((*lz4fRead)->dctxPtr, &info, buf, &consumedSize);
+ if (LZ4F_isError(ret)) {
+ LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr);
+ free(*lz4fRead);
+ return ret;
+ }
+
+ switch (info.blockSizeID) {
+ case LZ4F_default :
+ case LZ4F_max64KB :
+ (*lz4fRead)->srcBufMaxSize = 64 * 1024;
+ break;
+ case LZ4F_max256KB:
+ (*lz4fRead)->srcBufMaxSize = 256 * 1024;
+ break;
+ case LZ4F_max1MB:
+ (*lz4fRead)->srcBufMaxSize = 1 * 1024 * 1024;
+ break;
+ case LZ4F_max4MB:
+ (*lz4fRead)->srcBufMaxSize = 4 * 1024 * 1024;
+ break;
+ default:
+ LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr);
+ free(*lz4fRead);
+ return -LZ4F_ERROR_maxBlockSize_invalid;
+ }
+
+ (*lz4fRead)->srcBuf = (LZ4_byte*)malloc((*lz4fRead)->srcBufMaxSize);
+ if ((*lz4fRead)->srcBuf == NULL) {
+ LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr);
+ free(lz4fRead);
+ return -LZ4F_ERROR_allocation_failed;
+ }
+
+ (*lz4fRead)->srcBufSize = sizeof(buf) - consumedSize;
+ memcpy((*lz4fRead)->srcBuf, buf + consumedSize, (*lz4fRead)->srcBufSize);
+
+ return ret;
+}
+
+size_t LZ4F_read(LZ4_readFile_t* lz4fRead, void* buf, size_t size)
+{
+ LZ4_byte* p = (LZ4_byte*)buf;
+ size_t next = 0;
+
+ if (lz4fRead == NULL || buf == NULL)
+ return -LZ4F_ERROR_GENERIC;
+
+ while (next < size) {
+ size_t srcsize = lz4fRead->srcBufSize - lz4fRead->srcBufNext;
+ size_t dstsize = size - next;
+ size_t ret;
+
+ if (srcsize == 0) {
+ ret = fread(lz4fRead->srcBuf, 1, lz4fRead->srcBufMaxSize, lz4fRead->fp);
+ if (ret > 0) {
+ lz4fRead->srcBufSize = ret;
+ srcsize = lz4fRead->srcBufSize;
+ lz4fRead->srcBufNext = 0;
+ }
+ else if (ret == 0) {
+ break;
+ }
+ else {
+ return -LZ4F_ERROR_GENERIC;
+ }
+ }
+
+ ret = LZ4F_decompress(lz4fRead->dctxPtr,
+ p, &dstsize,
+ lz4fRead->srcBuf + lz4fRead->srcBufNext,
+ &srcsize,
+ NULL);
+ if (LZ4F_isError(ret)) {
+ return ret;
+ }
+
+ lz4fRead->srcBufNext += srcsize;
+ next += dstsize;
+ p += dstsize;
+ }
+
+ return next;
+}
+
+LZ4F_errorCode_t LZ4F_readClose(LZ4_readFile_t* lz4fRead)
+{
+ if (lz4fRead == NULL)
+ return -LZ4F_ERROR_GENERIC;
+ LZ4F_freeDecompressionContext(lz4fRead->dctxPtr);
+ free(lz4fRead->srcBuf);
+ free(lz4fRead);
+ return LZ4F_OK_NoError;
+}
+
+LZ4F_errorCode_t LZ4F_writeOpen(LZ4_writeFile_t** lz4fWrite, FILE* fp, const LZ4F_preferences_t* prefsPtr)
+{
+ LZ4_byte buf[LZ4F_HEADER_SIZE_MAX];
+ size_t ret;
+
+ if (fp == NULL || lz4fWrite == NULL)
+ return -LZ4F_ERROR_GENERIC;
+
+ *lz4fWrite = (LZ4_writeFile_t*)malloc(sizeof(LZ4_writeFile_t));
+ if (*lz4fWrite == NULL) {
+ return -LZ4F_ERROR_allocation_failed;
+ }
+ if (prefsPtr != NULL) {
+ switch (prefsPtr->frameInfo.blockSizeID) {
+ case LZ4F_default :
+ case LZ4F_max64KB :
+ (*lz4fWrite)->maxWriteSize = 64 * 1024;
+ break;
+ case LZ4F_max256KB:
+ (*lz4fWrite)->maxWriteSize = 256 * 1024;
+ break;
+ case LZ4F_max1MB:
+ (*lz4fWrite)->maxWriteSize = 1 * 1024 * 1024;
+ break;
+ case LZ4F_max4MB:
+ (*lz4fWrite)->maxWriteSize = 4 * 1024 * 1024;
+ break;
+ default:
+ free(lz4fWrite);
+ return -LZ4F_ERROR_maxBlockSize_invalid;
+ }
+ } else {
+ (*lz4fWrite)->maxWriteSize = 64 * 1024;
+ }
+
+ (*lz4fWrite)->dstBufMaxSize = LZ4F_compressBound((*lz4fWrite)->maxWriteSize, prefsPtr);
+ (*lz4fWrite)->dstBuf = (LZ4_byte*)malloc((*lz4fWrite)->dstBufMaxSize);
+ if ((*lz4fWrite)->dstBuf == NULL) {
+ free(*lz4fWrite);
+ return -LZ4F_ERROR_allocation_failed;
+ }
+
+ ret = LZ4F_createCompressionContext(&(*lz4fWrite)->cctxPtr, LZ4F_getVersion());
+ if (LZ4F_isError(ret)) {
+ free((*lz4fWrite)->dstBuf);
+ free(*lz4fWrite);
+ return ret;
+ }
+
+ ret = LZ4F_compressBegin((*lz4fWrite)->cctxPtr, buf, LZ4F_HEADER_SIZE_MAX, prefsPtr);
+ if (LZ4F_isError(ret)) {
+ LZ4F_freeCompressionContext((*lz4fWrite)->cctxPtr);
+ free((*lz4fWrite)->dstBuf);
+ free(*lz4fWrite);
+ return ret;
+ }
+
+ if (ret != fwrite(buf, 1, ret, fp)) {
+ LZ4F_freeCompressionContext((*lz4fWrite)->cctxPtr);
+ free((*lz4fWrite)->dstBuf);
+ free(*lz4fWrite);
+ return -LZ4F_ERROR_GENERIC;
+ }
+
+ (*lz4fWrite)->fp = fp;
+ (*lz4fWrite)->errCode = LZ4F_OK_NoError;
+ return LZ4F_OK_NoError;
+}
+
+size_t LZ4F_write(LZ4_writeFile_t* lz4fWrite, void* buf, size_t size)
+{
+ LZ4_byte* p = (LZ4_byte*)buf;
+ size_t remain = size;
+ size_t chunk;
+ size_t ret;
+
+ if (lz4fWrite == NULL || buf == NULL)
+ return -LZ4F_ERROR_GENERIC;
+ while (remain) {
+ if (remain > lz4fWrite->maxWriteSize)
+ chunk = lz4fWrite->maxWriteSize;
+ else
+ chunk = remain;
+
+ ret = LZ4F_compressUpdate(lz4fWrite->cctxPtr,
+ lz4fWrite->dstBuf, lz4fWrite->dstBufMaxSize,
+ p, chunk,
+ NULL);
+ if (LZ4F_isError(ret)) {
+ lz4fWrite->errCode = ret;
+ return ret;
+ }
+
+ if(ret != fwrite(lz4fWrite->dstBuf, 1, ret, lz4fWrite->fp)) {
+ lz4fWrite->errCode = -LZ4F_ERROR_GENERIC;
+ return -LZ4F_ERROR_GENERIC;
+ }
+
+ p += chunk;
+ remain -= chunk;
+ }
+
+ return size;
+}
+
+LZ4F_errorCode_t LZ4F_writeClose(LZ4_writeFile_t* lz4fWrite)
+{
+ LZ4F_errorCode_t ret = LZ4F_OK_NoError;
+
+ if (lz4fWrite == NULL)
+ return -LZ4F_ERROR_GENERIC;
+
+ if (lz4fWrite->errCode == LZ4F_OK_NoError) {
+ ret = LZ4F_compressEnd(lz4fWrite->cctxPtr,
+ lz4fWrite->dstBuf, lz4fWrite->dstBufMaxSize,
+ NULL);
+ if (LZ4F_isError(ret)) {
+ goto out;
+ }
+
+ if (ret != fwrite(lz4fWrite->dstBuf, 1, ret, lz4fWrite->fp)) {
+ ret = -LZ4F_ERROR_GENERIC;
+ }
+ }
+
+out:
+ LZ4F_freeCompressionContext(lz4fWrite->cctxPtr);
+ free(lz4fWrite->dstBuf);
+ free(lz4fWrite);
+ return ret;
+}
diff --git a/lib/lz4file.h b/lib/lz4file.h
new file mode 100644
index 0000000..5527130
--- /dev/null
+++ b/lib/lz4file.h
@@ -0,0 +1,93 @@
+/*
+ LZ4 file library
+ Header File
+ Copyright (C) 2022, Xiaomi Inc.
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "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 COPYRIGHT
+ OWNER OR CONTRIBUTORS 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.
+
+ You can contact the author at :
+ - LZ4 source repository : https://github.com/lz4/lz4
+ - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
+*/
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#ifndef LZ4FILE_H
+#define LZ4FILE_H
+
+#include <stdio.h>
+#include "lz4frame_static.h"
+
+typedef struct LZ4_readFile_s LZ4_readFile_t;
+typedef struct LZ4_writeFile_s LZ4_writeFile_t;
+
+/*! LZ4F_readOpen() :
+ * Set read lz4file handle.
+ * `lz4f` will set a lz4file handle.
+ * `fp` must be the return value of the lz4 file opened by fopen.
+ */
+LZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_readOpen(LZ4_readFile_t** lz4fRead, FILE* fp);
+
+/*! LZ4F_read() :
+ * Read lz4file content to buffer.
+ * `lz4f` must use LZ4_readOpen to set first.
+ * `buf` read data buffer.
+ * `size` read data buffer size.
+ */
+LZ4FLIB_STATIC_API size_t LZ4F_read(LZ4_readFile_t* lz4fRead, void* buf, size_t size);
+
+/*! LZ4F_readClose() :
+ * Close lz4file handle.
+ * `lz4f` must use LZ4_readOpen to set first.
+ */
+LZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_readClose(LZ4_readFile_t* lz4fRead);
+
+/*! LZ4F_writeOpen() :
+ * Set write lz4file handle.
+ * `lz4f` will set a lz4file handle.
+ * `fp` must be the return value of the lz4 file opened by fopen.
+ */
+LZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_writeOpen(LZ4_writeFile_t** lz4fWrite, FILE* fp, const LZ4F_preferences_t* prefsPtr);
+
+/*! LZ4F_write() :
+ * Write buffer to lz4file.
+ * `lz4f` must use LZ4F_writeOpen to set first.
+ * `buf` write data buffer.
+ * `size` write data buffer size.
+ */
+LZ4FLIB_STATIC_API size_t LZ4F_write(LZ4_writeFile_t* lz4fWrite, void* buf, size_t size);
+
+/*! LZ4F_writeClose() :
+ * Close lz4file handle.
+ * `lz4f` must use LZ4F_writeOpen to set first.
+ */
+LZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_writeClose(LZ4_writeFile_t* lz4fWrite);
+
+#endif /* LZ4FILE_H */
+
+#if defined (__cplusplus)
+}
+#endif