1/*
2 * qrencode - QR Code encoder
3 *
4 * Binary sequence class.
5 * Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#if HAVE_CONFIG_H
23# include "config.h"
24#endif
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28
29#include "bitstream.h"
30
31BitStream *BitStream_new(void)
32{
33	BitStream *bstream;
34
35	bstream = (BitStream *)malloc(sizeof(BitStream));
36	if(bstream == NULL) return NULL;
37
38	bstream->length = 0;
39	bstream->data = NULL;
40
41	return bstream;
42}
43
44static int BitStream_allocate(BitStream *bstream, int length)
45{
46	unsigned char *data;
47
48	if(bstream == NULL) {
49		return -1;
50	}
51
52	data = (unsigned char *)malloc(length);
53	if(data == NULL) {
54		return -1;
55	}
56
57	if(bstream->data) {
58		free(bstream->data);
59	}
60	bstream->length = length;
61	bstream->data = data;
62
63	return 0;
64}
65
66static BitStream *BitStream_newFromNum(int bits, unsigned int num)
67{
68	unsigned int mask;
69	int i;
70	unsigned char *p;
71	BitStream *bstream;
72
73	bstream = BitStream_new();
74	if(bstream == NULL) return NULL;
75
76	if(BitStream_allocate(bstream, bits)) {
77		BitStream_free(bstream);
78		return NULL;
79	}
80
81	p = bstream->data;
82	mask = 1 << (bits - 1);
83	for(i=0; i<bits; i++) {
84		if(num & mask) {
85			*p = 1;
86		} else {
87			*p = 0;
88		}
89		p++;
90		mask = mask >> 1;
91	}
92
93	return bstream;
94}
95
96static BitStream *BitStream_newFromBytes(int size, unsigned char *data)
97{
98	unsigned char mask;
99	int i, j;
100	unsigned char *p;
101	BitStream *bstream;
102
103	bstream = BitStream_new();
104	if(bstream == NULL) return NULL;
105
106	if(BitStream_allocate(bstream, size * 8)) {
107		BitStream_free(bstream);
108		return NULL;
109	}
110
111	p = bstream->data;
112	for(i=0; i<size; i++) {
113		mask = 0x80;
114		for(j=0; j<8; j++) {
115			if(data[i] & mask) {
116				*p = 1;
117			} else {
118				*p = 0;
119			}
120			p++;
121			mask = mask >> 1;
122		}
123	}
124
125	return bstream;
126}
127
128int BitStream_append(BitStream *bstream, BitStream *arg)
129{
130	unsigned char *data;
131
132	if(arg == NULL) {
133		return -1;
134	}
135	if(arg->length == 0) {
136		return 0;
137	}
138	if(bstream->length == 0) {
139		if(BitStream_allocate(bstream, arg->length)) {
140			return -1;
141		}
142		memcpy(bstream->data, arg->data, arg->length);
143		return 0;
144	}
145
146	data = (unsigned char *)malloc(bstream->length + arg->length);
147	if(data == NULL) {
148		return -1;
149	}
150	memcpy(data, bstream->data, bstream->length);
151	memcpy(data + bstream->length, arg->data, arg->length);
152
153	free(bstream->data);
154	bstream->length += arg->length;
155	bstream->data = data;
156
157	return 0;
158}
159
160int BitStream_appendNum(BitStream *bstream, int bits, unsigned int num)
161{
162	BitStream *b;
163	int ret;
164
165	if(bits == 0) return 0;
166
167	b = BitStream_newFromNum(bits, num);
168	if(b == NULL) return -1;
169
170	ret = BitStream_append(bstream, b);
171	BitStream_free(b);
172
173	return ret;
174}
175
176int BitStream_appendBytes(BitStream *bstream, int size, unsigned char *data)
177{
178	BitStream *b;
179	int ret;
180
181	if(size == 0) return 0;
182
183	b = BitStream_newFromBytes(size, data);
184	if(b == NULL) return -1;
185
186	ret = BitStream_append(bstream, b);
187	BitStream_free(b);
188
189	return ret;
190}
191
192unsigned char *BitStream_toByte(BitStream *bstream)
193{
194	int i, j, size, bytes;
195	unsigned char *data, v;
196	unsigned char *p;
197
198	size = BitStream_size(bstream);
199	if(size == 0) {
200		return NULL;
201	}
202	data = (unsigned char *)malloc((size + 7) / 8);
203	if(data == NULL) {
204		return NULL;
205	}
206
207	bytes = size  / 8;
208
209	p = bstream->data;
210	for(i=0; i<bytes; i++) {
211		v = 0;
212		for(j=0; j<8; j++) {
213			v = v << 1;
214			v |= *p;
215			p++;
216		}
217		data[i] = v;
218	}
219	if(size & 7) {
220		v = 0;
221		for(j=0; j<(size & 7); j++) {
222			v = v << 1;
223			v |= *p;
224			p++;
225		}
226		data[bytes] = v;
227	}
228
229	return data;
230}
231
232void BitStream_free(BitStream *bstream)
233{
234	if(bstream != NULL) {
235		free(bstream->data);
236		free(bstream);
237	}
238}
239