From: Petr Hodina <[email protected]>

Add CONFIG_LIB_QRCODE_GZIP (bool, depends on GZIP_COMPRESSED) and a
new helper qrcodegen_encodeBinaryCompressed() that tries the plain
binary encoder first, and on failure transparently gzip-compresses
the payload and re-encodes it in binary mode with a four-byte "QRGZ"
magic header so the scanner side knows to decompress.

The compressed payload can later be decoded by:
`zbarimg --raw -q <QR_CODE> | tail -c +5 | gunzip`

Signed-off-by: Petr Hodina <[email protected]>
---
 include/qrcodegen.h  | 14 ++++++++++++++
 lib/Kconfig          | 15 +++++++++++++++
 lib/Makefile         |  1 +
 lib/qrcodegen_gzip.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 75 insertions(+)

diff --git a/include/qrcodegen.h b/include/qrcodegen.h
index b67b77a30fe..590b61cd871 100644
--- a/include/qrcodegen.h
+++ b/include/qrcodegen.h
@@ -235,6 +235,20 @@ bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t 
dataLen, uint8_t qrcod
        enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum 
qrcodegen_Mask mask, bool boostEcl);
 
 
+#if defined(CONFIG_LIB_QRCODE_GZIP)
+/*
+ * Encode a payload, transparently falling back to gzip compression
+ * if the plain payload does not fit in any QR code version up to
+ * qrcodegen_VERSION_MAX at the requested ECC level.
+ *
+ * Returns true on success, false if neither plain nor gzip-compressed
+ * payload fits.
+ */
+bool qrcodegen_encodeBinaryCompressed(uint8_t dataAndTemp[], size_t dataLen,
+       uint8_t qrcode[], enum qrcodegen_Ecc ecl);
+#endif
+
+
 /*---- Functions (low level) to generate QR Codes ----*/
 
 /* 
diff --git a/lib/Kconfig b/lib/Kconfig
index 5f37a07e512..ed67d2f8161 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -321,6 +321,21 @@ config LIB_QRCODE_MAX_VERSION
          pairing tokens or short URLs and want to reclaim the static
          buffer footprint. The default of 40 matches upstream Nayuki.
 
+config LIB_QRCODE_GZIP
+       bool "Allow gzip pre-compression of QR code payloads"
+       depends on LIB_QRCODE
+       depends on GZIP_COMPRESSED
+       help
+         When a payload does not fit in the configured maximum QR code
+         version, transparently gzip-compress it and re-encode in binary
+         mode with a four-byte magic header ("QRGZ"), so the scanner side
+         knows to decompress.
+
+         Useful for diagnostic / state-dump QR codes where the raw payload
+         is highly compressible (printable text, log fragments) but would
+         not otherwise fit a small QR symbol. The plain (uncompressed)
+         encoder remains the first attempt; this just adds a fallback.
+
 choice
        prompt "Pseudo-random library support type"
        depends on NET_RANDOM_ETHADDR || RANDOM_UUID || CMD_UUID || \
diff --git a/lib/Makefile b/lib/Makefile
index 60e62d5e6e2..5f3e5300462 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -129,6 +129,7 @@ obj-y += linux_string.o
 obj-$(CONFIG_$(PHASE_)LMB) += lmb.o
 obj-y += membuf.o
 obj-$(CONFIG_LIB_QRCODE) += qrcodegen.o
+obj-$(CONFIG_LIB_QRCODE_GZIP) += qrcodegen_gzip.o
 obj-$(CONFIG_REGEX) += slre.o
 obj-y += string.o
 obj-y += tables_csum.o
diff --git a/lib/qrcodegen_gzip.c b/lib/qrcodegen_gzip.c
new file mode 100644
index 00000000000..fe0c6567a00
--- /dev/null
+++ b/lib/qrcodegen_gzip.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Optional gzip compression for QR code payloads.
+ */
+
+#include <gzip.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <qrcodegen.h>
+
+#define QRGZ_MAGIC_LEN 4
+
+static const u8 qrgz_magic[QRGZ_MAGIC_LEN] = { 'Q', 'R', 'G', 'Z' };
+
+bool qrcodegen_encodeBinaryCompressed(uint8_t dataAndTemp[], size_t dataLen,
+                                     uint8_t qrcode[], enum qrcodegen_Ecc ecl)
+{
+       size_t buf_max = 
qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MAX);
+       unsigned long out_len;
+       u8 *scratch;
+
+       if (qrcodegen_encodeBinary(dataAndTemp, dataLen, qrcode, ecl,
+                                  qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX,
+                                  qrcodegen_Mask_AUTO, true))
+               return true;
+
+       if (buf_max < QRGZ_MAGIC_LEN)
+               return false;
+
+       scratch = qrcode;
+       out_len = buf_max;
+       if (gzip(scratch, &out_len, dataAndTemp, dataLen) != 0)
+               return false;
+
+       if (out_len + QRGZ_MAGIC_LEN > buf_max)
+               return false;
+
+       memmove(dataAndTemp + QRGZ_MAGIC_LEN, scratch, out_len);
+       memcpy(dataAndTemp, qrgz_magic, QRGZ_MAGIC_LEN);
+
+       return qrcodegen_encodeBinary(dataAndTemp, out_len + QRGZ_MAGIC_LEN,
+                                     qrcode, ecl, qrcodegen_VERSION_MIN,
+                                     qrcodegen_VERSION_MAX, 
qrcodegen_Mask_AUTO,
+                                     true);
+}

-- 
2.55.0


Reply via email to