texlive[72890] trunk: extractbb lua reimplementation, with

commits+karl at tug.org commits+karl at tug.org
Mon Nov 18 23:29:09 CET 2024


Revision: 72890
          https://tug.org/svn/texlive?view=revision&revision=72890
Author:   karl
Date:     2024-11-18 23:29:08 +0100 (Mon, 18 Nov 2024)
Log Message:
-----------
extractbb lua reimplementation, with TEXLIVE_EXTRACTBB envvar (18nov24)

Modified Paths:
--------------
    trunk/Build/source/texk/texlive/linked_scripts/Makefile.am
    trunk/Build/source/texk/texlive/linked_scripts/Makefile.in
    trunk/Build/source/texk/texlive/linked_scripts/scripts.lst
    trunk/Master/bin/aarch64-linux/extractbb
    trunk/Master/bin/amd64-freebsd/extractbb
    trunk/Master/bin/amd64-netbsd/extractbb
    trunk/Master/bin/armhf-linux/extractbb
    trunk/Master/bin/i386-freebsd/extractbb
    trunk/Master/bin/i386-linux/extractbb
    trunk/Master/bin/i386-netbsd/extractbb
    trunk/Master/bin/i386-solaris/extractbb
    trunk/Master/bin/universal-darwin/extractbb
    trunk/Master/bin/x86_64-cygwin/extractbb
    trunk/Master/bin/x86_64-darwinlegacy/extractbb
    trunk/Master/bin/x86_64-linux/extractbb
    trunk/Master/bin/x86_64-linuxmusl/extractbb
    trunk/Master/bin/x86_64-solaris/extractbb
    trunk/Master/tlpkg/bin/tlpkg-ctan-check
    trunk/Master/tlpkg/libexec/ctan2tds
    trunk/Master/tlpkg/tlpsrc/collection-basic.tlpsrc
    trunk/Master/tlpkg/tlpsrc/dvipdfmx.tlpsrc

Added Paths:
-----------
    trunk/Build/source/texk/texlive/linked_scripts/extractbb/
    trunk/Build/source/texk/texlive/linked_scripts/extractbb/extractbb.lua
    trunk/Master/texmf-dist/doc/support/extractbb/
    trunk/Master/texmf-dist/doc/support/extractbb/README.md
    trunk/Master/texmf-dist/scripts/extractbb/
    trunk/Master/texmf-dist/scripts/extractbb/extractbb-scratch.lua
    trunk/Master/texmf-dist/scripts/extractbb/extractbb-wrapper.lua
    trunk/Master/texmf-dist/scripts/extractbb/extractbb.lua
    trunk/Master/tlpkg/tlpsrc/extractbb.tlpsrc

Modified: trunk/Build/source/texk/texlive/linked_scripts/Makefile.am
===================================================================
--- trunk/Build/source/texk/texlive/linked_scripts/Makefile.am	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Build/source/texk/texlive/linked_scripts/Makefile.am	2024-11-18 22:29:08 UTC (rev 72890)
@@ -148,6 +148,7 @@
 	epspdf/epspdftk.tcl \
 	epstopdf/epstopdf.pl \
 	exceltex/exceltex \
+	extractbb/extractbb.lua \
 	fig4latex/fig4latex \
 	findhyph/findhyph \
 	fontools/afm2afm \

Modified: trunk/Build/source/texk/texlive/linked_scripts/Makefile.in
===================================================================
--- trunk/Build/source/texk/texlive/linked_scripts/Makefile.in	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Build/source/texk/texlive/linked_scripts/Makefile.in	2024-11-18 22:29:08 UTC (rev 72890)
@@ -368,6 +368,7 @@
 	epspdf/epspdftk.tcl \
 	epstopdf/epstopdf.pl \
 	exceltex/exceltex \
+	extractbb/extractbb.lua \
 	fig4latex/fig4latex \
 	findhyph/findhyph \
 	fontools/afm2afm \

Added: trunk/Build/source/texk/texlive/linked_scripts/extractbb/extractbb.lua
===================================================================
--- trunk/Build/source/texk/texlive/linked_scripts/extractbb/extractbb.lua	                        (rev 0)
+++ trunk/Build/source/texk/texlive/linked_scripts/extractbb/extractbb.lua	2024-11-18 22:29:08 UTC (rev 72890)
@@ -0,0 +1,71 @@
+#!/usr/bin/env texlua
+-- extractbb-lua
+-- https://github.com/gucci-on-fleek/extractbb
+-- SPDX-License-Identifier: MPL-2.0+
+-- SPDX-FileCopyrightText: 2024 Max Chernoff
+--
+-- A wrapper script to allow you to choose which implementation of extractbb to
+-- use. Should hopefully be replaced with the ``scratch'' file in TeX Live 2025.
+--
+-- v1.0.0 (2024-11-17) %%version %%dashdate
+
+---------------------
+--- Configuration ---
+---------------------
+-- Choose which implementation of extractbb to use.
+local DEFAULT = "wrapper"
+
+
+-----------------
+--- Execution ---
+-----------------
+
+-- Get the value of the environment variable that decides which version to run.
+local env_choice = os.env["TEXLIVE_EXTRACTBB"]
+
+-- If the environment variable is set to a file path, run that directly.
+local env_mode = lfs.attributes(env_choice or "", "mode")
+if (env_mode == "file") or (env_mode == "link") then
+    arg[0] = env_choice
+    table.insert(arg, 1, env_choice)
+    arg[-1] = nil
+    return os.exec(arg)
+end
+
+-- Map the choice names to file names.
+kpse.set_program_name("texlua", "extractbb")
+local choice_mapping = {
+    wrapper = kpse.find_file("extractbb-wrapper.lua", "lua", true),
+    scratch = kpse.find_file("extractbb-scratch.lua", "lua", true),
+}
+
+-- Choose the implementation to run.
+local choice = choice_mapping[env_choice] or choice_mapping[DEFAULT]
+
+if not choice then
+    print("No implementation of extractbb found. Exiting.")
+    os.exit(1)
+end
+
+-- Make sure that the script is not writable.
+if kpse.out_name_ok_silent_extended(choice) then
+    if os.env["TEXLIVE_EXTRACTBB_UNSAFE"] == "unsafe" then
+        -- If we're running in development mode, then we can allow this.
+    else
+        print("Refusing to run a writable script. Exiting.")
+        os.exit(1)
+    end
+end
+
+-- Make sure that the script is beside this one, just to be safe
+local split_dir_pattern = "^(.*)[/\\]([^/\\]-)$"
+local current_dir, current_name = arg[0]:match(split_dir_pattern)
+local choice_dir, choice_name = choice:match(split_dir_pattern)
+
+if current_dir ~= choice_dir then
+    print("Refusing to run a script from a different directory. Exiting.")
+    os.exit(1)
+end
+
+-- And run it.
+dofile(choice)


