summaryrefslogtreecommitdiff
path: root/fitz
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2012-06-29 17:32:59 +0100
committerRobin Watts <robin.watts@artifex.com>2012-07-04 10:50:54 +0100
commit05908e59a3db355cd8cbaab99406bb401d3afa2d (patch)
tree050c1c7835577e838b6a6d3286375f26225d0c22 /fitz
parent5a2689c657ecb282f322f5141c46c03d13a231ae (diff)
downloadmupdf-05908e59a3db355cd8cbaab99406bb401d3afa2d.tar.xz
Bug 693160: Fix bug in fz_write_buffer_bits.
When writing few enough bits that they would fit into the 'spare' bits in the last byte, I was failing to update the buffer. Also, I was failing to grow the buffer enough, and calculating the wrong number of bits left over in various places. Both fixed here. Thanks to Robert Jedrzejczyk and Sebras!
Diffstat (limited to 'fitz')
-rw-r--r--fitz/stm_buffer.c72
1 files changed, 66 insertions, 6 deletions
diff --git a/fitz/stm_buffer.c b/fitz/stm_buffer.c
index 7a676a67..706be39a 100644
--- a/fitz/stm_buffer.c
+++ b/fitz/stm_buffer.c
@@ -110,9 +110,13 @@ void fz_write_buffer_byte(fz_context *ctx, fz_buffer *buf, int val)
void fz_write_buffer_bits(fz_context *ctx, fz_buffer *buf, int val, int bits)
{
- int extra;
int shift;
+ /* Throughout this code, the invariant is that we need to write the
+ * bottom 'bits' bits of 'val' into the stream. On entry we assume
+ * that val & ((1<<bits)-1) == val, but we do not rely on this after
+ * having written the first partial byte. */
+
if (bits == 0)
return;
@@ -121,12 +125,16 @@ void fz_write_buffer_bits(fz_context *ctx, fz_buffer *buf, int val, int bits)
* buf->unused_bits = the number of unused bits in the last byte.
*/
- /* Extend the buffer as required before we start; that way we never
- * fail part way during writing. */
+ /* Find the amount we need to shift val up by so that it will be in
+ * the correct position to be inserted into any existing data byte. */
shift = (buf->unused_bits - bits);
+
+ /* Extend the buffer as required before we start; that way we never
+ * fail part way during writing. If shift < 0, then we'll need -shift
+ * more bits. */
if (shift < 0)
{
- extra = (7-buf->unused_bits)>>3;
+ int extra = (7-shift)>>3; /* Round up to bytes */
fz_ensure_buffer(ctx, buf, buf->len + extra);
}
@@ -135,8 +143,14 @@ void fz_write_buffer_bits(fz_context *ctx, fz_buffer *buf, int val, int bits)
{
buf->data[buf->len-1] |= (shift >= 0 ? (((unsigned int)val)<<shift) : (((unsigned int)val)>>-shift));
if (shift >= 0)
+ {
+ /* If we were shifting up, we're done. */
+ buf->unused_bits -= bits;
return;
- bits += shift;
+ }
+ /* The number of bits left to write is the number that didn't
+ * fit in this first byte. */
+ bits = -shift;
}
/* Write any whole bytes */
@@ -149,7 +163,7 @@ void fz_write_buffer_bits(fz_context *ctx, fz_buffer *buf, int val, int bits)
/* Write trailing bits (with 0's in unused bits) */
if (bits > 0)
{
- bits += 8;
+ bits = 8-bits;
buf->data[buf->len++] = val<<bits;
}
buf->unused_bits = bits;
@@ -174,3 +188,49 @@ fz_buffer_printf(fz_context *ctx, fz_buffer *buffer, char *fmt, ...)
va_end(args);
}
+
+#ifdef TEST_BUFFER_WRITE
+
+#define TEST_LEN 1024
+
+void
+fz_test_buffer_write(fz_context *ctx)
+{
+ fz_buffer *master = fz_new_buffer(ctx, TEST_LEN);
+ fz_buffer *copy = fz_new_buffer(ctx, TEST_LEN);
+ fz_stream *stm;
+ int i, j, k;
+
+ /* Make us a dummy buffer */
+ for (i = 0; i < TEST_LEN; i++)
+ {
+ master->data[i] = rand();
+ }
+ master->len = TEST_LEN;
+
+ /* Now copy that buffer several times, checking it for validity */
+ stm = fz_open_buffer(ctx, master);
+ for (i = 0; i < 256; i++)
+ {
+ memset(copy->data, i, TEST_LEN);
+ copy->len = 0;
+ j = TEST_LEN * 8;
+ do
+ {
+ k = (rand() & 31)+1;
+ if (k > j)
+ k = j;
+ fz_write_buffer_bits(ctx, copy, fz_read_bits(stm, k), k);
+ j -= k;
+ }
+ while (j);
+
+ if (memcmp(copy->data, master->data, TEST_LEN) != 0)
+ fprintf(stderr, "Copied buffer is different!\n");
+ fz_seek(stm, 0, 0);
+ }
+ fz_close(stm);
+ fz_drop_buffer(ctx, master);
+ fz_drop_buffer(ctx, copy);
+}
+#endif