diff --git a/Makefile b/Makefile
index 658df84..c04753b 100755
--- a/Makefile
+++ b/Makefile
@@ -11,6 +11,7 @@ $(OBJDIR)/%.o: src/../%.c
APP := lzsa
OBJS := $(OBJDIR)/src/main.o
+OBJS += $(OBJDIR)/src/frame.o
OBJS += $(OBJDIR)/src/shrink.o
OBJS += $(OBJDIR)/src/expand.o
OBJS += $(OBJDIR)/src/libdivsufsort/lib/divsufsort.o
diff --git a/VS2017/lzsa.vcxproj b/VS2017/lzsa.vcxproj
index eb13c6d..8461495 100755
--- a/VS2017/lzsa.vcxproj
+++ b/VS2017/lzsa.vcxproj
@@ -179,6 +179,7 @@
+
@@ -187,6 +188,7 @@
+
diff --git a/VS2017/lzsa.vcxproj.filters b/VS2017/lzsa.vcxproj.filters
index 47ea518..6767357 100755
--- a/VS2017/lzsa.vcxproj.filters
+++ b/VS2017/lzsa.vcxproj.filters
@@ -45,6 +45,9 @@
Fichiers sources\libdivsufsort\include
+
+ Fichiers sources
+
@@ -68,5 +71,8 @@
Fichiers sources\libdivsufsort\lib
+
+ Fichiers sources
+
\ No newline at end of file
diff --git a/src/frame.c b/src/frame.c
new file mode 100644
index 0000000..ba99904
--- /dev/null
+++ b/src/frame.c
@@ -0,0 +1,177 @@
+/*
+ * frame.c - frame implementation
+ *
+ * Copyright (C) 2019 Emmanuel Marty
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#include
+#include "frame.h"
+#include "shrink.h"
+
+#define LZSA_ID_0 0x7b
+#define LZSA_ID_1 0x9e
+
+/**
+ * Get compressed file header size
+ *
+ * @return file header size
+ */
+int lzsa_get_header_size(void) {
+ return 3;
+}
+
+/**
+ * Get compressed frame header size
+ *
+ * @return frame header size
+ */
+int lzsa_get_frame_size(void) {
+ return 3;
+}
+
+/**
+ * Encode file header
+ *
+ * @param pFrameData encoding buffer
+ * @param nMaxFrameDataSize max encoding buffer size, in bytes
+ *
+ * @return number of encoded bytes, or -1 for failure
+ */
+int lzsa_encode_header(unsigned char *pFrameData, const int nMaxFrameDataSize) {
+ if (nMaxFrameDataSize >= 3) {
+ pFrameData[0] = LZSA_ID_0; /* Magic number */
+ pFrameData[1] = LZSA_ID_1;
+ pFrameData[2] = 0; /* Format version 1 */
+
+ return 3;
+ }
+ else {
+ return -1;
+ }
+}
+
+/**
+ * Encode compressed block frame header
+ *
+ * @param pFrameData encoding buffer
+ * @param nMaxFrameDataSize max encoding buffer size, in bytes
+ * @param nBlockDataSize compressed block's data size, in bytes
+ *
+ * @return number of encoded bytes, or -1 for failure
+ */
+int lzsa_encode_compressed_block_frame(unsigned char *pFrameData, const int nMaxFrameDataSize, const int nBlockDataSize) {
+ if (nMaxFrameDataSize >= 3 && nBlockDataSize <= 0x7fffff) {
+ pFrameData[0] = nBlockDataSize & 0xff;
+ pFrameData[1] = (nBlockDataSize >> 8) & 0xff;
+ pFrameData[2] = (nBlockDataSize >> 16) & 0x7f;
+
+ return 3;
+ }
+ else {
+ return -1;
+ }
+}
+
+/**
+ * Encode uncompressed block frame header
+ *
+ * @param pFrameData encoding buffer
+ * @param nMaxFrameDataSize max encoding buffer size, in bytes
+ * @param nBlockDataSize uncompressed block's data size, in bytes
+ *
+ * @return number of encoded bytes, or -1 for failure
+ */
+int lzsa_encode_uncompressed_block_frame(unsigned char *pFrameData, const int nMaxFrameDataSize, const int nBlockDataSize) {
+ if (nMaxFrameDataSize >= 3 && nBlockDataSize <= 0x7fffff) {
+ pFrameData[0] = nBlockDataSize & 0xff;
+ pFrameData[1] = (nBlockDataSize >> 8) & 0xff;
+ pFrameData[2] = ((nBlockDataSize >> 16) & 0x7f) | 0x80; /* Uncompressed block */
+
+ return 3;
+ }
+ else {
+ return -1;
+ }
+}
+
+/**
+ * Encode terminal frame header
+ *
+ * @param pFrameData encoding buffer
+ * @param nMaxFrameDataSize max encoding buffer size, in bytes
+ *
+ * @return number of encoded bytes, or -1 for failure
+ */
+int lzsa_encode_footer_frame(unsigned char *pFrameData, const int nMaxFrameDataSize) {
+ if (nMaxFrameDataSize >= 3) {
+ pFrameData[0] = 0x00; /* EOD frame */
+ pFrameData[1] = 0x00;
+ pFrameData[2] = 0x00;
+
+ return 3;
+ }
+ else {
+ return -1;
+ }
+}
+
+/**
+ * Decode file header
+ *
+ * @param pFrameData data bytes
+ * @param nFrameDataSize number of bytes to decode
+ *
+ * @return 0 for success, or -1 for failure
+ */
+int lzsa_decode_header(const unsigned char *pFrameData, const int nFrameDataSize) {
+ if (nFrameDataSize != 3 ||
+ pFrameData[0] != LZSA_ID_0 ||
+ pFrameData[1] != LZSA_ID_1 ||
+ pFrameData[2] != 0) {
+ return -1;
+ }
+ else {
+ return 0;
+ }
+}
+
+/**
+ * Decode frame header
+ *
+ * @param pFrameData data bytes
+ * @param nFrameDataSize number of bytes to decode
+ * @param nBlockSize pointer to block size, updated if this function succeeds (set to 0 if this is the terminal frame)
+ * @param nIsUncompressed pointer to compressed block flag, updated if this function succeeds
+ *
+ * @return 0 for success, or -1 for failure
+ */
+int lzsa_decode_frame(const unsigned char *pFrameData, const int nFrameDataSize, unsigned int *nBlockSize, int *nIsUncompressed) {
+ if (nFrameDataSize == 3) {
+ *nBlockSize = ((unsigned int)pFrameData[0]) |
+ (((unsigned int)pFrameData[1]) << 8) |
+ (((unsigned int)pFrameData[2]) << 16);
+
+ *nIsUncompressed = ((*nBlockSize & 0x800000) != 0) ? 1 : 0;
+ *nBlockSize &= 0x7fffff;
+ return 0;
+ }
+ else {
+ return -1;
+ }
+}
diff --git a/src/frame.h b/src/frame.h
new file mode 100644
index 0000000..e858110
--- /dev/null
+++ b/src/frame.h
@@ -0,0 +1,104 @@
+/*
+ * frame.h - frame definitions
+ *
+ * Copyright (C) 2019 Emmanuel Marty
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#ifndef _FRAME_H
+#define _FRAME_H
+
+/**
+ * Get compressed file header size
+ *
+ * @return file header size
+ */
+int lzsa_get_header_size(void);
+
+/**
+ * Get compressed frame header size
+ *
+ * @return frame header size
+ */
+int lzsa_get_frame_size(void);
+
+/**
+ * Encode file header
+ *
+ * @param pFrameData encoding buffer
+ * @param nMaxFrameDataSize max encoding buffer size, in bytes
+ *
+ * @return number of encoded bytes, or -1 for failure
+ */
+int lzsa_encode_header(unsigned char *pFrameData, const int nMaxFrameDataSize);
+
+/**
+ * Encode compressed block frame header
+ *
+ * @param pFrameData encoding buffer
+ * @param nMaxFrameDataSize max encoding buffer size, in bytes
+ * @param nBlockDataSize compressed block's data size, in bytes
+ *
+ * @return number of encoded bytes, or -1 for failure
+ */
+int lzsa_encode_compressed_block_frame(unsigned char *pFrameData, const int nMaxFrameDataSize, const int nBlockDataSize);
+
+/**
+ * Encode uncompressed block frame header
+ *
+ * @param pFrameData encoding buffer
+ * @param nMaxFrameDataSize max encoding buffer size, in bytes
+ * @param nBlockDataSize uncompressed block's data size, in bytes
+ *
+ * @return number of encoded bytes, or -1 for failure
+ */
+int lzsa_encode_uncompressed_block_frame(unsigned char *pFrameData, const int nMaxFrameDataSize, const int nBlockDataSize);
+
+/**
+ * Encode terminal frame header
+ *
+ * @param pFrameData encoding buffer
+ * @param nMaxFrameDataSize max encoding buffer size, in bytes
+ *
+ * @return number of encoded bytes, or -1 for failure
+ */
+int lzsa_encode_footer_frame(unsigned char *pFrameData, const int nMaxFrameDataSize);
+
+/**
+ * Decode file header
+ *
+ * @param pFrameData data bytes
+ * @param nFrameDataSize number of bytes to decode
+ *
+ * @return 0 for success, or -1 for failure
+ */
+int lzsa_decode_header(const unsigned char *pFrameData, const int nFrameDataSize);
+
+/**
+ * Decode frame header
+ *
+ * @param pFrameData data bytes
+ * @param nFrameDataSize number of bytes to decode
+ * @param nBlockSize pointer to block size, updated if this function succeeds (set to 0 if this is the terminal frame)
+ * @param nIsUncompressed pointer to compressed block flag, updated if this function succeeds
+ *
+ * @return 0 for success, or -1 for failure
+ */
+int lzsa_decode_frame(const unsigned char *pFrameData, const int nFrameDataSize, unsigned int *nBlockSize, int *nIsUncompressed);
+
+#endif /* _FRAME_H */
diff --git a/src/main.c b/src/main.c
index 0bbbdd1..e52dba8 100755
--- a/src/main.c
+++ b/src/main.c
@@ -30,6 +30,7 @@
#include
#endif
#include "format.h"
+#include "frame.h"
#include "shrink.h"
#include "expand.h"
@@ -67,6 +68,7 @@ static int lzsa_compress(const char *pszInFilename, const char *pszOutFilename,
long long nOriginalSize = 0LL, nCompressedSize = 0LL;
int nFlags;
int nResult;
+ unsigned char cFrameData[16];
bool bError = false;
f_in = fopen(pszInFilename, "rb");
@@ -163,14 +165,13 @@ static int lzsa_compress(const char *pszInFilename, const char *pszOutFilename,
}
if ((nOptions & OPT_RAW) == 0) {
- unsigned char cHeader[3];
-
- cHeader[0] = 0x7b; /* Magic number: 0x9e7b */
- cHeader[1] = 0x9e;
- cHeader[2] = 0; /* Format version 1 */
-
- bError = fwrite(cHeader, 1, 3, f_out) != 3;
- nCompressedSize += 3LL;
+ int nHeaderSize = lzsa_encode_header(cFrameData, 16);
+ if (nHeaderSize < 0)
+ bError = true;
+ else {
+ bError = fwrite(cFrameData, 1, nHeaderSize, f_out) != nHeaderSize;
+ nCompressedSize += (long long)nHeaderSize;
+ }
}
if (nOptions & OPT_VERBOSE) {
@@ -205,15 +206,14 @@ static int lzsa_compress(const char *pszInFilename, const char *pszOutFilename,
/* Write compressed block */
if ((nOptions & OPT_RAW) == 0) {
- unsigned char cBlockSize[3];
-
- cBlockSize[0] = nOutDataSize & 0xff;
- cBlockSize[1] = (nOutDataSize >> 8) & 0xff;
- cBlockSize[2] = (nOutDataSize >> 16) & 0xff;
- nCompressedSize += 3LL;
-
- if (fwrite(cBlockSize, 1, 3, f_out) != (size_t)3) {
+ int nBlockheaderSize = lzsa_encode_compressed_block_frame(cFrameData, 16, nOutDataSize);
+ if (nBlockheaderSize < 0)
bError = true;
+ else {
+ nCompressedSize += (long long)nBlockheaderSize;
+ if (fwrite(cFrameData, 1, nBlockheaderSize, f_out) != (size_t)nBlockheaderSize) {
+ bError = true;
+ }
}
}
@@ -236,22 +236,21 @@ static int lzsa_compress(const char *pszInFilename, const char *pszOutFilename,
break;
}
- unsigned char cBlockSize[3];
-
- cBlockSize[0] = nInDataSize & 0xff;
- cBlockSize[1] = (nInDataSize >> 8) & 0xff;
- cBlockSize[2] = ((nInDataSize >> 16) & 0x7f) | 0x80; /* Uncompressed block */
-
- if (fwrite(cBlockSize, 1, 3, f_out) != (size_t)3) {
+ int nBlockheaderSize = lzsa_encode_uncompressed_block_frame(cFrameData, 16, nInDataSize);
+ if (nBlockheaderSize < 0)
bError = true;
- }
else {
- if (fwrite(pInData + BLOCK_SIZE, 1, (size_t)nInDataSize, f_out) != (size_t)nInDataSize) {
+ if (fwrite(cFrameData, 1, nBlockheaderSize, f_out) != (size_t)nBlockheaderSize) {
bError = true;
}
else {
- nOriginalSize += (long long)nInDataSize;
- nCompressedSize += 3LL + (long long)nInDataSize;
+ if (fwrite(pInData + BLOCK_SIZE, 1, (size_t)nInDataSize, f_out) != (size_t)nInDataSize) {
+ bError = true;
+ }
+ else {
+ nOriginalSize += (long long)nInDataSize;
+ nCompressedSize += (long long)nBlockheaderSize + (long long)nInDataSize;
+ }
}
}
}
@@ -265,21 +264,19 @@ static int lzsa_compress(const char *pszInFilename, const char *pszOutFilename,
}
}
- unsigned char cFooter[4];
int nFooterSize;
if ((nOptions & OPT_RAW) != 0) {
nFooterSize = 0;
}
else {
- cFooter[0] = 0x00; /* EOD frame */
- cFooter[1] = 0x00;
- cFooter[2] = 0x00;
- nFooterSize = 3;
+ nFooterSize = lzsa_encode_footer_frame(cFrameData, 16);
+ if (nFooterSize < 0)
+ bError = true;
}
if (!bError)
- bError = fwrite(cFooter, 1, nFooterSize, f_out) != nFooterSize;
+ bError = fwrite(cFrameData, 1, nFooterSize, f_out) != nFooterSize;
nCompressedSize += (long long)nFooterSize;
if (!bError && (nOptions & OPT_VERBOSE)) {
@@ -322,6 +319,7 @@ static int lzsa_decompress(const char *pszInFilename, const char *pszOutFilename
long long nStartTime = 0LL, nEndTime = 0LL;
long long nOriginalSize = 0LL;
unsigned int nFileSize = 0;
+ unsigned char cFrameData[16];
FILE *pInFile = fopen(pszInFilename, "rb");
if (!pInFile) {
@@ -330,20 +328,17 @@ static int lzsa_decompress(const char *pszInFilename, const char *pszOutFilename
}
if ((nOptions & OPT_RAW) == 0) {
- unsigned char cHeader[3];
+ const int nHeaderSize = lzsa_get_header_size();
- memset(cHeader, 0, 3);
-
- if (fread(cHeader, 1, 3, pInFile) != 3) {
+ memset(cFrameData, 0, 16);
+ if (fread(cFrameData, 1, nHeaderSize, pInFile) != nHeaderSize) {
fclose(pInFile);
pInFile = NULL;
fprintf(stderr, "error reading header in input file\n");
return 100;
}
- if (cHeader[0] != 0x7b ||
- cHeader[1] != 0x9e ||
- cHeader[2] != 0) {
+ if (lzsa_decode_header(cFrameData, nHeaderSize) < 0) {
fclose(pInFile);
pInFile = NULL;
fprintf(stderr, "invalid magic number or format version in input file\n");
@@ -440,19 +435,21 @@ static int lzsa_decompress(const char *pszInFilename, const char *pszOutFilename
while (!feof(pInFile) && !nDecompressionError) {
unsigned int nBlockSize = 0;
+ int nIsUncompressed = 0;
if (nPrevDecompressedSize != 0) {
memcpy(pOutData + BLOCK_SIZE - nPrevDecompressedSize, pOutData + BLOCK_SIZE, nPrevDecompressedSize);
}
if ((nOptions & OPT_RAW) == 0) {
- unsigned char cBlockSize[3];
+ const int nFrameSize = lzsa_get_frame_size();
- memset(cBlockSize, 0, 3);
- if (fread(cBlockSize, 1, 3, pInFile) == 3) {
- nBlockSize = ((unsigned int)cBlockSize[0]) |
- (((unsigned int)cBlockSize[1]) << 8) |
- (((unsigned int)cBlockSize[2]) << 16);
+ memset(cFrameData, 0, 16);
+ if (fread(cFrameData, 1, nFrameSize, pInFile) == nFrameSize) {
+ if (lzsa_decode_frame(cFrameData, nFrameSize, &nBlockSize, &nIsUncompressed) < 0) {
+ nDecompressionError = 1;
+ nBlockSize = 0;
+ }
}
else {
nBlockSize = 0;
@@ -465,16 +462,14 @@ static int lzsa_decompress(const char *pszInFilename, const char *pszOutFilename
}
if (nBlockSize != 0) {
- bool bIsUncompressed = (nBlockSize & 0x800000) != 0;
int nDecompressedSize = 0;
- nBlockSize &= 0x7fffff;
if ((int)nBlockSize > BLOCK_SIZE) {
fprintf(stderr, "block size %d > max size %d\n", nBlockSize, BLOCK_SIZE);
break;
}
if (fread(pInBlock, 1, nBlockSize, pInFile) == nBlockSize) {
- if (bIsUncompressed) {
+ if (nIsUncompressed) {
memcpy(pOutData + BLOCK_SIZE, pInBlock, nBlockSize);
nDecompressedSize = nBlockSize;
}
@@ -539,6 +534,7 @@ static int lzsa_compare(const char *pszInFilename, const char *pszOutFilename, c
long long nOriginalSize = 0LL;
long long nKnownGoodSize = 0LL;
unsigned int nFileSize = 0;
+ unsigned char cFrameData[16];
FILE *pInFile = fopen(pszInFilename, "rb");
if (!pInFile) {
@@ -547,20 +543,17 @@ static int lzsa_compare(const char *pszInFilename, const char *pszOutFilename, c
}
if ((nOptions & OPT_RAW) == 0) {
- unsigned char cHeader[3];
+ const int nHeaderSize = lzsa_get_header_size();
- memset(cHeader, 0, 3);
-
- if (fread(cHeader, 1, 3, pInFile) != 3) {
+ memset(cFrameData, 0, 16);
+ if (fread(cFrameData, 1, nHeaderSize, pInFile) != nHeaderSize) {
fclose(pInFile);
pInFile = NULL;
fprintf(stderr, "error reading header in compressed input file\n");
return 100;
}
- if (cHeader[0] != 0x7b ||
- cHeader[1] != 0x9e ||
- cHeader[2] != 0) {
+ if (lzsa_decode_header(cFrameData, nHeaderSize) < 0) {
fclose(pInFile);
pInFile = NULL;
fprintf(stderr, "invalid magic number or format version in input file\n");
@@ -679,6 +672,7 @@ static int lzsa_compare(const char *pszInFilename, const char *pszOutFilename, c
while (!feof(pInFile) && !nDecompressionError && !bComparisonError) {
unsigned int nBlockSize = 0;
+ int nIsUncompressed = 0;
if (nPrevDecompressedSize != 0) {
memcpy(pOutData + BLOCK_SIZE - nPrevDecompressedSize, pOutData + BLOCK_SIZE, nPrevDecompressedSize);
@@ -687,13 +681,14 @@ static int lzsa_compare(const char *pszInFilename, const char *pszOutFilename, c
int nBytesToCompare = (int)fread(pCompareData, 1, BLOCK_SIZE, pOutFile);
if ((nOptions & OPT_RAW) == 0) {
- unsigned char cBlockSize[3];
+ const int nFrameSize = lzsa_get_frame_size();
- memset(cBlockSize, 0, 3);
- if (fread(cBlockSize, 1, 3, pInFile) == 3) {
- nBlockSize = ((unsigned int)cBlockSize[0]) |
- (((unsigned int)cBlockSize[1]) << 8) |
- (((unsigned int)cBlockSize[2]) << 16);
+ memset(cFrameData, 0, 16);
+ if (fread(cFrameData, 1, nFrameSize, pInFile) == nFrameSize) {
+ if (lzsa_decode_frame(cFrameData, nFrameSize, &nBlockSize, &nIsUncompressed) < 0) {
+ nDecompressionError = 1;
+ nBlockSize = 0;
+ }
}
else {
nBlockSize = 0;
@@ -706,16 +701,14 @@ static int lzsa_compare(const char *pszInFilename, const char *pszOutFilename, c
}
if (nBlockSize != 0) {
- bool bIsUncompressed = (nBlockSize & 0x800000) != 0;
int nDecompressedSize = 0;
- nBlockSize &= 0x7fffff;
if ((int)nBlockSize > BLOCK_SIZE) {
fprintf(stderr, "block size %d > max size %d\n", nBlockSize, BLOCK_SIZE);
break;
}
if (fread(pInBlock, 1, nBlockSize, pInFile) == nBlockSize) {
- if (bIsUncompressed) {
+ if (nIsUncompressed) {
memcpy(pOutData + BLOCK_SIZE, pInBlock, nBlockSize);
nDecompressedSize = nBlockSize;
}