Property changes on: trunk/Build/source/texk/texlive/linked_scripts/extractbb/extractbb.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Modified: trunk/Build/source/texk/texlive/linked_scripts/scripts.lst
===================================================================
--- trunk/Build/source/texk/texlive/linked_scripts/scripts.lst	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Build/source/texk/texlive/linked_scripts/scripts.lst	2024-11-18 22:29:08 UTC (rev 72890)
@@ -89,6 +89,7 @@
 epspdf/epspdftk.tcl
 epstopdf/epstopdf.pl
 exceltex/exceltex
+extractbb/extractbb.lua
 fig4latex/fig4latex
 findhyph/findhyph
 fontools/afm2afm

Modified: trunk/Master/bin/aarch64-linux/extractbb
===================================================================
--- trunk/Master/bin/aarch64-linux/extractbb	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Master/bin/aarch64-linux/extractbb	2024-11-18 22:29:08 UTC (rev 72890)
@@ -1 +1 @@
-link ../../texmf-dist/scripts/texlive/extractbb.lua
\ No newline at end of file
+link ../../texmf-dist/scripts/extractbb/extractbb.lua
\ No newline at end of file

Modified: trunk/Master/bin/amd64-freebsd/extractbb
===================================================================
--- trunk/Master/bin/amd64-freebsd/extractbb	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Master/bin/amd64-freebsd/extractbb	2024-11-18 22:29:08 UTC (rev 72890)
@@ -1 +1 @@
-link ../../texmf-dist/scripts/texlive/extractbb.lua
\ No newline at end of file
+link ../../texmf-dist/scripts/extractbb/extractbb.lua
\ No newline at end of file

Modified: trunk/Master/bin/amd64-netbsd/extractbb
===================================================================
--- trunk/Master/bin/amd64-netbsd/extractbb	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Master/bin/amd64-netbsd/extractbb	2024-11-18 22:29:08 UTC (rev 72890)
@@ -1 +1 @@
-link ../../texmf-dist/scripts/texlive/extractbb.lua
\ No newline at end of file
+link ../../texmf-dist/scripts/extractbb/extractbb.lua
\ No newline at end of file

Modified: trunk/Master/bin/armhf-linux/extractbb
===================================================================
--- trunk/Master/bin/armhf-linux/extractbb	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Master/bin/armhf-linux/extractbb	2024-11-18 22:29:08 UTC (rev 72890)
@@ -1 +1 @@
-link ../../texmf-dist/scripts/texlive/extractbb.lua
\ No newline at end of file
+link ../../texmf-dist/scripts/extractbb/extractbb.lua
\ No newline at end of file

Modified: trunk/Master/bin/i386-freebsd/extractbb
===================================================================
--- trunk/Master/bin/i386-freebsd/extractbb	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Master/bin/i386-freebsd/extractbb	2024-11-18 22:29:08 UTC (rev 72890)
@@ -1 +1 @@
-link ../../texmf-dist/scripts/texlive/extractbb.lua
\ No newline at end of file
+link ../../texmf-dist/scripts/extractbb/extractbb.lua
\ No newline at end of file

Modified: trunk/Master/bin/i386-linux/extractbb
===================================================================
--- trunk/Master/bin/i386-linux/extractbb	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Master/bin/i386-linux/extractbb	2024-11-18 22:29:08 UTC (rev 72890)
@@ -1 +1 @@
-link ../../texmf-dist/scripts/texlive/extractbb.lua
\ No newline at end of file
+link ../../texmf-dist/scripts/extractbb/extractbb.lua
\ No newline at end of file

Modified: trunk/Master/bin/i386-netbsd/extractbb
===================================================================
--- trunk/Master/bin/i386-netbsd/extractbb	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Master/bin/i386-netbsd/extractbb	2024-11-18 22:29:08 UTC (rev 72890)
@@ -1 +1 @@
-link ../../texmf-dist/scripts/texlive/extractbb.lua
\ No newline at end of file
+link ../../texmf-dist/scripts/extractbb/extractbb.lua
\ No newline at end of file

Modified: trunk/Master/bin/i386-solaris/extractbb
===================================================================
--- trunk/Master/bin/i386-solaris/extractbb	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Master/bin/i386-solaris/extractbb	2024-11-18 22:29:08 UTC (rev 72890)
@@ -1 +1 @@
-link ../../texmf-dist/scripts/texlive/extractbb.lua
\ No newline at end of file
+link ../../texmf-dist/scripts/extractbb/extractbb.lua
\ No newline at end of file

Modified: trunk/Master/bin/universal-darwin/extractbb
===================================================================
--- trunk/Master/bin/universal-darwin/extractbb	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Master/bin/universal-darwin/extractbb	2024-11-18 22:29:08 UTC (rev 72890)
@@ -1 +1 @@
-link ../../texmf-dist/scripts/texlive/extractbb.lua
\ No newline at end of file
+link ../../texmf-dist/scripts/extractbb/extractbb.lua
\ No newline at end of file

Modified: trunk/Master/bin/x86_64-cygwin/extractbb
===================================================================
--- trunk/Master/bin/x86_64-cygwin/extractbb	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Master/bin/x86_64-cygwin/extractbb	2024-11-18 22:29:08 UTC (rev 72890)
@@ -1 +1 @@
-link ../../texmf-dist/scripts/texlive/extractbb.lua
\ No newline at end of file
+link ../../texmf-dist/scripts/extractbb/extractbb.lua
\ No newline at end of file

Modified: trunk/Master/bin/x86_64-darwinlegacy/extractbb
===================================================================
--- trunk/Master/bin/x86_64-darwinlegacy/extractbb	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Master/bin/x86_64-darwinlegacy/extractbb	2024-11-18 22:29:08 UTC (rev 72890)
@@ -1 +1 @@
-link ../../texmf-dist/scripts/texlive/extractbb.lua
\ No newline at end of file
+link ../../texmf-dist/scripts/extractbb/extractbb.lua
\ No newline at end of file

Modified: trunk/Master/bin/x86_64-linux/extractbb
===================================================================
--- trunk/Master/bin/x86_64-linux/extractbb	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Master/bin/x86_64-linux/extractbb	2024-11-18 22:29:08 UTC (rev 72890)
@@ -1 +1 @@
-link ../../texmf-dist/scripts/texlive/extractbb.lua
\ No newline at end of file
+link ../../texmf-dist/scripts/extractbb/extractbb.lua
\ No newline at end of file

