diff mupdf-source/thirdparty/zint/backend/tools/gen_gs1_lint.php @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mupdf-source/thirdparty/zint/backend/tools/gen_gs1_lint.php	Mon Sep 15 11:43:07 2025 +0200
@@ -0,0 +1,488 @@
+<?php
+/* Generate GS1 verify include "backend/gs1_lint.h" for "backend/gs1.c" */
+/*
+    libzint - the open source barcode library
+    Copyright (C) 2021-2024 <rstuart114@gmail.com>
+ */
+/* SPDX-License-Identifier: BSD-3-Clause */
+
+/* To create "backend/gs1_lint.h" (from project directory):
+ *
+ *   php backend/tools/gen_gs1_lint.php > backend/gs1_lint.h
+ *
+ * or to use local copy of "gs1-syntax-dictionary.txt":
+ *
+ *   php backend/tools/gen_gs1_lint.php -f <local-path>/gs1-syntax-dictionary.txt backend/gs1_lint.h
+ *
+ *************************************************************************************************
+ * NOTE: up-to-date version requires syntax dictionary available from
+ * https://ref.gs1.org/tools/gs1-barcode-syntax-resource/syntax-dictionary/
+ *************************************************************************************************
+ */
+
+$basename = basename(__FILE__);
+$dirname = dirname(__FILE__);
+$dirdirname = basename(dirname($dirname)) . '/' . basename($dirname);
+
+$opts = getopt('c:f:h:l:t:');
+
+$print_copyright = isset($opts['c']) ? (bool) $opts['c'] : true;
+$file = isset($opts['f']) ? $opts['f']
+                    : 'https://raw.githubusercontent.com/gs1/gs1-syntax-dictionary/main/gs1-syntax-dictionary.txt';
+$print_h_guard = isset($opts['h']) ? (bool) $opts['h'] : true;
+$use_length_only = isset($opts['l']) ? (bool) $opts['l'] : true;
+$tab = isset($opts['t']) ? $opts['t'] : '    ';
+
+if (($get = file_get_contents($file)) === false) {
+    exit("$basename:" . __LINE__ . " ERROR: Could not read file \"$file\"" . PHP_EOL);
+}
+if (strncasecmp($file, "http", 4) != 0) {
+    // Strip to last 2 directories
+    $stripped_dir = dirname($file);
+    $stripped_file = basename(dirname($stripped_dir)) . '/' . basename($stripped_dir) . '/' . basename($file);
+} else {
+    $stripped_file = $file;
+}
+
+$lines = explode("\n", $get);
+
+$spec_ais = $spec_parts = $spec_funcs = $spec_comments = $fixed_ais = array();
+$batches = array_fill(0, 100, array());
+
+// Parse the lines into AIs and specs
+$line_no = 0;
+foreach ($lines as $line) {
+    $line_no++;
+    if ($line === '' || $line[0] === '#') {
+        continue;
+    }
+    if (!preg_match('/^([0-9]+(?:-[0-9]+)?) +([ *?]* )([NXYZ][0-9.][ NXYZ0-9.,a-z=|+\[\]]*)(?:# (.+))?$/',
+                    $line, $matches)) {
+        print $line . PHP_EOL;
+        exit("$basename:" . __LINE__ . " ERROR: Could not parse line $line_no" . PHP_EOL);
+    }
+    $ai = $matches[1];
+    $flags = trim($matches[2]);
+    $fixed = strpos($flags, "*") !== false;
+    $spec = preg_replace('/ +req=[0-9,n+]*/', '', trim($matches[3])); // Strip mandatory association info
+    $spec = preg_replace('/ +ex=[0-9,n]*/', '', $spec); // Strip invalid pairings info
+    $spec = preg_replace('/ +dlpkey[=0-9,|]*/', '', $spec); // Strip Digital Link primary key info
+    $comment = isset($matches[4]) ? trim($matches[4]) : '';
+
+    if (isset($spec_ais[$spec])) {
+        $ais = $spec_ais[$spec];
+    } else {
+        $ais = array();
+    }
+
+    if (($hyphen = strpos($ai, '-')) !== false) {
+        if ($fixed !== '') {
+            $fixed_ais[substr($ai, 0, 2)] = true;
+        }
+        $ai_s = (int) substr($ai, 0, $hyphen);
+        $ai_e = (int) substr($ai, $hyphen + 1);
+        $ais[] = array($ai_s, $ai_e);
+
+        $batch_s_idx = (int) ($ai_s / 100);
+        $batch_e_idx = (int) ($ai_e / 100);
+        if ($batch_s_idx !== $batch_e_idx) {
+            if (!in_array($spec, $batches[$batch_s_idx])) {
+                $batches[$batch_s_idx][] = $spec;
+            }
+            if (!in_array($spec, $batches[$batch_e_idx])) {
+                $batches[$batch_e_idx][] = $spec;
+            }
+        } else {
+            if (!in_array($spec, $batches[$batch_s_idx])) {
+                $batches[$batch_s_idx][] = $spec;
+            }
+        }
+    } else {
+        if ($fixed !== '') {
+            $fixed_ais[substr($ai, 0, 2)] = true;
+        }
+        $ai = (int) $ai;
+        $ais[] = $ai;
+        $batch_idx = (int) ($ai / 100);
+        if (!in_array($spec, $batches[$batch_idx])) {
+            $batches[$batch_idx][] = $spec;
+        }
+    }
+
+    $spec_ais[$spec] = $ais;
+    if ($comment !== '') {
+        if (isset($spec_comments[$spec])) {
+            if (!in_array($comment, $spec_comments[$spec])) {
+                $spec_comments[$spec][] = $comment;
+            }
+        } else {
+            $spec_comments[$spec] = array($comment);
+        }
+    }
+
+    $spec_parts[$spec] = array();
+    $parts = explode(' ', $spec);
+    foreach ($parts as $part) {
+        $checkers = explode(',', $part);
+        $validator = array_shift($checkers);
+        if (preg_match('/^([NXYZ])([0-9]+)?(\.\.[0-9|]+)?$/', $validator, $matches)) {
+            if (count($matches) === 3) {
+                $min = $max = (int) $matches[2];
+            } else {
+                $min = $matches[2] === '' ? 1 : (int) $matches[2];
+                $max = (int) substr($matches[3], 2);
+            }
+            if ($matches[1] === 'N') {
+                $validator = "numeric";
+            } elseif ($matches[1] === 'X') {
+                $validator = "cset82";
+            } elseif ($matches[1] === 'Y') {
+                $validator = "cset39";
+            } else { // 'Z'
+                $validator = "cset64";
+            }
+        } else if (preg_match('/^\[([NXYZ])([1-9]+)?(\.\.[0-9|]+)?\]$/', $validator, $matches)) {
+            if (count($matches) === 3) {
+                $min = 0;
+                $max = (int) $matches[2];
+            } else {
+                $min = $matches[2] === '' ? 0 : (int) $matches[2];
+                $max = (int) substr($matches[3], 2);
+            }
+            if ($matches[1] === 'N') {
+                $validator = "numeric";
+            } elseif ($matches[1] === 'X') {
+                $validator = "cset82";
+            } elseif ($matches[1] === 'Y') {
+                $validator = "cset39";
+            } else { // 'Z'
+                $validator = "cset64";
+            }
+        } else {
+            exit("$basename:" . __LINE__ . " ERROR: Could not parse validator \"$validator\" line $line_no"
+                    . PHP_EOL);
+        }
+        $spec_parts[$spec][] = array($min, $max, $validator, $checkers);
+    }
+}
+
+// Calculate total min/maxs and convert the AIs into ranges
+
+foreach ($spec_ais as $spec => $ais) {
+    // Total min/maxs
+    $total_min = $total_max = 0;
+    foreach ($spec_parts[$spec] as list($min, $max)) {
+        $total_min += $min;
+        $total_max += $max;
+    }
+
+    // Sort the AIs
+    $sort_ais = array();
+    foreach ($ais as $ai) {
+        if (is_array($ai)) {
+            $sort_ais[] = $ai[0];
+        } else {
+            $sort_ais[] = $ai;
+        }
+    }
+    array_multisort($sort_ais, $ais);
+
+    // Consolidate contiguous AIs into ranges
+    $tmp_ais = array();
+    foreach ($ais as $ai) {
+        $cnt = count($tmp_ais);
+        if ($cnt === 0) {
+            $tmp_ais[] = $ai;
+        } else {
+            $prev_ai = $tmp_ais[$cnt - 1];
+            if (is_array($prev_ai)) {
+                $prev_s = $prev_ai[0];
+                $prev_e = $prev_ai[1];
+            } else {
+                $prev_e = $prev_s = $prev_ai;
+            }
+            if (is_array($ai)) {
+                $this_s = $ai[0];
+                $this_e = $ai[1];
+            } else {
+                $this_s = $this_e = $ai;
+            }
+            if ($this_s === $prev_e + 1 && $this_e - $prev_s < 100) { // Confine to batches of 100
+                $tmp_ais[$cnt - 1] = array($prev_s, $this_e);
+            } else {
+                $tmp_ais[] = $ai;
+            }
+        }
+    }
+
+    // Unconsolidate ranges of 1 into separate entries
+    $ais = array();
+    foreach ($tmp_ais as $ai) {
+        if (is_array($ai) && $ai[1] === $ai[0] + 1) {
+            $ais[] = $ai[0];
+            $ais[] = $ai[1];
+        } else {
+            $ais[] = $ai;
+        }
+    }
+
+    $spec_ais[$spec] = array($total_min, $total_max, $ais);
+}
+
+// Print output
+
+print <<<EOD
+/*
+ * GS1 AI checker generated by "$dirdirname/$basename" from
+ * $stripped_file
+ */
+
+EOD;
+
+if ($print_copyright) {
+print <<<'EOD'
+/*
+    libzint - the open source barcode library
+    Copyright (C) 2021-2024 Robin Stuart <rstuart114@gmail.com>
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+    1. Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+       notice, this list of conditions and the following disclaimer in the
+       documentation and/or other materials provided with the distribution.
+    3. Neither the name of the project nor the names of its contributors
+       may be used to endorse or promote products derived from this software
+       without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+    ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+ */
+/* SPDX-License-Identifier: BSD-3-Clause */
+
+
+EOD;
+}
+
+if ($print_h_guard) {
+print <<<'EOD'
+#ifndef Z_GS1_LINT_H
+#define Z_GS1_LINT_H
+
+
+EOD;
+}
+
+// Print the spec validator/checkers functions
+
+foreach ($spec_parts as $spec => $spec_part) {
+    $spec_funcs[$spec] = $spec_func = str_replace(array(' ', '.', ',', '[', ']'), '_', strtolower($spec));
+    $comment = '';
+    if (isset($spec_comments[$spec])) {
+        $comment = ' (Used by';
+        foreach ($spec_comments[$spec] as $i => $spec_comment) {
+            if ($i) {
+                $comment .= ', ';
+            } else {
+                $comment .= ' ';
+            }
+            $comment .= $spec_comment;
+        }
+        if (strlen($comment) > 118 - 3 /*start comment*/ - 4 /*)end comment*/ - strlen($spec)) {
+            $comment = substr($comment, 0, 118 - 3 - 4 - strlen($spec) - 3) . '...';
+        }
+        $comment .= ')';
+    }
+    print <<<EOD
+/* $spec$comment */
+static int $spec_func(const unsigned char *data,
+$tab$tab{$tab}const int data_len, int *p_err_no, int *p_err_posn, char err_msg[50]) {
+{$tab}return 
+EOD;
+
+    list($total_min, $total_max) = $spec_ais[$spec];
+    if ($total_min === $total_max) {
+        print "data_len == $total_max";
+    } else {
+        print "data_len >= $total_min && data_len <= $total_max";
+    }
+
+    if ($use_length_only) {
+        // Call checkers checking for length only first
+        $length_only_arg = ", 1 /*length_only*/";
+        $offset = 0;
+        foreach ($spec_part as list($min, $max, $validator, $checkers)) {
+            foreach ($checkers as $checker) {
+                print <<<EOD
+
+$tab$tab{$tab}&& $checker(data, data_len, $offset, $min, $max, p_err_no, p_err_posn, err_msg$length_only_arg)
+EOD;
+            }
+
+            $offset += $max;
+        }
+    }
+
+    // Validator and full checkers
+    $length_only_arg = $use_length_only ? ", 0" : "";
+    $offset = 0;
+    foreach ($spec_part as list($min, $max, $validator, $checkers)) {
+        print <<<EOD
+
+$tab$tab{$tab}&& $validator(data, data_len, $offset, $min, $max, p_err_no, p_err_posn, err_msg)
+EOD;
+
+        foreach ($checkers as $checker) {
+            print <<<EOD
+
+$tab$tab{$tab}&& $checker(data, data_len, $offset, $min, $max, p_err_no, p_err_posn, err_msg$length_only_arg)
+EOD;
+        }
+
+        $offset += $max;
+    }
+    print ";\n}\n\n";
+}
+
+// Print main routine
+
+print <<<EOD
+/* Entry point. Returns 1 on success, 0 on failure: `*p_err_no` set to 1 if unknown AI, 2 if bad data length */
+static int gs1_lint(const int ai, const unsigned char *data, const int data_len, int *p_err_no, int *p_err_posn,
+$tab$tab{$tab}char err_msg[50]) {
+
+$tab/* Assume data length failure */
+$tab*p_err_no = 2;
+
+EOD;
+
+// Split AIs into batches of 100 to lessen the number of comparisons
+
+$not_first_batch = false;
+$last_batch_e = -1;
+foreach ($batches as $batch => $batch_specs) {
+    if (empty($batch_specs)) {
+        continue;
+    }
+    $batch_s = $batch * 100;
+    $batch_e = $batch_s + 100;
+    if ($not_first_batch) {
+        print "\n$tab} else if (ai < $batch_e) {\n\n";
+    } else {
+        print "\n{$tab}if (ai < $batch_e) {\n\n";
+        $not_first_batch = true;
+    }
+    foreach ($batch_specs as $spec) {
+        $total_min = $spec_ais[$spec][0];
+        $total_max = $spec_ais[$spec][1];
+        $ais = $spec_ais[$spec][2];
+
+        $str = "$tab{$tab}if (";
+        print $str;
+        $width = strlen($str);
+
+        // Count the applicable AIs
+        $ais_cnt = 0;
+        foreach ($ais as $ai) {
+            if (is_array($ai)) {
+                if ($ai[1] < $batch_s || $ai[0] >= $batch_e) {
+                    continue;
+                }
+            } else {
+                if ($ai < $batch_s || $ai >= $batch_e) {
+                    continue;
+                }
+            }
+            $ais_cnt++;
+        }
+
+        // Output
+        $not_first_ai = false;
+        foreach ($ais as $ai) {
+            if (is_array($ai)) {
+                if ($ai[1] < $batch_s || $ai[0] >= $batch_e) {
+                    continue;
+                }
+            } else {
+                if ($ai < $batch_s || $ai >= $batch_e) {
+                    continue;
+                }
+            }
+
+            $str = '';
+            if ($not_first_ai) {
+                $str .= " || ";
+            } else {
+                $not_first_ai = true;
+            }
+            if (is_array($ai)) {
+                if ($ai[0] === $last_batch_e) { // Don't need 1st element of range if excluded by previous batch
+                    $str .= "ai <= " . $ai[1];
+                } else if ($ai[1] + 1 == $batch_e) { // Don't need 2nd element of range if excluded by this batch
+                    $str .= "ai >= " . $ai[0];
+                } else {
+                    if ($ais_cnt > 1) {
+                        $str .= "(ai >= " . $ai[0] . " && ai <= " . $ai[1] . ")";
+                    } else {
+                        $str .= "ai >= " . $ai[0] . " && ai <= " . $ai[1];
+                    }
+                }
+            } else {
+                $str .= "ai == " . $ai;
+            }
+            if ($width + strlen($str) > 118) {
+                print "\n";
+                $str2 = "$tab$tab$tab   ";
+                print $str2;
+                $width = strlen($str2);
+            }
+            print $str;
+            $width += strlen($str);
+        }
+        $spec_func = $spec_funcs[$spec];
+        $str = "$tab$tab{$tab}return $spec_func(data, data_len, p_err_no, p_err_posn, err_msg);";
+        if (strlen($str) > 118) {
+            print ") {\n$tab$tab{$tab}return $spec_func(data,\n";
+            print "$tab$tab$tab$tab$tab{$tab}data_len, p_err_no, p_err_posn, err_msg);\n";
+        } else {
+            print ") {\n$str\n";
+        }
+        print <<<EOD
+$tab$tab}
+
+EOD;
+    }
+    $last_batch_e = $batch_e;
+}
+
+print <<<EOD
+$tab}
+
+{$tab}/* Unknown AI */
+{$tab}*p_err_no = 1;
+{$tab}return 0;
+}
+
+EOD;
+
+if ($print_h_guard) {
+print <<<'EOD'
+
+#endif /* Z_GS1_LINT_H */
+
+EOD;
+}
+
+/* vim: set ts=4 sw=4 et : */