2 * Copyright 2012, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Michael Lotz <mmlr@mlotz.ch>
22 extern void abort_debugger_command();
26 static const char* kWebPostBaseURL
= "http://mlotz.ch/q";
28 static char sStringBuffer
[16 * 1024];
29 static char sEncodeBuffer
[3 * 1024];
30 static int sBufferPosition
= 0;
31 static int sQRCodeVersion
= 19;
32 static QRecLevel sQRCodeLevel
= QR_ECLEVEL_L
;
33 static char sWebPostId
[64];
34 static int sWebPostCounter
= 0;
38 qrcode_bit(QRcode
* qrCode
, int x
, int y
)
40 if (x
>= qrCode
->width
|| y
>= qrCode
->width
)
43 return (qrCode
->data
[y
* qrCode
->width
+ x
] & 0x01) == 1;
48 move_to_and_clear_line(int line
)
50 kprintf(" \x1b[%dd\x1b[G\x1b[K", line
+ 1);
55 print_qrcode(QRcode
* qrCode
, bool waitForKey
)
57 move_to_and_clear_line(0);
58 for (int y
= 0; y
< qrCode
->width
; y
+= 2) {
59 move_to_and_clear_line(y
/ 2 + 1);
62 for (int x
= 0; x
< qrCode
->width
; x
++) {
63 bool upper
= qrcode_bit(qrCode
, x
, y
);
64 bool lower
= qrcode_bit(qrCode
, x
, y
+ 1);
66 kputs(upper
? "\x11" : " ");
68 kputs(upper
? "\x12" : "\x13");
72 move_to_and_clear_line(qrCode
->width
/ 2 + 2);
73 move_to_and_clear_line(qrCode
->width
/ 2 + 3);
76 kputs("press q to abort or any other key to continue...\x1b[1B\x1b[G");
86 encode_url(const char* query
, const char* data
, int encodeLength
,
90 strlcat(sEncodeBuffer
, kWebPostBaseURL
, encodeLength
+ 1);
91 strlcat(sEncodeBuffer
, "?i=", encodeLength
+ 1);
92 strlcat(sEncodeBuffer
, sWebPostId
, encodeLength
+ 1);
93 strlcat(sEncodeBuffer
, "&", encodeLength
+ 1);
94 strlcat(sEncodeBuffer
, query
, encodeLength
+ 1);
95 int position
= strlcat(sEncodeBuffer
, "=", encodeLength
+ 1);
96 if (position
> encodeLength
)
100 while (inputLength
> 0 && position
< encodeLength
) {
101 char character
= data
[copyCount
];
102 if ((character
>= 'a' && character
<= 'z')
103 || (character
>= 'A' && character
<= 'Z')
104 || (character
>= '0' && character
<= '9')
105 || character
== '.' || character
== '-' || character
== '_'
107 // These aren't strictly valid, but seem to work.
108 || character
== '/' || character
== '(' || character
== ')'
109 || character
== '=' || character
== '^' || character
== '?'
110 || character
== '|' || character
== '*' || character
== '@'
111 || character
== ';' || character
== ':' || character
== ','
112 || character
== '{' || character
== '}' || character
== '['
113 || character
== ']' || character
== '<' || character
== '>'
114 || character
== '!' || character
== '\\') {
115 sEncodeBuffer
[position
++] = character
;
116 sEncodeBuffer
[position
] = 0;
117 } else if (character
== ' ') {
118 // Encode spaces as '+' as that's shorter than %20.
119 sEncodeBuffer
[position
++] = '+';
120 sEncodeBuffer
[position
] = 0;
122 // Encode to a %xx escape.
123 if (encodeLength
- position
< 3) {
124 // Doesn't fit anymore, we're done.
129 sprintf(escaped
, "%%%.2x", character
);
130 position
= strlcat(sEncodeBuffer
, escaped
, encodeLength
+ 1);
142 qrencode(int argc
, char* argv
[])
144 if (argc
> 1 && strcmp(argv
[1], "--help") == 0) {
145 kprintf("%s [<string>]\n", argv
[0]);
146 kprintf("If an argument is given, encodes that string as a QR code.\n"
147 "Otherwise the current QR buffer is encoded as QR codes.\n"
148 "When encoding from the QR buffer, the buffer is left intact.\n"
149 "use qrclear to clear the QR buffer or qrflush to encode/clear.\n");
153 const char* source
= NULL
;
155 sStringBuffer
[sBufferPosition
] = 0;
156 source
= sStringBuffer
;
160 int inputLength
= strlen(source
);
161 int encodeLength
= QRspec_getDataLength(sQRCodeVersion
, sQRCodeLevel
) - 3;
162 while (inputLength
> 0) {
164 if (sWebPostId
[0] != 0) {
165 copyCount
= encode_url(sWebPostCounter
++ == 0 ? "clear" : "d",
166 source
, encodeLength
, inputLength
);
168 kprintf("Failed to URL encode buffer.\n");
173 copyCount
= inputLength
< encodeLength
? inputLength
: encodeLength
;
174 memcpy(sEncodeBuffer
, source
, copyCount
);
175 sEncodeBuffer
[copyCount
] = 0;
178 QRcode
* qrCode
= QRcode_encodeString8bit(sEncodeBuffer
, sQRCodeVersion
,
180 if (qrCode
== NULL
) {
181 kprintf("Failed to encode buffer into qr code.\n");
187 inputLength
-= copyCount
;
189 bool doContinue
= print_qrcode(qrCode
, inputLength
> 0);
194 abort_debugger_command();
205 qrclear(int argc
, char* argv
[])
207 if (argc
> 1 && strcmp(argv
[1], "--help") == 0) {
208 kprintf("Clears the current QR buffer.\n");
213 sStringBuffer
[0] = 0;
219 qrflush(int argc
, char* argv
[])
221 if (argc
> 1 && strcmp(argv
[1], "--help") == 0) {
222 kprintf("Flushes the current QR buffer by encoding QR codes from\n"
223 "the data and then clears the QR buffer.\n");
234 qrappend(int argc
, char* argv
[])
236 if (argc
< 2 || (argc
> 1 && strcmp(argv
[1], "--help") == 0)) {
237 kprintf("%s <string>\n", argv
[0]);
238 kprintf("Appends the given string to the QR buffer. Can be used as\n"
239 "the target of a pipe command to accumulate the output of other\n"
240 "commands in the QR buffer.\n"
241 "Note that this command will flush the QR buffer when it runs\n"
242 "full to make room for the new string. This will cause QR codes\n"
243 "to be generated while the append command still runs. As these\n"
244 "implicit flushes only happen to make room in the buffer, the\n"
245 "strings are afterwards appended aren't flushed, so make sure to\n"
246 "execute the qrflush command to generate codes for these as\n"
251 const char* source
= argv
[1];
252 int length
= strlen(source
) + 1;
255 int copyCount
= sizeof(sStringBuffer
) - sBufferPosition
- 1;
256 if (copyCount
== 0) {
257 // The buffer is full, we need to flush it.
261 if (length
< copyCount
)
264 memcpy(sStringBuffer
+ sBufferPosition
, source
, copyCount
);
265 sBufferPosition
+= copyCount
;
270 // Overwrite the 0 byte that was copied extra with a newline.
271 if (sBufferPosition
> 0)
272 sStringBuffer
[sBufferPosition
- 1] = '\n';
279 qrconfig(int argc
, char* argv
[])
281 if (argc
< 2 || (argc
> 1 && strcmp(argv
[1], "--help") == 0)) {
282 kprintf("%s <version>\n", argv
[0]);
283 kprintf("Sets the QR version to be used. Valid versions range from 1\n"
284 "to 40 where each version determines the size of the QR code.\n"
285 "Version 1 is 21x21 in size and each version increments that size\n"
286 "by 4x4 up to 177x177 for version 40.\n"
287 "Bigger QR codes can hold more data, so ideally you use a version\n"
288 "that makes the QR code as big as possible while still fitting on\n"
290 "You can test the new config by running qrencode\n"
291 "with a test string.\n"
292 "Note that due to memory constraints in the kernel debugger, some\n"
293 "of the higher versions may actually not work. The kernel\n"
294 "debugger heap size can be adjusted using the KDEBUG_HEAP define\n"
295 "in the kernel_debug_config.h header\n");
299 int newVersion
= atoi(argv
[1]);
300 if (newVersion
<= 0 || newVersion
> 40) {
301 kprintf("Invalid QR code version supplied, "
302 "must be between 1 and 40.\n");
306 sQRCodeVersion
= newVersion
;
312 qrwebpost(int argc
, char* argv
[])
314 if (argc
>= 3 && strcmp(argv
[1], "start") == 0) {
315 strlcpy(sWebPostId
, argv
[2], sizeof(sWebPostId
));
318 // Generate the clear code.
319 const char* args
[2] = { "", "yes" };
320 qrencode(2, (char**)args
);
321 } else if (argc
>= 2 && strcmp(argv
[1], "stop") == 0) {
324 kprintf("%s start <id>\n", argv
[0]);
325 kprintf("%s stop\n", argv
[0]);
326 kprintf("Causes the QR codes to be rendered as URLs that resolve to\n"
327 "a service that allows appending the data of multiple QR codes\n"
328 "for easier handling.\n"
329 "An initial QR code is generated that invokes a clear operation\n"
330 "to prepare the output file on the server.\n"
331 "Note that there is no logic behind the service, if you and\n"
332 "someone else use the same id at the same time, they will\n"
333 "overwrite eachother. Therefore use a reasonably unique name.\n");
342 std_ops(int32 op
, ...)
346 add_debugger_command("qrencode", qrencode
,
347 "encodes a string / the current QR buffer");
348 add_debugger_command("qrappend", qrappend
,
349 "appends a string to the QR buffer");
350 add_debugger_command("qrclear", qrclear
,
351 "clears the current QR buffer");
352 add_debugger_command("qrflush", qrflush
,
353 "encodes the current QR buffer and clears it");
354 add_debugger_command("qrconfig", qrconfig
,
355 "sets the QR code version to be used");
356 add_debugger_command("qrwebpost", qrwebpost
,
357 "sets up URL encoding for QR codes");
359 case B_MODULE_UNINIT
:
360 remove_debugger_command("qrencode", qrencode
);
361 remove_debugger_command("qrappend", qrappend
);
362 remove_debugger_command("qrclear", qrclear
);
363 remove_debugger_command("qrflush", qrflush
);
364 remove_debugger_command("qrconfig", qrconfig
);
365 remove_debugger_command("qrwebpost", qrwebpost
);
373 static struct debugger_module_info sModuleInfo
= {
375 "debugger/qrencode/v1",
385 module_info
*modules
[] = {
386 (module_info
*)&sModuleInfo
,