232 lines
4.5 KiB
C
232 lines
4.5 KiB
C
/*
|
|
* qrencode - QR Code encoder
|
|
*
|
|
* Binary sequence class.
|
|
* Copyright (C) 2006-2017 Kentaro Fukuchi <kentaro@fukuchi.org>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#if HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "bitstream.h"
|
|
|
|
#define DEFAULT_BUFSIZE (128)
|
|
|
|
BitStream *BitStream_new(void)
|
|
{
|
|
BitStream *bstream;
|
|
|
|
bstream = (BitStream *)malloc(sizeof(BitStream));
|
|
if(bstream == NULL) return NULL;
|
|
|
|
bstream->length = 0;
|
|
bstream->data = (unsigned char *)malloc(DEFAULT_BUFSIZE);
|
|
if(bstream->data == NULL) {
|
|
free(bstream);
|
|
return NULL;
|
|
}
|
|
bstream->datasize = DEFAULT_BUFSIZE;
|
|
|
|
return bstream;
|
|
}
|
|
|
|
#ifdef WITH_TESTS
|
|
BitStream *BitStream_newWithBits(size_t size, unsigned char *bits)
|
|
{
|
|
BitStream *bstream;
|
|
|
|
if(size == 0) return BitStream_new();
|
|
|
|
bstream = (BitStream *)malloc(sizeof(BitStream));
|
|
if(bstream == NULL) return NULL;
|
|
|
|
bstream->data = (unsigned char *)malloc(size);
|
|
if(bstream->data == NULL) {
|
|
free(bstream);
|
|
return NULL;
|
|
}
|
|
|
|
bstream->length = size;
|
|
bstream->datasize = size;
|
|
memcpy(bstream->data, bits, size);
|
|
|
|
return bstream;
|
|
}
|
|
#endif
|
|
|
|
static int BitStream_expand(BitStream *bstream)
|
|
{
|
|
unsigned char *data;
|
|
|
|
data = (unsigned char *)realloc(bstream->data, bstream->datasize * 2);
|
|
if(data == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
bstream->data = data;
|
|
bstream->datasize *= 2;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void BitStream_writeNum(unsigned char *dest, size_t bits, unsigned int num)
|
|
{
|
|
unsigned int mask;
|
|
size_t i;
|
|
unsigned char *p;
|
|
|
|
p = dest;
|
|
mask = 1U << (bits - 1);
|
|
for(i = 0; i < bits; i++) {
|
|
if(num & mask) {
|
|
*p = 1;
|
|
} else {
|
|
*p = 0;
|
|
}
|
|
p++;
|
|
mask = mask >> 1;
|
|
}
|
|
}
|
|
|
|
static void BitStream_writeBytes(unsigned char *dest, size_t size, unsigned char *data)
|
|
{
|
|
unsigned char mask;
|
|
size_t i, j;
|
|
unsigned char *p;
|
|
|
|
p = dest;
|
|
for(i = 0; i < size; i++) {
|
|
mask = 0x80;
|
|
for(j = 0; j < 8; j++) {
|
|
if(data[i] & mask) {
|
|
*p = 1;
|
|
} else {
|
|
*p = 0;
|
|
}
|
|
p++;
|
|
mask = mask >> 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
int BitStream_append(BitStream *bstream, BitStream *arg)
|
|
{
|
|
int ret;
|
|
|
|
if(arg == NULL) {
|
|
return -1;
|
|
}
|
|
if(arg->length == 0) {
|
|
return 0;
|
|
}
|
|
|
|
while(bstream->length + arg->length > bstream->datasize) {
|
|
ret = BitStream_expand(bstream);
|
|
if(ret < 0) return ret;
|
|
}
|
|
|
|
memcpy(bstream->data + bstream->length, arg->data, arg->length);
|
|
bstream->length += arg->length;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int BitStream_appendNum(BitStream *bstream, size_t bits, unsigned int num)
|
|
{
|
|
int ret;
|
|
|
|
if(bits == 0) return 0;
|
|
|
|
while(bstream->datasize - bstream->length < bits) {
|
|
ret = BitStream_expand(bstream);
|
|
if(ret < 0) return ret;
|
|
}
|
|
BitStream_writeNum(bstream->data + bstream->length, bits, num);
|
|
bstream->length += bits;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int BitStream_appendBytes(BitStream *bstream, size_t size, unsigned char *data)
|
|
{
|
|
int ret;
|
|
|
|
if(size == 0) return 0;
|
|
|
|
while(bstream->datasize - bstream->length < size * 8) {
|
|
ret = BitStream_expand(bstream);
|
|
if(ret < 0) return ret;
|
|
}
|
|
BitStream_writeBytes(bstream->data + bstream->length, size, data);
|
|
bstream->length += size * 8;
|
|
|
|
return 0;
|
|
}
|
|
|
|
unsigned char *BitStream_toByte(BitStream *bstream)
|
|
{
|
|
size_t i, j, size, bytes, oddbits;
|
|
unsigned char *data, v;
|
|
unsigned char *p;
|
|
|
|
size = BitStream_size(bstream);
|
|
if(size == 0) {
|
|
return NULL;
|
|
}
|
|
data = (unsigned char *)malloc((size + 7) / 8);
|
|
if(data == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
bytes = size / 8;
|
|
|
|
p = bstream->data;
|
|
for(i = 0; i < bytes; i++) {
|
|
v = 0;
|
|
for(j = 0; j < 8; j++) {
|
|
v = (unsigned char)(v << 1);
|
|
v |= *p;
|
|
p++;
|
|
}
|
|
data[i] = v;
|
|
}
|
|
oddbits = size & 7;
|
|
if(oddbits > 0) {
|
|
v = 0;
|
|
for(j = 0; j < oddbits; j++) {
|
|
v = (unsigned char)(v << 1);
|
|
v |= *p;
|
|
p++;
|
|
}
|
|
data[bytes] = (unsigned char)(v << (8 - oddbits));
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
void BitStream_free(BitStream *bstream)
|
|
{
|
|
if(bstream != NULL) {
|
|
free(bstream->data);
|
|
free(bstream);
|
|
}
|
|
}
|