From f4af12aab158fbe39a44d9f314e5adbb8c223b26 Mon Sep 17 00:00:00 2001 From: Ben Mares Date: Mon, 8 Jul 2024 23:32:50 +0200 Subject: [PATCH 1/6] Distinguish between buffered and unbuffered code128 conversion --- barcode/codex.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/barcode/codex.py b/barcode/codex.py index b82c020..a6e1457 100755 --- a/barcode/codex.py +++ b/barcode/codex.py @@ -209,12 +209,33 @@ def look_next() -> bool: codes = self._new_charset("B") return codes - def _convert(self, char: str): + def _convert(self, char: str) -> int: + """Convert a character to a code number for the current charset. + + NOTE: encoding digits with charset C requires buffering and is not supported + here. Use _convert_or_buffer instead. + """ if self._charset == "A": return code128.A[char] if self._charset == "B": return code128.B[char] if self._charset == "C": + if char in ["TO_A", "TO_B"]: + return code128.C[char] + raise RuntimeError("Use _convert_or_buffer for charset C.") + raise RuntimeError( + f"Character {char} could not be converted in charset {self._charset}." + ) + + def _convert_or_buffer(self, char: str) -> int | None: + """Convert a character to a code number for the current charset. + + If charset C is active then digits are encoded in pairs. When the first digit + is encountered, it is buffered and None is returned. + """ + if self._charset != "C": + return self._convert(char) + else: if char in code128.C: return code128.C[char] if char.isdigit(): @@ -243,7 +264,7 @@ def _build(self) -> list[int]: encoded: list[int] = [code128.START_CODES[self._charset]] for i, char in enumerate(self.code): encoded.extend(self._maybe_switch_charset(i)) - code_num = self._convert(char) + code_num = self._convert_or_buffer(char) if code_num is not None: encoded.append(code_num) # Finally look in the buffer From 08af591dd68f2b97f790c4ea860145876f7bf050 Mon Sep 17 00:00:00 2001 From: Ben Mares Date: Mon, 8 Jul 2024 23:39:18 +0200 Subject: [PATCH 2/6] Be more explicit about the cases --- barcode/codex.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/barcode/codex.py b/barcode/codex.py index a6e1457..3eac890 100755 --- a/barcode/codex.py +++ b/barcode/codex.py @@ -240,14 +240,14 @@ def _convert_or_buffer(self, char: str) -> int | None: return code128.C[char] if char.isdigit(): self._buffer += char - if len(self._buffer) == 2: - value = int(self._buffer) - self._buffer = "" - return value - return None - raise RuntimeError( - f"Character {char} could not be converted in charset {self._charset}." - ) + if len(self._buffer) == 1: + # Wait for the second digit to group in pairs + return None + assert len(self._buffer) == 2 + value = int(self._buffer) + self._buffer = "" + return value + raise RuntimeError(f"Character {char} could not be converted in charset C.") def _try_to_optimize(self, encoded: list[int]) -> list[int]: if encoded[1] in code128.TO: From af30bd19d675e2a307ac412b09a71f9383c73170 Mon Sep 17 00:00:00 2001 From: Ben Mares Date: Mon, 8 Jul 2024 23:41:57 +0200 Subject: [PATCH 3/6] Dedent --- barcode/codex.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/barcode/codex.py b/barcode/codex.py index 3eac890..3c389e5 100755 --- a/barcode/codex.py +++ b/barcode/codex.py @@ -235,18 +235,17 @@ def _convert_or_buffer(self, char: str) -> int | None: """ if self._charset != "C": return self._convert(char) - else: - if char in code128.C: - return code128.C[char] - if char.isdigit(): - self._buffer += char - if len(self._buffer) == 1: - # Wait for the second digit to group in pairs - return None - assert len(self._buffer) == 2 - value = int(self._buffer) - self._buffer = "" - return value + if char in code128.C: + return code128.C[char] + if char.isdigit(): + self._buffer += char + if len(self._buffer) == 1: + # Wait for the second digit to group in pairs + return None + assert len(self._buffer) == 2 + value = int(self._buffer) + self._buffer = "" + return value raise RuntimeError(f"Character {char} could not be converted in charset C.") def _try_to_optimize(self, encoded: list[int]) -> list[int]: From 2cbaec0b8571e7c26daf59ae3461e792418291f6 Mon Sep 17 00:00:00 2001 From: Ben Mares Date: Mon, 8 Jul 2024 23:54:47 +0200 Subject: [PATCH 4/6] Don't return None in Code 39 calculate_checksum --- barcode/codex.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/barcode/codex.py b/barcode/codex.py index 3c389e5..b18fe8b 100755 --- a/barcode/codex.py +++ b/barcode/codex.py @@ -64,12 +64,14 @@ def get_fullcode(self) -> str: """:returns: The full code as it will be encoded.""" return self.code - def calculate_checksum(self): + def calculate_checksum(self) -> str: check = sum(code39.MAP[x][0] for x in self.code) % 43 for k, v in code39.MAP.items(): if check == v[0]: return k - return None + raise RuntimeError( + "All possible values for the checksum should have been included in the map." + ) def build(self) -> list[str]: chars = [code39.EDGE] From df5fb19c4df96a85b95e5722c864d1e47d07b978 Mon Sep 17 00:00:00 2001 From: Ben Mares Date: Tue, 9 Jul 2024 00:22:36 +0200 Subject: [PATCH 5/6] =?UTF-8?q?Improve=20the=20name=20=5Fbuffer=20?= =?UTF-8?q?=E2=86=92=20=5Fdigit=5Fbuffer=20for=20Code128=20charset=20C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- barcode/codex.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/barcode/codex.py b/barcode/codex.py index b18fe8b..bd4b803 100755 --- a/barcode/codex.py +++ b/barcode/codex.py @@ -152,7 +152,7 @@ def __init__(self, code: str, writer=None) -> None: self.code = code self.writer = writer or self.default_writer() self._charset = "B" - self._buffer = "" + self._digit_buffer = "" # Accumulate pairs of digits for charset C check_code(self.code, self.name, code128.ALL) def __str__(self) -> str: @@ -196,9 +196,9 @@ def look_next() -> bool: codes = self._new_charset("B") elif char in code128.A: codes = self._new_charset("A") - if len(self._buffer) == 1: - codes.append(self._convert(self._buffer[0])) - self._buffer = "" + if len(self._digit_buffer) == 1: + codes.append(self._convert(self._digit_buffer[0])) + self._digit_buffer = "" elif self._charset == "B": if look_next(): codes = self._new_charset("C") @@ -240,13 +240,13 @@ def _convert_or_buffer(self, char: str) -> int | None: if char in code128.C: return code128.C[char] if char.isdigit(): - self._buffer += char - if len(self._buffer) == 1: + self._digit_buffer += char + if len(self._digit_buffer) == 1: # Wait for the second digit to group in pairs return None - assert len(self._buffer) == 2 - value = int(self._buffer) - self._buffer = "" + assert len(self._digit_buffer) == 2 + value = int(self._digit_buffer) + self._digit_buffer = "" return value raise RuntimeError(f"Character {char} could not be converted in charset C.") @@ -269,10 +269,10 @@ def _build(self) -> list[int]: if code_num is not None: encoded.append(code_num) # Finally look in the buffer - if len(self._buffer) == 1: + if len(self._digit_buffer) == 1: encoded.extend(self._new_charset("B")) - encoded.append(self._convert(self._buffer[0])) - self._buffer = "" + encoded.append(self._convert(self._digit_buffer[0])) + self._digit_buffer = "" return self._try_to_optimize(encoded) def build(self) -> list[str]: From e72b03d6a05808f830d8bd8bc0d3ed4b3f9312c0 Mon Sep 17 00:00:00 2001 From: Ben Mares Date: Tue, 9 Jul 2024 16:36:38 +0200 Subject: [PATCH 6/6] Add some comments explaining buffer flush --- barcode/codex.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/barcode/codex.py b/barcode/codex.py index bd4b803..165fc4b 100755 --- a/barcode/codex.py +++ b/barcode/codex.py @@ -196,7 +196,9 @@ def look_next() -> bool: codes = self._new_charset("B") elif char in code128.A: codes = self._new_charset("A") + assert self._charset != "C" if len(self._digit_buffer) == 1: + # Flush the remaining single digit from the buffer codes.append(self._convert(self._digit_buffer[0])) self._digit_buffer = "" elif self._charset == "B": @@ -268,7 +270,8 @@ def _build(self) -> list[int]: code_num = self._convert_or_buffer(char) if code_num is not None: encoded.append(code_num) - # Finally look in the buffer + # If we finish in charset C with a single digit remaining in the buffer, + # switch to charset B and flush out the buffer. if len(self._digit_buffer) == 1: encoded.extend(self._new_charset("B")) encoded.append(self._convert(self._digit_buffer[0]))