diff options
author | Leo Howell <leo@lwh.jp> | 2009-09-05 09:33:22 +0900 |
---|---|---|
committer | Leo Howell <leo@lwh.jp> | 2009-09-05 09:33:22 +0900 |
commit | ef01767c732629b7eff7d1601e76a1bac58f5bfd (patch) | |
tree | ac29871fd3c6f1bab8dc8e3c51e33292d5544a96 /lpg/libqr/data-create.c | |
download | pdf-simple-sign-ef01767c732629b7eff7d1601e76a1bac58f5bfd.tar.gz pdf-simple-sign-ef01767c732629b7eff7d1601e76a1bac58f5bfd.tar.xz pdf-simple-sign-ef01767c732629b7eff7d1601e76a1bac58f5bfd.zip |
The story so far
Diffstat (limited to 'lpg/libqr/data-create.c')
-rw-r--r-- | lpg/libqr/data-create.c | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/lpg/libqr/data-create.c b/lpg/libqr/data-create.c new file mode 100644 index 0000000..2910997 --- /dev/null +++ b/lpg/libqr/data-create.c @@ -0,0 +1,223 @@ +/** + * Not "pure" C - only works with ASCII + */ + +/** XXX: check that the data will fit! **/ +/** NOTE: should store ec type in qr_data **/ + +#include <ctype.h> +#include <stdlib.h> +#include <qr/data.h> + +#include "bitstream.h" +#include "data-common.h" + +static void write_type_and_length(struct qr_data * data, + enum qr_data_type type, + size_t length) +{ + (void)bitstream_write(data->bits, QR_TYPE_CODES[type], 4); + (void)bitstream_write(data->bits, length, + get_size_field_length(data->format, type)); +} + +static struct qr_data * encode_numeric(struct qr_data * data, + const char * input, + size_t length) +{ + struct bitstream * stream = data->bits; + size_t bits; + + bits = 4 + get_size_field_length(data->format, QR_DATA_NUMERIC) + + 10 * (length / 3); + + if (length % 3 == 1) + bits += 4; + else if (length % 3 == 2) + bits += 7; + + stream = data->bits; + if (bitstream_resize(stream, + bitstream_size(stream) + bits) != 0) + return 0; + + write_type_and_length(data, QR_DATA_NUMERIC, length); + + for (; length >= 3; length -= 3) { + unsigned int x; + + if (!isdigit(input[0]) || + !isdigit(input[1]) || + !isdigit(input[2])) + return 0; + + x = (input[0] - '0') * 100 + + (input[1] - '0') * 10 + + (input[2] - '0'); + bitstream_write(stream, x, 10); + input += 3; + } + + if (length > 0) { + unsigned int x; + + if (!isdigit(*input)) + return 0; + + x = *input++ - '0'; + + if (length == 2) { + if (!isdigit(*input)) + return 0; + x = x * 10 + (*input - '0'); + } + + bitstream_write(stream, x, length == 2 ? 7 : 4); + } + + return data; +} + +static int get_alpha_code(char c) +{ + if (isdigit(c)) + return c - '0'; + else if (isalpha(c)) + return toupper(c) - 'A' + 10; + + switch (c) { + case ' ': return 36; + case '$': return 37; + case '%': return 38; + case '*': return 39; + case '+': return 40; + case '-': return 41; + case '.': return 42; + case '/': return 43; + case ':': return 44; + default: return -1; + } +} + +static struct qr_data * encode_alpha(struct qr_data * data, + const char * input, + size_t length) +{ + struct bitstream * stream = data->bits; + size_t bits; + + bits = 4 + get_size_field_length(data->format, QR_DATA_ALPHA) + + 11 * (length / 2) + + 6 * (length % 2); + + stream = data->bits; + if (bitstream_resize(stream, + bitstream_size(stream) + bits) != 0) + return 0; + + write_type_and_length(data, QR_DATA_ALPHA, length); + + for (; length >= 2; length -= 2) { + unsigned int x; + int c1, c2; + + c1 = get_alpha_code(*input++); + c2 = get_alpha_code(*input++); + + if (c1 < 0 || c2 < 0) + return 0; + + x = c1 * 45 + c2; + bitstream_write(stream, x, 11); + } + + if (length > 0) { + int c = get_alpha_code(*input); + + if (c < 0) + return 0; + + bitstream_write(stream, c, 6); + } + + return data; +} + +static struct qr_data * encode_8bit(struct qr_data * data, + const char * input, + size_t length) +{ + struct bitstream * stream = data->bits; + size_t bits; + + bits = 4 + get_size_field_length(data->format, QR_DATA_8BIT) + + 8 * length; + + stream = data->bits; + if (bitstream_resize(stream, + bitstream_size(stream) + bits) != 0) + return 0; + + write_type_and_length(data, QR_DATA_8BIT, length); + + while (length--) + bitstream_write(stream, *input++, 8); + + return data; +} + +static struct qr_data * encode_kanji(struct qr_data * data, + const char * input, + size_t length) +{ + return 0; +} + +struct qr_data * qr_create_data(int format, + enum qr_data_type type, + const char * input, + size_t length) +{ + struct qr_data * data; + + if (format < 1 || format > 40) + return 0; + + data = malloc(sizeof(*data)); + if (!data) + return 0; + + data->format = format; + data->bits = bitstream_create(); + data->offset = 0; + + if (data->bits) { + struct qr_data * ret; + + switch (type) { + case QR_DATA_NUMERIC: + ret = encode_numeric(data, input, length); break; + case QR_DATA_ALPHA: + ret = encode_alpha(data, input, length); break; + case QR_DATA_8BIT: + ret = encode_8bit(data, input, length); break; + case QR_DATA_KANJI: + ret = encode_kanji(data, input, length); break; + default: + /* unsupported / invalid */ + ret = 0; + break; + } + + if (!ret) { + bitstream_destroy(data->bits); + free(data); + } + + return ret; + } else { + free(data); + return 0; + } +} + |