There should be enough space to generate a new DEFLATE block with an
end-of-block symbol, which requires at least 10 bits for BTYPE 01.

Fixes: 861037f4fc15 ("erofs-utils: add a built-in DEFLATE compressor")
Signed-off-by: Gao Xiang <hsiang...@linux.alibaba.com>
---
 lib/kite_deflate.c | 134 ++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 115 insertions(+), 19 deletions(-)

diff --git a/lib/kite_deflate.c b/lib/kite_deflate.c
index 7e92c7ca..e9f7e40e 100644
--- a/lib/kite_deflate.c
+++ b/lib/kite_deflate.c
@@ -1005,6 +1005,8 @@ static void kite_deflate_writestore(struct kite_deflate 
*s)
 
 static void kite_deflate_endblock(struct kite_deflate *s)
 {
+       u64 b = s->outlen - s->pos_out;
+
        if (s->encode_mode == 1) {
                u32 fixedcost = s->costbits;
                unsigned int storelen, storeblocks, storecost;
@@ -1025,8 +1027,11 @@ static void kite_deflate_endblock(struct kite_deflate *s)
                }
        }
 
-       s->lastblock |= (s->costbits + s->bitpos >=
-                       (s->outlen - s->pos_out) * 8);
+       if (s->costbits + s->bitpos +
+           3 + kstaticHuff_litLenLevels[kSymbolEndOfBlock] >= b * 8) {
+               DBG_BUGON(s->costbits + s->bitpos > b * 8);
+               s->lastblock = true;
+       }
 }
 
 static void kite_deflate_startblock(struct kite_deflate *s)
@@ -1256,38 +1261,129 @@ int kite_deflate_destsize(struct kite_deflate *s, 
const u8 *in, u8 *out,
 #include <fcntl.h>
 #include <sys/mman.h>
 
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+
+static int kite_deflate_decompress_zlib(const u8 *in, size_t inlen,
+                                       u8 *out, size_t out_capacity)
+{
+       z_stream z;
+       int res;
+
+       memset(&z, 0, sizeof(z));
+       res = inflateInit2(&z, -15);
+       if (res != Z_OK) {
+               DBG_BUGON(1);
+               return -1;
+       }
+       z.next_in = (void *)in;
+       z.avail_in = inlen;
+       z.next_out = (void *)out;
+       z.avail_out = out_capacity;
+       res = inflate(&z, Z_FINISH);
+       if (res != Z_STREAM_END) {
+               DBG_BUGON(1);
+               return -1;
+       }
+       inflateEnd(&z);
+       return out_capacity - z.avail_out;
+}
+
+static void kite_deflate_decompress_test_zlib(const u8 *in, size_t inlen,
+                                             u8 *out, size_t out_capacity,
+                                             const u8 *expected_out,
+                                             size_t expected_outlen)
+{
+       int outlen;
+
+       outlen = kite_deflate_decompress_zlib(in, inlen, out, out_capacity);
+       BUG_ON(outlen != expected_outlen);
+       if (expected_outlen)
+               BUG_ON(memcmp(out, expected_out, expected_outlen));
+}
+#endif
+
+static void kite_deflate_decompress_test(const u8 *in, size_t inlen,
+                                        u8 *out, size_t out_capacity,
+                                        const u8 *expected_out,
+                                        size_t expected_outlen)
+{
+#ifdef HAVE_ZLIB
+       kite_deflate_decompress_test_zlib(in, inlen, out, out_capacity,
+                                         expected_out, expected_outlen);
+#endif
+}
+
+static void kite_deflate_test1(void)
+{
+       struct kite_deflate *s;
+       u8 enc[3], vb[10];
+
+       s = kite_deflate_init(1, 0);
+       BUG_ON(!s || IS_ERR(s));
+
+       s->out = enc;
+       s->outlen = sizeof(enc);
+
+       writebits(s, (kFixedHuffman << 1) + 1, 3);
+       writebits(s, kstaticHuff_mainCodes[kSymbolEndOfBlock],
+                 kstaticHuff_litLenLevels[kSymbolEndOfBlock]);
+       flushbits(s);
+
+       kite_deflate_decompress_test(enc, s->pos_out,
+                                    vb, sizeof(vb), NULL, 0);
+}
+
 int main(int argc, char *argv[])
 {
-       int fd;
-       u64 filelength;
-       u8 out[1048576], *buf;
-       int dstsize = 4096;
-       unsigned int srcsize, outsize;
+       unsigned int srcsize, outsize, dstsize, level;
        struct kite_deflate *s;
+       u8 out[1048576], *buf;
+       u64 filelength;
+       u8 *vbuf;
+       int fd;
 
+       if (argc < 2) {
+               kite_deflate_test1();
+               fprintf(stdout, "PASS\n");
+               return 0;
+       }
+       dstsize = level = 0;
        fd = open(argv[1], O_RDONLY);
-       if (fd < 0)
-               return -errno;
-       if (argc > 2)
+       BUG_ON(fd < 0);
+       if (argc > 2) {
                dstsize = atoi(argv[2]);
-       filelength = lseek(fd, 0, SEEK_END);
+               if (argc > 3)
+                       level = atoi(argv[3]);
+       }
+       if (!dstsize || dstsize > sizeof(out))
+               dstsize = 4096;
+       if (!level)
+               level = 9;
 
-       s = kite_deflate_init(9, 0);
-       if (IS_ERR(s))
-               return PTR_ERR(s);
+       s = kite_deflate_init(level, 0);
+       BUG_ON(IS_ERR(s));
 
        filelength = lseek(fd, 0, SEEK_END);
        buf = mmap(NULL, filelength, PROT_READ, MAP_SHARED, fd, 0);
-       if (buf == MAP_FAILED)
-               return -errno;
+       BUG_ON(buf == MAP_FAILED);
        close(fd);
 
        srcsize = filelength;
        outsize = kite_deflate_destsize(s, buf, out, &srcsize, dstsize);
-       fd = open("out.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
-       write(fd, out, outsize);
-       close(fd);
        kite_deflate_end(s);
+#ifdef HAVE_ZLIB
+       vbuf = malloc(srcsize);
+       if (!vbuf) {
+               fprintf(stderr, "buffer allocation failed\n");
+       } else {
+               BUG_ON(kite_deflate_decompress_zlib(out, outsize,
+                                                   vbuf, srcsize) != srcsize);
+               BUG_ON(memcmp(buf, vbuf, srcsize));
+               free(vbuf);
+       }
+#endif
+       BUG_ON(fwrite(out, outsize, 1, stdout) != 1);
        return 0;
 }
 #endif
-- 
2.43.5


Reply via email to