Modified: trunk/Master/bin/x86_64-linuxmusl/extractbb
===================================================================
--- trunk/Master/bin/x86_64-linuxmusl/extractbb	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Master/bin/x86_64-linuxmusl/extractbb	2024-11-18 22:29:08 UTC (rev 72890)
@@ -1 +1 @@
-link ../../texmf-dist/scripts/texlive/extractbb.lua
\ No newline at end of file
+link ../../texmf-dist/scripts/extractbb/extractbb.lua
\ No newline at end of file

Modified: trunk/Master/bin/x86_64-solaris/extractbb
===================================================================
--- trunk/Master/bin/x86_64-solaris/extractbb	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Master/bin/x86_64-solaris/extractbb	2024-11-18 22:29:08 UTC (rev 72890)
@@ -1 +1 @@
-link ../../texmf-dist/scripts/texlive/extractbb.lua
\ No newline at end of file
+link ../../texmf-dist/scripts/extractbb/extractbb.lua
\ No newline at end of file

Added: trunk/Master/texmf-dist/doc/support/extractbb/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/support/extractbb/README.md	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/support/extractbb/README.md	2024-11-18 22:29:08 UTC (rev 72890)
@@ -0,0 +1,81 @@
+<!-- extractbb-lua
+     https://github.com/gucci-on-fleek/extractbb
+     SPDX-License-Identifier: MPL-2.0+ OR CC-BY-SA-4.0+
+     SPDX-FileCopyrightText: 2024 Max Chernoff
+-->
+
+`extractbb-lua`
+===============
+
+A reimplementation of
+[`extractbb`](https://texdoc.org/serve/extractbb/0), written in Lua.
+
+
+Variants
+--------
+
+There are two variants of `extractbb-lua`:
+
+- **`wrapper`**: A wrapper script around the original `xdvipdmfx`-based
+  `extractbb` that is used to fix a security vulernability in
+  `xdvipdfmx`.
+
+- **`scratch`**: A standalone implementation of `extractbb`, written in
+  Lua from scratch, with no dependencies on `xdvipdfmx`.
+
+Currently, the script `extractbb` defaults to the `wrapper` variant, but
+you can manually select any specific variant by setting the
+`TEXLIVE_EXTRACTBB` environment variable to either `wrapper` or
+`scratch`.
+
+> [!WARNING]
+> The `scratch` variant is still in development and may be buggy or
+> insecure.
+
+
+### Secret Developer Options
+
+If you set `TEXLIVE_EXTRACTBB` to the full path of an executable, it
+will run that directly. And if you set
+`TEXLIVE_EXTRACTBB_UNSAFE=unsafe`, then it will ignore some of the
+security checks.
+
+
+Support
+-------
+
+If you have any problems with this tool, please report it (in order of
+preference):
+
+1. By [opening a new issue on
+   GitHub](https://github.com/gucci-on-fleek/extractbb/issues/new).
+
+2. Via email to the public [`tex-live at tug.org` mailing list](https://tug.org/mailman/listinfo/tex-live).
+
+3. By contacting the author directly at `tex at maxchernoff.ca`.
+
+
+Building
+--------
+
+Please see the file
+[`BUILDING.md`](https://github.com/gucci-on-fleek/extractbb/blob/master/BUILDING.md)
+on GitHub.
+
+
+Licence
+-------
+
+`extractbb-lua` is licensed under the [_Mozilla Public License_, version
+2.0](https://www.mozilla.org/en-US/MPL/2.0/) or greater. The
+documentation is additionally licensed under [CC-BY-SA, version
+4.0](https://creativecommons.org/licenses/by-sa/4.0/legalcode) or
+greater.
+
+The test files have various licences, please see the file
+[`tests/LICENCE.md`](tests/LICENCE.md) for more information. (Since
+these files are not distributed with the package, neither is this
+licence file.)
+
+---
+_v1.0.0 (2024-11-17)_ <!--%%version %%dashdate-->


Property changes on: trunk/Master/texmf-dist/doc/support/extractbb/README.md
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/scripts/extractbb/extractbb-scratch.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/extractbb/extractbb-scratch.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/scripts/extractbb/extractbb-scratch.lua	2024-11-18 22:29:08 UTC (rev 72890)
@@ -0,0 +1,695 @@
+#!/usr/bin/env texlua
+-- extractbb-lua
+-- https://github.com/gucci-on-fleek/extractbb
+-- SPDX-License-Identifier: MPL-2.0+
+-- SPDX-FileCopyrightText: 2024 Max Chernoff
+--
+-- Inclusion Methods
+-- =================
+--
+-- This script can use two different methods to extract bounding boxes from
+-- images: the "img" module and the "pdfe" module. The "img" module will be
+-- automatically selected in most cases and supports all image types that are
+-- supported by the original "extractbb" program. If and only if the "img"
+-- module fails to load, the "pdfe" module will be used as a fallback. However,
+-- the "pdfe" module only supports PDF files. Both modules are built in to the
+-- LuaTeX binaries, however due to some technical issues, the "img" module may
+-- fail to load on some more exotic platforms.
+--
+--
+-- Compatibility
+-- =============
+--
+-- Based off of my testing, this Lua script is 100% compatible with the original
+-- C-based "extractbb" program, with the following exceptions:
+--
+--   * When running in "img" mode, the PDF version is always reported as "1.5".
+--
+--   * When running in "img" mode, if the requested bounding box is not found,
+--     the script will fallback to the Crop box or the Media box, instead of
+--     following the original fallback order. (In practice, almost all PDFs set
+--     all their bounding boxes equal to each other, and even if the boxes are
+--     set to different values, the script will still return the requested box,
+--     provided that it is set in the PDF.)
+--
+--   * When running in "pdfe" mode, only PDF files are supported.
+--
+-- All of these issues are very unlikely to affect any real-world documents.
+--
+--
+-- Security
+-- ========
+--
+-- This script is designed to be safely ran from restricted shell escape. A few
+-- security features:
+--
+--   * The majority of this script runs inside a sandboxed Lua environment,
+--     which only exposes a very restricted set of functions.
+--
+--   * All file-related functions available inside the sandbox first check with
+--     kpathsea to ensure that the file is allowed to be opened.
+--
+--   * In the event of any errors, the script immediately exits.
+--
+--   * This script does not run (fork/exec) any external programs.
+--
+--   * This script is written entirely in Lua, so overflow/use-after-free
+--     vulnerabilities are not possible.
+--
+-- Some potential security concerns:
+--
+--   * This script has not been audited or reviewed by anyone other than myself.
+--
+--   * Using the "ffi" module to load the "img" library is technically undefined
+--     behaviour, and as such may potentially lead to unforeseen security
+--     issues.
+--
+--   * The underlying LuaTeX modules may themselves have security
+--     vulnerabilities, which would be inherited by this script.
+
+
+----------------------
+--- Initialization ---
+----------------------
+
+-- Pre-sandbox variables/constants
+local show_errors = true
+local SOURCE_DATE_EPOCH = tonumber(os.getenv("SOURCE_DATE_EPOCH"))
+local version = "extractbb.lua v1.0.0 (2024-11-17)" --%%version %%dashdate
+
+-- Required for any kpathsea calls to work.
+kpse.set_program_name("texlua", "extractbb")
+
+
+--------------------------
+--- Questionable Hacks ---
+--------------------------
+
+-- LuaTeX doesn't load the "img" library in "texlua" mode, so we need this
+-- questionable hack to load it manually. We do it inside of "pcall" since there
+-- are some exotic platforms where the "ffi" module is unsupported.
+pcall(function()
+    local ffi = package.loaded.ffi
+
+    ffi.cdef[[
+        typedef struct lua_State lua_State;
+        typedef int (*lua_CFunction) (lua_State *L);
+
+        lua_State *Luas;
+        void luaL_requiref(lua_State *L, const char *modname,
+                            lua_CFunction openf, int glb);
+        int luaopen_img(lua_State * L);
+
+        int lua_only;
+    ]]
+
+    -- Basic initialization
+    ffi.C.lua_only = 0
+    tex.initialize()
+
+    -- "tex" module
+    _G.tex = package.loaded.tex
+    tex.enableprimitives("", tex.extraprimitives())
+    tex.outputmode = 1
+    tex.interactionmode = 0
+
+    -- "pdf" module
+    _G.pdf = package.loaded.pdf
+    pdf.setignoreunknownimages(1)
+    pdf.setmajorversion(2)
+    pdf.setminorversion(0)
+
+    -- "img" module
+    ffi.C.luaL_requiref(ffi.C.Luas, "img", ffi.C.luaopen_img, 1)
+end)
+
+-- In case of failure, define an empty "img" table.
+if not img then
+    _G.img = {}
+end
+
+
+------------------
+--- Sandboxing ---
+------------------
+
+-- Prepare the sandbox for the rest of the script.
+local env = {
+    arg      = arg,
+    io       = { stdout = io.stdout, },
+    ipairs   = ipairs,
+    math     = math,
+    os       = { date = os.date, exit = os.exit, },
+    pairs    = pairs,
+    pdfe     = pdfe,
+    print    = print,
+    select   = select,
+    table    = table,
+    tonumber = tonumber,
+    type     = type,
+}
+
+do
+    -- Saved global functions
+    local debug_traceback  = debug.traceback
+    local find_file        = kpse.find_file
+    local img_scan         = img.scan
+    local io_open          = io.open
+    local io_stderr        = io.stderr
+    local kpse_in_name_ok  = kpse.in_name_ok
+    local kpse_out_name_ok = kpse.out_name_ok
+    local kpse_var_value   = kpse.var_value
+    local lfs_attributes   = lfs.attributes
+    local os_exit          = os.exit
+    local os_setenv        = os.setenv
+    local pdfe_open        = pdfe.open
+    local select           = select
+    local tostring         = tostring
+
+    -- Error messages
+    local function error(...)
+        if show_errors then
+            -- Header
+            io_stderr:write("! extractbb ERROR: ")
+
+            -- Message
+            for i = 1, select("#", ...) do
+                io_stderr:write(tostring(select(i, ...)), " ")
+            end
+
+            -- Traceback
+            io_stderr:write("\n", "\n")
+            io_stderr:write(debug_traceback(nil, 2), "\n")
+        end
+
+        -- Flush and exit
+        io_stderr:flush()
+        os_exit(1)
+    end
+
+    env.error = error
+
+    -- Make sure that "openin_any" is at least "restricted", and that
+    -- "openout_any" is at least "paranoid".
+    local initial_openin  = kpse_var_value("openin_any")
+    local initial_openout = kpse_var_value("openout_any")
+
+    if (initial_openin ~= "r") or (initial_openout ~= "p") then
+        os_setenv("openin_any",  "r")
+    end
+
+    if (initial_openout ~= "p") then
+        os_setenv("openout_any", "p")
+    end
+
+    -- Check the input paths.
+    local function resolve_input_name(file_name)
+        local file_path = find_file(file_name, "graphic/figure", true)
+        if not file_path then
+            error("Cannot find input file:", file_name)
+        end
+
+        local allowed = kpse_in_name_ok(file_path)
+        if not allowed then
+            error("Input file is not allowed:", file_path)
+        end
+
+        local mode = lfs_attributes(file_path, "mode")
+        if mode ~= "file" then
+            error("Input file is not a regular file:", file_path)
+        end
+
+        return file_path
+    end
+
+    -- Check the output paths.
+    local function resolve_output_name(file_name)
+        local allowed = kpse_out_name_ok(file_name)
+        if not allowed then
+            error("Output file is not allowed:", file_name)
+        end
+
+        local name, extension = file_name:match("(.+)%.([^.]-)$")
+
+        if (not name) or (not extension) or
+           (name == "") or (extension == "")
+        then
+            error("Output file has no extension:", file_name)
+        end
+
+        if (extension ~= "xbb") and (extension ~= "bb") then
+            error("Output file has an invalid extension:", file_name)
+        end
+
+        -- We shouldn't allow files with weird characters in their names.
+        if name:match("[%c%%\t\r\n><*|]") then
+            error("Output file has an invalid name:", file_name)
+        end
+
+        return file_name
+    end
+
+    -- Opens a file.
+    function env.open_file(file_name, read_write, binary_text)
+        local file_path, mode
+        if read_write == "read" then
+            file_path = resolve_input_name(file_name)
+            mode = "r"
+        elseif read_write == "write" then
+            file_path = resolve_output_name(file_name)
+            mode = "w"
+        else
+            error("Invalid read/write mode:", read_write)
+        end
+
+        if binary_text == "binary" then
+            mode = mode .. "b"
+        elseif binary_text == "text" then
+            mode = mode .. ""
+        else
+            error("Invalid binary/text mode:", binary_text)
+        end
+
+        local file, message = io_open(file_path, mode)
+
+        if not file then
+            error("Cannot open file:", file_path, message)
+        end
+
+        return file
+    end
+
+    -- Open an PDF file.
+    function env.pdfe.open(file_name)
+        local file_path = resolve_input_name(file_name)
+        return pdfe_open(file_path)
+    end
+
+    -- Open an image file.
+    function env.open_image(file_name, page, box)
+        local file_path = resolve_input_name(file_name)
+        return img_scan {
+            filename = file_path,
+            filepath = file_path,
+            page     = page,
+            pagebox  = box,
+        }
+    end
+
+    if not img_scan then
+        env.open_image = false
+    end
+end
+
+-- Prevent trying to change the environment.
+local function bad_index(...)
+    env.error("Attempt to access an undefined index:", select(2, ...))
+end
+
+setmetatable(env, {
+    __index     = bad_index,
+    __metatable = false,
+    __newindex  = bad_index,
+})
+
+-- Set the environment.
+_ENV = env
+
+
+-----------------------------------
+--- Post-Sandbox Initialization ---
+-----------------------------------
+
+-- Constants
+local BP_TO_SP    = 65781.76
+local IN_TO_BP    = 72
+
+-- Save often-used globals for a slight speed boost.
+local floor            = math.floor
+local insert           = table.insert
+local remove           = table.remove
+local script_arguments = arg
+local unpack           = table.unpack
+
+-- General-purpose functions
+local function round(number)
+    return floor(number +0.5)
+end
+
+
+-------------------------
+--- Argument Handling ---
+-------------------------
+
+-- Define the argument handling functions.
+local process_arguments = {}
+
+-- > Specify a PDF pagebox for bounding box
+-- > pagebox=cropbox, mediabox, artbox, trimbox, bleedbox
+local bbox_option = "auto"
+function process_arguments.B(script_arguments)
+    bbox_option = remove(script_arguments, 1)
+end
+
+-- > Show this help message and exit
+function process_arguments.h(script_arguments)
+    print [[
+Usage: extractbb [-B pagebox] [-p page] [-q|-v] [-O] [-m|-x] FILE...
+       extractbb --help|--version
+Extract bounding box from PDF, PNG, JPEG, JP2, or BMP file; default output below.
+
+Options:
+  -B pagebox    Specify a PDF pagebox for bounding box
+                pagebox=cropbox, mediabox, artbox, trimbox, bleedbox
+  -h | --help   Show this help message and exit
+  --version     Output version information and exit
+  -p page       Specify a PDF page to extract bounding box
+  -q            Be quiet
+  -v            Be verbose
+  -O            Write output to stdout
+  -m            Output .bb  file used in DVIPDFM (default)
+  -x            Output .xbb file used in DVIPDFMx
+]]
+    os.exit(0)
+end
+
+process_arguments["-help"] = process_arguments.h
+
+-- > Output version information and exit
+function process_arguments.V(script_arguments)
+    print(version)
+    os.exit(0)
+end
+
+process_arguments["-version"] = process_arguments.V
+
+-- > Specify a PDF page to extract bounding box
+local page_number = 1
+function process_arguments.p(script_arguments)
+    page_number = tonumber(remove(script_arguments, 1))
+end
+
+-- > Be quiet
+function process_arguments.q(script_arguments)
+    show_errors = false
+end
+
+-- > Be verbose
+function process_arguments.v(script_arguments)
+    show_errors = true
+end
+
+-- > Write output to stdout
+local output_file
+function process_arguments.O(script_arguments)
+    output_file = io.stdout
+end
+
+-- Output format
+local output_format = "xbb"
+
+if script_arguments[0]:match("ebb") then
+    output_format = "bb"
+end
+
+-- > Output .bb  file used in DVIPDFM (default)
+function process_arguments.m(script_arguments)
+    output_format = "bb"
+end
+
+-- > Output .xbb file used in DVIPDFMx
+function process_arguments.x(script_arguments)
+    output_format = "xbb"
+end
+
+-- Get the input file name.
+local input_name
+function process_arguments.i(script_arguments)
+    input_name = remove(script_arguments, 1)
+end
+
+process_arguments["-input-name"] = process_arguments.i
+
+-- Clear the interpreter and script names.
+script_arguments[-1] = nil
+script_arguments[0]  = nil
+
+-- Process the arguments.
+while script_arguments[1] do
+    -- Get the next argument.
+    local arg = remove(script_arguments, 1)
+    local cmd = arg:match("^%-(.*)$")
+
+    -- Default to "--input-name" if no command is given.
+    if not cmd then
+        insert(script_arguments, 1, arg)
+        cmd = "-input-name"
+    end
+
+    -- Handle multi-character arguments.
+    if (cmd:len() >= 2) and (not cmd:match("^%-")) then
+        local i = 0
+        for char in cmd:gmatch(".") do
+            i = i + 1
+            insert(script_arguments, i, "-" .. char)
+        end
+
+        goto continue
+    end
+
+    -- Get the function to process the argument and run it.
+    local func = process_arguments[cmd]
+
+    if not func then
+        error("Invalid argument:", arg)
+    end
+
+    func(script_arguments)
+
+    ::continue::
+end
+
+-- Validate the arguments.
+if not type(page_number) == "number" then
+    error("Invalid page number:", page_number)
+end
+
+if not input_name then
+    error("No input file specified.")
+end
+
+-- Validate the bounding box type. We need this rather crazy fallback scheme
+-- to match the behaviour of "extractbb".
+local bbox_orders = {}
+bbox_orders.mediabox = {
+    { img = "media", pdfe = "MediaBox" },
+}
+bbox_orders.cropbox = {
+    { img = "crop", pdfe = "CropBox" }, unpack(bbox_orders.mediabox)
+}
+bbox_orders.artbox = {
+    { img = "art", pdfe = "ArtBox" }, unpack(bbox_orders.cropbox)
+}
+bbox_orders.trimbox = {
+    { img = "trim", pdfe = "TrimBox" }, unpack(bbox_orders.artbox)
+}
+bbox_orders.bleedbox = {
+    { img = "bleed", pdfe = "BleedBox" }, unpack(bbox_orders.trimbox)
+}
+bbox_orders.auto = {
+    bbox_orders.cropbox[1], bbox_orders.artbox[1], bbox_orders.trimbox[1],
+    bbox_orders.bleedbox[1], bbox_orders.mediabox[1],
+}
+
+local bbox_order = bbox_orders[bbox_option]
+
+if not bbox_order then
+    error("Invalid PDF box type:", bbox_option)
+end
+
+-- Set the default pixel resolution.
+local default_dpi
+if output_format == "xbb" then
+    default_dpi = 72
+elseif output_format == "bb" then
+    default_dpi = 100
+else
+    error("Invalid output format:", output_format)
+end
+
+-- Open the output file.
+if not output_file then
+    local base_name   = input_name:match("(.+)%.([^.]-)$") or input_name
+    local output_name = base_name .. "." .. output_format
+    output_file = open_file(output_name, "write", "text")
+end
+
+
+------------------------
+--- Image Processing ---
+------------------------
+
+local x_min, y_min, x_max, y_max
+local num_pages, image_type
+local pdf_major_version, pdf_minor_version
+
+if open_image then
+    -- Check the number of pages.
+    local image = open_image(input_name)
+    num_pages = image.pages
+
+    if page_number > num_pages then
+        error("Invalid page number:", page_number)
+    end
+
+    -- Open the image to the specified page and bounding box. If the requested
+    -- bounding box is not available, LuaTeX will fall back to the crop box
+    -- or the media box.
+    image = open_image(input_name, page_number, bbox_order[1].img)
+
+    if not image then
+        error("Cannot open image:", input_name)
+    end
+
+    -- Get the image metadata.
+    image_type   = image.imagetype
+    local bounding_box = image.bbox
+
+    if not bounding_box then
+        error("Cannot get bounding box:", page_number)
+    end
+
+    local x_resolution = image.xres
+    local y_resolution = image.yres
+
+    if (x_resolution or 0) == 0 then
+        x_resolution = default_dpi
+    end
+
+    if (y_resolution or 0) == 0 then
+        y_resolution = default_dpi
+    end
+
+    -- Convert the bounding box to PostScript points.
+    for i, dimen in ipairs(bounding_box) do
+        if image_type == "pdf" then
+            dimen = dimen / BP_TO_SP
+        else
+            if i % 2 == 1 then
+                dimen = dimen / x_resolution * IN_TO_BP
+            else
+                dimen = dimen / y_resolution * IN_TO_BP
+            end
+        end
+
+        bounding_box[i] = dimen
+    end
+
+    -- Save the bounding box.
+    x_min, y_min, x_max, y_max = unpack(bounding_box)
+
+    -- We can't get the PDF version with the "img" library, so we'll just
+    -- pretend that it's v1.5 (which supports most features).
+    pdf_major_version = 1
+    pdf_minor_version = 5
+else
+    -- Fallback to PDFs only.
+    image_type = "pdf"
+    local document = pdfe.open(input_name)
+
+    if pdfe.getstatus(document) ~= 0 then
+        error("Cannot open PDF file:", input_name)
+    end
+
+    -- Check the number of pages.
+    num_pages = pdfe.getnofpages(document)
+
+    if type(num_pages) ~= "number" then
+        error("Invalid number of pages:", num_pages)
+    end
+
+    if page_number > num_pages then
+        error("Invalid page number:", page_number)
+    end
+
+    -- Get the page.
+    local page = pdfe.getpage(document, page_number)
+
+    if not page then
+        error("Cannot get page:", page_number)
+    end
+
+    -- Get the bounding box. Here, we check the boxes in the exact same order
+    -- that "extractbb" does.
+    local bounding_box
+    for _, bbox in ipairs(bbox_order) do
+        bounding_box = pdfe.getbox(page, bbox.pdfe)
+
+        if bounding_box then
+            break
+        end
+    end
+
+    if not bounding_box then
+        error("Cannot get bounding box:", page_number)
+    end
+
+    -- Save the bounding box.
+    x_min, y_min, x_max, y_max = unpack(bounding_box)
+
+    -- Get the PDF version.
+    pdf_major_version, pdf_minor_version = pdfe.getversion(document)
+end
+
+-- Validate the bounding box.
+for _, dimen in ipairs { x_min, y_min, x_max, y_max } do
+    if type(dimen) ~= "number" then
+        error("Invalid bounding box:", x_min, y_min, x_max, y_max)
+    end
+end
+
+
+--------------
+--- Output ---
+--------------
+
+-- Get the output fields and values.
+local lines = {}
+
+insert(lines, ("Title: %s"):format(input_name))
+insert(lines, ("Creator: %s"):format(version))
+insert(lines,
+       ("BoundingBox: %d %d %d %d")
+       :format(round(x_min), round(y_min), round(x_max), round(y_max)))
+
+if output_format == "xbb" then
+    insert(lines,
+           ("HiResBoundingBox: %0.6f %0.6f %0.6f %0.6f")
+           :format(x_min, y_min, x_max, y_max))
+
+    if image_type == "pdf" then
+        insert(lines,
+               ("PDFVersion: %d.%d")
+               :format(pdf_major_version, pdf_minor_version))
+
+        insert(lines, ("Pages: %d"):format(num_pages))
+    end
+
+end
+
+insert(lines, ("CreationDate: %s"):format(os.date("%c", SOURCE_DATE_EPOCH)))
+
+-- Create the output text.
+local begin_line = "%%"
+local end_line   = "\n"
+
+local text = begin_line ..
+             table.concat(lines, end_line .. begin_line) ..
+             end_line .. end_line
+
+-- Write the output text.
+output_file:write(text)
+output_file:close()
+
+-- Everything is done, so now we can exit.
+os.exit(0)


Property changes on: trunk/Master/texmf-dist/scripts/extractbb/extractbb-scratch.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/texmf-dist/scripts/extractbb/extractbb-wrapper.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/extractbb/extractbb-wrapper.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/scripts/extractbb/extractbb-wrapper.lua	2024-11-18 22:29:08 UTC (rev 72890)
@@ -0,0 +1,270 @@
+#!/usr/bin/env texlua
+-- extractbb-lua
+-- https://github.com/gucci-on-fleek/extractbb
+-- SPDX-License-Identifier: MPL-2.0+
+-- SPDX-FileCopyrightText: 2024 Max Chernoff
+--
+-- A generic wrapper to make commands safe to run with restricted shell escape.
+--
+-- Originally created for extractbb, which is listed in shell_escape_commands,
+-- but can be run as dvipdfm(x), which in turn can run arbitrary commands
+-- using its -D option.
+--
+-- The idea is to exec "ebb --ebb <other args>", since only argv[1] is
+-- used by dvipdfmx to determine its behavior.
+--
+-- Note: This script can only adjust the paths and arguments of the target
+-- executable; it *CANNOT* make an arbitrary program safe to run with
+-- restricted shell escape.
+
+-- A shorter, less paranoid version.
+-- (Prepend a hyphen to the line below to enable).
+--[=[
+arg[0] = arg[0]:gsub("extractbb", "ebb")
+table.insert(arg, 1, "ebb")
+table.insert(arg, 2, "--extractbb")
+os.exec(arg)
+os.exit(1)
+--]=]
+
+---------------------
+--- Configuration ---
+---------------------
+
+-- The base name of this script. (Example: ``extractbb'')
+local SCRIPT_NAME = "extractbb"
+
+-- The base name of the path to the target program. (Example: ``xdvipdfmx'')
+local TARGET_PATH_NAME = "xdvipdfmx"
+
+-- The name to use when calling the target program. Equivalent to ``argv[0]''
+-- in C. (Example: ``extractbb'')
+local TARGET_EXEC_NAME = "ebb"
+
+-- Any extra arguments to be prepended to the target program, before any
+-- user-supplied arguments. Equivalent to ``argv[1], ...'' in C.
+-- (Example: ``--extractbb'')
+local TARGET_PREPEND_ARGS = { "--extractbb" }
+
+-- Any extra arguments to be appended to the target program, after any
+-- user-supplied arguments. Equivalent to ``..., argv[argc]'' in C.
+local TARGET_APPEND_ARGS = {}
+
+-- Sets the value of ``openin_any'' to this value. If ``nil'', then the value
+-- will be left unchanged. (Example: ``r'')
+local READ_PERMS = "r"
+
+-- Sets the value of ``openout_any'' to this value. If ``nil'', then the value
+-- will be left unchanged. (Example: ``p'')
+local WRITE_PERMS = "p"
+
+-- The name of the Lua interpreter. (Example: ``texlua'')
+local INTERPRETER_NAME = "texlua"
+
+-- The extension of the interpreter. Extensionless-names are also permitted.
+-- (Example: ``exe'')
+local INTERPRETER_EXT = "exe"
+
+
+----------------------
+--- Initialization ---
+----------------------
+
+-- Save often-used globals for a slight speed boost.
+local insert = table.insert
+
+-- Set the kpathsea program name
+kpse.set_program_name(INTERPRETER_NAME, SCRIPT_NAME)
+
+-- Rename the input arguments so we don't get confused
+local script_args = arg
+
+
+----------------------------
+--- Function Definitions ---
+----------------------------
+
+-- Error messages
+local function error(title, details)
+    -- Header
+    io.stderr:write("! extractbb ERROR: ")
+    io.stderr:write(title)
+    io.stderr:write(".\n\nTechnical Details:\n")
+
+    -- Messages
+    for key, value in pairs(details) do
+        io.stderr:write(tostring(key), ": ")
+        io.stderr:write("(", type(value), ") ")
+        io.stderr:write(tostring(value), "\n")
+    end
+
+    -- Traceback
+    io.stderr:write("\n")
+    io.stderr:write(debug.traceback(nil, 2), "\n")
+
+    -- Flush and exit
+    io.stderr:flush()
+    os.exit(1)
+end
+
+-- Get the directory, name, and extension from a full path. We'll split on
+-- either a forward or backward slash---Windows can use either, and we don't
+-- need to support Unix systems with TL installed to a directory with
+-- backslashes in its name.
+local split_dir_pattern = "^(.*)[/\\]([^/\\]-)$"
+local split_ext_pattern = "(.*)%.([^.]-)$"
+
+local function split_path(path)
+    -- Make sure that we were given a string
+    if type(path) ~= "string" then
+        return nil, nil, nil
+    end
+
+    -- Split the (directory) from the (name and extension)
+    local dir, name_ext = path:match(split_dir_pattern)
+
+    -- No directory
+    if not dir then
+        dir      = nil
+        name_ext = path
+
+    -- A bare directory (with a trailing slash)
+    elseif name_ext == "" then
+        return dir, nil, nil
+    end
+
+    -- Split the (name) from the (extension)
+    local name, ext = name_ext:match(split_ext_pattern)
+
+    -- No extension (or a dotfile)
+    if (not name) or (name == "") then
+        name = name_ext
+        ext  = nil
+    end
+
+    return dir, name, ext
+end
+
+-- See if a file exists
+local function file_exists(path)
+    local mode = lfs.attributes(path, "mode")
+    return (mode == "file") or (mode == "link")
+end
+
+
+---------------------
+--- Safety Checks ---
+---------------------
+
+-- Make sure that we're running unrestricted.
+if status.shell_escape ~= 1 then
+    error("Shell escape has been disabled", {
+        shell_escape = status.shell_escape,
+    })
+end
+
+if status.safer_option ~= 0 then
+    error("The ``safer'' option has been enabled", {
+        safer_option = status.safer_option,
+    })
+end
+
+-- Set the file permissions.
+if READ_PERMS then
+    os.setenv("openin_any", READ_PERMS)
+end
+
+if WRITE_PERMS then
+    os.setenv("openout_any", WRITE_PERMS)
+end
+
+-- Get the location of the interpreter
+local interpreter_dir = os.selfdir or kpse.var_value("SELFAUTOLOC")
+local _, interpreter_name, interpreter_ext = split_path(script_args[-1])
+
+if os.type == "windows" then
+    interpreter_ext = INTERPRETER_EXT
+end
+
+-- Error details
+local error_details = {
+    interpreter_dir     = interpreter_dir  or "<nil>",
+    interpreter_name    = interpreter_name or "<nil>",
+    interpreter_ext     = interpreter_ext  or "<nil>",
+    os_type             = os.type          or "<nil>",
+    os_name             = os.name          or "<nil>",
+}
+
+-- Get the path to the target program
+local target_ext  = interpreter_ext and ("." .. interpreter_ext) or ""
+local target_path = interpreter_dir .. "/" .. TARGET_PATH_NAME .. target_ext
+
+error_details.target_path = target_path or "<nil>"
+error_details.target_ext  = target_ext  or "<nil>"
+
+-- Make sure that the target program exists
+if not file_exists(target_path) then
+    error("The target program does not exist", error_details)
+end
+
+
+----------------------
+--- Run the target ---
+----------------------
+
+-- Generate the target arguments
+local target_args = {
+    [0] = target_path,      -- Path to the executable
+    [1] = TARGET_EXEC_NAME, -- argv[0]
+}
+
+-- argv[2] through argv[n]
+for _, arg in ipairs(TARGET_PREPEND_ARGS) do
+    insert(target_args, arg)
+end
+
+for i = 1, #script_args do
+    -- We use a numeric iterator here to avoid ``arg[-1]'' and ``arg[0]''.
+    local this_arg = script_args[i]
+    insert(target_args, this_arg)
+
+    -- Show version information
+    if this_arg:match("%-version") then
+        print("[Wrapped by extractbb.lua v1.0.0 (2024-11-17)]") --%%version %%dashdate
+    end
+end
+
+for _, arg in ipairs(TARGET_APPEND_ARGS) do
+    insert(target_args, arg)
+end
+
+-- For Unixish OSs, argv is passed as an array into a spawned process, so no
+-- further tokenization is done by the C runtime, therefore arguments containing
+-- special characters won't cause any issues. For Windows, argv is concatenated
+-- into a single string when spawning a new process, then retokenized by the C
+-- runtime in the new program, so we need to be careful with special characters
+-- here since they might be interpreted as token separators.
+if os.type == "windows" then
+    for i, arg in ipairs(target_args) do
+        -- Hmm, which characters do we need to protect against?
+        if arg:match('"') then
+            -- Already contains a quote, so let's hope that this means that
+            -- someone already quoted it correctly.
+        elseif arg:match("[^-_%l%u%d]") then
+            -- Contains a special character, so let's quote it.
+            target_args[i] = '"' .. arg .. '"'
+        end
+        -- Any other cases and things should be fine. Probably.
+    end
+end
+
+-- Run the target program, replacing the current process
+local _, err = os.exec(target_args)
+
+-- Unreachable except in the case of a failed exec
+for key, value in ipairs(target_args) do
+    error_details["target_args[" .. key .. "]"] = value
+end
+
+error_details.exec_message = err or "<nil>"
+error("The target program failed to run", error_details)


Property changes on: trunk/Master/texmf-dist/scripts/extractbb/extractbb-wrapper.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: trunk/Master/texmf-dist/scripts/extractbb/extractbb.lua
===================================================================
--- trunk/Master/texmf-dist/scripts/extractbb/extractbb.lua	                        (rev 0)
+++ trunk/Master/texmf-dist/scripts/extractbb/extractbb.lua	2024-11-18 22:29:08 UTC (rev 72890)
@@ -0,0 +1,71 @@
+#!/usr/bin/env texlua
+-- extractbb-lua
+-- https://github.com/gucci-on-fleek/extractbb
+-- SPDX-License-Identifier: MPL-2.0+
+-- SPDX-FileCopyrightText: 2024 Max Chernoff
+--
+-- A wrapper script to allow you to choose which implementation of extractbb to
+-- use. Should hopefully be replaced with the ``scratch'' file in TeX Live 2025.
+--
+-- v1.0.0 (2024-11-17) %%version %%dashdate
+
+---------------------
+--- Configuration ---
+---------------------
+-- Choose which implementation of extractbb to use.
+local DEFAULT = "wrapper"
+
+
+-----------------
+--- Execution ---
+-----------------
+
+-- Get the value of the environment variable that decides which version to run.
+local env_choice = os.env["TEXLIVE_EXTRACTBB"]
+
+-- If the environment variable is set to a file path, run that directly.
+local env_mode = lfs.attributes(env_choice or "", "mode")
+if (env_mode == "file") or (env_mode == "link") then
+    arg[0] = env_choice
+    table.insert(arg, 1, env_choice)
+    arg[-1] = nil
+    return os.exec(arg)
+end
+
+-- Map the choice names to file names.
+kpse.set_program_name("texlua", "extractbb")
+local choice_mapping = {
+    wrapper = kpse.find_file("extractbb-wrapper.lua", "lua", true),
+    scratch = kpse.find_file("extractbb-scratch.lua", "lua", true),
+}
+
+-- Choose the implementation to run.
+local choice = choice_mapping[env_choice] or choice_mapping[DEFAULT]
+
+if not choice then
+    print("No implementation of extractbb found. Exiting.")
+    os.exit(1)
+end
+
+-- Make sure that the script is not writable.
+if kpse.out_name_ok_silent_extended(choice) then
+    if os.env["TEXLIVE_EXTRACTBB_UNSAFE"] == "unsafe" then
+        -- If we're running in development mode, then we can allow this.
+    else
+        print("Refusing to run a writable script. Exiting.")
+        os.exit(1)
+    end
+end
+
+-- Make sure that the script is beside this one, just to be safe
+local split_dir_pattern = "^(.*)[/\\]([^/\\]-)$"
+local current_dir, current_name = arg[0]:match(split_dir_pattern)
+local choice_dir, choice_name = choice:match(split_dir_pattern)
+
+if current_dir ~= choice_dir then
+    print("Refusing to run a script from a different directory. Exiting.")
+    os.exit(1)
+end
+
+-- And run it.
+dofile(choice)


Property changes on: trunk/Master/texmf-dist/scripts/extractbb/extractbb.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Modified: trunk/Master/tlpkg/bin/tlpkg-ctan-check
===================================================================
--- trunk/Master/tlpkg/bin/tlpkg-ctan-check	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Master/tlpkg/bin/tlpkg-ctan-check	2024-11-18 22:29:08 UTC (rev 72890)
@@ -328,7 +328,7 @@
     expdlist expex expex-acro expex-glossonly expkv-bundle export
     expose-expl3-dunkerque-2019 expressg
     exsheets exsol extarrows exteps
-    extpfeil extract extsizes ezedits
+    extpfeil extract extractbb extsizes ezedits
   facsimile factura facture facture-belge-simple-sans-tva fadingimage
     fail-fast faktor familytree
     fancybox fancyhandout fancyhdr fancyhdr-it fancylabel fancynum fancypar

Modified: trunk/Master/tlpkg/libexec/ctan2tds
===================================================================
--- trunk/Master/tlpkg/libexec/ctan2tds	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Master/tlpkg/libexec/ctan2tds	2024-11-18 22:29:08 UTC (rev 72890)
@@ -3764,6 +3764,7 @@
  'changes'		=> '\.py$',
  'cloze'		=> '\.lua$',
  'epspdf'               => '(epspdf(|\.help|\.tlu|.*tk.*)|\.rb|makegray\.pro)$',
+ 'extractbb'		=> 'extractbb-.*\.lua$',
  'latex2nemeth'         => '\.jar$',
  'latex-make'           => '\.py$',
  'latexindent'          => 'LatexIndent|\.yaml$',
@@ -3837,6 +3838,7 @@
  'eolang'		=> '\.pl$',
  'epstopdf'             => 'epstopdf\.pl',      # doscripts() does r*
  'exceltex'             => 'exceltex$',
+ 'extractbb'		=> 'extractbb\.lua$',
  'fig4latex'            => 'fig4latex',
  'findhyph'             => 'findhyph$',
  'fragmaster'           => 'fragmaster\.pl$',

Modified: trunk/Master/tlpkg/tlpsrc/collection-basic.tlpsrc
===================================================================
--- trunk/Master/tlpkg/tlpsrc/collection-basic.tlpsrc	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Master/tlpkg/tlpsrc/collection-basic.tlpsrc	2024-11-18 22:29:08 UTC (rev 72890)
@@ -18,6 +18,7 @@
 depend enctex
 depend etex
 depend etex-pkg
+depend extractbb
 depend glyphlist
 depend graphics-def
 depend hyph-utf8

Modified: trunk/Master/tlpkg/tlpsrc/dvipdfmx.tlpsrc
===================================================================
--- trunk/Master/tlpkg/tlpsrc/dvipdfmx.tlpsrc	2024-11-18 21:06:13 UTC (rev 72889)
+++ trunk/Master/tlpkg/tlpsrc/dvipdfmx.tlpsrc	2024-11-18 22:29:08 UTC (rev 72890)
@@ -1,4 +1,5 @@
 category TLCore
+depend extractbb
 depend glyphlist
 depend texlive-scripts-extra
 #

Added: trunk/Master/tlpkg/tlpsrc/extractbb.tlpsrc
===================================================================
--- trunk/Master/tlpkg/tlpsrc/extractbb.tlpsrc	                        (rev 0)
+++ trunk/Master/tlpkg/tlpsrc/extractbb.tlpsrc	2024-11-18 22:29:08 UTC (rev 72890)
@@ -0,0 +1 @@
+binpattern f bin/${ARCH}/${PKGNAME}



More information about the tex-live-commits mailing list.