diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index ffc8d7ea74..61adf50d76 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -239,7 +239,8 @@ AddFilesToHaikuImage system add-ons kernel busses usb AddFilesToHaikuImage system add-ons kernel console : vga_text ; AddFilesToHaikuImage system add-ons kernel debugger : demangle $(X86_ONLY)disasm hangman - invalidate_on_exit usb_keyboard run_on_exit ; + invalidate_on_exit usb_keyboard qrencode + run_on_exit ; AddFilesToHaikuImage system add-ons kernel file_systems : $(SYSTEM_ADD_ONS_FILE_SYSTEMS) ; AddFilesToHaikuImage system add-ons kernel generic diff --git a/data/system/data/fonts/ttfonts/VL-Gothic-Regular.ttf b/data/system/data/fonts/ttfonts/VL-Gothic-Regular.ttf index 016461965c..f880d709e7 100644 Binary files a/data/system/data/fonts/ttfonts/VL-Gothic-Regular.ttf and b/data/system/data/fonts/ttfonts/VL-Gothic-Regular.ttf differ diff --git a/data/system/data/fonts/ttfonts/VL-PGothic-Regular.ttf b/data/system/data/fonts/ttfonts/VL-PGothic-Regular.ttf index 6512f78020..293825428c 100644 Binary files a/data/system/data/fonts/ttfonts/VL-PGothic-Regular.ttf and b/data/system/data/fonts/ttfonts/VL-PGothic-Regular.ttf differ diff --git a/headers/private/kernel/debug_heap.h b/headers/private/kernel/debug_heap.h index ae110b9840..552a07a8cd 100644 --- a/headers/private/kernel/debug_heap.h +++ b/headers/private/kernel/debug_heap.h @@ -19,6 +19,7 @@ extern "C" { debug_alloc_pool* create_debug_alloc_pool(); void delete_debug_alloc_pool(debug_alloc_pool* pool); void* debug_malloc(size_t size); +void* debug_calloc(size_t num, size_t size); void debug_free(void* address); void debug_heap_init(); diff --git a/headers/private/kernel/util/AVLTreeMap.h b/headers/private/kernel/util/AVLTreeMap.h index 2405bb79b8..ea436be3c1 100644 --- a/headers/private/kernel/util/AVLTreeMap.h +++ b/headers/private/kernel/util/AVLTreeMap.h @@ -26,7 +26,7 @@ namespace AVLTreeMapStrategy { typename Node; inline Node* Allocate(const Key& key, const Value& value) inline void Free(Node* node) - inline Key GetKey(Node* node) const + inline const Key GetKey(const Node* node) const inline Value& GetValue(Node* node) const inline AVLTreeNode* GetAVLTreeNode(Node* node) const inline Node* GetNode(AVLTreeNode* node) const @@ -622,7 +622,7 @@ public: fAllocator.Deallocate(node); } - inline Key& GetKey(Node* node) const + inline const Key& GetKey(const Node* node) const { return node->key; } diff --git a/src/add-ons/kernel/debugger/Jamfile b/src/add-ons/kernel/debugger/Jamfile index dcf3f4a83d..ef05494cf9 100644 --- a/src/add-ons/kernel/debugger/Jamfile +++ b/src/add-ons/kernel/debugger/Jamfile @@ -7,5 +7,6 @@ SubInclude HAIKU_TOP src add-ons kernel debugger disasm ; SubInclude HAIKU_TOP src add-ons kernel debugger hangman ; SubInclude HAIKU_TOP src add-ons kernel debugger invalidate_on_exit ; SubInclude HAIKU_TOP src add-ons kernel debugger laplinkll ; +SubInclude HAIKU_TOP src add-ons kernel debugger qrencode ; SubInclude HAIKU_TOP src add-ons kernel debugger run_on_exit ; SubInclude HAIKU_TOP src add-ons kernel debugger usb_keyboard ; diff --git a/src/add-ons/kernel/debugger/qrencode/Jamfile b/src/add-ons/kernel/debugger/qrencode/Jamfile new file mode 100644 index 0000000000..c196777fbe --- /dev/null +++ b/src/add-ons/kernel/debugger/qrencode/Jamfile @@ -0,0 +1,22 @@ +SubDir HAIKU_TOP src add-ons kernel debugger qrencode ; + +UsePrivateHeaders kernel ; + +DEFINES += HAVE_CONFIG_H ; +DEFINES += malloc=debug_malloc ; +DEFINES += calloc=debug_calloc ; +DEFINES += free=debug_free ; + +KernelAddon qrencode : + bitstream.c + mask.c + mmask.c + mqrspec.c + qrencode.c + qrinput.c + qrspec.c + rscode.c + split.c + + module.cpp + ; diff --git a/src/add-ons/kernel/debugger/qrencode/bitstream.c b/src/add-ons/kernel/debugger/qrencode/bitstream.c new file mode 100644 index 0000000000..a0b9283cb0 --- /dev/null +++ b/src/add-ons/kernel/debugger/qrencode/bitstream.c @@ -0,0 +1,238 @@ +/* + * qrencode - QR Code encoder + * + * Binary sequence class. + * Copyright (C) 2006-2011 Kentaro Fukuchi + * + * 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 +#include +#include + +#include "bitstream.h" + +BitStream *BitStream_new(void) +{ + BitStream *bstream; + + bstream = (BitStream *)malloc(sizeof(BitStream)); + if(bstream == NULL) return NULL; + + bstream->length = 0; + bstream->data = NULL; + + return bstream; +} + +static int BitStream_allocate(BitStream *bstream, int length) +{ + unsigned char *data; + + if(bstream == NULL) { + return -1; + } + + data = (unsigned char *)malloc(length); + if(data == NULL) { + return -1; + } + + if(bstream->data) { + free(bstream->data); + } + bstream->length = length; + bstream->data = data; + + return 0; +} + +static BitStream *BitStream_newFromNum(int bits, unsigned int num) +{ + unsigned int mask; + int i; + unsigned char *p; + BitStream *bstream; + + bstream = BitStream_new(); + if(bstream == NULL) return NULL; + + if(BitStream_allocate(bstream, bits)) { + BitStream_free(bstream); + return NULL; + } + + p = bstream->data; + mask = 1 << (bits - 1); + for(i=0; i> 1; + } + + return bstream; +} + +static BitStream *BitStream_newFromBytes(int size, unsigned char *data) +{ + unsigned char mask; + int i, j; + unsigned char *p; + BitStream *bstream; + + bstream = BitStream_new(); + if(bstream == NULL) return NULL; + + if(BitStream_allocate(bstream, size * 8)) { + BitStream_free(bstream); + return NULL; + } + + p = bstream->data; + for(i=0; i> 1; + } + } + + return bstream; +} + +int BitStream_append(BitStream *bstream, BitStream *arg) +{ + unsigned char *data; + + if(arg == NULL) { + return -1; + } + if(arg->length == 0) { + return 0; + } + if(bstream->length == 0) { + if(BitStream_allocate(bstream, arg->length)) { + return -1; + } + memcpy(bstream->data, arg->data, arg->length); + return 0; + } + + data = (unsigned char *)malloc(bstream->length + arg->length); + if(data == NULL) { + return -1; + } + memcpy(data, bstream->data, bstream->length); + memcpy(data + bstream->length, arg->data, arg->length); + + free(bstream->data); + bstream->length += arg->length; + bstream->data = data; + + return 0; +} + +int BitStream_appendNum(BitStream *bstream, int bits, unsigned int num) +{ + BitStream *b; + int ret; + + if(bits == 0) return 0; + + b = BitStream_newFromNum(bits, num); + if(b == NULL) return -1; + + ret = BitStream_append(bstream, b); + BitStream_free(b); + + return ret; +} + +int BitStream_appendBytes(BitStream *bstream, int size, unsigned char *data) +{ + BitStream *b; + int ret; + + if(size == 0) return 0; + + b = BitStream_newFromBytes(size, data); + if(b == NULL) return -1; + + ret = BitStream_append(bstream, b); + BitStream_free(b); + + return ret; +} + +unsigned char *BitStream_toByte(BitStream *bstream) +{ + int i, j, size, bytes; + 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; idata); + free(bstream); + } +} diff --git a/src/add-ons/kernel/debugger/qrencode/bitstream.h b/src/add-ons/kernel/debugger/qrencode/bitstream.h new file mode 100644 index 0000000000..ffe743c5e0 --- /dev/null +++ b/src/add-ons/kernel/debugger/qrencode/bitstream.h @@ -0,0 +1,38 @@ +/* + * qrencode - QR Code encoder + * + * Binary sequence class. + * Copyright (C) 2006-2011 Kentaro Fukuchi + * + * 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 + */ + +#ifndef __BITSTREAM_H__ +#define __BITSTREAM_H__ + +typedef struct { + int length; + unsigned char *data; +} BitStream; + +extern BitStream *BitStream_new(void); +extern int BitStream_append(BitStream *bstream, BitStream *arg); +extern int BitStream_appendNum(BitStream *bstream, int bits, unsigned int num); +extern int BitStream_appendBytes(BitStream *bstream, int size, unsigned char *data); +#define BitStream_size(__bstream__) (__bstream__->length) +extern unsigned char *BitStream_toByte(BitStream *bstream); +extern void BitStream_free(BitStream *bstream); + +#endif /* __BITSTREAM_H__ */ diff --git a/src/add-ons/kernel/debugger/qrencode/config.h b/src/add-ons/kernel/debugger/qrencode/config.h new file mode 100644 index 0000000000..20515db864 --- /dev/null +++ b/src/add-ons/kernel/debugger/qrencode/config.h @@ -0,0 +1,5 @@ +#define MAJOR_VERSION 3 +#define MINOR_VERSION 3 +#define MICRO_VERSION 0 +#define VERSION "3.3.0" +#define __STATIC static diff --git a/src/add-ons/kernel/debugger/qrencode/mask.c b/src/add-ons/kernel/debugger/qrencode/mask.c new file mode 100644 index 0000000000..47c658ca0e --- /dev/null +++ b/src/add-ons/kernel/debugger/qrencode/mask.c @@ -0,0 +1,330 @@ +/* + * qrencode - QR Code encoder + * + * Masking. + * Copyright (C) 2006-2011 Kentaro Fukuchi + * + * 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 +#include +#include +#include + +#include "qrencode.h" +#include "qrspec.h" +#include "mask.h" + +__STATIC int Mask_writeFormatInformation(int width, unsigned char *frame, int mask, QRecLevel level) +{ + unsigned int format; + unsigned char v; + int i; + int blacks = 0; + + format = QRspec_getFormatInfo(mask, level); + + for(i=0; i<8; i++) { + if(format & 1) { + blacks += 2; + v = 0x85; + } else { + v = 0x84; + } + frame[width * 8 + width - 1 - i] = v; + if(i < 6) { + frame[width * i + 8] = v; + } else { + frame[width * (i + 1) + 8] = v; + } + format= format >> 1; + } + for(i=0; i<7; i++) { + if(format & 1) { + blacks += 2; + v = 0x85; + } else { + v = 0x84; + } + frame[width * (width - 7 + i) + 8] = v; + if(i == 0) { + frame[width * 8 + 7] = v; + } else { + frame[width * 8 + 6 - i] = v; + } + format= format >> 1; + } + + return blacks; +} + +/** + * Demerit coefficients. + * See Section 8.8.2, pp.45, JIS X0510:2004. + */ +#define N1 (3) +#define N2 (3) +#define N3 (40) +#define N4 (10) + +#define MASKMAKER(__exp__) \ + int x, y;\ + int b = 0;\ +\ + for(y=0; y= maskNum) { + errno = EINVAL; + return NULL; + } + + masked = (unsigned char *)malloc(width * width); + if(masked == NULL) return NULL; + + maskMakers[mask](width, frame, masked); + Mask_writeFormatInformation(width, masked, mask, level); + + return masked; +} + + +//static int n1; +//static int n2; +//static int n3; +//static int n4; + +__STATIC int Mask_calcN1N3(int length, int *runLength) +{ + int i; + int demerit = 0; + int fact; + + for(i=0; i= 5) { + demerit += N1 + (runLength[i] - 5); + //n1 += N1 + (runLength[i] - 5); + } + if((i & 1)) { + if(i >= 3 && i < length-2 && (runLength[i] % 3) == 0) { + fact = runLength[i] / 3; + if(runLength[i-2] == fact && + runLength[i-1] == fact && + runLength[i+1] == fact && + runLength[i+2] == fact) { + if(i == 3 || runLength[i-3] >= 4 * fact) { + demerit += N3; + //n3 += N3; + } else if(i+4 >= length || runLength[i+3] >= 4 * fact) { + demerit += N3; + //n3 += N3; + } + } + } + } + } + + return demerit; +} + +__STATIC int Mask_calcN2(int width, unsigned char *frame) +{ + int x, y; + unsigned char *p; + unsigned char b22, w22; + int demerit = 0; + + p = frame + width + 1; + for(y=1; y + * + * 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 + */ + +#ifndef __MASK_H__ +#define __MASK_H__ + +extern unsigned char *Mask_makeMask(int width, unsigned char *frame, int mask, QRecLevel level); +extern unsigned char *Mask_mask(int width, unsigned char *frame, QRecLevel level); + +#ifdef WITH_TESTS +extern int Mask_calcN2(int width, unsigned char *frame); +extern int Mask_calcN1N3(int length, int *runLength); +extern int Mask_calcRunLength(int width, unsigned char *frame, int dir, int *runLength); +extern int Mask_evaluateSymbol(int width, unsigned char *frame); +extern int Mask_writeFormatInformation(int width, unsigned char *frame, int mask, QRecLevel level); +extern unsigned char *Mask_makeMaskedFrame(int width, unsigned char *frame, int mask); +#endif + +#endif /* __MASK_H__ */ diff --git a/src/add-ons/kernel/debugger/qrencode/mmask.c b/src/add-ons/kernel/debugger/qrencode/mmask.c new file mode 100644 index 0000000000..99470f2008 --- /dev/null +++ b/src/add-ons/kernel/debugger/qrencode/mmask.c @@ -0,0 +1,177 @@ +/* + * qrencode - QR Code encoder + * + * Masking for Micro QR Code. + * Copyright (C) 2006-2011 Kentaro Fukuchi + * + * 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 +#include +#include +#include + +#include "qrencode.h" +#include "mqrspec.h" +#include "mmask.h" + +__STATIC void MMask_writeFormatInformation(int version, int width, unsigned char *frame, int mask, QRecLevel level) +{ + unsigned int format; + unsigned char v; + int i; + + format = MQRspec_getFormatInfo(mask, version, level); + + for(i=0; i<8; i++) { + v = 0x84 | (format & 1); + frame[width * (i + 1) + 8] = v; + format = format >> 1; + } + for(i=0; i<7; i++) { + v = 0x84 | (format & 1); + frame[width * 8 + 7 - i] = v; + format = format >> 1; + } +} + +#define MASKMAKER(__exp__) \ + int x, y;\ +\ + for(y=0; y= maskNum) { + errno = EINVAL; + return NULL; + } + + width = MQRspec_getWidth(version); + masked = (unsigned char *)malloc(width * width); + if(masked == NULL) return NULL; + + maskMakers[mask](width, frame, masked); + MMask_writeFormatInformation(version, width, masked, mask, level); + + return masked; +} + +__STATIC int MMask_evaluateSymbol(int width, unsigned char *frame) +{ + int x, y; + unsigned char *p; + int sum1 = 0, sum2 = 0; + + p = frame + width * (width - 1); + for(x=1; x maxScore) { + maxScore = score; + free(bestMask); + bestMask = mask; + mask = (unsigned char *)malloc(width * width); + if(mask == NULL) break; + } + } + free(mask); + return bestMask; +} diff --git a/src/add-ons/kernel/debugger/qrencode/mmask.h b/src/add-ons/kernel/debugger/qrencode/mmask.h new file mode 100644 index 0000000000..f6556e877d --- /dev/null +++ b/src/add-ons/kernel/debugger/qrencode/mmask.h @@ -0,0 +1,34 @@ +/* + * qrencode - QR Code encoder + * + * Masking for Micro QR Code. + * Copyright (C) 2006-2011 Kentaro Fukuchi + * + * 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 + */ + +#ifndef __MMASK_H__ +#define __MMASK_H__ + +extern unsigned char *MMask_makeMask(int version, unsigned char *frame, int mask, QRecLevel level); +extern unsigned char *MMask_mask(int version, unsigned char *frame, QRecLevel level); + +#ifdef WITH_TESTS +extern int MMask_evaluateSymbol(int width, unsigned char *frame); +extern void MMask_writeFormatInformation(int version, int width, unsigned char *frame, int mask, QRecLevel level); +extern unsigned char *MMask_makeMaskedFrame(int width, unsigned char *frame, int mask); +#endif + +#endif /* __MMASK_H__ */ diff --git a/src/add-ons/kernel/debugger/qrencode/module.cpp b/src/add-ons/kernel/debugger/qrencode/module.cpp new file mode 100644 index 0000000000..b2f215ddce --- /dev/null +++ b/src/add-ons/kernel/debugger/qrencode/module.cpp @@ -0,0 +1,389 @@ +/* + * Copyright 2012, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ + + +#include +#include +#include +#include + +extern "C" { +#include "qrencode.h" +#include "qrspec.h" +} + + +extern "C" { +extern void abort_debugger_command(); +} + + +static const char* kWebPostBaseURL = "http://mlotz.ch/q"; + +static char sStringBuffer[16 * 1024]; +static char sEncodeBuffer[3 * 1024]; +static int sBufferPosition = 0; +static int sQRCodeVersion = 19; +static QRecLevel sQRCodeLevel = QR_ECLEVEL_L; +static char sWebPostId[64]; +static int sWebPostCounter = 0; + + +static bool +qrcode_bit(QRcode* qrCode, int x, int y) +{ + if (x >= qrCode->width || y >= qrCode->width) + return false; + + return (qrCode->data[y * qrCode->width + x] & 0x01) == 1; +} + + +static void +move_to_and_clear_line(int line) +{ + kprintf(" \x1b[%dd\x1b[G\x1b[K", line + 1); +} + + +static bool +print_qrcode(QRcode* qrCode, bool waitForKey) +{ + move_to_and_clear_line(0); + for (int y = 0; y < qrCode->width; y += 2) { + move_to_and_clear_line(y / 2 + 1); + kputs(" "); + + for (int x = 0; x < qrCode->width; x++) { + bool upper = qrcode_bit(qrCode, x, y); + bool lower = qrcode_bit(qrCode, x, y + 1); + if (upper == lower) + kputs(upper ? "\x11" : " "); + else + kputs(upper ? "\x12" : "\x13"); + } + } + + move_to_and_clear_line(qrCode->width / 2 + 2); + move_to_and_clear_line(qrCode->width / 2 + 3); + + if (waitForKey) { + kputs("press q to abort or any other key to continue...\x1b[1B\x1b[G"); + if (kgetc() == 'q') + return false; + } + + return true; +} + + +static int +encode_url(const char* query, const char* data, int encodeLength, + int inputLength) +{ + sEncodeBuffer[0] = 0; + strlcat(sEncodeBuffer, kWebPostBaseURL, encodeLength + 1); + strlcat(sEncodeBuffer, "?i=", encodeLength + 1); + strlcat(sEncodeBuffer, sWebPostId, encodeLength + 1); + strlcat(sEncodeBuffer, "&", encodeLength + 1); + strlcat(sEncodeBuffer, query, encodeLength + 1); + int position = strlcat(sEncodeBuffer, "=", encodeLength + 1); + if (position > encodeLength) + return -1; + + int copyCount = 0; + while (inputLength > 0 && position < encodeLength) { + char character = data[copyCount]; + if ((character >= 'a' && character <= 'z') + || (character >= 'A' && character <= 'Z') + || (character >= '0' && character <= '9') + || character == '.' || character == '-' || character == '_' + || character == '~' + // These aren't strictly valid, but seem to work. + || character == '/' || character == '(' || character == ')' + || character == '=' || character == '^' || character == '?' + || character == '|' || character == '*' || character == '@' + || character == ';' || character == ':' || character == ',' + || character == '{' || character == '}' || character == '[' + || character == ']' || character == '<' || character == '>' + || character == '!' || character == '\\') { + sEncodeBuffer[position++] = character; + sEncodeBuffer[position] = 0; + } else if (character == ' ') { + // Encode spaces as '+' as that's shorter than %20. + sEncodeBuffer[position++] = '+'; + sEncodeBuffer[position] = 0; + } else { + // Encode to a %xx escape. + if (encodeLength - position < 3) { + // Doesn't fit anymore, we're done. + break; + } + + char escaped[4]; + sprintf(escaped, "%%%.2x", character); + position = strlcat(sEncodeBuffer, escaped, encodeLength + 1); + } + + inputLength--; + copyCount++; + } + + return copyCount; +} + + +static int +qrencode(int argc, char* argv[]) +{ + if (argc > 1 && strcmp(argv[1], "--help") == 0) { + kprintf("%s []\n", argv[0]); + kprintf("If an argument is given, encodes that string as a QR code.\n" + "Otherwise the current QR buffer is encoded as QR codes.\n" + "When encoding from the QR buffer, the buffer is left intact.\n" + "use qrclear to clear the QR buffer or qrflush to encode/clear.\n"); + return 1; + } + + const char* source = NULL; + if (argc < 2) { + sStringBuffer[sBufferPosition] = 0; + source = sStringBuffer; + } else + source = argv[1]; + + int inputLength = strlen(source); + int encodeLength = QRspec_getDataLength(sQRCodeVersion, sQRCodeLevel) - 3; + while (inputLength > 0) { + int copyCount = 0; + if (sWebPostId[0] != 0) { + copyCount = encode_url(sWebPostCounter++ == 0 ? "clear" : "d", + source, encodeLength, inputLength); + if (copyCount < 0) { + kprintf("Failed to URL encode buffer.\n"); + QRcode_clearCache(); + return 1; + } + } else { + copyCount = inputLength < encodeLength ? inputLength : encodeLength; + memcpy(sEncodeBuffer, source, copyCount); + sEncodeBuffer[copyCount] = 0; + } + + QRcode* qrCode = QRcode_encodeString8bit(sEncodeBuffer, sQRCodeVersion, + sQRCodeLevel); + if (qrCode == NULL) { + kprintf("Failed to encode buffer into qr code.\n"); + QRcode_clearCache(); + return 1; + } + + source += copyCount; + inputLength -= copyCount; + + bool doContinue = print_qrcode(qrCode, inputLength > 0); + QRcode_free(qrCode); + + if (!doContinue) { + QRcode_clearCache(); + abort_debugger_command(); + // Does not return. + } + } + + QRcode_clearCache(); + return 0; +} + + +static int +qrclear(int argc, char* argv[]) +{ + if (argc > 1 && strcmp(argv[1], "--help") == 0) { + kprintf("Clears the current QR buffer.\n"); + return 0; + } + + sBufferPosition = 0; + sStringBuffer[0] = 0; + return 0; +} + + +static int +qrflush(int argc, char* argv[]) +{ + if (argc > 1 && strcmp(argv[1], "--help") == 0) { + kprintf("Flushes the current QR buffer by encoding QR codes from\n" + "the data and then clears the QR buffer.\n"); + return 1; + } + + qrencode(0, NULL); + qrclear(0, NULL); + return 0; +} + + +static int +qrappend(int argc, char* argv[]) +{ + if (argc < 2 || (argc > 1 && strcmp(argv[1], "--help") == 0)) { + kprintf("%s \n", argv[0]); + kprintf("Appends the given string to the QR buffer. Can be used as\n" + "the target of a pipe command to accumulate the output of other\n" + "commands in the QR buffer.\n" + "Note that this command will flush the QR buffer when it runs\n" + "full to make room for the new string. This will cause QR codes\n" + "to be generated while the append command still runs. As these\n" + "implicit flushes only happen to make room in the buffer, the\n" + "strings are afterwards appended aren't flushed, so make sure to\n" + "execute the qrflush command to generate codes for these as\n" + "well.\n"); + return 1; + } + + const char* source = argv[1]; + int length = strlen(source) + 1; + + while (length > 0) { + int copyCount = sizeof(sStringBuffer) - sBufferPosition - 1; + if (copyCount == 0) { + // The buffer is full, we need to flush it. + qrflush(0, NULL); + } + + if (length < copyCount) + copyCount = length; + + memcpy(sStringBuffer + sBufferPosition, source, copyCount); + sBufferPosition += copyCount; + source += copyCount; + length -= copyCount; + } + + // Overwrite the 0 byte that was copied extra with a newline. + if (sBufferPosition > 0) + sStringBuffer[sBufferPosition - 1] = '\n'; + + return 0; +} + + +static int +qrconfig(int argc, char* argv[]) +{ + if (argc < 2 || (argc > 1 && strcmp(argv[1], "--help") == 0)) { + kprintf("%s \n", argv[0]); + kprintf("Sets the QR version to be used. Valid versions range from 1\n" + "to 40 where each version determines the size of the QR code.\n" + "Version 1 is 21x21 in size and each version increments that size\n" + "by 4x4 up to 177x177 for version 40.\n" + "Bigger QR codes can hold more data, so ideally you use a version\n" + "that makes the QR code as big as possible while still fitting on\n" + "your screen.\n" + "You can test the new config by running qrencode\n" + "with a test string.\n" + "Note that due to memory constraints in the kernel debugger, some\n" + "of the higher versions may actually not work. The kernel\n" + "debugger heap size can be adjusted using the KDEBUG_HEAP define\n" + "in the kernel_debug_config.h header\n"); + return 1; + } + + int newVersion = atoi(argv[1]); + if (newVersion <= 0 || newVersion > 40) { + kprintf("Invalid QR code version supplied, " + "must be between 1 and 40.\n"); + return 1; + } + + sQRCodeVersion = newVersion; + return 0; +} + + +static int +qrwebpost(int argc, char* argv[]) +{ + if (argc >= 3 && strcmp(argv[1], "start") == 0) { + strlcpy(sWebPostId, argv[2], sizeof(sWebPostId)); + sWebPostCounter = 0; + + // Generate the clear code. + const char* args[2] = { "", "yes" }; + qrencode(2, (char**)args); + } else if (argc >= 2 && strcmp(argv[1], "stop") == 0) { + sWebPostId[0] = 0; + } else { + kprintf("%s start \n", argv[0]); + kprintf("%s stop\n", argv[0]); + kprintf("Causes the QR codes to be rendered as URLs that resolve to\n" + "a service that allows appending the data of multiple QR codes\n" + "for easier handling.\n" + "An initial QR code is generated that invokes a clear operation\n" + "to prepare the output file on the server.\n" + "Note that there is no logic behind the service, if you and\n" + "someone else use the same id at the same time, they will\n" + "overwrite eachother. Therefore use a reasonably unique name.\n"); + return 1; + } + + return 0; +} + + +static status_t +std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + add_debugger_command("qrencode", qrencode, + "encodes a string / the current QR buffer"); + add_debugger_command("qrappend", qrappend, + "appends a string to the QR buffer"); + add_debugger_command("qrclear", qrclear, + "clears the current QR buffer"); + add_debugger_command("qrflush", qrflush, + "encodes the current QR buffer and clears it"); + add_debugger_command("qrconfig", qrconfig, + "sets the QR code version to be used"); + add_debugger_command("qrwebpost", qrwebpost, + "sets up URL encoding for QR codes"); + return B_OK; + case B_MODULE_UNINIT: + remove_debugger_command("qrencode", qrencode); + remove_debugger_command("qrappend", qrappend); + remove_debugger_command("qrclear", qrclear); + remove_debugger_command("qrflush", qrflush); + remove_debugger_command("qrconfig", qrconfig); + remove_debugger_command("qrwebpost", qrwebpost); + return B_OK; + } + + return B_BAD_VALUE; +} + + +static struct debugger_module_info sModuleInfo = { + { + "debugger/qrencode/v1", + 0, + &std_ops + }, + NULL, + NULL, + NULL, + NULL +}; + +module_info *modules[] = { + (module_info *)&sModuleInfo, + NULL +}; + diff --git a/src/add-ons/kernel/debugger/qrencode/mqrspec.c b/src/add-ons/kernel/debugger/qrencode/mqrspec.c new file mode 100644 index 0000000000..76d2d261a6 --- /dev/null +++ b/src/add-ons/kernel/debugger/qrencode/mqrspec.c @@ -0,0 +1,280 @@ +/* + * qrencode - QR Code encoder + * + * Micor QR Code specification in convenient format. + * Copyright (C) 2006-2011 Kentaro Fukuchi + * + * The following data / specifications are taken from + * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004) + * or + * "Automatic identification and data capture techniques -- + * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006) + * + * 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 +#include +#include +#include +#ifdef HAVE_LIBPTHREAD +#include +#endif + +#include "mqrspec.h" + +/****************************************************************************** + * Version and capacity + *****************************************************************************/ + +typedef struct { + int width; //< Edge length of the symbol + int ec[4]; //< Number of ECC code (bytes) +} MQRspec_Capacity; + +/** + * Table of the capacity of symbols + * See Table 1 (pp.106) and Table 8 (pp.113) of Appendix 1, JIS X0510:2004. + */ +static const MQRspec_Capacity mqrspecCapacity[MQRSPEC_VERSION_MAX + 1] = { + { 0, {0, 0, 0, 0}}, + { 11, {2, 0, 0, 0}}, + { 13, {5, 6, 0, 0}}, + { 15, {6, 8, 0, 0}}, + { 17, {8, 10, 14, 0}} +}; + +int MQRspec_getDataLengthBit(int version, QRecLevel level) +{ + int w; + int ecc; + + w = mqrspecCapacity[version].width - 1; + ecc = mqrspecCapacity[version].ec[level]; + if(ecc == 0) return 0; + return w * w - 64 - ecc * 8; +} + +int MQRspec_getDataLength(int version, QRecLevel level) +{ + return (MQRspec_getDataLengthBit(version, level) + 4) / 8; +} + +int MQRspec_getECCLength(int version, QRecLevel level) +{ + return mqrspecCapacity[version].ec[level]; +} + +int MQRspec_getWidth(int version) +{ + return mqrspecCapacity[version].width; +} + +/****************************************************************************** + * Length indicator + *****************************************************************************/ + +/** + * See Table 3 (pp.107) of Appendix 1, JIS X0510:2004. + */ +static const int lengthTableBits[4][4] = { + { 3, 4, 5, 6}, + { 0, 3, 4, 5}, + { 0, 0, 4, 5}, + { 0, 0, 3, 4} +}; + +int MQRspec_lengthIndicator(QRencodeMode mode, int version) +{ + return lengthTableBits[mode][version - 1]; +} + +int MQRspec_maximumWords(QRencodeMode mode, int version) +{ + int bits; + int words; + + bits = lengthTableBits[mode][version - 1]; + words = (1 << bits) - 1; + if(mode == QR_MODE_KANJI) { + words *= 2; // the number of bytes is required + } + + return words; +} + +/****************************************************************************** + * Format information + *****************************************************************************/ + +/* See calcFormatInfo in tests/test_mqrspec.c */ +static const unsigned int formatInfo[4][8] = { + {0x4445, 0x55ae, 0x6793, 0x7678, 0x06de, 0x1735, 0x2508, 0x34e3}, + {0x4172, 0x5099, 0x62a4, 0x734f, 0x03e9, 0x1202, 0x203f, 0x31d4}, + {0x4e2b, 0x5fc0, 0x6dfd, 0x7c16, 0x0cb0, 0x1d5b, 0x2f66, 0x3e8d}, + {0x4b1c, 0x5af7, 0x68ca, 0x7921, 0x0987, 0x186c, 0x2a51, 0x3bba} +}; + +/* See Table 10 of Appendix 1. (pp.115) */ +static const int typeTable[MQRSPEC_VERSION_MAX + 1][3] = { + {-1, -1, -1}, + { 0, -1, -1}, + { 1, 2, -1}, + { 3, 4, -1}, + { 5, 6, 7} +}; + +unsigned int MQRspec_getFormatInfo(int mask, int version, QRecLevel level) +{ + int type; + + if(mask < 0 || mask > 3) return 0; + if(version <= 0 || version > MQRSPEC_VERSION_MAX) return 0; + if(level == QR_ECLEVEL_H) return 0; + type = typeTable[version][level]; + if(type < 0) return 0; + + return formatInfo[mask][type]; +} + +/****************************************************************************** + * Frame + *****************************************************************************/ + +/** + * Cache of initial frames. + */ +/* C99 says that static storage shall be initialized to a null pointer + * by compiler. */ +static unsigned char *frames[MQRSPEC_VERSION_MAX + 1]; +#ifdef HAVE_LIBPTHREAD +static pthread_mutex_t frames_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + +/** + * Put a finder pattern. + * @param frame + * @param width + * @param ox,oy upper-left coordinate of the pattern + */ +static void putFinderPattern(unsigned char *frame, int width, int ox, int oy) +{ + static const unsigned char finder[] = { + 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, + 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, + 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, + }; + int x, y; + const unsigned char *s; + + frame += oy * width + ox; + s = finder; + for(y=0; y<7; y++) { + for(x=0; x<7; x++) { + frame[x] = s[x]; + } + frame += width; + s += 7; + } +} + +static unsigned char *MQRspec_createFrame(int version) +{ + unsigned char *frame, *p, *q; + int width; + int x, y; + + width = mqrspecCapacity[version].width; + frame = (unsigned char *)malloc(width * width); + if(frame == NULL) return NULL; + + memset(frame, 0, width * width); + /* Finder pattern */ + putFinderPattern(frame, width, 0, 0); + /* Separator */ + p = frame; + for(y=0; y<7; y++) { + p[7] = 0xc0; + p += width; + } + memset(frame + width * 7, 0xc0, 8); + /* Mask format information area */ + memset(frame + width * 8 + 1, 0x84, 8); + p = frame + width + 8; + for(y=0; y<7; y++) { + *p = 0x84; + p += width; + } + /* Timing pattern */ + p = frame + 8; + q = frame + width * 8; + for(x=1; x MQRSPEC_VERSION_MAX) return NULL; + +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&frames_mutex); +#endif + if(frames[version] == NULL) { + frames[version] = MQRspec_createFrame(version); + } +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&frames_mutex); +#endif + if(frames[version] == NULL) return NULL; + + width = mqrspecCapacity[version].width; + frame = (unsigned char *)malloc(width * width); + if(frame == NULL) return NULL; + memcpy(frame, frames[version], width * width); + + return frame; +} + +void MQRspec_clearCache(void) +{ + int i; + +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&frames_mutex); +#endif + for(i=1; i<=MQRSPEC_VERSION_MAX; i++) { + free(frames[i]); + frames[i] = NULL; + } +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&frames_mutex); +#endif +} diff --git a/src/add-ons/kernel/debugger/qrencode/mqrspec.h b/src/add-ons/kernel/debugger/qrencode/mqrspec.h new file mode 100644 index 0000000000..2d4b90d281 --- /dev/null +++ b/src/add-ons/kernel/debugger/qrencode/mqrspec.h @@ -0,0 +1,157 @@ +/* + * qrencode - QR Code encoder + * + * Micro QR Code specification in convenient format. + * Copyright (C) 2006-2011 Kentaro Fukuchi + * + * 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 + */ + +#ifndef __MQRSPEC_H__ +#define __MQRSPEC_H__ + +#include "qrencode.h" + +/****************************************************************************** + * Version and capacity + *****************************************************************************/ + +/** + * Maximum width of a symbol + */ +#define MQRSPEC_WIDTH_MAX 17 + +/** + * Return maximum data code length (bits) for the version. + * @param version + * @param level + * @return maximum size (bits) + */ +extern int MQRspec_getDataLengthBit(int version, QRecLevel level); + +/** + * Return maximum data code length (bytes) for the version. + * @param version + * @param level + * @return maximum size (bytes) + */ +extern int MQRspec_getDataLength(int version, QRecLevel level); + +/** + * Return maximum error correction code length (bytes) for the version. + * @param version + * @param level + * @return ECC size (bytes) + */ +extern int MQRspec_getECCLength(int version, QRecLevel level); + +/** + * Return a version number that satisfies the input code length. + * @param size input code length (byte) + * @param level + * @return version number + */ +extern int MQRspec_getMinimumVersion(int size, QRecLevel level); + +/** + * Return the width of the symbol for the version. + * @param version + * @return width + */ +extern int MQRspec_getWidth(int version); + +/** + * Return the numer of remainder bits. + * @param version + * @return number of remainder bits + */ +extern int MQRspec_getRemainder(int version); + +/****************************************************************************** + * Length indicator + *****************************************************************************/ + +/** + * Return the size of lenght indicator for the mode and version. + * @param mode + * @param version + * @return the size of the appropriate length indicator (bits). + */ +extern int MQRspec_lengthIndicator(QRencodeMode mode, int version); + +/** + * Return the maximum length for the mode and version. + * @param mode + * @param version + * @return the maximum length (bytes) + */ +extern int MQRspec_maximumWords(QRencodeMode mode, int version); + +/****************************************************************************** + * Version information pattern + *****************************************************************************/ + +/** + * Return BCH encoded version information pattern that is used for the symbol + * of version 7 or greater. Use lower 18 bits. + * @param version + * @return BCH encoded version information pattern + */ +extern unsigned int MQRspec_getVersionPattern(int version); + +/****************************************************************************** + * Format information + *****************************************************************************/ + +/** + * Return BCH encoded format information pattern. + * @param mask + * @param version + * @param level + * @return BCH encoded format information pattern + */ +extern unsigned int MQRspec_getFormatInfo(int mask, int version, QRecLevel level); + +/****************************************************************************** + * Frame + *****************************************************************************/ + +/** + * Return a copy of initialized frame. + * When the same version is requested twice or more, a copy of cached frame + * is returned. + * @param version + * @return Array of unsigned char. You can free it by free(). + */ +extern unsigned char *MQRspec_newFrame(int version); + +/** + * Clear the frame cache. Typically for debug. + */ +extern void MQRspec_clearCache(void); + +/****************************************************************************** + * Mode indicator + *****************************************************************************/ + +/** + * Mode indicator. See Table 2 in Appendix 1 of JIS X0510:2004, pp.107. + */ +#define MQRSPEC_MODEID_NUM 0 +#define MQRSPEC_MODEID_AN 1 +#define MQRSPEC_MODEID_8 2 +#define MQRSPEC_MODEID_KANJI 3 + +#endif /* __MQRSPEC_H__ */ diff --git a/src/add-ons/kernel/debugger/qrencode/qrencode.c b/src/add-ons/kernel/debugger/qrencode/qrencode.c new file mode 100644 index 0000000000..d166a24812 --- /dev/null +++ b/src/add-ons/kernel/debugger/qrencode/qrencode.c @@ -0,0 +1,929 @@ +/* + * qrencode - QR Code encoder + * + * Copyright (C) 2006-2012 Kentaro Fukuchi + * + * 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 +#include +#include +#include + +#include "qrencode.h" +#include "qrspec.h" +#include "mqrspec.h" +#include "bitstream.h" +#include "qrinput.h" +#include "rscode.h" +#include "split.h" +#include "mask.h" +#include "mmask.h" + +/****************************************************************************** + * Raw code + *****************************************************************************/ + +typedef struct { + int dataLength; + unsigned char *data; + int eccLength; + unsigned char *ecc; +} RSblock; + +typedef struct { + int version; + int dataLength; + int eccLength; + unsigned char *datacode; + unsigned char *ecccode; + int b1; + int blocks; + RSblock *rsblock; + int count; +} QRRawCode; + +static void RSblock_initBlock(RSblock *block, int dl, unsigned char *data, int el, unsigned char *ecc, RS *rs) +{ + block->dataLength = dl; + block->data = data; + block->eccLength = el; + block->ecc = ecc; + + encode_rs_char(rs, data, ecc); +} + +static int RSblock_init(RSblock *blocks, int spec[5], unsigned char *data, unsigned char *ecc) +{ + int i; + RSblock *block; + unsigned char *dp, *ep; + RS *rs; + int el, dl; + + dl = QRspec_rsDataCodes1(spec); + el = QRspec_rsEccCodes1(spec); + rs = init_rs(8, 0x11d, 0, 1, el, 255 - dl - el); + if(rs == NULL) return -1; + + block = blocks; + dp = data; + ep = ecc; + for(i=0; idatacode = QRinput_getByteStream(input); + if(raw->datacode == NULL) { + free(raw); + return NULL; + } + + QRspec_getEccSpec(input->version, input->level, spec); + + raw->version = input->version; + raw->b1 = QRspec_rsBlockNum1(spec); + raw->dataLength = QRspec_rsDataLength(spec); + raw->eccLength = QRspec_rsEccLength(spec); + raw->ecccode = (unsigned char *)malloc(raw->eccLength); + if(raw->ecccode == NULL) { + free(raw->datacode); + free(raw); + return NULL; + } + + raw->blocks = QRspec_rsBlockNum(spec); + raw->rsblock = (RSblock *)calloc(sizeof(RSblock), raw->blocks); + if(raw->rsblock == NULL) { + QRraw_free(raw); + return NULL; + } + ret = RSblock_init(raw->rsblock, spec, raw->datacode, raw->ecccode); + if(ret < 0) { + QRraw_free(raw); + return NULL; + } + + raw->count = 0; + + return raw; +} + +/** + * Return a code (byte). + * This function can be called iteratively. + * @param raw raw code. + * @return code + */ +__STATIC unsigned char QRraw_getCode(QRRawCode *raw) +{ + int col, row; + unsigned char ret; + + if(raw->count < raw->dataLength) { + row = raw->count % raw->blocks; + col = raw->count / raw->blocks; + if(col >= raw->rsblock[0].dataLength) { + row += raw->b1; + } + ret = raw->rsblock[row].data[col]; + } else if(raw->count < raw->dataLength + raw->eccLength) { + row = (raw->count - raw->dataLength) % raw->blocks; + col = (raw->count - raw->dataLength) / raw->blocks; + ret = raw->rsblock[row].ecc[col]; + } else { + return 0; + } + raw->count++; + return ret; +} + +__STATIC void QRraw_free(QRRawCode *raw) +{ + if(raw != NULL) { + free(raw->datacode); + free(raw->ecccode); + free(raw->rsblock); + free(raw); + } +} + +/****************************************************************************** + * Raw code for Micro QR Code + *****************************************************************************/ + +typedef struct { + int version; + int dataLength; + int eccLength; + unsigned char *datacode; + unsigned char *ecccode; + RSblock *rsblock; + int oddbits; + int count; +} MQRRawCode; + +__STATIC void MQRraw_free(MQRRawCode *raw); +__STATIC MQRRawCode *MQRraw_new(QRinput *input) +{ + MQRRawCode *raw; + RS *rs; + + raw = (MQRRawCode *)malloc(sizeof(MQRRawCode)); + if(raw == NULL) return NULL; + + raw->version = input->version; + raw->dataLength = MQRspec_getDataLength(input->version, input->level); + raw->eccLength = MQRspec_getECCLength(input->version, input->level); + raw->oddbits = raw->dataLength * 8 - MQRspec_getDataLengthBit(input->version, input->level); + raw->datacode = QRinput_getByteStream(input); + if(raw->datacode == NULL) { + free(raw); + return NULL; + } + raw->ecccode = (unsigned char *)malloc(raw->eccLength); + if(raw->ecccode == NULL) { + free(raw->datacode); + free(raw); + return NULL; + } + + raw->rsblock = (RSblock *)calloc(sizeof(RSblock), 1); + if(raw->rsblock == NULL) { + MQRraw_free(raw); + return NULL; + } + + rs = init_rs(8, 0x11d, 0, 1, raw->eccLength, 255 - raw->dataLength - raw->eccLength); + if(rs == NULL) { + MQRraw_free(raw); + return NULL; + } + + RSblock_initBlock(raw->rsblock, raw->dataLength, raw->datacode, raw->eccLength, raw->ecccode, rs); + + raw->count = 0; + + return raw; +} + +/** + * Return a code (byte). + * This function can be called iteratively. + * @param raw raw code. + * @return code + */ +__STATIC unsigned char MQRraw_getCode(MQRRawCode *raw) +{ + unsigned char ret; + + if(raw->count < raw->dataLength) { + ret = raw->datacode[raw->count]; + } else if(raw->count < raw->dataLength + raw->eccLength) { + ret = raw->ecccode[raw->count - raw->dataLength]; + } else { + return 0; + } + raw->count++; + return ret; +} + +__STATIC void MQRraw_free(MQRRawCode *raw) +{ + if(raw != NULL) { + free(raw->datacode); + free(raw->ecccode); + free(raw->rsblock); + free(raw); + } +} + + +/****************************************************************************** + * Frame filling + *****************************************************************************/ + +typedef struct { + int width; + unsigned char *frame; + int x, y; + int dir; + int bit; + int mqr; +} FrameFiller; + +static FrameFiller *FrameFiller_new(int width, unsigned char *frame, int mqr) +{ + FrameFiller *filler; + + filler = (FrameFiller *)malloc(sizeof(FrameFiller)); + if(filler == NULL) return NULL; + filler->width = width; + filler->frame = frame; + filler->x = width - 1; + filler->y = width - 1; + filler->dir = -1; + filler->bit = -1; + filler->mqr = mqr; + + return filler; +} + +static unsigned char *FrameFiller_next(FrameFiller *filler) +{ + unsigned char *p; + int x, y, w; + + if(filler->bit == -1) { + filler->bit = 0; + return filler->frame + filler->y * filler->width + filler->x; + } + + x = filler->x; + y = filler->y; + p = filler->frame; + w = filler->width; + + if(filler->bit == 0) { + x--; + filler->bit++; + } else { + x++; + y += filler->dir; + filler->bit--; + } + + if(filler->dir < 0) { + if(y < 0) { + y = 0; + x -= 2; + filler->dir = 1; + if(!filler->mqr && x == 6) { + x--; + y = 9; + } + } + } else { + if(y == w) { + y = w - 1; + x -= 2; + filler->dir = -1; + if(!filler->mqr && x == 6) { + x--; + y -= 8; + } + } + } + if(x < 0 || y < 0) return NULL; + + filler->x = x; + filler->y = y; + + if(p[y * w + x] & 0x80) { + // This tail recursion could be optimized. + return FrameFiller_next(filler); + } + return &p[y * w + x]; +} + +#ifdef WITH_TESTS +extern unsigned char *FrameFiller_test(int version) +{ + int width; + unsigned char *frame, *p; + FrameFiller *filler; + int i, length; + + width = QRspec_getWidth(version); + frame = QRspec_newFrame(version); + if(frame == NULL) return NULL; + filler = FrameFiller_new(width, frame, 0); + if(filler == NULL) { + free(frame); + return NULL; + } + length = QRspec_getDataLength(version, QR_ECLEVEL_L) * 8 + + QRspec_getECCLength(version, QR_ECLEVEL_L) * 8 + + QRspec_getRemainder(version); + for(i=0; iversion = version; + qrcode->width = width; + qrcode->data = data; + + return qrcode; +} + +void QRcode_free(QRcode *qrcode) +{ + if(qrcode != NULL) { + free(qrcode->data); + free(qrcode); + } +} + +__STATIC QRcode *QRcode_encodeMask(QRinput *input, int mask) +{ + int width, version; + QRRawCode *raw; + unsigned char *frame, *masked, *p, code, bit; + FrameFiller *filler; + int i, j; + QRcode *qrcode = NULL; + + if(input->mqr) { + errno = EINVAL; + return NULL; + } + if(input->version < 0 || input->version > QRSPEC_VERSION_MAX) { + errno = EINVAL; + return NULL; + } + if(input->level > QR_ECLEVEL_H) { + errno = EINVAL; + return NULL; + } + + raw = QRraw_new(input); + if(raw == NULL) return NULL; + + version = raw->version; + width = QRspec_getWidth(version); + frame = QRspec_newFrame(version); + if(frame == NULL) { + QRraw_free(raw); + return NULL; + } + filler = FrameFiller_new(width, frame, 0); + if(filler == NULL) { + QRraw_free(raw); + free(frame); + return NULL; + } + + /* inteleaved data and ecc codes */ + for(i=0; idataLength + raw->eccLength; i++) { + code = QRraw_getCode(raw); + bit = 0x80; + for(j=0; j<8; j++) { + p = FrameFiller_next(filler); + if(p == NULL) goto EXIT; + *p = 0x02 | ((bit & code) != 0); + bit = bit >> 1; + } + } + QRraw_free(raw); + raw = NULL; + /* remainder bits */ + j = QRspec_getRemainder(version); + for(i=0; ilevel); + } else { + masked = Mask_makeMask(width, frame, mask, input->level); + } + if(masked == NULL) { + goto EXIT; + } + qrcode = QRcode_new(version, width, masked); + +EXIT: + QRraw_free(raw); + free(filler); + free(frame); + return qrcode; +} + +__STATIC QRcode *QRcode_encodeMaskMQR(QRinput *input, int mask) +{ + int width, version; + MQRRawCode *raw; + unsigned char *frame, *masked, *p, code, bit; + FrameFiller *filler; + int i, j; + QRcode *qrcode = NULL; + + if(!input->mqr) { + errno = EINVAL; + return NULL; + } + if(input->version <= 0 || input->version > MQRSPEC_VERSION_MAX) { + errno = EINVAL; + return NULL; + } + if(input->level > QR_ECLEVEL_Q) { + errno = EINVAL; + return NULL; + } + + raw = MQRraw_new(input); + if(raw == NULL) return NULL; + + version = raw->version; + width = MQRspec_getWidth(version); + frame = MQRspec_newFrame(version); + if(frame == NULL) { + MQRraw_free(raw); + return NULL; + } + filler = FrameFiller_new(width, frame, 1); + if(filler == NULL) { + MQRraw_free(raw); + free(frame); + return NULL; + } + + /* inteleaved data and ecc codes */ + for(i=0; idataLength + raw->eccLength; i++) { + code = MQRraw_getCode(raw); + if(raw->oddbits && i == raw->dataLength - 1) { + bit = 1 << raw->oddbits; + for(j=0; joddbits; j++) { + p = FrameFiller_next(filler); + if(p == NULL) goto EXIT; + *p = 0x02 | ((bit & code) != 0); + bit = bit >> 1; + } + } else { + bit = 0x80; + for(j=0; j<8; j++) { + p = FrameFiller_next(filler); + if(p == NULL) goto EXIT; + *p = 0x02 | ((bit & code) != 0); + bit = bit >> 1; + } + } + } + MQRraw_free(raw); + raw = NULL; + + /* masking */ + if(mask < 0) { + masked = MMask_mask(version, frame, input->level); + } else { + masked = MMask_makeMask(version, frame, mask, input->level); + } + if(masked == NULL) { + goto EXIT; + } + + qrcode = QRcode_new(version, width, masked); + +EXIT: + MQRraw_free(raw); + free(filler); + free(frame); + return qrcode; +} + +QRcode *QRcode_encodeInput(QRinput *input) +{ + if(input->mqr) { + return QRcode_encodeMaskMQR(input, -1); + } else { + return QRcode_encodeMask(input, -1); + } +} + +static QRcode *QRcode_encodeStringReal(const char *string, int version, QRecLevel level, int mqr, QRencodeMode hint, int casesensitive) +{ + QRinput *input; + QRcode *code; + int ret; + + if(string == NULL) { + errno = EINVAL; + return NULL; + } + if(hint != QR_MODE_8 && hint != QR_MODE_KANJI) { + errno = EINVAL; + return NULL; + } + + if(mqr) { + input = QRinput_newMQR(version, level); + } else { + input = QRinput_new2(version, level); + } + if(input == NULL) return NULL; + + ret = Split_splitStringToQRinput(string, input, hint, casesensitive); + if(ret < 0) { + QRinput_free(input); + return NULL; + } + code = QRcode_encodeInput(input); + QRinput_free(input); + + return code; +} + +QRcode *QRcode_encodeString(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive) +{ + return QRcode_encodeStringReal(string, version, level, 0, hint, casesensitive); +} + +QRcode *QRcode_encodeStringMQR(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive) +{ + return QRcode_encodeStringReal(string, version, level, 1, hint, casesensitive); +} + +static QRcode *QRcode_encodeDataReal(const unsigned char *data, int length, int version, QRecLevel level, int mqr) +{ + QRinput *input; + QRcode *code; + int ret; + + if(data == NULL || length == 0) { + errno = EINVAL; + return NULL; + } + + if(mqr) { + input = QRinput_newMQR(version, level); + } else { + input = QRinput_new2(version, level); + } + if(input == NULL) return NULL; + + ret = QRinput_append(input, QR_MODE_8, length, data); + if(ret < 0) { + QRinput_free(input); + return NULL; + } + code = QRcode_encodeInput(input); + QRinput_free(input); + + return code; +} + +QRcode *QRcode_encodeData(int size, const unsigned char *data, int version, QRecLevel level) +{ + return QRcode_encodeDataReal(data, size, version, level, 0); +} + +QRcode *QRcode_encodeString8bit(const char *string, int version, QRecLevel level) +{ + if(string == NULL) { + errno = EINVAL; + return NULL; + } + return QRcode_encodeDataReal((unsigned char *)string, strlen(string), version, level, 0); +} + +QRcode *QRcode_encodeDataMQR(int size, const unsigned char *data, int version, QRecLevel level) +{ + return QRcode_encodeDataReal(data, size, version, level, 1); +} + +QRcode *QRcode_encodeString8bitMQR(const char *string, int version, QRecLevel level) +{ + if(string == NULL) { + errno = EINVAL; + return NULL; + } + return QRcode_encodeDataReal((unsigned char *)string, strlen(string), version, level, 1); +} + + +/****************************************************************************** + * Structured QR-code encoding + *****************************************************************************/ + +static QRcode_List *QRcode_List_newEntry(void) +{ + QRcode_List *entry; + + entry = (QRcode_List *)malloc(sizeof(QRcode_List)); + if(entry == NULL) return NULL; + + entry->next = NULL; + entry->code = NULL; + + return entry; +} + +static void QRcode_List_freeEntry(QRcode_List *entry) +{ + if(entry != NULL) { + QRcode_free(entry->code); + free(entry); + } +} + +void QRcode_List_free(QRcode_List *qrlist) +{ + QRcode_List *list = qrlist, *next; + + while(list != NULL) { + next = list->next; + QRcode_List_freeEntry(list); + list = next; + } +} + +int QRcode_List_size(QRcode_List *qrlist) +{ + QRcode_List *list = qrlist; + int size = 0; + + while(list != NULL) { + size++; + list = list->next; + } + + return size; +} + +#if 0 +static unsigned char QRcode_parity(const char *str, int size) +{ + unsigned char parity = 0; + int i; + + for(i=0; ihead; + + while(list != NULL) { + if(head == NULL) { + entry = QRcode_List_newEntry(); + if(entry == NULL) goto ABORT; + head = entry; + tail = head; + } else { + entry = QRcode_List_newEntry(); + if(entry == NULL) goto ABORT; + tail->next = entry; + tail = tail->next; + } + tail->code = QRcode_encodeInput(list->input); + if(tail->code == NULL) { + goto ABORT; + } + list = list->next; + } + + return head; +ABORT: + QRcode_List_free(head); + return NULL; +} + +static QRcode_List *QRcode_encodeInputToStructured(QRinput *input) +{ + QRinput_Struct *s; + QRcode_List *codes; + + s = QRinput_splitQRinputToStruct(input); + if(s == NULL) return NULL; + + codes = QRcode_encodeInputStructured(s); + QRinput_Struct_free(s); + + return codes; +} + +static QRcode_List *QRcode_encodeDataStructuredReal( + int size, const unsigned char *data, + int version, QRecLevel level, + int eightbit, QRencodeMode hint, int casesensitive) +{ + QRinput *input; + QRcode_List *codes; + int ret; + + if(version <= 0) { + errno = EINVAL; + return NULL; + } + if(!eightbit && (hint != QR_MODE_8 && hint != QR_MODE_KANJI)) { + errno = EINVAL; + return NULL; + } + + input = QRinput_new2(version, level); + if(input == NULL) return NULL; + + if(eightbit) { + ret = QRinput_append(input, QR_MODE_8, size, data); + } else { + ret = Split_splitStringToQRinput((char *)data, input, hint, casesensitive); + } + if(ret < 0) { + QRinput_free(input); + return NULL; + } + codes = QRcode_encodeInputToStructured(input); + QRinput_free(input); + + return codes; +} + +QRcode_List *QRcode_encodeDataStructured(int size, const unsigned char *data, int version, QRecLevel level) { + return QRcode_encodeDataStructuredReal(size, data, version, level, 1, QR_MODE_NUL, 0); +} + +QRcode_List *QRcode_encodeString8bitStructured(const char *string, int version, QRecLevel level) { + if(string == NULL) { + errno = EINVAL; + return NULL; + } + return QRcode_encodeDataStructured(strlen(string), (unsigned char *)string, version, level); +} + +QRcode_List *QRcode_encodeStringStructured(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive) +{ + if(string == NULL) { + errno = EINVAL; + return NULL; + } + return QRcode_encodeDataStructuredReal(strlen(string), (unsigned char *)string, version, level, 0, hint, casesensitive); +} + +/****************************************************************************** + * System utilities + *****************************************************************************/ + +void QRcode_APIVersion(int *major_version, int *minor_version, int *micro_version) +{ + if(major_version != NULL) { + *major_version = MAJOR_VERSION; + } + if(minor_version != NULL) { + *minor_version = MINOR_VERSION; + } + if(micro_version != NULL) { + *micro_version = MICRO_VERSION; + } +} + +char *QRcode_APIVersionString(void) +{ + return VERSION; +} + +void QRcode_clearCache(void) +{ + QRspec_clearCache(); + MQRspec_clearCache(); + free_rs_cache(); +} diff --git a/src/add-ons/kernel/debugger/qrencode/qrencode.h b/src/add-ons/kernel/debugger/qrencode/qrencode.h new file mode 100644 index 0000000000..fa53e364d5 --- /dev/null +++ b/src/add-ons/kernel/debugger/qrencode/qrencode.h @@ -0,0 +1,565 @@ +/** + * qrencode - QR Code encoder + * + * Copyright (C) 2006-2011 Kentaro Fukuchi + * + * 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 + */ + +/** \mainpage + * Libqrencode is a library for encoding data in a QR Code symbol, a kind of 2D + * symbology. + * + * \section encoding Encoding + * + * There are two ways to encode data: encoding a string or + * encoding a structured data. + * + * \subsection encoding-string Encoding a string + * You can encode a string by calling QRcode_encodeString(). + * The given string is parsed automatically and encoded. If you want to encode + * data that can be represented as a C string style (NUL terminated), you can + * simply use this way. + * + * If the input data contains Kanji (Shift-JIS) characters and you want to + * encode them as Kanji in QR Code, you should give QR_MODE_KANJI as a hint. + * Otherwise, all of non-alphanumeric characters are encoded as 8 bit data. + * If you want to encode a whole string in 8 bit mode, use + * QRcode_encodeString8bit() instead. + * + * Please note that a C string can not contain NUL character. If your data + * contains NUL, you should chose the second way. + * + * \subsection encoding-input Encoding a structured data + * You can construct a structured input data manually. If the structure of the + * input data is known, you can use this way. + * At first, create a ::QRinput object by QRinput_new(). Then add input data + * to the QRinput object by QRinput_append(). Finally call QRcode_encodeInput() + * to encode the QRinput data. + * You can reuse the QRinput data again to encode it in other symbols with + * different parameters. + * + * \section result Result + * The encoded symbol is resulted as a ::QRcode object. It will contain + * its version number, width of the symbol and an array represents the symbol. + * See ::QRcode for the details. You can free the object by QRcode_free(). + * + * Please note that the version of the result may be larger than specified. + * In such cases, the input data would be too large to be encoded in a + * symbol of the specified version. + * + * \section structured Structured append + * Libqrencode can generate "Structured-appended" symbols that enables to split + * a large data set into mulitple QR codes. A QR code reader concatenates + * multiple QR code symbols into a string. + * Just like QRcode_encodeString(), you can use QRcode_encodeStringStructured() + * to generate structured-appended symbols. This functions returns an instance + * of ::QRcode_List. The returned list is a singly-linked list of QRcode: you + * can retrieve each QR code in this way: + * + * \code + * QRcode_List *qrcodes; + * QRcode_List *entry; + * QRcode *qrcode; + * + * qrcodes = QRcode_encodeStringStructured(...); + * entry = qrcodes; + * while(entry != NULL) { + * qrcode = entry->code; + * // do something + * entry = entry->next; + * } + * QRcode_List_free(entry); + * \endcode + * + * Instead of using auto-parsing functions, you can construct your own + * structured input. At first, instantiate an object of ::QRinput_Struct + * by calling QRinput_Struct_new(). This object can hold multiple ::QRinput, + * and one QR code is generated for a ::QRinput. + * QRinput_Struct_appendInput() appends a ::QRinput to a ::QRinput_Struct + * object. In order to generate structured-appended symbols, it is required to + * embed headers to each symbol. You can use + * QRinput_Struct_insertStructuredAppendHeaders() to insert appropriate + * headers to each symbol. You should call this function just once before + * encoding symbols. + */ + +#ifndef __QRENCODE_H__ +#define __QRENCODE_H__ + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * Encoding mode. + */ +typedef enum { + QR_MODE_NUL = -1, ///< Terminator (NUL character). Internal use only + QR_MODE_NUM = 0, ///< Numeric mode + QR_MODE_AN, ///< Alphabet-numeric mode + QR_MODE_8, ///< 8-bit data mode + QR_MODE_KANJI, ///< Kanji (shift-jis) mode + QR_MODE_STRUCTURE, ///< Internal use only + QR_MODE_ECI, ///< ECI mode + QR_MODE_FNC1FIRST, ///< FNC1, first position + QR_MODE_FNC1SECOND, ///< FNC1, second position +} QRencodeMode; + +/** + * Level of error correction. + */ +typedef enum { + QR_ECLEVEL_L = 0, ///< lowest + QR_ECLEVEL_M, + QR_ECLEVEL_Q, + QR_ECLEVEL_H ///< highest +} QRecLevel; + +/** + * Maximum version (size) of QR-code symbol. + */ +#define QRSPEC_VERSION_MAX 40 + +/** + * Maximum version (size) of QR-code symbol. + */ +#define MQRSPEC_VERSION_MAX 4 + + +/****************************************************************************** + * Input data (qrinput.c) + *****************************************************************************/ + +/** + * Singly linked list to contain input strings. An instance of this class + * contains its version and error correction level too. It is required to + * set them by QRinput_setVersion() and QRinput_setErrorCorrectionLevel(), + * or use QRinput_new2() to instantiate an object. + */ +typedef struct _QRinput QRinput; + +/** + * Instantiate an input data object. The version is set to 0 (auto-select) + * and the error correction level is set to QR_ECLEVEL_L. + * @return an input object (initialized). On error, NULL is returned and errno + * is set to indicate the error. + * @throw ENOMEM unable to allocate memory. + */ +extern QRinput *QRinput_new(void); + +/** + * Instantiate an input data object. + * @param version version number. + * @param level Error correction level. + * @return an input object (initialized). On error, NULL is returned and errno + * is set to indicate the error. + * @throw ENOMEM unable to allocate memory for input objects. + * @throw EINVAL invalid arguments. + */ +extern QRinput *QRinput_new2(int version, QRecLevel level); + +/** + * Instantiate an input data object. Object's Micro QR Code flag is set. + * Unlike with full-sized QR Code, version number must be specified (>0). + * @param version version number (1--4). + * @param level Error correction level. + * @return an input object (initialized). On error, NULL is returned and errno + * is set to indicate the error. + * @throw ENOMEM unable to allocate memory for input objects. + * @throw EINVAL invalid arguments. + */ +extern QRinput *QRinput_newMQR(int version, QRecLevel level); + +/** + * Append data to an input object. + * The data is copied and appended to the input object. + * @param input input object. + * @param mode encoding mode. + * @param size size of data (byte). + * @param data a pointer to the memory area of the input data. + * @retval 0 success. + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL input data is invalid. + * + */ +extern int QRinput_append(QRinput *input, QRencodeMode mode, int size, const unsigned char *data); + +/** + * Append ECI header. + * @param input input object. + * @param ecinum ECI indicator number (0 - 999999) + * @retval 0 success. + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL input data is invalid. + * + */ +extern int QRinput_appendECIheader(QRinput *input, unsigned int ecinum); + +/** + * Get current version. + * @param input input object. + * @return current version. + */ +extern int QRinput_getVersion(QRinput *input); + +/** + * Set version of the QR code that is to be encoded. + * This function cannot be applied to Micro QR Code. + * @param input input object. + * @param version version number (0 = auto) + * @retval 0 success. + * @retval -1 invalid argument. + */ +extern int QRinput_setVersion(QRinput *input, int version); + +/** + * Get current error correction level. + * @param input input object. + * @return Current error correcntion level. + */ +extern QRecLevel QRinput_getErrorCorrectionLevel(QRinput *input); + +/** + * Set error correction level of the QR code that is to be encoded. + * This function cannot be applied to Micro QR Code. + * @param input input object. + * @param level Error correction level. + * @retval 0 success. + * @retval -1 invalid argument. + */ +extern int QRinput_setErrorCorrectionLevel(QRinput *input, QRecLevel level); + +/** + * Set version and error correction level of the QR code at once. + * This function is recommened for Micro QR Code. + * @param input input object. + * @param version version number (0 = auto) + * @param level Error correction level. + * @retval 0 success. + * @retval -1 invalid argument. + */ +extern int QRinput_setVersionAndErrorCorrectionLevel(QRinput *input, int version, QRecLevel level); + +/** + * Free the input object. + * All of data chunks in the input object are freed too. + * @param input input object. + */ +extern void QRinput_free(QRinput *input); + +/** + * Validate the input data. + * @param mode encoding mode. + * @param size size of data (byte). + * @param data a pointer to the memory area of the input data. + * @retval 0 success. + * @retval -1 invalid arguments. + */ +extern int QRinput_check(QRencodeMode mode, int size, const unsigned char *data); + +/** + * Set of QRinput for structured symbols. + */ +typedef struct _QRinput_Struct QRinput_Struct; + +/** + * Instantiate a set of input data object. + * @return an instance of QRinput_Struct. On error, NULL is returned and errno + * is set to indicate the error. + * @throw ENOMEM unable to allocate memory. + */ +extern QRinput_Struct *QRinput_Struct_new(void); + +/** + * Set parity of structured symbols. + * @param s structured input object. + * @param parity parity of s. + */ +extern void QRinput_Struct_setParity(QRinput_Struct *s, unsigned char parity); + +/** + * Append a QRinput object to the set. QRinput created by QRinput_newMQR() + * will be rejected. + * @warning never append the same QRinput object twice or more. + * @param s structured input object. + * @param input an input object. + * @retval >0 number of input objects in the structure. + * @retval -1 an error occurred. See Exceptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL invalid arguments. + */ +extern int QRinput_Struct_appendInput(QRinput_Struct *s, QRinput *input); + +/** + * Free all of QRinput in the set. + * @param s a structured input object. + */ +extern void QRinput_Struct_free(QRinput_Struct *s); + +/** + * Split a QRinput to QRinput_Struct. It calculates a parity, set it, then + * insert structured-append headers. QRinput created by QRinput_newMQR() will + * be rejected. + * @param input input object. Version number and error correction level must be + * set. + * @return a set of input data. On error, NULL is returned, and errno is set + * to indicate the error. See Exceptions for the details. + * @throw ERANGE input data is too large. + * @throw EINVAL invalid input data. + * @throw ENOMEM unable to allocate memory. + */ +extern QRinput_Struct *QRinput_splitQRinputToStruct(QRinput *input); + +/** + * Insert structured-append headers to the input structure. It calculates + * a parity and set it if the parity is not set yet. + * @param s input structure + * @retval 0 success. + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory. + */ +extern int QRinput_Struct_insertStructuredAppendHeaders(QRinput_Struct *s); + +/** + * Set FNC1-1st position flag. + */ +extern int QRinput_setFNC1First(QRinput *input); + +/** + * Set FNC1-2nd position flag and application identifier. + */ +extern int QRinput_setFNC1Second(QRinput *input, unsigned char appid); + +/****************************************************************************** + * QRcode output (qrencode.c) + *****************************************************************************/ + +/** + * QRcode class. + * Symbol data is represented as an array contains width*width uchars. + * Each uchar represents a module (dot). If the less significant bit of + * the uchar is 1, the corresponding module is black. The other bits are + * meaningless for usual applications, but here its specification is described. + * + *
+ * MSB 76543210 LSB
+ *     |||||||`- 1=black/0=white
+ *     ||||||`-- data and ecc code area
+ *     |||||`--- format information
+ *     ||||`---- version information
+ *     |||`----- timing pattern
+ *     ||`------ alignment pattern
+ *     |`------- finder pattern and separator
+ *     `-------- non-data modules (format, timing, etc.)
+ * 
+ */ +typedef struct { + int version; ///< version of the symbol + int width; ///< width of the symbol + unsigned char *data; ///< symbol data +} QRcode; + +/** + * Singly-linked list of QRcode. Used to represent a structured symbols. + * A list is terminated with NULL. + */ +typedef struct _QRcode_List QRcode_List; + +struct _QRcode_List { + QRcode *code; + QRcode_List *next; +}; + +/** + * Create a symbol from the input data. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param input input data. + * @return an instance of QRcode class. The version of the result QRcode may + * be larger than the designated version. On error, NULL is returned, + * and errno is set to indicate the error. See Exceptions for the + * details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + */ +extern QRcode *QRcode_encodeInput(QRinput *input); + +/** + * Create a symbol from the string. The library automatically parses the input + * string and encodes in a QR Code symbol. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param string input string. It must be NUL terminated. + * @param version version of the symbol. If 0, the library chooses the minimum + * version for the given input data. + * @param level error correction level. + * @param hint tell the library how non-alphanumerical characters should be + * encoded. If QR_MODE_KANJI is given, kanji characters will be + * encoded as Shif-JIS characters. If QR_MODE_8 is given, all of + * non-alphanumerical characters will be encoded as is. If you want + * to embed UTF-8 string, choose this. + * @param casesensitive case-sensitive(1) or not(0). + * @return an instance of QRcode class. The version of the result QRcode may + * be larger than the designated version. On error, NULL is returned, + * and errno is set to indicate the error. See Exceptions for the + * details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + * @throw ERANGE input data is too large. + */ +extern QRcode *QRcode_encodeString(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive); + +/** + * Same to QRcode_encodeString(), but encode whole data in 8-bit mode. + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode *QRcode_encodeString8bit(const char *string, int version, QRecLevel level); + +/** + * Micro QR Code version of QRcode_encodeString(). + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode *QRcode_encodeStringMQR(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive); + +/** + * Micro QR Code version of QRcode_encodeString8bit(). + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode *QRcode_encodeString8bitMQR(const char *string, int version, QRecLevel level); + +/** + * Encode byte stream (may include '\0') in 8-bit mode. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param size size of the input data. + * @param data input data. + * @param version version of the symbol. If 0, the library chooses the minimum + * version for the given input data. + * @param level error correction level. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + * @throw ERANGE input data is too large. + */ +extern QRcode *QRcode_encodeData(int size, const unsigned char *data, int version, QRecLevel level); + +/** + * Micro QR Code version of QRcode_encodeData(). + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode *QRcode_encodeDataMQR(int size, const unsigned char *data, int version, QRecLevel level); + +/** + * Free the instance of QRcode class. + * @param qrcode an instance of QRcode class. + */ +extern void QRcode_free(QRcode *qrcode); + +/** + * Create structured symbols from the input data. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param s + * @return a singly-linked list of QRcode. + */ +extern QRcode_List *QRcode_encodeInputStructured(QRinput_Struct *s); + +/** + * Create structured symbols from the string. The library automatically parses + * the input string and encodes in a QR Code symbol. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param string input string. It must be NUL terminated. + * @param version version of the symbol. + * @param level error correction level. + * @param hint tell the library how non-alphanumerical characters should be + * encoded. If QR_MODE_KANJI is given, kanji characters will be + * encoded as Shif-JIS characters. If QR_MODE_8 is given, all of + * non-alphanumerical characters will be encoded as is. If you want + * to embed UTF-8 string, choose this. + * @param casesensitive case-sensitive(1) or not(0). + * @return a singly-linked list of QRcode. On error, NULL is returned, and + * errno is set to indicate the error. See Exceptions for the details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + */ +extern QRcode_List *QRcode_encodeStringStructured(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive); + +/** + * Same to QRcode_encodeStringStructured(), but encode whole data in 8-bit mode. + * @warning This function is THREAD UNSAFE when pthread is disabled. + */ +extern QRcode_List *QRcode_encodeString8bitStructured(const char *string, int version, QRecLevel level); + +/** + * Create structured symbols from byte stream (may include '\0'). Wholde data + * are encoded in 8-bit mode. + * @warning This function is THREAD UNSAFE when pthread is disabled. + * @param size size of the input data. + * @param data input dat. + * @param version version of the symbol. + * @param level error correction level. + * @return a singly-linked list of QRcode. On error, NULL is returned, and + * errno is set to indicate the error. See Exceptions for the details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + */ +extern QRcode_List *QRcode_encodeDataStructured(int size, const unsigned char *data, int version, QRecLevel level); + +/** + * Return the number of symbols included in a QRcode_List. + * @param qrlist a head entry of a QRcode_List. + * @return number of symbols in the list. + */ +extern int QRcode_List_size(QRcode_List *qrlist); + +/** + * Free the QRcode_List. + * @param qrlist a head entry of a QRcode_List. + */ +extern void QRcode_List_free(QRcode_List *qrlist); + + +/****************************************************************************** + * System utilities + *****************************************************************************/ + +/** + * Return a string that identifies the library version. + * @param major_version + * @param minor_version + * @param micro_version + */ +extern void QRcode_APIVersion(int *major_version, int *minor_version, int *micro_version); + +/** + * Return a string that identifies the library version. + * @return a string identifies the library version. The string is held by the + * library. Do NOT free it. + */ +extern char *QRcode_APIVersionString(void); + +/** + * Clear all caches. This is only for debug purpose. If you are attacking a + * complicated memory leak bug, try this to reduce the reachable blocks record. + */ +extern void QRcode_clearCache(void); + +#if defined(__cplusplus) +} +#endif + +#endif /* __QRENCODE_H__ */ diff --git a/src/add-ons/kernel/debugger/qrencode/qrencode_inner.h b/src/add-ons/kernel/debugger/qrencode/qrencode_inner.h new file mode 100644 index 0000000000..3c40d0622a --- /dev/null +++ b/src/add-ons/kernel/debugger/qrencode/qrencode_inner.h @@ -0,0 +1,88 @@ +/** + * qrencode - QR Code encoder + * + * Header for test use + * Copyright (C) 2006-2011 Kentaro Fukuchi + * + * 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 + */ + +#ifndef __QRENCODE_INNER_H__ +#define __QRENCODE_INNER_H__ + +/** + * This header file includes definitions for test use. + */ + +/****************************************************************************** + * Raw code + *****************************************************************************/ + +typedef struct { + int dataLength; + unsigned char *data; + int eccLength; + unsigned char *ecc; +} RSblock; + +typedef struct { + int version; + int dataLength; + int eccLength; + unsigned char *datacode; + unsigned char *ecccode; + int b1; + int blocks; + RSblock *rsblock; + int count; +} QRRawCode; + +extern QRRawCode *QRraw_new(QRinput *input); +extern unsigned char QRraw_getCode(QRRawCode *raw); +extern void QRraw_free(QRRawCode *raw); + +/****************************************************************************** + * Raw code for Micro QR Code + *****************************************************************************/ + +typedef struct { + int version; + int dataLength; + int eccLength; + unsigned char *datacode; + unsigned char *ecccode; + RSblock *rsblock; + int oddbits; + int count; +} MQRRawCode; + +extern MQRRawCode *MQRraw_new(QRinput *input); +extern unsigned char MQRraw_getCode(MQRRawCode *raw); +extern void MQRraw_free(MQRRawCode *raw); + +/****************************************************************************** + * Frame filling + *****************************************************************************/ +extern unsigned char *FrameFiller_test(int version); +extern unsigned char *FrameFiller_testMQR(int version); + +/****************************************************************************** + * QR-code encoding + *****************************************************************************/ +extern QRcode *QRcode_encodeMask(QRinput *input, int mask); +extern QRcode *QRcode_encodeMaskMQR(QRinput *input, int mask); +extern QRcode *QRcode_new(int version, int width, unsigned char *data); + +#endif /* __QRENCODE_INNER_H__ */ diff --git a/src/add-ons/kernel/debugger/qrencode/qrinput.c b/src/add-ons/kernel/debugger/qrencode/qrinput.c new file mode 100644 index 0000000000..5dcacf8aa2 --- /dev/null +++ b/src/add-ons/kernel/debugger/qrencode/qrinput.c @@ -0,0 +1,1724 @@ +/* + * qrencode - QR Code encoder + * + * Input data chunk class + * Copyright (C) 2006-2011 Kentaro Fukuchi + * + * 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 +#include +#include +#include + +#include "qrencode.h" +#include "qrspec.h" +#include "mqrspec.h" +#include "bitstream.h" +#include "qrinput.h" + +/****************************************************************************** + * Utilities + *****************************************************************************/ +int QRinput_isSplittableMode(QRencodeMode mode) +{ + return (mode >= QR_MODE_NUM && mode <= QR_MODE_KANJI); +} + +/****************************************************************************** + * Entry of input data + *****************************************************************************/ + +static QRinput_List *QRinput_List_newEntry(QRencodeMode mode, int size, const unsigned char *data) +{ + QRinput_List *entry; + + if(QRinput_check(mode, size, data)) { + errno = EINVAL; + return NULL; + } + + entry = (QRinput_List *)malloc(sizeof(QRinput_List)); + if(entry == NULL) return NULL; + + entry->mode = mode; + entry->size = size; + if(size > 0) { + entry->data = (unsigned char *)malloc(size); + if(entry->data == NULL) { + free(entry); + return NULL; + } + memcpy(entry->data, data, size); + } + entry->bstream = NULL; + entry->next = NULL; + + return entry; +} + +static void QRinput_List_freeEntry(QRinput_List *entry) +{ + if(entry != NULL) { + free(entry->data); + BitStream_free(entry->bstream); + free(entry); + } +} + +static QRinput_List *QRinput_List_dup(QRinput_List *entry) +{ + QRinput_List *n; + + n = (QRinput_List *)malloc(sizeof(QRinput_List)); + if(n == NULL) return NULL; + + n->mode = entry->mode; + n->size = entry->size; + n->data = (unsigned char *)malloc(n->size); + if(n->data == NULL) { + free(n); + return NULL; + } + memcpy(n->data, entry->data, entry->size); + n->bstream = NULL; + n->next = NULL; + + return n; +} + +/****************************************************************************** + * Input Data + *****************************************************************************/ + +QRinput *QRinput_new(void) +{ + return QRinput_new2(0, QR_ECLEVEL_L); +} + +QRinput *QRinput_new2(int version, QRecLevel level) +{ + QRinput *input; + + if(version < 0 || version > QRSPEC_VERSION_MAX || level > QR_ECLEVEL_H) { + errno = EINVAL; + return NULL; + } + + input = (QRinput *)malloc(sizeof(QRinput)); + if(input == NULL) return NULL; + + input->head = NULL; + input->tail = NULL; + input->version = version; + input->level = level; + input->mqr = 0; + input->fnc1 = 0; + + return input; +} + +QRinput *QRinput_newMQR(int version, QRecLevel level) +{ + QRinput *input; + + if(version <= 0 || version > MQRSPEC_VERSION_MAX) goto INVALID; + if((MQRspec_getECCLength(version, level) == 0)) goto INVALID; + + input = QRinput_new2(version, level); + if(input == NULL) return NULL; + + input->mqr = 1; + + return input; + +INVALID: + errno = EINVAL; + return NULL; +} + +int QRinput_getVersion(QRinput *input) +{ + return input->version; +} + +int QRinput_setVersion(QRinput *input, int version) +{ + if(input->mqr || version < 0 || version > QRSPEC_VERSION_MAX) { + errno = EINVAL; + return -1; + } + + input->version = version; + + return 0; +} + +QRecLevel QRinput_getErrorCorrectionLevel(QRinput *input) +{ + return input->level; +} + +int QRinput_setErrorCorrectionLevel(QRinput *input, QRecLevel level) +{ + if(input->mqr || level > QR_ECLEVEL_H) { + errno = EINVAL; + return -1; + } + + input->level = level; + + return 0; +} + +int QRinput_setVersionAndErrorCorrectionLevel(QRinput *input, int version, QRecLevel level) +{ + if(input->mqr) { + if(version <= 0 || version > MQRSPEC_VERSION_MAX) goto INVALID; + if((MQRspec_getECCLength(version, level) == 0)) goto INVALID; + } else { + if(version < 0 || version > QRSPEC_VERSION_MAX) goto INVALID; + if(level > QR_ECLEVEL_H) goto INVALID; + } + + input->version = version; + input->level = level; + + return 0; + +INVALID: + errno = EINVAL; + return -1; +} + +static void QRinput_appendEntry(QRinput *input, QRinput_List *entry) +{ + if(input->tail == NULL) { + input->head = entry; + input->tail = entry; + } else { + input->tail->next = entry; + input->tail = entry; + } + entry->next = NULL; +} + +int QRinput_append(QRinput *input, QRencodeMode mode, int size, const unsigned char *data) +{ + QRinput_List *entry; + + entry = QRinput_List_newEntry(mode, size, data); + if(entry == NULL) { + return -1; + } + + QRinput_appendEntry(input, entry); + + return 0; +} + +/** + * Insert a structured-append header to the head of the input data. + * @param input input data. + * @param size number of structured symbols. + * @param index index number of the symbol. (1 <= index <= size) + * @param parity parity among input data. (NOTE: each symbol of a set of structured symbols has the same parity data) + * @retval 0 success. + * @retval -1 error occurred and errno is set to indeicate the error. See Execptions for the details. + * @throw EINVAL invalid parameter. + * @throw ENOMEM unable to allocate memory. + */ +__STATIC int QRinput_insertStructuredAppendHeader(QRinput *input, int size, int index, unsigned char parity) +{ + QRinput_List *entry; + unsigned char buf[3]; + + if(size > MAX_STRUCTURED_SYMBOLS) { + errno = EINVAL; + return -1; + } + if(index <= 0 || index > MAX_STRUCTURED_SYMBOLS) { + errno = EINVAL; + return -1; + } + + buf[0] = (unsigned char)size; + buf[1] = (unsigned char)index; + buf[2] = parity; + entry = QRinput_List_newEntry(QR_MODE_STRUCTURE, 3, buf); + if(entry == NULL) { + return -1; + } + + entry->next = input->head; + input->head = entry; + + return 0; +} + +int QRinput_appendECIheader(QRinput *input, unsigned int ecinum) +{ + unsigned char data[4]; + + if(ecinum > 999999) { + errno = EINVAL; + return -1; + } + + /* We manually create byte array of ecinum because + (unsigned char *)&ecinum may cause bus error on some architectures, */ + data[0] = ecinum & 0xff; + data[1] = (ecinum >> 8) & 0xff; + data[2] = (ecinum >> 16) & 0xff; + data[3] = (ecinum >> 24) & 0xff; + return QRinput_append(input, QR_MODE_ECI, 4, data); +} + +void QRinput_free(QRinput *input) +{ + QRinput_List *list, *next; + + if(input != NULL) { + list = input->head; + while(list != NULL) { + next = list->next; + QRinput_List_freeEntry(list); + list = next; + } + free(input); + } +} + +static unsigned char QRinput_calcParity(QRinput *input) +{ + unsigned char parity = 0; + QRinput_List *list; + int i; + + list = input->head; + while(list != NULL) { + if(list->mode != QR_MODE_STRUCTURE) { + for(i=list->size-1; i>=0; i--) { + parity ^= list->data[i]; + } + } + list = list->next; + } + + return parity; +} + +QRinput *QRinput_dup(QRinput *input) +{ + QRinput *n; + QRinput_List *list, *e; + + if(input->mqr) { + n = QRinput_newMQR(input->version, input->level); + } else { + n = QRinput_new2(input->version, input->level); + } + if(n == NULL) return NULL; + + list = input->head; + while(list != NULL) { + e = QRinput_List_dup(list); + if(e == NULL) { + QRinput_free(n); + return NULL; + } + QRinput_appendEntry(n, e); + list = list->next; + } + + return n; +} + +/****************************************************************************** + * Numeric data + *****************************************************************************/ + +/** + * Check the input data. + * @param size + * @param data + * @return result + */ +static int QRinput_checkModeNum(int size, const char *data) +{ + int i; + + for(i=0; i '9') + return -1; + } + + return 0; +} + +/** + * Estimates the length of the encoded bit stream of numeric data. + * @param size + * @return number of bits + */ +int QRinput_estimateBitsModeNum(int size) +{ + int w; + int bits; + + w = size / 3; + bits = w * 10; + switch(size - w * 3) { + case 1: + bits += 4; + break; + case 2: + bits += 7; + break; + default: + break; + } + + return bits; +} + +/** + * Convert the number data to a bit stream. + * @param entry + * @param mqr + * @retval 0 success + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + */ +static int QRinput_encodeModeNum(QRinput_List *entry, int version, int mqr) +{ + int words, i, ret; + unsigned int val; + + entry->bstream = BitStream_new(); + if(entry->bstream == NULL) return -1; + + if(mqr) { + if(version > 1) { + ret = BitStream_appendNum(entry->bstream, version - 1, MQRSPEC_MODEID_NUM); + if(ret < 0) goto ABORT; + } + ret = BitStream_appendNum(entry->bstream, MQRspec_lengthIndicator(QR_MODE_NUM, version), entry->size); + if(ret < 0) goto ABORT; + } else { + ret = BitStream_appendNum(entry->bstream, 4, QRSPEC_MODEID_NUM); + if(ret < 0) goto ABORT; + + ret = BitStream_appendNum(entry->bstream, QRspec_lengthIndicator(QR_MODE_NUM, version), entry->size); + if(ret < 0) goto ABORT; + } + + words = entry->size / 3; + for(i=0; idata[i*3 ] - '0') * 100; + val += (entry->data[i*3+1] - '0') * 10; + val += (entry->data[i*3+2] - '0'); + + ret = BitStream_appendNum(entry->bstream, 10, val); + if(ret < 0) goto ABORT; + } + + if(entry->size - words * 3 == 1) { + val = entry->data[words*3] - '0'; + ret = BitStream_appendNum(entry->bstream, 4, val); + if(ret < 0) goto ABORT; + } else if(entry->size - words * 3 == 2) { + val = (entry->data[words*3 ] - '0') * 10; + val += (entry->data[words*3+1] - '0'); + BitStream_appendNum(entry->bstream, 7, val); + if(ret < 0) goto ABORT; + } + + return 0; +ABORT: + BitStream_free(entry->bstream); + entry->bstream = NULL; + return -1; +} + +/****************************************************************************** + * Alphabet-numeric data + *****************************************************************************/ + +const signed char QRinput_anTable[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +/** + * Check the input data. + * @param size + * @param data + * @return result + */ +static int QRinput_checkModeAn(int size, const char *data) +{ + int i; + + for(i=0; ibstream = BitStream_new(); + if(entry->bstream == NULL) return -1; + + if(mqr) { + if(version < 2) { + errno = EINVAL; + goto ABORT; + } + ret = BitStream_appendNum(entry->bstream, version - 1, MQRSPEC_MODEID_AN); + if(ret < 0) goto ABORT; + ret = BitStream_appendNum(entry->bstream, MQRspec_lengthIndicator(QR_MODE_AN, version), entry->size); + if(ret < 0) goto ABORT; + } else { + ret = BitStream_appendNum(entry->bstream, 4, QRSPEC_MODEID_AN); + if(ret < 0) goto ABORT; + ret = BitStream_appendNum(entry->bstream, QRspec_lengthIndicator(QR_MODE_AN, version), entry->size); + if(ret < 0) goto ABORT; + } + + words = entry->size / 2; + for(i=0; idata[i*2 ]) * 45; + val += (unsigned int)QRinput_lookAnTable(entry->data[i*2+1]); + + ret = BitStream_appendNum(entry->bstream, 11, val); + if(ret < 0) goto ABORT; + } + + if(entry->size & 1) { + val = (unsigned int)QRinput_lookAnTable(entry->data[words * 2]); + + ret = BitStream_appendNum(entry->bstream, 6, val); + if(ret < 0) goto ABORT; + } + + return 0; +ABORT: + BitStream_free(entry->bstream); + entry->bstream = NULL; + return -1; +} + +/****************************************************************************** + * 8 bit data + *****************************************************************************/ + +/** + * Estimates the length of the encoded bit stream of 8 bit data. + * @param size + * @return number of bits + */ +int QRinput_estimateBitsMode8(int size) +{ + return size * 8; +} + +/** + * Convert the 8bits data to a bit stream. + * @param entry + * @param mqr + * @retval 0 success + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + */ +static int QRinput_encodeMode8(QRinput_List *entry, int version, int mqr) +{ + int ret; + + entry->bstream = BitStream_new(); + if(entry->bstream == NULL) return -1; + + if(mqr) { + if(version < 3) { + errno = EINVAL; + goto ABORT; + } + ret = BitStream_appendNum(entry->bstream, version - 1, MQRSPEC_MODEID_8); + if(ret < 0) goto ABORT; + ret = BitStream_appendNum(entry->bstream, MQRspec_lengthIndicator(QR_MODE_8, version), entry->size); + if(ret < 0) goto ABORT; + } else { + ret = BitStream_appendNum(entry->bstream, 4, QRSPEC_MODEID_8); + if(ret < 0) goto ABORT; + ret = BitStream_appendNum(entry->bstream, QRspec_lengthIndicator(QR_MODE_8, version), entry->size); + if(ret < 0) goto ABORT; + } + + ret = BitStream_appendBytes(entry->bstream, entry->size, entry->data); + if(ret < 0) goto ABORT; + + return 0; +ABORT: + BitStream_free(entry->bstream); + entry->bstream = NULL; + return -1; +} + + +/****************************************************************************** + * Kanji data + *****************************************************************************/ + +/** + * Estimates the length of the encoded bit stream of kanji data. + * @param size + * @return number of bits + */ +int QRinput_estimateBitsModeKanji(int size) +{ + return (size / 2) * 13; +} + +/** + * Check the input data. + * @param size + * @param data + * @return result + */ +static int QRinput_checkModeKanji(int size, const unsigned char *data) +{ + int i; + unsigned int val; + + if(size & 1) + return -1; + + for(i=0; i 0x9ffc && val < 0xe040) || val > 0xebbf) { + return -1; + } + } + + return 0; +} + +/** + * Convert the kanji data to a bit stream. + * @param entry + * @param mqr + * @retval 0 success + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL invalid version. + */ +static int QRinput_encodeModeKanji(QRinput_List *entry, int version, int mqr) +{ + int ret, i; + unsigned int val, h; + + entry->bstream = BitStream_new(); + if(entry->bstream == NULL) return -1; + + if(mqr) { + if(version < 2) { + errno = EINVAL; + goto ABORT; + } + ret = BitStream_appendNum(entry->bstream, version - 1, MQRSPEC_MODEID_KANJI); + if(ret < 0) goto ABORT; + ret = BitStream_appendNum(entry->bstream, MQRspec_lengthIndicator(QR_MODE_KANJI, version), entry->size/2); + if(ret < 0) goto ABORT; + } else { + ret = BitStream_appendNum(entry->bstream, 4, QRSPEC_MODEID_KANJI); + if(ret < 0) goto ABORT; + ret = BitStream_appendNum(entry->bstream, QRspec_lengthIndicator(QR_MODE_KANJI, version), entry->size/2); + if(ret < 0) goto ABORT; + } + + for(i=0; isize; i+=2) { + val = ((unsigned int)entry->data[i] << 8) | entry->data[i+1]; + if(val <= 0x9ffc) { + val -= 0x8140; + } else { + val -= 0xc140; + } + h = (val >> 8) * 0xc0; + val = (val & 0xff) + h; + + ret = BitStream_appendNum(entry->bstream, 13, val); + if(ret < 0) goto ABORT; + } + + return 0; +ABORT: + BitStream_free(entry->bstream); + entry->bstream = NULL; + return -1; +} + +/****************************************************************************** + * Structured Symbol + *****************************************************************************/ + +/** + * Convert a structure symbol code to a bit stream. + * @param entry + * @param mqr + * @retval 0 success + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw EINVAL invalid entry. + */ +static int QRinput_encodeModeStructure(QRinput_List *entry, int mqr) +{ + int ret; + + if(mqr) { + errno = EINVAL; + return -1; + } + entry->bstream = BitStream_new(); + if(entry->bstream == NULL) return -1; + + ret = BitStream_appendNum(entry->bstream, 4, QRSPEC_MODEID_STRUCTURE); + if(ret < 0) goto ABORT; + ret = BitStream_appendNum(entry->bstream, 4, entry->data[1] - 1); + if(ret < 0) goto ABORT; + ret = BitStream_appendNum(entry->bstream, 4, entry->data[0] - 1); + if(ret < 0) goto ABORT; + ret = BitStream_appendNum(entry->bstream, 8, entry->data[2]); + if(ret < 0) goto ABORT; + + return 0; +ABORT: + BitStream_free(entry->bstream); + entry->bstream = NULL; + return -1; +} + +/****************************************************************************** + * FNC1 + *****************************************************************************/ + +static int QRinput_checkModeFNC1Second(int size, const unsigned char *data) +{ + if(size != 1) return -1; + + return 0; +} + +static int QRinput_encodeModeFNC1Second(QRinput_List *entry, int version) +{ + int ret; + + entry->bstream = BitStream_new(); + if(entry->bstream == NULL) return -1; + + ret = BitStream_appendNum(entry->bstream, 4, QRSPEC_MODEID_FNC1SECOND); + if(ret < 0) goto ABORT; + + ret = BitStream_appendBytes(entry->bstream, 1, entry->data); + if(ret < 0) goto ABORT; + + return 0; +ABORT: + BitStream_free(entry->bstream); + entry->bstream = NULL; + return -1; +} + +/****************************************************************************** + * ECI header + *****************************************************************************/ +static unsigned int QRinput_decodeECIfromByteArray(unsigned char *data) +{ + int i; + unsigned int ecinum; + + ecinum = 0; + for(i=0; i<4; i++) { + ecinum = ecinum << 8; + ecinum |= data[3-i]; + } + + return ecinum; +} + +int QRinput_estimateBitsModeECI(unsigned char *data) +{ + unsigned int ecinum; + + ecinum = QRinput_decodeECIfromByteArray(data);; + + /* See Table 4 of JISX 0510:2004 pp.17. */ + if(ecinum < 128) { + return MODE_INDICATOR_SIZE + 8; + } else if(ecinum < 16384) { + return MODE_INDICATOR_SIZE + 16; + } else { + return MODE_INDICATOR_SIZE + 24; + } +} + +static int QRinput_encodeModeECI(QRinput_List *entry, int version) +{ + int ret, words; + unsigned int ecinum, code; + + entry->bstream = BitStream_new(); + if(entry->bstream == NULL) return -1; + + ecinum = QRinput_decodeECIfromByteArray(entry->data);; + + /* See Table 4 of JISX 0510:2004 pp.17. */ + if(ecinum < 128) { + words = 1; + code = ecinum; + } else if(ecinum < 16384) { + words = 2; + code = 0x8000 + ecinum; + } else { + words = 3; + code = 0xc0000 + ecinum; + } + + ret = BitStream_appendNum(entry->bstream, 4, QRSPEC_MODEID_ECI); + if(ret < 0) goto ABORT; + + ret = BitStream_appendNum(entry->bstream, words * 8, code); + if(ret < 0) goto ABORT; + + return 0; +ABORT: + BitStream_free(entry->bstream); + entry->bstream = NULL; + return -1; +} + +/****************************************************************************** + * Validation + *****************************************************************************/ + +int QRinput_check(QRencodeMode mode, int size, const unsigned char *data) +{ + if((mode == QR_MODE_FNC1FIRST && size < 0) || size <= 0) return -1; + + switch(mode) { + case QR_MODE_NUM: + return QRinput_checkModeNum(size, (const char *)data); + case QR_MODE_AN: + return QRinput_checkModeAn(size, (const char *)data); + case QR_MODE_KANJI: + return QRinput_checkModeKanji(size, data); + case QR_MODE_8: + return 0; + case QR_MODE_STRUCTURE: + return 0; + case QR_MODE_ECI: + return 0; + case QR_MODE_FNC1FIRST: + return 0; + case QR_MODE_FNC1SECOND: + return QRinput_checkModeFNC1Second(size, data); + case QR_MODE_NUL: + break; + } + + return -1; +} + +/****************************************************************************** + * Estimation of the bit length + *****************************************************************************/ + +/** + * Estimates the length of the encoded bit stream on the current version. + * @param entry + * @param version version of the symbol + * @param mqr + * @return number of bits + */ +static int QRinput_estimateBitStreamSizeOfEntry(QRinput_List *entry, int version, int mqr) +{ + int bits = 0; + int l, m; + int num; + + if(version == 0) version = 1; + + switch(entry->mode) { + case QR_MODE_NUM: + bits = QRinput_estimateBitsModeNum(entry->size); + break; + case QR_MODE_AN: + bits = QRinput_estimateBitsModeAn(entry->size); + break; + case QR_MODE_8: + bits = QRinput_estimateBitsMode8(entry->size); + break; + case QR_MODE_KANJI: + bits = QRinput_estimateBitsModeKanji(entry->size); + break; + case QR_MODE_STRUCTURE: + return STRUCTURE_HEADER_SIZE; + case QR_MODE_ECI: + bits = QRinput_estimateBitsModeECI(entry->data); + break; + case QR_MODE_FNC1FIRST: + return MODE_INDICATOR_SIZE; + break; + case QR_MODE_FNC1SECOND: + return MODE_INDICATOR_SIZE + 8; + default: + return 0; + } + + if(mqr) { + l = QRspec_lengthIndicator(entry->mode, version); + m = version - 1; + bits += l + m; + } else { + l = QRspec_lengthIndicator(entry->mode, version); + m = 1 << l; + num = (entry->size + m - 1) / m; + + bits += num * (MODE_INDICATOR_SIZE + l); + } + + return bits; +} + +/** + * Estimates the length of the encoded bit stream of the data. + * @param input input data + * @param version version of the symbol + * @return number of bits + */ +__STATIC int QRinput_estimateBitStreamSize(QRinput *input, int version) +{ + QRinput_List *list; + int bits = 0; + + list = input->head; + while(list != NULL) { + bits += QRinput_estimateBitStreamSizeOfEntry(list, version, input->mqr); + list = list->next; + } + + return bits; +} + +/** + * Estimates the required version number of the symbol. + * @param input input data + * @return required version number + */ +static int QRinput_estimateVersion(QRinput *input) +{ + int bits; + int version, prev; + + version = 0; + do { + prev = version; + bits = QRinput_estimateBitStreamSize(input, prev); + version = QRspec_getMinimumVersion((bits + 7) / 8, input->level); + if (version < 0) { + return -1; + } + } while (version > prev); + + return version; +} + +/** + * Returns required length in bytes for specified mode, version and bits. + * @param mode + * @param version + * @param bits + * @return required length of code words in bytes. + */ +__STATIC int QRinput_lengthOfCode(QRencodeMode mode, int version, int bits) +{ + int payload, size, chunks, remain, maxsize; + + payload = bits - 4 - QRspec_lengthIndicator(mode, version); + switch(mode) { + case QR_MODE_NUM: + chunks = payload / 10; + remain = payload - chunks * 10; + size = chunks * 3; + if(remain >= 7) { + size += 2; + } else if(remain >= 4) { + size += 1; + } + break; + case QR_MODE_AN: + chunks = payload / 11; + remain = payload - chunks * 11; + size = chunks * 2; + if(remain >= 6) size++; + break; + case QR_MODE_8: + size = payload / 8; + break; + case QR_MODE_KANJI: + size = (payload / 13) * 2; + break; + case QR_MODE_STRUCTURE: + size = payload / 8; + break; + default: + size = 0; + break; + } + maxsize = QRspec_maximumWords(mode, version); + if(size < 0) size = 0; + if(maxsize > 0 && size > maxsize) size = maxsize; + + return size; +} + +/****************************************************************************** + * Data conversion + *****************************************************************************/ + +/** + * Convert the input data in the data chunk to a bit stream. + * @param entry + * @return number of bits (>0) or -1 for failure. + */ +static int QRinput_encodeBitStream(QRinput_List *entry, int version, int mqr) +{ + int words, ret; + QRinput_List *st1 = NULL, *st2 = NULL; + + if(entry->bstream != NULL) { + BitStream_free(entry->bstream); + entry->bstream = NULL; + } + + words = QRspec_maximumWords(entry->mode, version); + if(words != 0 && entry->size > words) { + st1 = QRinput_List_newEntry(entry->mode, words, entry->data); + if(st1 == NULL) goto ABORT; + st2 = QRinput_List_newEntry(entry->mode, entry->size - words, &entry->data[words]); + if(st2 == NULL) goto ABORT; + + ret = QRinput_encodeBitStream(st1, version, mqr); + if(ret < 0) goto ABORT; + ret = QRinput_encodeBitStream(st2, version, mqr); + if(ret < 0) goto ABORT; + entry->bstream = BitStream_new(); + if(entry->bstream == NULL) goto ABORT; + ret = BitStream_append(entry->bstream, st1->bstream); + if(ret < 0) goto ABORT; + ret = BitStream_append(entry->bstream, st2->bstream); + if(ret < 0) goto ABORT; + QRinput_List_freeEntry(st1); + QRinput_List_freeEntry(st2); + } else { + ret = 0; + switch(entry->mode) { + case QR_MODE_NUM: + ret = QRinput_encodeModeNum(entry, version, mqr); + break; + case QR_MODE_AN: + ret = QRinput_encodeModeAn(entry, version, mqr); + break; + case QR_MODE_8: + ret = QRinput_encodeMode8(entry, version, mqr); + break; + case QR_MODE_KANJI: + ret = QRinput_encodeModeKanji(entry, version, mqr); + break; + case QR_MODE_STRUCTURE: + ret = QRinput_encodeModeStructure(entry, mqr); + break; + case QR_MODE_ECI: + ret = QRinput_encodeModeECI(entry, version); + break; + case QR_MODE_FNC1SECOND: + ret = QRinput_encodeModeFNC1Second(entry, version); + default: + break; + } + if(ret < 0) return -1; + } + + return BitStream_size(entry->bstream); +ABORT: + QRinput_List_freeEntry(st1); + QRinput_List_freeEntry(st2); + return -1; +} + +/** + * Convert the input data to a bit stream. + * @param input input data. + * @retval 0 success + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + */ +static int QRinput_createBitStream(QRinput *input) +{ + QRinput_List *list; + int bits, total = 0; + + list = input->head; + while(list != NULL) { + bits = QRinput_encodeBitStream(list, input->version, input->mqr); + if(bits < 0) return -1; + total += bits; + list = list->next; + } + + return total; +} + +/** + * Convert the input data to a bit stream. + * When the version number is given and that is not sufficient, it is increased + * automatically. + * @param input input data. + * @retval 0 success + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ENOMEM unable to allocate memory. + * @throw ERANGE input is too large. + */ +static int QRinput_convertData(QRinput *input) +{ + int bits; + int ver; + + ver = QRinput_estimateVersion(input); + if(ver > QRinput_getVersion(input)) { + QRinput_setVersion(input, ver); + } + + for(;;) { + bits = QRinput_createBitStream(input); + if(bits < 0) return -1; + ver = QRspec_getMinimumVersion((bits + 7) / 8, input->level); + if(ver < 0) { + errno = ERANGE; + return -1; + } else if(ver > QRinput_getVersion(input)) { + QRinput_setVersion(input, ver); + } else { + break; + } + } + + return 0; +} + +/** + * Append padding bits for the input data. + * @param bstream Bitstream to be appended. + * @param input input data. + * @retval 0 success + * @retval -1 an error occurred and errno is set to indeicate the error. + * See Execptions for the details. + * @throw ERANGE input data is too large. + * @throw ENOMEM unable to allocate memory. + */ +static int QRinput_appendPaddingBit(BitStream *bstream, QRinput *input) +{ + int bits, maxbits, words, maxwords, i, ret; + BitStream *padding = NULL; + unsigned char *padbuf; + int padlen; + + bits = BitStream_size(bstream); + maxwords = QRspec_getDataLength(input->version, input->level); + maxbits = maxwords * 8; + + if(maxbits < bits) { + errno = ERANGE; + return -1; + } + if(maxbits == bits) { + return 0; + } + + if(maxbits - bits <= 4) { + ret = BitStream_appendNum(bstream, maxbits - bits, 0); + goto DONE; + } + + words = (bits + 4 + 7) / 8; + + padding = BitStream_new(); + if(padding == NULL) return -1; + ret = BitStream_appendNum(padding, words * 8 - bits, 0); + if(ret < 0) goto DONE; + + padlen = maxwords - words; + if(padlen > 0) { + padbuf = (unsigned char *)malloc(padlen); + if(padbuf == NULL) { + ret = -1; + goto DONE; + } + for(i=0; iversion, input->level); + maxwords = maxbits / 8; + + if(maxbits < bits) { + errno = ERANGE; + return -1; + } + if(maxbits == bits) { + return 0; + } + + termbits = input->version * 2 + 1; + + if(maxbits - bits <= termbits) { + ret = BitStream_appendNum(bstream, maxbits - bits, 0); + goto DONE; + } + + bits += termbits; + + words = (bits + 7) / 8; + if(maxbits - words * 8 > 0) { + termbits += words * 8 - bits; + if(words == maxwords) termbits += maxbits - words * 8; + } else { + termbits += words * 8 - bits; + } + padding = BitStream_new(); + if(padding == NULL) return -1; + ret = BitStream_appendNum(padding, termbits, 0); + if(ret < 0) goto DONE; + + padlen = maxwords - words; + if(padlen > 0) { + padbuf = (unsigned char *)malloc(padlen); + if(padbuf == NULL) { + ret = -1; + goto DONE; + } + for(i=0; i 0) { + ret = BitStream_appendNum(padding, termbits, 0); + if(ret < 0) goto DONE; + } + } + + ret = BitStream_append(bstream, padding); + +DONE: + BitStream_free(padding); + return ret; +} + +static int QRinput_insertFNC1Header(QRinput *input) +{ + QRinput_List *entry = NULL; + + if(input->fnc1 == 1) { + entry = QRinput_List_newEntry(QR_MODE_FNC1FIRST, 0, NULL); + } else if(input->fnc1 == 2) { + entry = QRinput_List_newEntry(QR_MODE_FNC1SECOND, 1, &(input->appid)); + } + if(entry == NULL) { + return -1; + } + + if(input->head->mode != QR_MODE_STRUCTURE || input->head->mode != QR_MODE_ECI) { + entry->next = input->head; + input->head = entry; + } else { + entry->next = input->head->next; + input->head->next = entry; + } + + return 0; +} + +/** + * Merge all bit streams in the input data. + * @param input input data. + * @return merged bit stream + */ + +__STATIC BitStream *QRinput_mergeBitStream(QRinput *input) +{ + BitStream *bstream; + QRinput_List *list; + int ret; + + if(input->mqr) { + if(QRinput_createBitStream(input) < 0) { + return NULL; + } + } else { + if(input->fnc1) { + if(QRinput_insertFNC1Header(input) < 0) { + return NULL; + } + } + if(QRinput_convertData(input) < 0) { + return NULL; + } + } + + bstream = BitStream_new(); + if(bstream == NULL) return NULL; + + list = input->head; + while(list != NULL) { + ret = BitStream_append(bstream, list->bstream); + if(ret < 0) { + BitStream_free(bstream); + return NULL; + } + list = list->next; + } + + return bstream; +} + +/** + * Merge all bit streams in the input data and append padding bits + * @param input input data. + * @return padded merged bit stream + */ + +__STATIC BitStream *QRinput_getBitStream(QRinput *input) +{ + BitStream *bstream; + int ret; + + bstream = QRinput_mergeBitStream(input); + if(bstream == NULL) { + return NULL; + } + if(input->mqr) { + ret = QRinput_appendPaddingBitMQR(bstream, input); + } else { + ret = QRinput_appendPaddingBit(bstream, input); + } + if(ret < 0) { + BitStream_free(bstream); + return NULL; + } + + return bstream; +} + +/** + * Pack all bit streams padding bits into a byte array. + * @param input input data. + * @return padded merged byte stream + */ + +unsigned char *QRinput_getByteStream(QRinput *input) +{ + BitStream *bstream; + unsigned char *array; + + bstream = QRinput_getBitStream(input); + if(bstream == NULL) { + return NULL; + } + array = BitStream_toByte(bstream); + BitStream_free(bstream); + + return array; +} + +/****************************************************************************** + * Structured input data + *****************************************************************************/ + +static QRinput_InputList *QRinput_InputList_newEntry(QRinput *input) +{ + QRinput_InputList *entry; + + entry = (QRinput_InputList *)malloc(sizeof(QRinput_InputList)); + if(entry == NULL) return NULL; + + entry->input = input; + entry->next = NULL; + + return entry; +} + +static void QRinput_InputList_freeEntry(QRinput_InputList *entry) +{ + if(entry != NULL) { + QRinput_free(entry->input); + free(entry); + } +} + +QRinput_Struct *QRinput_Struct_new(void) +{ + QRinput_Struct *s; + + s = (QRinput_Struct *)malloc(sizeof(QRinput_Struct)); + if(s == NULL) return NULL; + + s->size = 0; + s->parity = -1; + s->head = NULL; + s->tail = NULL; + + return s; +} + +void QRinput_Struct_setParity(QRinput_Struct *s, unsigned char parity) +{ + s->parity = (int)parity; +} + +int QRinput_Struct_appendInput(QRinput_Struct *s, QRinput *input) +{ + QRinput_InputList *e; + + if(input->mqr) { + errno = EINVAL; + return -1; + } + + e = QRinput_InputList_newEntry(input); + if(e == NULL) return -1; + + s->size++; + if(s->tail == NULL) { + s->head = e; + s->tail = e; + } else { + s->tail->next = e; + s->tail = e; + } + + return s->size; +} + +void QRinput_Struct_free(QRinput_Struct *s) +{ + QRinput_InputList *list, *next; + + if(s != NULL) { + list = s->head; + while(list != NULL) { + next = list->next; + QRinput_InputList_freeEntry(list); + list = next; + } + free(s); + } +} + +static unsigned char QRinput_Struct_calcParity(QRinput_Struct *s) +{ + QRinput_InputList *list; + unsigned char parity = 0; + + list = s->head; + while(list != NULL) { + parity ^= QRinput_calcParity(list->input); + list = list->next; + } + + QRinput_Struct_setParity(s, parity); + + return parity; +} + +static int QRinput_List_shrinkEntry(QRinput_List *entry, int bytes) +{ + unsigned char *data; + + data = (unsigned char *)malloc(bytes); + if(data == NULL) return -1; + + memcpy(data, entry->data, bytes); + free(entry->data); + entry->data = data; + entry->size = bytes; + + return 0; +} + +__STATIC int QRinput_splitEntry(QRinput_List *entry, int bytes) +{ + QRinput_List *e; + int ret; + + e = QRinput_List_newEntry(entry->mode, entry->size - bytes, entry->data + bytes); + if(e == NULL) { + return -1; + } + + ret = QRinput_List_shrinkEntry(entry, bytes); + if(ret < 0) { + QRinput_List_freeEntry(e); + return -1; + } + + e->next = entry->next; + entry->next = e; + + return 0; +} + +QRinput_Struct *QRinput_splitQRinputToStruct(QRinput *input) +{ + QRinput *p; + QRinput_Struct *s; + int bits, maxbits, nextbits, bytes, ret; + QRinput_List *list, *next, *prev; + + if(input->mqr) { + errno = EINVAL; + return NULL; + } + + s = QRinput_Struct_new(); + if(s == NULL) return NULL; + + input = QRinput_dup(input); + if(input == NULL) { + QRinput_Struct_free(s); + return NULL; + } + + QRinput_Struct_setParity(s, QRinput_calcParity(input)); + maxbits = QRspec_getDataLength(input->version, input->level) * 8 - STRUCTURE_HEADER_SIZE; + + if(maxbits <= 0) { + QRinput_Struct_free(s); + QRinput_free(input); + return NULL; + } + + bits = 0; + list = input->head; + prev = NULL; + while(list != NULL) { + nextbits = QRinput_estimateBitStreamSizeOfEntry(list, input->version, input->mqr); + if(bits + nextbits <= maxbits) { + ret = QRinput_encodeBitStream(list, input->version, input->mqr); + if(ret < 0) goto ABORT; + bits += ret; + prev = list; + list = list->next; + } else { + bytes = QRinput_lengthOfCode(list->mode, input->version, maxbits - bits); + if(bytes > 0) { + /* Splits this entry into 2 entries. */ + ret = QRinput_splitEntry(list, bytes); + if(ret < 0) goto ABORT; + /* First half is the tail of the current input. */ + next = list->next; + list->next = NULL; + /* Second half is the head of the next input, p.*/ + p = QRinput_new2(input->version, input->level); + if(p == NULL) goto ABORT; + p->head = next; + /* Renew QRinput.tail. */ + p->tail = input->tail; + input->tail = list; + /* Point to the next entry. */ + prev = list; + list = next; + } else { + /* Current entry will go to the next input. */ + prev->next = NULL; + p = QRinput_new2(input->version, input->level); + if(p == NULL) goto ABORT; + p->head = list; + p->tail = input->tail; + input->tail = prev; + } + ret = QRinput_Struct_appendInput(s, input); + if(ret < 0) goto ABORT; + input = p; + bits = 0; + } + } + QRinput_Struct_appendInput(s, input); + if(s->size > MAX_STRUCTURED_SYMBOLS) { + QRinput_Struct_free(s); + errno = ERANGE; + return NULL; + } + ret = QRinput_Struct_insertStructuredAppendHeaders(s); + if(ret < 0) { + QRinput_Struct_free(s); + return NULL; + } + + return s; + +ABORT: + QRinput_free(input); + QRinput_Struct_free(s); + return NULL; +} + +int QRinput_Struct_insertStructuredAppendHeaders(QRinput_Struct *s) +{ + int num, i; + QRinput_InputList *list; + + if(s->parity < 0) { + QRinput_Struct_calcParity(s); + } + num = 0; + list = s->head; + while(list != NULL) { + num++; + list = list->next; + } + i = 1; + list = s->head; + while(list != NULL) { + if(QRinput_insertStructuredAppendHeader(list->input, num, i, s->parity)) + return -1; + i++; + list = list->next; + } + + return 0; +} + +/****************************************************************************** + * Extended encoding mode (FNC1 and ECI) + *****************************************************************************/ + +int QRinput_setFNC1First(QRinput *input) +{ + if(input->mqr) { + errno = EINVAL; + return -1; + } + input->fnc1 = 1; + + return 0; +} + +int QRinput_setFNC1Second(QRinput *input, unsigned char appid) +{ + if(input->mqr) { + errno = EINVAL; + return -1; + } + input->fnc1 = 2; + input->appid = appid; + + return 0; +} diff --git a/src/add-ons/kernel/debugger/qrencode/qrinput.h b/src/add-ons/kernel/debugger/qrencode/qrinput.h new file mode 100644 index 0000000000..9e6bad625d --- /dev/null +++ b/src/add-ons/kernel/debugger/qrencode/qrinput.h @@ -0,0 +1,123 @@ +/* + * qrencode - QR Code encoder + * + * Input data chunk class + * Copyright (C) 2006-2011 Kentaro Fukuchi + * + * 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 + */ + +#ifndef __QRINPUT_H__ +#define __QRINPUT_H__ + +#include "qrencode.h" +#include "bitstream.h" + +int QRinput_isSplittableMode(QRencodeMode mode); + +/****************************************************************************** + * Entry of input data + *****************************************************************************/ +typedef struct _QRinput_List QRinput_List; + +struct _QRinput_List { + QRencodeMode mode; + int size; ///< Size of data chunk (byte). + unsigned char *data; ///< Data chunk. + BitStream *bstream; + QRinput_List *next; +}; + +/****************************************************************************** + * Input Data + *****************************************************************************/ +struct _QRinput { + int version; + QRecLevel level; + QRinput_List *head; + QRinput_List *tail; + int mqr; + int fnc1; + unsigned char appid; +}; + +/****************************************************************************** + * Structured append input data + *****************************************************************************/ +typedef struct _QRinput_InputList QRinput_InputList; + +struct _QRinput_InputList { + QRinput *input; + QRinput_InputList *next; +}; + +struct _QRinput_Struct { + int size; ///< number of structured symbols + int parity; + QRinput_InputList *head; + QRinput_InputList *tail; +}; + +/** + * Pack all bit streams padding bits into a byte array. + * @param input input data. + * @return padded merged byte stream + */ +extern unsigned char *QRinput_getByteStream(QRinput *input); + + +extern int QRinput_estimateBitsModeNum(int size); +extern int QRinput_estimateBitsModeAn(int size); +extern int QRinput_estimateBitsMode8(int size); +extern int QRinput_estimateBitsModeKanji(int size); + +extern QRinput *QRinput_dup(QRinput *input); + +extern const signed char QRinput_anTable[128]; + +/** + * Look up the alphabet-numeric convesion table (see JIS X0510:2004, pp.19). + * @param __c__ character + * @return value + */ +#define QRinput_lookAnTable(__c__) \ + ((__c__ & 0x80)?-1:QRinput_anTable[(int)__c__]) + +/** + * Length of a standard mode indicator in bits. + */ + +#define MODE_INDICATOR_SIZE 4 + +/** + * Length of a segment of structured-append header. + */ +#define STRUCTURE_HEADER_SIZE 20 + +/** + * Maximum number of symbols in a set of structured-appended symbols. + */ +#define MAX_STRUCTURED_SYMBOLS 16 + +#ifdef WITH_TESTS +extern BitStream *QRinput_mergeBitStream(QRinput *input); +extern BitStream *QRinput_getBitStream(QRinput *input); +extern int QRinput_estimateBitStreamSize(QRinput *input, int version); +extern int QRinput_splitEntry(QRinput_List *entry, int bytes); +extern int QRinput_lengthOfCode(QRencodeMode mode, int version, int bits); +extern int QRinput_insertStructuredAppendHeader(QRinput *input, int size, int index, unsigned char parity); +#endif + +#endif /* __QRINPUT_H__ */ diff --git a/src/add-ons/kernel/debugger/qrencode/qrspec.c b/src/add-ons/kernel/debugger/qrencode/qrspec.c new file mode 100644 index 0000000000..a42706f4b8 --- /dev/null +++ b/src/add-ons/kernel/debugger/qrencode/qrspec.c @@ -0,0 +1,562 @@ +/* + * qrencode - QR Code encoder + * + * QR Code specification in convenient format. + * Copyright (C) 2006-2011 Kentaro Fukuchi + * + * The following data / specifications are taken from + * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004) + * or + * "Automatic identification and data capture techniques -- + * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006) + * + * 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 +#include +#include +#include +#ifdef HAVE_LIBPTHREAD +#include +#endif + +#include "qrspec.h" +#include "qrinput.h" + +/****************************************************************************** + * Version and capacity + *****************************************************************************/ + +typedef struct { + int width; //< Edge length of the symbol + int words; //< Data capacity (bytes) + int remainder; //< Remainder bit (bits) + int ec[4]; //< Number of ECC code (bytes) +} QRspec_Capacity; + +/** + * Table of the capacity of symbols + * See Table 1 (pp.13) and Table 12-16 (pp.30-36), JIS X0510:2004. + */ +static const QRspec_Capacity qrspecCapacity[QRSPEC_VERSION_MAX + 1] = { + { 0, 0, 0, { 0, 0, 0, 0}}, + { 21, 26, 0, { 7, 10, 13, 17}}, // 1 + { 25, 44, 7, { 10, 16, 22, 28}}, + { 29, 70, 7, { 15, 26, 36, 44}}, + { 33, 100, 7, { 20, 36, 52, 64}}, + { 37, 134, 7, { 26, 48, 72, 88}}, // 5 + { 41, 172, 7, { 36, 64, 96, 112}}, + { 45, 196, 0, { 40, 72, 108, 130}}, + { 49, 242, 0, { 48, 88, 132, 156}}, + { 53, 292, 0, { 60, 110, 160, 192}}, + { 57, 346, 0, { 72, 130, 192, 224}}, //10 + { 61, 404, 0, { 80, 150, 224, 264}}, + { 65, 466, 0, { 96, 176, 260, 308}}, + { 69, 532, 0, { 104, 198, 288, 352}}, + { 73, 581, 3, { 120, 216, 320, 384}}, + { 77, 655, 3, { 132, 240, 360, 432}}, //15 + { 81, 733, 3, { 144, 280, 408, 480}}, + { 85, 815, 3, { 168, 308, 448, 532}}, + { 89, 901, 3, { 180, 338, 504, 588}}, + { 93, 991, 3, { 196, 364, 546, 650}}, + { 97, 1085, 3, { 224, 416, 600, 700}}, //20 + {101, 1156, 4, { 224, 442, 644, 750}}, + {105, 1258, 4, { 252, 476, 690, 816}}, + {109, 1364, 4, { 270, 504, 750, 900}}, + {113, 1474, 4, { 300, 560, 810, 960}}, + {117, 1588, 4, { 312, 588, 870, 1050}}, //25 + {121, 1706, 4, { 336, 644, 952, 1110}}, + {125, 1828, 4, { 360, 700, 1020, 1200}}, + {129, 1921, 3, { 390, 728, 1050, 1260}}, + {133, 2051, 3, { 420, 784, 1140, 1350}}, + {137, 2185, 3, { 450, 812, 1200, 1440}}, //30 + {141, 2323, 3, { 480, 868, 1290, 1530}}, + {145, 2465, 3, { 510, 924, 1350, 1620}}, + {149, 2611, 3, { 540, 980, 1440, 1710}}, + {153, 2761, 3, { 570, 1036, 1530, 1800}}, + {157, 2876, 0, { 570, 1064, 1590, 1890}}, //35 + {161, 3034, 0, { 600, 1120, 1680, 1980}}, + {165, 3196, 0, { 630, 1204, 1770, 2100}}, + {169, 3362, 0, { 660, 1260, 1860, 2220}}, + {173, 3532, 0, { 720, 1316, 1950, 2310}}, + {177, 3706, 0, { 750, 1372, 2040, 2430}} //40 +}; + +int QRspec_getDataLength(int version, QRecLevel level) +{ + return qrspecCapacity[version].words - qrspecCapacity[version].ec[level]; +} + +int QRspec_getECCLength(int version, QRecLevel level) +{ + return qrspecCapacity[version].ec[level]; +} + +int QRspec_getMinimumVersion(int size, QRecLevel level) +{ + int i; + int words; + + for(i=1; i<= QRSPEC_VERSION_MAX; i++) { + words = qrspecCapacity[i].words - qrspecCapacity[i].ec[level]; + if(words >= size) return i; + } + + return -1; +} + +int QRspec_getWidth(int version) +{ + return qrspecCapacity[version].width; +} + +int QRspec_getRemainder(int version) +{ + return qrspecCapacity[version].remainder; +} + +/****************************************************************************** + * Length indicator + *****************************************************************************/ + +static const int lengthTableBits[4][3] = { + {10, 12, 14}, + { 9, 11, 13}, + { 8, 16, 16}, + { 8, 10, 12} +}; + +int QRspec_lengthIndicator(QRencodeMode mode, int version) +{ + int l; + + if(!QRinput_isSplittableMode(mode)) return 0; + if(version <= 9) { + l = 0; + } else if(version <= 26) { + l = 1; + } else { + l = 2; + } + + return lengthTableBits[mode][l]; +} + +int QRspec_maximumWords(QRencodeMode mode, int version) +{ + int l; + int bits; + int words; + + if(!QRinput_isSplittableMode(mode)) return 0; + if(version <= 9) { + l = 0; + } else if(version <= 26) { + l = 1; + } else { + l = 2; + } + + bits = lengthTableBits[mode][l]; + words = (1 << bits) - 1; + if(mode == QR_MODE_KANJI) { + words *= 2; // the number of bytes is required + } + + return words; +} + +/****************************************************************************** + * Error correction code + *****************************************************************************/ + +/** + * Table of the error correction code (Reed-Solomon block) + * See Table 12-16 (pp.30-36), JIS X0510:2004. + */ +static const int eccTable[QRSPEC_VERSION_MAX+1][4][2] = { + {{ 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}, + {{ 1, 0}, { 1, 0}, { 1, 0}, { 1, 0}}, // 1 + {{ 1, 0}, { 1, 0}, { 1, 0}, { 1, 0}}, + {{ 1, 0}, { 1, 0}, { 2, 0}, { 2, 0}}, + {{ 1, 0}, { 2, 0}, { 2, 0}, { 4, 0}}, + {{ 1, 0}, { 2, 0}, { 2, 2}, { 2, 2}}, // 5 + {{ 2, 0}, { 4, 0}, { 4, 0}, { 4, 0}}, + {{ 2, 0}, { 4, 0}, { 2, 4}, { 4, 1}}, + {{ 2, 0}, { 2, 2}, { 4, 2}, { 4, 2}}, + {{ 2, 0}, { 3, 2}, { 4, 4}, { 4, 4}}, + {{ 2, 2}, { 4, 1}, { 6, 2}, { 6, 2}}, //10 + {{ 4, 0}, { 1, 4}, { 4, 4}, { 3, 8}}, + {{ 2, 2}, { 6, 2}, { 4, 6}, { 7, 4}}, + {{ 4, 0}, { 8, 1}, { 8, 4}, {12, 4}}, + {{ 3, 1}, { 4, 5}, {11, 5}, {11, 5}}, + {{ 5, 1}, { 5, 5}, { 5, 7}, {11, 7}}, //15 + {{ 5, 1}, { 7, 3}, {15, 2}, { 3, 13}}, + {{ 1, 5}, {10, 1}, { 1, 15}, { 2, 17}}, + {{ 5, 1}, { 9, 4}, {17, 1}, { 2, 19}}, + {{ 3, 4}, { 3, 11}, {17, 4}, { 9, 16}}, + {{ 3, 5}, { 3, 13}, {15, 5}, {15, 10}}, //20 + {{ 4, 4}, {17, 0}, {17, 6}, {19, 6}}, + {{ 2, 7}, {17, 0}, { 7, 16}, {34, 0}}, + {{ 4, 5}, { 4, 14}, {11, 14}, {16, 14}}, + {{ 6, 4}, { 6, 14}, {11, 16}, {30, 2}}, + {{ 8, 4}, { 8, 13}, { 7, 22}, {22, 13}}, //25 + {{10, 2}, {19, 4}, {28, 6}, {33, 4}}, + {{ 8, 4}, {22, 3}, { 8, 26}, {12, 28}}, + {{ 3, 10}, { 3, 23}, { 4, 31}, {11, 31}}, + {{ 7, 7}, {21, 7}, { 1, 37}, {19, 26}}, + {{ 5, 10}, {19, 10}, {15, 25}, {23, 25}}, //30 + {{13, 3}, { 2, 29}, {42, 1}, {23, 28}}, + {{17, 0}, {10, 23}, {10, 35}, {19, 35}}, + {{17, 1}, {14, 21}, {29, 19}, {11, 46}}, + {{13, 6}, {14, 23}, {44, 7}, {59, 1}}, + {{12, 7}, {12, 26}, {39, 14}, {22, 41}}, //35 + {{ 6, 14}, { 6, 34}, {46, 10}, { 2, 64}}, + {{17, 4}, {29, 14}, {49, 10}, {24, 46}}, + {{ 4, 18}, {13, 32}, {48, 14}, {42, 32}}, + {{20, 4}, {40, 7}, {43, 22}, {10, 67}}, + {{19, 6}, {18, 31}, {34, 34}, {20, 61}},//40 +}; + +void QRspec_getEccSpec(int version, QRecLevel level, int spec[5]) +{ + int b1, b2; + int data, ecc; + + b1 = eccTable[version][level][0]; + b2 = eccTable[version][level][1]; + data = QRspec_getDataLength(version, level); + ecc = QRspec_getECCLength(version, level); + + if(b2 == 0) { + spec[0] = b1; + spec[1] = data / b1; + spec[2] = ecc / b1; + spec[3] = spec[4] = 0; + } else { + spec[0] = b1; + spec[1] = data / (b1 + b2); + spec[2] = ecc / (b1 + b2); + spec[3] = b2; + spec[4] = spec[1] + 1; + } +} + +/****************************************************************************** + * Alignment pattern + *****************************************************************************/ + +/** + * Positions of alignment patterns. + * This array includes only the second and the third position of the alignment + * patterns. Rest of them can be calculated from the distance between them. + * + * See Table 1 in Appendix E (pp.71) of JIS X0510:2004. + */ +static const int alignmentPattern[QRSPEC_VERSION_MAX+1][2] = { + { 0, 0}, + { 0, 0}, {18, 0}, {22, 0}, {26, 0}, {30, 0}, // 1- 5 + {34, 0}, {22, 38}, {24, 42}, {26, 46}, {28, 50}, // 6-10 + {30, 54}, {32, 58}, {34, 62}, {26, 46}, {26, 48}, //11-15 + {26, 50}, {30, 54}, {30, 56}, {30, 58}, {34, 62}, //16-20 + {28, 50}, {26, 50}, {30, 54}, {28, 54}, {32, 58}, //21-25 + {30, 58}, {34, 62}, {26, 50}, {30, 54}, {26, 52}, //26-30 + {30, 56}, {34, 60}, {30, 58}, {34, 62}, {30, 54}, //31-35 + {24, 50}, {28, 54}, {32, 58}, {26, 54}, {30, 58}, //35-40 +}; + +/** + * Put an alignment marker. + * @param frame + * @param width + * @param ox,oy center coordinate of the pattern + */ +static void QRspec_putAlignmentMarker(unsigned char *frame, int width, int ox, int oy) +{ + static const unsigned char finder[] = { + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa0, 0xa0, 0xa0, 0xa1, + 0xa1, 0xa0, 0xa1, 0xa0, 0xa1, + 0xa1, 0xa0, 0xa0, 0xa0, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + }; + int x, y; + const unsigned char *s; + + frame += (oy - 2) * width + ox - 2; + s = finder; + for(y=0; y<5; y++) { + for(x=0; x<5; x++) { + frame[x] = s[x]; + } + frame += width; + s += 5; + } +} + +static void QRspec_putAlignmentPattern(int version, unsigned char *frame, int width) +{ + int d, w, x, y, cx, cy; + + if(version < 2) return; + + d = alignmentPattern[version][1] - alignmentPattern[version][0]; + if(d < 0) { + w = 2; + } else { + w = (width - alignmentPattern[version][0]) / d + 2; + } + + if(w * w - 3 == 1) { + x = alignmentPattern[version][0]; + y = alignmentPattern[version][0]; + QRspec_putAlignmentMarker(frame, width, x, y); + return; + } + + cx = alignmentPattern[version][0]; + for(x=1; x QRSPEC_VERSION_MAX) return 0; + + return versionPattern[version - 7]; +} + +/****************************************************************************** + * Format information + *****************************************************************************/ + +/* See calcFormatInfo in tests/test_qrspec.c */ +static const unsigned int formatInfo[4][8] = { + {0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976}, + {0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0}, + {0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed}, + {0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b} +}; + +unsigned int QRspec_getFormatInfo(int mask, QRecLevel level) +{ + if(mask < 0 || mask > 7) return 0; + + return formatInfo[level][mask]; +} + +/****************************************************************************** + * Frame + *****************************************************************************/ + +/** + * Cache of initial frames. + */ +/* C99 says that static storage shall be initialized to a null pointer + * by compiler. */ +static unsigned char *frames[QRSPEC_VERSION_MAX + 1]; +#ifdef HAVE_LIBPTHREAD +static pthread_mutex_t frames_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + +/** + * Put a finder pattern. + * @param frame + * @param width + * @param ox,oy upper-left coordinate of the pattern + */ +static void putFinderPattern(unsigned char *frame, int width, int ox, int oy) +{ + static const unsigned char finder[] = { + 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, + 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc1, 0xc1, 0xc1, 0xc0, 0xc1, + 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, + 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, + }; + int x, y; + const unsigned char *s; + + frame += oy * width + ox; + s = finder; + for(y=0; y<7; y++) { + for(x=0; x<7; x++) { + frame[x] = s[x]; + } + frame += width; + s += 7; + } +} + + +static unsigned char *QRspec_createFrame(int version) +{ + unsigned char *frame, *p, *q; + int width; + int x, y; + unsigned int verinfo, v; + + width = qrspecCapacity[version].width; + frame = (unsigned char *)malloc(width * width); + if(frame == NULL) return NULL; + + memset(frame, 0, width * width); + /* Finder pattern */ + putFinderPattern(frame, width, 0, 0); + putFinderPattern(frame, width, width - 7, 0); + putFinderPattern(frame, width, 0, width - 7); + /* Separator */ + p = frame; + q = frame + width * (width - 7); + for(y=0; y<7; y++) { + p[7] = 0xc0; + p[width - 8] = 0xc0; + q[7] = 0xc0; + p += width; + q += width; + } + memset(frame + width * 7, 0xc0, 8); + memset(frame + width * 8 - 8, 0xc0, 8); + memset(frame + width * (width - 8), 0xc0, 8); + /* Mask format information area */ + memset(frame + width * 8, 0x84, 9); + memset(frame + width * 9 - 8, 0x84, 8); + p = frame + 8; + for(y=0; y<8; y++) { + *p = 0x84; + p += width; + } + p = frame + width * (width - 7) + 8; + for(y=0; y<7; y++) { + *p = 0x84; + p += width; + } + /* Timing pattern */ + p = frame + width * 6 + 8; + q = frame + width * 8 + 6; + for(x=1; x= 7) { + verinfo = QRspec_getVersionPattern(version); + + p = frame + width * (width - 11); + v = verinfo; + for(x=0; x<6; x++) { + for(y=0; y<3; y++) { + p[width * y + x] = 0x88 | (v & 1); + v = v >> 1; + } + } + + p = frame + width - 11; + v = verinfo; + for(y=0; y<6; y++) { + for(x=0; x<3; x++) { + p[x] = 0x88 | (v & 1); + v = v >> 1; + } + p += width; + } + } + /* and a little bit... */ + frame[width * (width - 8) + 8] = 0x81; + + return frame; +} + +unsigned char *QRspec_newFrame(int version) +{ + unsigned char *frame; + int width; + + if(version < 1 || version > QRSPEC_VERSION_MAX) return NULL; + +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&frames_mutex); +#endif + if(frames[version] == NULL) { + frames[version] = QRspec_createFrame(version); + } +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&frames_mutex); +#endif + if(frames[version] == NULL) return NULL; + + width = qrspecCapacity[version].width; + frame = (unsigned char *)malloc(width * width); + if(frame == NULL) return NULL; + memcpy(frame, frames[version], width * width); + + return frame; +} + +void QRspec_clearCache(void) +{ + int i; + +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&frames_mutex); +#endif + for(i=1; i<=QRSPEC_VERSION_MAX; i++) { + free(frames[i]); + frames[i] = NULL; + } +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&frames_mutex); +#endif +} diff --git a/src/add-ons/kernel/debugger/qrencode/qrspec.h b/src/add-ons/kernel/debugger/qrencode/qrspec.h new file mode 100644 index 0000000000..54a3d9f09e --- /dev/null +++ b/src/add-ons/kernel/debugger/qrencode/qrspec.h @@ -0,0 +1,181 @@ +/* + * qrencode - QR Code encoder + * + * QR Code specification in convenient format. + * Copyright (C) 2006-2011 Kentaro Fukuchi + * + * 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 + */ + +#ifndef __QRSPEC_H__ +#define __QRSPEC_H__ + +#include "qrencode.h" + +/****************************************************************************** + * Version and capacity + *****************************************************************************/ + +/** + * Maximum width of a symbol + */ +#define QRSPEC_WIDTH_MAX 177 + +/** + * Return maximum data code length (bytes) for the version. + * @param version + * @param level + * @return maximum size (bytes) + */ +extern int QRspec_getDataLength(int version, QRecLevel level); + +/** + * Return maximum error correction code length (bytes) for the version. + * @param version + * @param level + * @return ECC size (bytes) + */ +extern int QRspec_getECCLength(int version, QRecLevel level); + +/** + * Return a version number that satisfies the input code length. + * @param size input code length (byte) + * @param level + * @return version number + */ +extern int QRspec_getMinimumVersion(int size, QRecLevel level); + +/** + * Return the width of the symbol for the version. + * @param version + * @return width + */ +extern int QRspec_getWidth(int version); + +/** + * Return the numer of remainder bits. + * @param version + * @return number of remainder bits + */ +extern int QRspec_getRemainder(int version); + +/****************************************************************************** + * Length indicator + *****************************************************************************/ + +/** + * Return the size of lenght indicator for the mode and version. + * @param mode + * @param version + * @return the size of the appropriate length indicator (bits). + */ +extern int QRspec_lengthIndicator(QRencodeMode mode, int version); + +/** + * Return the maximum length for the mode and version. + * @param mode + * @param version + * @return the maximum length (bytes) + */ +extern int QRspec_maximumWords(QRencodeMode mode, int version); + +/****************************************************************************** + * Error correction code + *****************************************************************************/ + +/** + * Return an array of ECC specification. + * @param version + * @param level + * @param spec an array of ECC specification contains as following: + * {# of type1 blocks, # of data code, # of ecc code, + * # of type2 blocks, # of data code} + */ +void QRspec_getEccSpec(int version, QRecLevel level, int spec[5]); + +#define QRspec_rsBlockNum(__spec__) (__spec__[0] + __spec__[3]) +#define QRspec_rsBlockNum1(__spec__) (__spec__[0]) +#define QRspec_rsDataCodes1(__spec__) (__spec__[1]) +#define QRspec_rsEccCodes1(__spec__) (__spec__[2]) +#define QRspec_rsBlockNum2(__spec__) (__spec__[3]) +#define QRspec_rsDataCodes2(__spec__) (__spec__[4]) +#define QRspec_rsEccCodes2(__spec__) (__spec__[2]) + +#define QRspec_rsDataLength(__spec__) \ + ((QRspec_rsBlockNum1(__spec__) * QRspec_rsDataCodes1(__spec__)) + \ + (QRspec_rsBlockNum2(__spec__) * QRspec_rsDataCodes2(__spec__))) +#define QRspec_rsEccLength(__spec__) \ + (QRspec_rsBlockNum(__spec__) * QRspec_rsEccCodes1(__spec__)) + +/****************************************************************************** + * Version information pattern + *****************************************************************************/ + +/** + * Return BCH encoded version information pattern that is used for the symbol + * of version 7 or greater. Use lower 18 bits. + * @param version + * @return BCH encoded version information pattern + */ +extern unsigned int QRspec_getVersionPattern(int version); + +/****************************************************************************** + * Format information + *****************************************************************************/ + +/** + * Return BCH encoded format information pattern. + * @param mask + * @param level + * @return BCH encoded format information pattern + */ +extern unsigned int QRspec_getFormatInfo(int mask, QRecLevel level); + +/****************************************************************************** + * Frame + *****************************************************************************/ + +/** + * Return a copy of initialized frame. + * When the same version is requested twice or more, a copy of cached frame + * is returned. + * @param version + * @return Array of unsigned char. You can free it by free(). + */ +extern unsigned char *QRspec_newFrame(int version); + +/** + * Clear the frame cache. Typically for debug. + */ +extern void QRspec_clearCache(void); + +/****************************************************************************** + * Mode indicator + *****************************************************************************/ + +/** + * Mode indicator. See Table 2 of JIS X0510:2004, pp.16. + */ +#define QRSPEC_MODEID_ECI 7 +#define QRSPEC_MODEID_NUM 1 +#define QRSPEC_MODEID_AN 2 +#define QRSPEC_MODEID_8 4 +#define QRSPEC_MODEID_KANJI 8 +#define QRSPEC_MODEID_FNC1FIRST 5 +#define QRSPEC_MODEID_FNC1SECOND 9 +#define QRSPEC_MODEID_STRUCTURE 3 +#define QRSPEC_MODEID_TERMINATOR 0 + +#endif /* __QRSPEC_H__ */ diff --git a/src/add-ons/kernel/debugger/qrencode/rscode.c b/src/add-ons/kernel/debugger/qrencode/rscode.c new file mode 100644 index 0000000000..edc32e2c92 --- /dev/null +++ b/src/add-ons/kernel/debugger/qrencode/rscode.c @@ -0,0 +1,327 @@ +/* + * qrencode - QR Code encoder + * + * Reed solomon encoder. This code is taken from Phil Karn's libfec then + * editted and packed into a pair of .c and .h files. + * + * Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q + * (libfec is released under the GNU Lesser General Public License.) + * + * Copyright (C) 2006-2011 Kentaro Fukuchi + * + * 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 +#include +#ifdef HAVE_LIBPTHREAD +# include +#endif + +#include "rscode.h" + +/* Stuff specific to the 8-bit symbol version of the general purpose RS codecs + * + */ +typedef unsigned char data_t; + + +/** + * Reed-Solomon codec control block + */ +struct _RS { + int mm; /* Bits per symbol */ + int nn; /* Symbols per block (= (1<= rs->nn) { + x -= rs->nn; + x = (x >> rs->mm) + (x & rs->nn); + } + return x; +} + + +#define MODNN(x) modnn(rs,x) + +#define MM (rs->mm) +#define NN (rs->nn) +#define ALPHA_TO (rs->alpha_to) +#define INDEX_OF (rs->index_of) +#define GENPOLY (rs->genpoly) +#define NROOTS (rs->nroots) +#define FCR (rs->fcr) +#define PRIM (rs->prim) +#define IPRIM (rs->iprim) +#define PAD (rs->pad) +#define A0 (NN) + + +/* Initialize a Reed-Solomon codec + * symsize = symbol size, bits + * gfpoly = Field generator polynomial coefficients + * fcr = first root of RS code generator polynomial, index form + * prim = primitive element to generate polynomial roots + * nroots = RS code generator polynomial degree (number of roots) + * pad = padding bytes at front of shortened block + */ +static RS *init_rs_char(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad) +{ + RS *rs; + + +/* Common code for intializing a Reed-Solomon control block (char or int symbols) + * Copyright 2004 Phil Karn, KA9Q + * May be used under the terms of the GNU Lesser General Public License (LGPL) + */ +//#undef NULL +//#define NULL ((void *)0) + + int i, j, sr,root,iprim; + + rs = NULL; + /* Check parameter ranges */ + if(symsize < 0 || symsize > (int)(8*sizeof(data_t))){ + goto done; + } + + if(fcr < 0 || fcr >= (1<= (1<= (1<= ((1<mm = symsize; + rs->nn = (1<pad = pad; + + rs->alpha_to = (data_t *)malloc(sizeof(data_t)*(rs->nn+1)); + if(rs->alpha_to == NULL){ + free(rs); + rs = NULL; + goto done; + } + rs->index_of = (data_t *)malloc(sizeof(data_t)*(rs->nn+1)); + if(rs->index_of == NULL){ + free(rs->alpha_to); + free(rs); + rs = NULL; + goto done; + } + + /* Generate Galois field lookup tables */ + rs->index_of[0] = A0; /* log(zero) = -inf */ + rs->alpha_to[A0] = 0; /* alpha**-inf = 0 */ + sr = 1; + for(i=0;inn;i++){ + rs->index_of[sr] = i; + rs->alpha_to[i] = sr; + sr <<= 1; + if(sr & (1<nn; + } + if(sr != 1){ + /* field generator polynomial is not primitive! */ + free(rs->alpha_to); + free(rs->index_of); + free(rs); + rs = NULL; + goto done; + } + + /* Form RS code generator polynomial from its roots */ + rs->genpoly = (data_t *)malloc(sizeof(data_t)*(nroots+1)); + if(rs->genpoly == NULL){ + free(rs->alpha_to); + free(rs->index_of); + free(rs); + rs = NULL; + goto done; + } + rs->fcr = fcr; + rs->prim = prim; + rs->nroots = nroots; + rs->gfpoly = gfpoly; + + /* Find prim-th root of 1, used in decoding */ + for(iprim=1;(iprim % prim) != 0;iprim += rs->nn) + ; + rs->iprim = iprim / prim; + + rs->genpoly[0] = 1; + for (i = 0,root=fcr*prim; i < nroots; i++,root += prim) { + rs->genpoly[i+1] = 1; + + /* Multiply rs->genpoly[] by @**(root + x) */ + for (j = i; j > 0; j--){ + if (rs->genpoly[j] != 0) + rs->genpoly[j] = rs->genpoly[j-1] ^ rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[j]] + root)]; + else + rs->genpoly[j] = rs->genpoly[j-1]; + } + /* rs->genpoly[0] can never be zero */ + rs->genpoly[0] = rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[0]] + root)]; + } + /* convert rs->genpoly[] to index form for quicker encoding */ + for (i = 0; i <= nroots; i++) + rs->genpoly[i] = rs->index_of[rs->genpoly[i]]; + done:; + + return rs; +} + +RS *init_rs(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad) +{ + RS *rs; + +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&rslist_mutex); +#endif + for(rs = rslist; rs != NULL; rs = rs->next) { + if(rs->pad != pad) continue; + if(rs->nroots != nroots) continue; + if(rs->mm != symsize) continue; + if(rs->gfpoly != gfpoly) continue; + if(rs->fcr != fcr) continue; + if(rs->prim != prim) continue; + + goto DONE; + } + + rs = init_rs_char(symsize, gfpoly, fcr, prim, nroots, pad); + if(rs == NULL) goto DONE; + rs->next = rslist; + rslist = rs; + +DONE: +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&rslist_mutex); +#endif + return rs; +} + + +void free_rs_char(RS *rs) +{ + free(rs->alpha_to); + free(rs->index_of); + free(rs->genpoly); + free(rs); +} + +void free_rs_cache(void) +{ + RS *rs, *next; + +#ifdef HAVE_LIBPTHREAD + pthread_mutex_lock(&rslist_mutex); +#endif + rs = rslist; + while(rs != NULL) { + next = rs->next; + free_rs_char(rs); + rs = next; + } + rslist = NULL; +#ifdef HAVE_LIBPTHREAD + pthread_mutex_unlock(&rslist_mutex); +#endif +} + +/* The guts of the Reed-Solomon encoder, meant to be #included + * into a function body with the following typedefs, macros and variables supplied + * according to the code parameters: + + * data_t - a typedef for the data symbol + * data_t data[] - array of NN-NROOTS-PAD and type data_t to be encoded + * data_t parity[] - an array of NROOTS and type data_t to be written with parity symbols + * NROOTS - the number of roots in the RS code generator polynomial, + * which is the same as the number of parity symbols in a block. + Integer variable or literal. + * + * NN - the total number of symbols in a RS block. Integer variable or literal. + * PAD - the number of pad symbols in a block. Integer variable or literal. + * ALPHA_TO - The address of an array of NN elements to convert Galois field + * elements in index (log) form to polynomial form. Read only. + * INDEX_OF - The address of an array of NN elements to convert Galois field + * elements in polynomial form to index (log) form. Read only. + * MODNN - a function to reduce its argument modulo NN. May be inline or a macro. + * GENPOLY - an array of NROOTS+1 elements containing the generator polynomial in index form + + * The memset() and memmove() functions are used. The appropriate header + * file declaring these functions (usually ) must be included by the calling + * program. + + * Copyright 2004, Phil Karn, KA9Q + * May be used under the terms of the GNU Lesser General Public License (LGPL) + */ + +#undef A0 +#define A0 (NN) /* Special reserved value encoding zero in index form */ + +void encode_rs_char(RS *rs, const data_t *data, data_t *parity) +{ + int i, j; + data_t feedback; + + memset(parity,0,NROOTS*sizeof(data_t)); + + for(i=0;i + * + * 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 + */ + +#ifndef __RSCODE_H__ +#define __RSCODE_H__ + +/* + * General purpose RS codec, 8-bit symbols. + */ + +typedef struct _RS RS; + +extern RS *init_rs(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad); +extern void encode_rs_char(RS *rs, const unsigned char *data, unsigned char *parity); +extern void free_rs_char(RS *rs); +extern void free_rs_cache(void); + +#endif /* __RSCODE_H__ */ diff --git a/src/add-ons/kernel/debugger/qrencode/split.c b/src/add-ons/kernel/debugger/qrencode/split.c new file mode 100644 index 0000000000..cf66d0a177 --- /dev/null +++ b/src/add-ons/kernel/debugger/qrencode/split.c @@ -0,0 +1,311 @@ +/* + * qrencode - QR Code encoder + * + * Input data splitter. + * Copyright (C) 2006-2011 Kentaro Fukuchi + * + * The following data / specifications are taken from + * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004) + * or + * "Automatic identification and data capture techniques -- + * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006) + * + * 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 +#include +#include +#include "qrencode.h" +#include "qrinput.h" +#include "qrspec.h" +#include "split.h" + +#define isdigit(__c__) ((unsigned char)((signed char)(__c__) - '0') < 10) +#define isalnum(__c__) (QRinput_lookAnTable(__c__) >= 0) + +#if !HAVE_STRDUP +#undef strdup +char *strdup_internal(const char *s) +{ + size_t len = strlen(s) + 1; + void *new = malloc(len); + if(new == NULL) return NULL; + return (char *)memcpy(new, s, len); +} +#endif + +static QRencodeMode Split_identifyMode(const char *string, QRencodeMode hint) +{ + unsigned char c, d; + unsigned int word; + + c = string[0]; + + if(c == '\0') return QR_MODE_NUL; + if(isdigit(c)) { + return QR_MODE_NUM; + } else if(isalnum(c)) { + return QR_MODE_AN; + } else if(hint == QR_MODE_KANJI) { + d = string[1]; + if(d != '\0') { + word = ((unsigned int)c << 8) | d; + if((word >= 0x8140 && word <= 0x9ffc) || (word >= 0xe040 && word <= 0xebbf)) { + return QR_MODE_KANJI; + } + } + } + + return QR_MODE_8; +} + +static int Split_eatNum(const char *string, QRinput *input, QRencodeMode hint); +static int Split_eatAn(const char *string, QRinput *input, QRencodeMode hint); +static int Split_eat8(const char *string, QRinput *input, QRencodeMode hint); +static int Split_eatKanji(const char *string, QRinput *input, QRencodeMode hint); + +static int Split_eatNum(const char *string, QRinput *input,QRencodeMode hint) +{ + const char *p; + int ret; + int run; + int dif; + int ln; + QRencodeMode mode; + + ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version); + + p = string; + while(isdigit(*p)) { + p++; + } + run = p - string; + mode = Split_identifyMode(p, hint); + if(mode == QR_MODE_8) { + dif = QRinput_estimateBitsModeNum(run) + 4 + ln + + QRinput_estimateBitsMode8(1) /* + 4 + l8 */ + - QRinput_estimateBitsMode8(run + 1) /* - 4 - l8 */; + if(dif > 0) { + return Split_eat8(string, input, hint); + } + } + if(mode == QR_MODE_AN) { + dif = QRinput_estimateBitsModeNum(run) + 4 + ln + + QRinput_estimateBitsModeAn(1) /* + 4 + la */ + - QRinput_estimateBitsModeAn(run + 1) /* - 4 - la */; + if(dif > 0) { + return Split_eatAn(string, input, hint); + } + } + + ret = QRinput_append(input, QR_MODE_NUM, run, (unsigned char *)string); + if(ret < 0) return -1; + + return run; +} + +static int Split_eatAn(const char *string, QRinput *input, QRencodeMode hint) +{ + const char *p, *q; + int ret; + int run; + int dif; + int la, ln; + + la = QRspec_lengthIndicator(QR_MODE_AN, input->version); + ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version); + + p = string; + while(isalnum(*p)) { + if(isdigit(*p)) { + q = p; + while(isdigit(*q)) { + q++; + } + dif = QRinput_estimateBitsModeAn(p - string) /* + 4 + la */ + + QRinput_estimateBitsModeNum(q - p) + 4 + ln + - QRinput_estimateBitsModeAn(q - string) /* - 4 - la */; + if(dif < 0) { + break; + } else { + p = q; + } + } else { + p++; + } + } + + run = p - string; + + if(*p && !isalnum(*p)) { + dif = QRinput_estimateBitsModeAn(run) + 4 + la + + QRinput_estimateBitsMode8(1) /* + 4 + l8 */ + - QRinput_estimateBitsMode8(run + 1) /* - 4 - l8 */; + if(dif > 0) { + return Split_eat8(string, input, hint); + } + } + + ret = QRinput_append(input, QR_MODE_AN, run, (unsigned char *)string); + if(ret < 0) return -1; + + return run; +} + +static int Split_eatKanji(const char *string, QRinput *input, QRencodeMode hint) +{ + const char *p; + int ret; + int run; + + p = string; + while(Split_identifyMode(p, hint) == QR_MODE_KANJI) { + p += 2; + } + run = p - string; + ret = QRinput_append(input, QR_MODE_KANJI, run, (unsigned char *)string); + if(ret < 0) return -1; + + return run; +} + +static int Split_eat8(const char *string, QRinput *input, QRencodeMode hint) +{ + const char *p, *q; + QRencodeMode mode; + int ret; + int run; + int dif; + int la, ln; + + la = QRspec_lengthIndicator(QR_MODE_AN, input->version); + ln = QRspec_lengthIndicator(QR_MODE_NUM, input->version); + + p = string + 1; + while(*p != '\0') { + mode = Split_identifyMode(p, hint); + if(mode == QR_MODE_KANJI) { + break; + } + if(mode == QR_MODE_NUM) { + q = p; + while(isdigit(*q)) { + q++; + } + dif = QRinput_estimateBitsMode8(p - string) /* + 4 + l8 */ + + QRinput_estimateBitsModeNum(q - p) + 4 + ln + - QRinput_estimateBitsMode8(q - string) /* - 4 - l8 */; + if(dif < 0) { + break; + } else { + p = q; + } + } else if(mode == QR_MODE_AN) { + q = p; + while(isalnum(*q)) { + q++; + } + dif = QRinput_estimateBitsMode8(p - string) /* + 4 + l8 */ + + QRinput_estimateBitsModeAn(q - p) + 4 + la + - QRinput_estimateBitsMode8(q - string) /* - 4 - l8 */; + if(dif < 0) { + break; + } else { + p = q; + } + } else { + p++; + } + } + + run = p - string; + ret = QRinput_append(input, QR_MODE_8, run, (unsigned char *)string); + if(ret < 0) return -1; + + return run; +} + +static int Split_splitString(const char *string, QRinput *input, + QRencodeMode hint) +{ + int length; + QRencodeMode mode; + + if(*string == '\0') return 0; + + mode = Split_identifyMode(string, hint); + if(mode == QR_MODE_NUM) { + length = Split_eatNum(string, input, hint); + } else if(mode == QR_MODE_AN) { + length = Split_eatAn(string, input, hint); + } else if(mode == QR_MODE_KANJI && hint == QR_MODE_KANJI) { + length = Split_eatKanji(string, input, hint); + } else { + length = Split_eat8(string, input, hint); + } + if(length == 0) return 0; + if(length < 0) return -1; + return Split_splitString(&string[length], input, hint); +} + +static char *dupAndToUpper(const char *str, QRencodeMode hint) +{ + char *newstr, *p; + QRencodeMode mode; + + newstr = strdup_internal(str); + if(newstr == NULL) return NULL; + + p = newstr; + while(*p != '\0') { + mode = Split_identifyMode(p, hint); + if(mode == QR_MODE_KANJI) { + p += 2; + } else { + if (*p >= 'a' && *p <= 'z') { + *p = (char)((int)*p - 32); + } + p++; + } + } + + return newstr; +} + +int Split_splitStringToQRinput(const char *string, QRinput *input, + QRencodeMode hint, int casesensitive) +{ + char *newstr; + int ret; + + if(string == NULL || *string == '\0') { + errno = EINVAL; + return -1; + } + if(!casesensitive) { + newstr = dupAndToUpper(string, hint); + if(newstr == NULL) return -1; + ret = Split_splitString(newstr, input, hint); + free(newstr); + } else { + ret = Split_splitString(string, input, hint); + } + + return ret; +} diff --git a/src/add-ons/kernel/debugger/qrencode/split.h b/src/add-ons/kernel/debugger/qrencode/split.h new file mode 100644 index 0000000000..b2cdbe5468 --- /dev/null +++ b/src/add-ons/kernel/debugger/qrencode/split.h @@ -0,0 +1,47 @@ +/* + * qrencode - QR Code encoder + * + * Input data splitter. + * Copyright (C) 2006-2011 Kentaro Fukuchi + * + * The following data / specifications are taken from + * "Two dimensional symbol -- QR-code -- Basic Specification" (JIS X0510:2004) + * or + * "Automatic identification and data capture techniques -- + * QR Code 2005 bar code symbology specification" (ISO/IEC 18004:2006) + * + * 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 + */ + +#ifndef __SPLIT_H__ +#define __SPLIT_H__ + +#include "qrencode.h" + +/** + * Split the input string (null terminated) into QRinput. + * @param string input string + * @param hint give QR_MODE_KANJI if the input string contains Kanji character encoded in Shift-JIS. If not, give QR_MODE_8. + * @param casesensitive 0 for case-insensitive encoding (all alphabet characters are replaced to UPPER-CASE CHARACTERS. + * @retval 0 success. + * @retval -1 an error occurred. errno is set to indicate the error. See + * Exceptions for the details. + * @throw EINVAL invalid input object. + * @throw ENOMEM unable to allocate memory for input objects. + */ +extern int Split_splitStringToQRinput(const char *string, QRinput *input, + QRencodeMode hint, int casesensitive); + +#endif /* __SPLIT_H__ */ diff --git a/src/apps/aboutsystem/AboutSystem.cpp b/src/apps/aboutsystem/AboutSystem.cpp index deba9af5e7..ec3303c6ab 100644 --- a/src/apps/aboutsystem/AboutSystem.cpp +++ b/src/apps/aboutsystem/AboutSystem.cpp @@ -1694,6 +1694,12 @@ AboutView::_CreateCreditsView() .SetLicense(B_TRANSLATE("BSD (3-clause)")) .SetURL("http://gtf.sourceforge.net/")); + // libqrencode + _AddPackageCredit(PackageCredit("libqrencode") + .SetCopyright(B_TRANSLATE(COPYRIGHT_STRING "2006-2012 Kentaro Fukuchi")) + .SetLicense(B_TRANSLATE("GNU LGPL v2.1")) + .SetURL("http://fukuchi.org/works/qrencode/")); + _AddCopyrightsFromAttribute(); _AddPackageCreditEntries(); diff --git a/src/preferences/media/MediaListItem.cpp b/src/preferences/media/MediaListItem.cpp index cfd6f51b09..2e1e508d7e 100644 --- a/src/preferences/media/MediaListItem.cpp +++ b/src/preferences/media/MediaListItem.cpp @@ -2,7 +2,7 @@ // // Copyright (c) 2003, OpenBeOS // -// This software is part of the OpenBeOS distribution and is covered +// This software is part of the OpenBeOS distribution and is covered // by the OpenBeOS license. // // @@ -10,7 +10,7 @@ // Author: Sikosis, Jérôme Duval // Description: Media Preferences // Created : June 25, 2003 -// +// // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ #include "MediaListItem.h" @@ -70,13 +70,13 @@ struct MediaListItem::Renderer { { fDoubleInsets = doubleInset; } - + void Render(BView* onto, BRect frame, bool complete = false) { const rgb_color lowColor = onto->LowColor(); const rgb_color highColor = onto->HighColor(); const rgb_color kBlack = {0, 0, 0, 255}; - + if (fSelected || complete) { if (fSelected) onto->SetLowColor(tint_color(lowColor, B_DARKEN_2_TINT)); @@ -86,7 +86,7 @@ struct MediaListItem::Renderer { frame.left += 4; frame.top += kITEM_MARGIN; BRect iconFrame(MediaIcons::IconRectAt(frame.LeftTop() + BPoint(1, 0))); - + onto->SetDrawingMode(B_OP_OVER); if (fPrimaryIcon && !fDoubleInsets) { onto->DrawBitmap(fPrimaryIcon, iconFrame); @@ -103,7 +103,7 @@ struct MediaListItem::Renderer { onto->SetDrawingMode(B_OP_COPY); onto->SetHighColor(kBlack); - + BFont font = be_plain_font; font_height fontInfo; font.GetHeight(&fontInfo); @@ -130,8 +130,8 @@ struct MediaListItem::Renderer { width += iconSpace; width += 8.0f; // space between icons and text - - width += be_plain_font->StringWidth(fTitle) + 3.0f; + + width += be_plain_font->StringWidth(fTitle) + 16.0f; return width; } diff --git a/src/preferences/media/MediaWindow.cpp b/src/preferences/media/MediaWindow.cpp index 9d599b8529..a9efbc12ec 100644 --- a/src/preferences/media/MediaWindow.cpp +++ b/src/preferences/media/MediaWindow.cpp @@ -405,7 +405,7 @@ MediaWindow::InitWindow() BLayoutBuilder::Group<>(this, B_HORIZONTAL) .SetInsets(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING) - .Add(scrollView) + .Add(scrollView, 0.0f) .AddGroup(B_VERTICAL) .SetInsets(0, 0, 0, 0) .Add(fTitleView) @@ -413,11 +413,10 @@ MediaWindow::InitWindow() // Start the window fInitCheck = InitMedia(true); - if (fInitCheck != B_OK) { + if (fInitCheck != B_OK) PostMessage(B_QUIT_REQUESTED); - } else if (IsHidden()) { + else if (IsHidden()) Show(); - } } @@ -753,7 +752,7 @@ MediaWindow::_MakeEmptyParamView() B_ALIGN_VERTICAL_CENTER); stringView->SetExplicitAlignment(centered); stringView->SetAlignment(B_ALIGN_CENTER); - + fContentLayout->AddView(stringView); fContentLayout->SetVisibleItem(fContentLayout->CountItems() - 1); diff --git a/src/system/kernel/arch/x86/arch_cpu.cpp b/src/system/kernel/arch/x86/arch_cpu.cpp index c2b5a45454..9ce5d7b867 100644 --- a/src/system/kernel/arch/x86/arch_cpu.cpp +++ b/src/system/kernel/arch/x86/arch_cpu.cpp @@ -4,6 +4,7 @@ * * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. * Distributed under the terms of the NewOS License. + * */ @@ -988,65 +989,6 @@ arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages) } -ssize_t -arch_cpu_user_strlcpy(char *to, const char *from, size_t size, - addr_t *faultHandler) -{ - int fromLength = 0; - addr_t oldFaultHandler = *faultHandler; - - // this check is to trick the gcc4 compiler and have it keep the error label - if (to == NULL && size > 0) - goto error; - - *faultHandler = (addr_t)&&error; - - if (size > 0) { - to[--size] = '\0'; - // copy - for ( ; size; size--, fromLength++, to++, from++) { - if ((*to = *from) == '\0') - break; - } - } - // count any leftover from chars - while (*from++ != '\0') { - fromLength++; - } - - *faultHandler = oldFaultHandler; - return fromLength; - -error: - *faultHandler = oldFaultHandler; - return B_BAD_ADDRESS; -} - - -status_t -arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler) -{ - char *xs = (char *)s; - addr_t oldFaultHandler = *faultHandler; - - // this check is to trick the gcc4 compiler and have it keep the error label - if (s == NULL) - goto error; - - *faultHandler = (addr_t)&&error; - - while (count--) - *xs++ = c; - - *faultHandler = oldFaultHandler; - return 0; - -error: - *faultHandler = oldFaultHandler; - return B_BAD_ADDRESS; -} - - status_t arch_cpu_shutdown(bool rebootSystem) { diff --git a/src/system/kernel/arch/x86/arch_x86.S b/src/system/kernel/arch/x86/arch_x86.S index 28611fe247..58e20fc8cc 100644 --- a/src/system/kernel/arch/x86/arch_x86.S +++ b/src/system/kernel/arch/x86/arch_x86.S @@ -1,5 +1,6 @@ /* * Copyright 2003-2007, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2012, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. * * Copyright 2001, Travis Geiselbrecht. All rights reserved. @@ -219,6 +220,108 @@ FUNCTION(arch_cpu_user_memcpy): FUNCTION_END(arch_cpu_user_memcpy) +/* status_t arch_cpu_user_memset(void *to, char c, size_t count, addr_t *faultHandler) */ +FUNCTION(arch_cpu_user_memset): + pushl %esi + pushl %edi + movl 12(%esp),%edi /* dest */ + movb 16(%esp),%al /* c */ + movl 20(%esp),%ecx /* count */ + + /* set the fault handler */ + movl 24(%esp),%edx /* fault handler */ + movl (%edx),%esi + movl $.L_user_memset_error, (%edx) + + rep + stosb + + /* restore the old fault handler */ + movl %esi,(%edx) + xor %eax,%eax + + popl %edi + popl %esi + ret + + /* error condition */ +.L_user_memset_error: + /* restore the old fault handler */ + movl %esi,(%edx) + movl $-1,%eax /* return a generic error, the wrapper routine will deal with it */ + popl %edi + popl %esi + ret +FUNCTION_END(arch_cpu_user_memset) + + +/* ssize_t arch_cpu_user_strlcpy(void *to, const void *from, size_t size, addr_t *faultHandler) */ +FUNCTION(arch_cpu_user_strlcpy): + pushl %esi + pushl %edi + pushl %ebx + movl 16(%esp),%edi /* dest */ + movl 20(%esp),%esi /* source */ + movl 24(%esp),%ecx /* count */ + + /* set the fault handler */ + movl 28(%esp),%edx /* fault handler */ + movl (%edx),%ebx + movl $.L_user_strlcpy_error, (%edx) + + /* Check for 0 length */ + cmp $0,%ecx + je .L_user_strlcpy_source_count + + /* Copy at most count - 1 bytes */ + dec %ecx + + /* move data by bytes */ + cld + repnz + movsb + + /* null terminate string */ + movb $0,(%edi) + dec %esi + + /* check if we copied the entire source string */ + cmp $0,%ecx + jne .L_user_strlcpy_source_done + + /* count remaining bytes in src */ +.L_user_strlcpy_source_count: + not %ecx + movb $0,%al + repnz + scasb + +.L_user_strlcpy_source_done: + + movl %esi,%eax + subl 20(%esp),%eax + subl $1,%eax + + /* restore the old fault handler */ + movl %ebx,(%edx) + + popl %ebx + popl %edi + popl %esi + ret + + /* error condition */ +.L_user_strlcpy_error: + /* restore the old fault handler */ + movl %ebx,(%edx) + movl $-1,%eax /* return a generic error, the wrapper routine will deal with it */ + popl %ebx + popl %edi + popl %esi + ret +FUNCTION_END(arch_cpu_user_strlcpy) + + /*! \fn void arch_debug_call_with_fault_handler(cpu_ent* cpu, jmp_buf jumpBuffer, void (*function)(void*), void* parameter) diff --git a/src/system/kernel/debug/debug_heap.cpp b/src/system/kernel/debug/debug_heap.cpp index 069e97d6f1..996f5213b9 100644 --- a/src/system/kernel/debug/debug_heap.cpp +++ b/src/system/kernel/debug/debug_heap.cpp @@ -278,6 +278,19 @@ debug_malloc(size_t size) } +void* +debug_calloc(size_t num, size_t size) +{ + size_t allocationSize = num * size; + void* allocation = debug_malloc(allocationSize); + if (allocation == NULL) + return NULL; + + memset(allocation, 0, allocationSize); + return allocation; +} + + void debug_free(void* address) { diff --git a/src/system/kernel/debug/font.h b/src/system/kernel/debug/font.h index 502c77c1ea..9258dd4743 100644 --- a/src/system/kernel/debug/font.h +++ b/src/system/kernel/debug/font.h @@ -46,9 +46,9 @@ static unsigned char FONT[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* ' ' */ +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* ' ' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ' ' */ diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 13073782a4..6cd652cd49 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -5112,8 +5112,10 @@ user_strlcpy(char* to, const char* from, size_t size) &thread_get_current_thread()->fault_handler); // If we hit the address overflow boundary, fail. - if (result >= 0 && (size_t)result >= maxSize && maxSize < size) + if (result < 0 || (result >= 0 && (size_t)result >= maxSize + && maxSize < size)) { return B_BAD_ADDRESS; + } return result; }