]> wimlib.net Git - wimlib/blob - src/decomp.c
Initial commit (current version is wimlib 0.6.2)
[wimlib] / src / decomp.c
1 /*
2  * decomp.c
3  *
4  * Functions too long to declare as inline in decomp.h.
5  *
6  * Copyright (C) 2012 Eric Biggers
7  *
8  * wimlib - Library for working with WIM files 
9  *
10  * This library is free software; you can redistribute it and/or modify it under
11  * the terms of the GNU Lesser General Public License as published by the Free
12  * Software Foundation; either version 2.1 of the License, or (at your option) any
13  * later version.
14  *
15  * This library is distributed in the hope that it will be useful, but WITHOUT ANY
16  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
17  * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License along
20  * with this library; if not, write to the Free Software Foundation, Inc., 59
21  * Temple Place, Suite 330, Boston, MA 02111-1307 USA 
22  */
23
24 #include "decomp.h"
25 #include <string.h>
26
27 /* Reads @n bytes from the bitstream @stream into the location pointed to by @dest.
28  * The bitstream must be 16-bit aligned. */
29 int bitstream_read_bytes(struct input_bitstream *stream, size_t n, void *dest)
30 {
31         /* Precondition:  The bitstream is 16-byte aligned. */
32         wimlib_assert(stream->bitsleft % 16 == 0);
33
34         u8 *p = dest;
35
36         /* Get the bytes currently in the buffer variable. */
37         while (stream->bitsleft != 0) {
38                 if (n-- == 0)
39                         return 0;
40                 *p++ = bitstream_peek_bits(stream, 8);
41                 bitstream_remove_bits(stream, 8);
42         }
43
44         /* Get the rest directly from the pointer to the data.  Of course, it's
45          * necessary to check there are really n bytes available. */
46         if (n > stream->data_bytes_left) {
47                 ERROR("Unexpected end of input when "
48                                 "reading %zu bytes from bitstream "
49                                 "(only have %u bytes left)\n", n,
50                                 stream->data_bytes_left);
51                 return 1;
52         }
53         memcpy(p, stream->data, n);
54         stream->data += n;
55         stream->data_bytes_left -= n;
56
57         /* It's possible to copy an odd number of bytes and leave the stream in
58          * an inconsistent state. Fix it by reading the next byte, if it is
59          * there. */
60         if ((n & 1) && stream->data_bytes_left != 0) {
61                 stream->bitsleft = 8;
62                 stream->data_bytes_left--;
63                 stream->bitbuf |= (input_bitbuf_t)(*stream->data) << 
64                                         (sizeof(input_bitbuf_t) * 8 - 8);
65                 stream->data++;
66         }
67         return 0;
68 }
69
70 /* Aligns the bitstream on a 16-bit boundary.
71  *
72  * Note: M$'s idea of "alignment" means that for some reason, a 16-bit word
73  * should be skipped over if the buffer happens to already be aligned on such a
74  * boundary.  This only applies for realigning the stream after the blocktype
75  * and length fields of an uncompressed block, however; it does not apply when
76  * realigning the stream after the end of the uncompressed block.
77  */
78 int align_input_bitstream(struct input_bitstream *stream, 
79                           bool skip_word_if_aligned)
80 {
81         int ret;
82         if (stream->bitsleft % 16 != 0) {
83                 bitstream_remove_bits(stream, stream->bitsleft % 16);
84         } else if (skip_word_if_aligned) {
85                 if (stream->bitsleft == 0) {
86                         ret = bitstream_ensure_bits(stream, 16);
87                         if (ret != 0) {
88                                 ERROR("Unexpected end of input when "
89                                                 "aligning bitstream!\n");
90                                 return ret;
91                         }
92                 }
93                 bitstream_remove_bits(stream, 16);
94         }
95         return 0;
96 }