summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Lotz <mmlr@mlotz.ch>2012-07-01 04:04:54 (GMT)
committerMichael Lotz <mmlr@mlotz.ch>2012-07-01 04:37:27 (GMT)
commit0948c0ff50ebdb04a5e60f0ed3ad3f1a9968c7f2 (patch)
tree0dffdaf2030328124c0a9313ae319e2dc81bcd8a
parent5521e284150a6f2fcebcfabf1010f1c827224788 (diff)
Add module code that wraps qrencode and does the printing.
* Generates QR codes using the qrencode library functions and prints them using terminal escape sequences and the special "block" characters. * Supplies a static QR buffer that can be used to accumulate output for later conversion into QR codes. * Adds qrencode debugger command that allows to generate QR codes for arbitrary strings. * Adds qrappend, qrflush and qrclear to manipulate the QR buffer. qrappend can be the target of a pipe to accumulate output from other commands. qrflush causes the QR buffer to be encoded and cleared and qrclear only clears the QR buffer. * Adds qrconfig that allows changing the QR code version, determining what size QR codes are to be used.
-rw-r--r--src/add-ons/kernel/debugger/qrencode/module.cpp270
1 files changed, 270 insertions, 0 deletions
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 0000000..58751ca
--- /dev/null
+++ b/src/add-ons/kernel/debugger/qrencode/module.cpp
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2012, Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ * Michael Lotz <mmlr@mlotz.ch>
+ */
+
+
+#include <debug.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern "C" {
+#include "qrencode.h"
+#include "qrspec.h"
+}
+
+
+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 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 void
+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 any key to continue...\x1b[1B\x1b[G");
+ kgetc();
+ }
+}
+
+
+static int
+qrencode(int argc, char* argv[])
+{
+ if (argc > 1 && strcmp(argv[1], "--help") == 0) {
+ kprintf("%s [<string>]\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 = 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;
+
+ print_qrcode(qrCode, inputLength > 0);
+ QRcode_free(qrCode);
+ }
+
+ 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 <string>\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 <version>\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 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");
+ 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);
+ 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
+};
+