]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/qrcode-util.c
license: LGPL-2.1+ -> LGPL-2.1-or-later
[thirdparty/systemd.git] / src / shared / qrcode-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
4368277c 2
da3920c3 3#include "qrcode-util.h"
f1b82359
ZJS
4
5#if HAVE_QRENCODE
6#include <qrencode.h>
7
8#include "dlfcn-util.h"
9#include "locale-util.h"
da3920c3
LP
10#include "terminal-util.h"
11
12#define ANSI_WHITE_ON_BLACK "\033[40;37;1m"
13
14static void print_border(FILE *output, unsigned width) {
da3920c3 15 /* Four rows of border */
c9e9a57f 16 for (unsigned y = 0; y < 4; y += 2) {
da3920c3
LP
17 fputs(ANSI_WHITE_ON_BLACK, output);
18
c9e9a57f 19 for (unsigned x = 0; x < 4 + width + 4; x++)
da3920c3
LP
20 fputs("\342\226\210", output);
21
22 fputs(ANSI_NORMAL "\n", output);
23 }
24}
25
f1b82359 26static void write_qrcode(FILE *output, QRcode *qr) {
da3920c3
LP
27 assert(qr);
28
29 if (!output)
30 output = stdout;
31
32 print_border(output, qr->width);
33
c9e9a57f
ZJS
34 for (unsigned y = 0; y < (unsigned) qr->width; y += 2) {
35 const uint8_t *row1 = qr->data + qr->width * y;
36 const uint8_t *row2 = row1 + qr->width;
da3920c3
LP
37
38 fputs(ANSI_WHITE_ON_BLACK, output);
c9e9a57f 39 for (unsigned x = 0; x < 4; x++)
da3920c3
LP
40 fputs("\342\226\210", output);
41
c9e9a57f 42 for (unsigned x = 0; x < (unsigned) qr->width; x++) {
da3920c3
LP
43 bool a, b;
44
45 a = row1[x] & 1;
46 b = (y+1) < (unsigned) qr->width ? (row2[x] & 1) : false;
47
48 if (a && b)
49 fputc(' ', output);
50 else if (a)
51 fputs("\342\226\204", output);
52 else if (b)
53 fputs("\342\226\200", output);
54 else
55 fputs("\342\226\210", output);
56 }
57
c9e9a57f 58 for (unsigned x = 0; x < 4; x++)
da3920c3
LP
59 fputs("\342\226\210", output);
60 fputs(ANSI_NORMAL "\n", output);
61 }
62
63 print_border(output, qr->width);
64 fflush(output);
65}
f1b82359
ZJS
66
67int print_qrcode(FILE *out, const char *header, const char *string) {
68 QRcode* (*sym_QRcode_encodeString)(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive);
69 void (*sym_QRcode_free)(QRcode *qrcode);
70 _cleanup_(dlclosep) void *dl = NULL;
71 QRcode* qr;
72 int r;
73
74 /* If this is not an UTF-8 system or ANSI colors aren't supported/disabled don't print any QR
75 * codes */
76 if (!is_locale_utf8() || !colors_enabled())
77 return -EOPNOTSUPP;
78
79 dl = dlopen("libqrencode.so.4", RTLD_LAZY);
80 if (!dl)
81 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
82 "QRCODE support is not installed: %s", dlerror());
83
84 r = dlsym_many_and_warn(
85 dl,
86 LOG_DEBUG,
87 &sym_QRcode_encodeString, "QRcode_encodeString",
88 &sym_QRcode_free, "QRcode_free",
89 NULL);
90 if (r < 0)
91 return r;
92
93 qr = sym_QRcode_encodeString(string, 0, QR_ECLEVEL_L, QR_MODE_8, 0);
94 if (!qr)
95 return -ENOMEM;
96
97 if (header)
98 fprintf(out, "\n%s:\n\n", header);
99
100 write_qrcode(out, qr);
101
102 fputc('\n', out);
103
104 sym_QRcode_free(qr);
105 return 0;
106}
107#endif