From a5917f1137916c59aa3da1c398bf8dd8442af1c2 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 f296855..78587cb 100755 --- a/barcode/codex.py +++ b/barcode/codex.py @@ -223,12 +223,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(): @@ -257,7 +278,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 65914f8cb72ffd9bf2eb4632d5a9e3d8f28e83bc 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 78587cb..7ebebbc 100755 --- a/barcode/codex.py +++ b/barcode/codex.py @@ -254,14 +254,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 610948407496dd732cb38e020f332e104ee92046 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 7ebebbc..cbd91c3 100755 --- a/barcode/codex.py +++ b/barcode/codex.py @@ -249,18 +249,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 1aa5068fb8992c796e4245b9ab04f472aa5f2f46 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 cbd91c3..e782932 100755 --- a/barcode/codex.py +++ b/barcode/codex.py @@ -66,12 +66,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 2814211105c4431b0fba1356b80574739c8346a1 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 | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/barcode/codex.py b/barcode/codex.py index e782932..a0a5234 100755 --- a/barcode/codex.py +++ b/barcode/codex.py @@ -154,7 +154,7 @@ def __init__(self, code: str, writer=None) -> None: self.code = code self.writer = writer or self.default_writer() self._charset = "C" - self._buffer = "" + self._digit_buffer = "" # Accumulate pairs of digits for charset C check_code(self.code, self.name, code128.ALL) def __str__(self) -> str: @@ -204,15 +204,15 @@ def look_next() -> bool: codes: list[int] = [] if self._charset == "C" and not char.isdigit(): - if self._is_char_fnc1_char(char) and not self._buffer: + if self._is_char_fnc1_char(char) and not self._digit_buffer: return codes if char in code128.B: 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") @@ -254,13 +254,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.") @@ -283,10 +283,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 85acbda24151d5ce155b3299077a87b25fcd2cc2 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 a0a5234..9a60c31 100755 --- a/barcode/codex.py +++ b/barcode/codex.py @@ -210,7 +210,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": @@ -282,7 +284,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]))