% \iffalse
% vim: set expandtab:
% vim: set shiftwidth=2:
% vim: set tabstop=2:
% \fi
% \iffalse meta-comment
%
% Copyright (C) 2026 by Lukas Heindl <oss.heindl+latex@protonmail.com>
% ---------------------------------------------------------------------------
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3c
% of this license or (at your option) any later version.
% The latest version of this license is in
%   http://www.latex-project.org/lppl.txt
% and version 1.3c or later is part of all distributions of LaTeX
% version 2008/05/04 or later.
%
% This work has the LPPL maintenance status `maintained'.
%
% The Current Maintainer of this work is Lukas Heindl.
%
% This work consists of all files listed in manifest.txt.
%
% \fi
%
% \iffalse
%<*driver>
\ProvidesFile{hexdumptikz-draw.dtx}
%</driver>
%<package>\NeedsTeXFormat{LaTeX2e}[2022-06-01]
%
%<*driver>
\begin{document}
  \DocInput{\jobname.dtx}
  \PrintChanges
  \PrintIndex
\end{document}
%
% \changes{v0.0.0}{2026-05-14}{First draft}
%
%</driver>
% \fi
%
% \iffalse
%<*package>
%<@@=hexdumptikz_draw>
% \fi
%
% \maketitle
%
% \begin{abstract}
%   Draws the hexdump.
%   For the most part this defines configuration keys regarding the hexdump drawing and provides a callback which then can be passed to the parser.
% \end{abstract}
%
% Identify the package and give the over all version information.
%    \begin{macrocode}
\ProvidesExplPackage {hexdumptikz-draw} {2026-06-16} {1.0.0}
  {Common functionality for working with hexdumps and (large) addresses}
%    \end{macrocode}
%
% Load the requirements.
%    \begin{macrocode}
\RequirePackage { pgfkeys }
\RequirePackage { hexdumptikz-common }
\RequirePackage { hexdumptikz-selector }
\RequirePackage { hexdumptikz-parser }
%    \end{macrocode}
%
% \begin{var}{\l_@@_print_selector_ctx_tl}
% Initialize / Declare a selector-context which is used for selecting which rows should be shown in the output.
%    \begin{macrocode}
\tl_new:N \l_@@_print_selector_ctx_tl
\hexdumptikz_selector_ctx_new:N \l_@@_print_selector_ctx_tl
%    \end{macrocode}
% \end{var}
%
% \begin{var}{\l_@@_print_styled_ctx_tl}
% Initialize / Declare a selector-context which is used for assigning \emph{styles} to the bytes.
%    \begin{macrocode}
\tl_new:N \l_@@_print_styled_ctx_tl
\hexdumptikz_selector_ctx_new:N \l_@@_print_styled_ctx_tl
%    \end{macrocode}
% \end{var}
%
% \subsection{Variables}
%
% \begin{var}{\g_@@_addr_index_int}
% \begin{var}{\g_@@_addr_used_index_int}
% \begin{var}{\g_@@_byte_index_int}
% Variables for counting the node indices
%    \begin{macrocode}
\int_new:N \g_@@_addr_index_int
\int_new:N \g_@@_addr_used_index_int
\int_new:N \g_@@_byte_index_int
%    \end{macrocode}
% \end{var}
% \end{var}
% \end{var}

% \begin{var}{\g_@@_last_addr_node_tl}
% \begin{var}{\g_@@_last_byte_node_tl}
% Store the nodenames of the most recently generated nodes to be able to create \texttt{-end} aliases.
% Due to the nesting of tikz-\texttt{scope}s, these variables must be global.
%    \begin{macrocode}
\tl_new:N \g_@@_last_addr_node_tl
\tl_new:N \g_@@_last_byte_node_tl
%    \end{macrocode}
% \end{var}
% \end{var}

% \begin{var}{\l_@@_cur_addr_tl}
% \begin{var}{\l_@@_cur_addr_padded_str}
% Variables for storing the current (padded) address
%    \begin{macrocode}
\tl_new:N \l_@@_cur_addr_tl
\str_new:N \l_@@_cur_addr_padded_str
%    \end{macrocode}
% \end{var}
% \end{var}

% \begin{var}{\g_@@_first_addr_node_bool}
% The first address node gets a special style applied.
% This allows e.g. for placing the whole hexdump at a specific position.
%    \begin{macrocode}
\bool_new:N \g_@@_first_addr_node_bool
%    \end{macrocode}
% \end{var}
%
% \subsection{Constants}
%
% \begin{var}{\l_@@_tmp_box}
% this box has the maximal height and depth a hexadecimal node can have
%    \begin{macrocode}
\box_new:N \l_@@_tmp_box
\hbox_set:Nn \l_@@_tmp_box { \ttfamily 0x0123456789abcdef }
%    \end{macrocode}
% \end{var}
% \begin{var}{\l_@@_tmp_box}
% variables for uniform node heights
%    \begin{macrocode}
\dim_const:Nn
  \c_@@_hexheight_dim
  { \box_ht:N \l_@@_tmp_box }
\dim_const:Nn
  \c_@@_hexdepth_dim
  { \box_dp:N \l_@@_tmp_box }
%    \end{macrocode}
% \end{var}
%
%
% \subsection{Settings / Config Variables}
% decisions about address printing
% \begin{var}{\l_hexdumptikz_draw_show_addr_padded_bool}
% Whether the address which gets shown shall be padded
%    \begin{macrocode}
\bool_new:N \l_hexdumptikz_draw_show_addr_padded_bool
%    \end{macrocode}
% \end{var}
% \begin{var}{\l_hexdumptikz_draw_show_addr_bool}
% Whether the address shall be shown at all in the output
%    \begin{macrocode}
\bool_new:N \l_hexdumptikz_draw_show_addr_bool
%    \end{macrocode}
% \end{var}
% \begin{var}{\l_hexdumptikz_draw_show_addr_base_bool}
% Whether the shown address should be prefixed with \texttt{0x} as indicator of the hexadecimal base
%    \begin{macrocode}
\bool_new:N \l_hexdumptikz_draw_show_addr_base_bool
%    \end{macrocode}
% \end{var}
%
% \begin{var}{\l_hexdumptikz_draw_byte_sep_int}
% \begin{var}{\l_hexdumptikz_draw_byte_sep_tl}
% insert separating space in the hexdump. Every \texttt{int} columns, insert \texttt{dim} additional space.
%    \begin{macrocode}
\int_new:N \l_hexdumptikz_draw_byte_sep_int
\tl_new:N \l_hexdumptikz_draw_byte_sep_tl
%    \end{macrocode}
% \end{var}
% \end{var}
%
% \subsubsection{pgfkeys wiring}
% define explicit keys
%    \begin{macrocode}
\pgfkeys {
  /hexdumptikz,
  % prefix for the nodenames
  name~prefix/.code = {
    \tl_set:Ne \l_hexdumptikz_common_nodename_prefix_tl { #1 }
    \pgfkeys { /hexdumptikz/next~scope/.append~style = { name~prefix = #1 } }
  },
  name~prefix = { },
  name~prefix/.value~required,

  % insert space after that many bytes
  bytes~sep~after/.code = {
    \int_set:Nn \l_hexdumptikz_draw_byte_sep_int { \int_abs:n { #1 } }
  },
  bytes~sep~after = 64, % basically deactivated
  bytes~sep~after/.default = { 8 },

  % size of the gap
  bytes~sep/.code = { \tl_set:Nn \l_hexdumptikz_draw_byte_sep_tl { #1 } },
  bytes~sep = { 2em },
  bytes~sep/.value~required,

  % whether to even show the address nodes
  % this is a bit more complicated as the address-nodes cannot be simply omitted as they are relevant for the positioning -> inner sep=0, and first byte in each row needs special placement with no 'node distance'
  show~addr/.code = {
    \hexdumptikz_common_parse_bool:Nn
      \l_hexdumptikz_draw_show_addr_bool
      { #1 }
  },
  show~addr = { true },
  show~addr/.default = { true },

  % whether to display 0x when showing the addresses
  show~addr~base/.code = {
    \hexdumptikz_common_parse_bool:Nn
      \l_hexdumptikz_draw_show_addr_base_bool
      { #1 }
  },
  show~addr~base = { true },
  show~addr~base/.default = { true },

  % whether the shown addresses should be padded (otherwise padding only for ranges, node-names and internals)
  show~addr~padded/.code = {
    \hexdumptikz_common_parse_bool:Nn
      \l_hexdumptikz_draw_show_addr_padded_bool
      { #1 }
  },
  show~addr~padded = { false },
  show~addr~padded/.default = { true },

  styled~bytes/.code = {
    \hexdumptikz_selector_parse:Nn
      \l_@@_print_styled_ctx_tl
      { #1 }
  }
}
%    \end{macrocode}
%
% Define styles which get applied to the corresponding nodes
%    \begin{macrocode}
\pgfkeys {
  /hexdumptikz,
  address~node~first/.style= { },
  address~node/.style= {
    left,
    on~chain,
    text~height = \c_@@_hexheight_dim,
    text~depth  = \c_@@_hexdepth_dim,
  },
  byte~node/.style = {
    on~chain,
    text~height = \c_@@_hexheight_dim,
    text~depth  = \c_@@_hexdepth_dim,
  },
}
%    \end{macrocode}
%
% \subsection{Actual drawing}
% in principle there are the following node-names:
% \begin{itemize}
%   \item one chain going down where every node gets three names:
%     \begin{enumerate}
%       \item based on the index in the input
%       \item based on the index in the output
%       \item based on the address/offset
%     \end{enumerate}
%   \item three chains in each row for every node-name going right where every node just gets the intuitive name
%   \item every chain comes with an -end node
% \end{itemize}
%
% \subsubsection{Helpers for generating specific nodes}
% \begin{fn}{\@@_print_handle_first_node:}
% Small helper for handling the \emph{first node} which also modifies the state accordingly.
%    \begin{macrocode}
\prg_new_conditional:Npnn
  \@@_print_handle_first_node:
  { TF }
{
  \bool_if:NTF \g_@@_first_addr_node_bool
  {
    \bool_gset_false:N \g_@@_first_addr_node_bool
    \prg_return_true:
  } {
    \prg_return_false:
  }
}
%    \end{macrocode}
% \end{fn}

% \begin{fn}{\@@_generate_gap_node:n}
% Generate an empty node which is intended to be a \emph{gap} node (same placement / category like an address node)
% \begin{sideeffects}
% \end{sideeffects}
% \begin{args}
%   1 & \ain  & number/index of the gap \\
%   - & \ain  & \texttt{g\_@@\_addr\_index\_int} \\
%   - & \ain  & \texttt{l\_@@\_cur\_addr\_padded\_str} \\
%   - & \aout & \texttt{g\_@@\_last\_addr\_node\_tl} \\
% \end{args}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_generate_gap_node:n #1
{
%    \end{macrocode}
% Construct the nodename only once so it can be reused later
%    \begin{macrocode}
  \tl_gset:Ne
    \g_@@_last_addr_node_tl
    { hexdumptikz-in- \int_use:N \g_@@_addr_index_int -gap #1 }
%    \end{macrocode}
%
% Draw the node depending on whether it's the first one (in this hexdump) or not
%    \begin{macrocode}
  \@@_print_handle_first_node:TF
  {
    \node[
      /hexdumptikz/address~node,
      /hexdumptikz/address~node~first,
    ]
    ( \tl_use:N \g_@@_last_addr_node_tl )
    { }
    ;
  } {
    \node[
      /hexdumptikz/address~node,
    ]
    ( \tl_use:N \g_@@_last_addr_node_tl )
    { }
    ;
  }
%    \end{macrocode}
%
% Add some node-aliases. This encodes additional information about the node.
%    \begin{macrocode}
  \pgfnodealias
    { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl hexdumptikz- \str_use:N \l_@@_cur_addr_padded_str -gap #1 }
    { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl \tl_use:N \g_@@_last_addr_node_tl }
  \pgfnodealias
    { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl hexdumptikz-out- \int_use:N \g_@@_addr_used_index_int -gap #1 } % noqa: S103
    { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl \tl_use:N \g_@@_last_addr_node_tl }
}
%    \end{macrocode}
% \end{fn}
%
% \begin{fn}{\@@_generate_addr_node:n}
% Generate a node showing the address / offset
% \begin{sideeffects}
% \end{sideeffects}
% \begin{args}
%   1 & \ain  & address which shall be shown \\
%   - & \ain  & \texttt{g\_@@\_addr\_index\_int} \\
%   - & \aout & \texttt{g\_@@\_last\_addr\_node\_tl} \\
% \end{args}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_generate_addr_node:n #1
{
%    \end{macrocode}
% Construct the nodename only once so it can be reused later
%    \begin{macrocode}
  \tl_gset:Ne
    \g_@@_last_addr_node_tl
    { hexdumptikz-in- \int_use:N \g_@@_addr_index_int }
%    \end{macrocode}
%
% Draw the node depending on whether it's the first one (in this hexdump) or not
%    \begin{macrocode}
  \@@_print_handle_first_node:TF
  {
    \node[
      /hexdumptikz/address~node,
      /hexdumptikz/address~node~first,
    ]
      ( \tl_use:N \g_@@_last_addr_node_tl )
      { #1 }
      ;
  } {
    \node[
      /hexdumptikz/address~node,
    ]
      ( \tl_use:N \g_@@_last_addr_node_tl )
      { #1 }
      ;
  }
}
\cs_generate_variant:Nn \@@_generate_addr_node:n { e }
%    \end{macrocode}
% \end{fn}
%
% \begin{fn}{\@@_generate_byte_node:nn}
% Generate a node showing a single byte
% \begin{sideeffects}
% \end{sideeffects}
% \begin{args}
%   1 & \ain  & value of the byte \\
%   2 & \ain  & style which is to be applied \\
%   - & \ain  & \texttt{g\_@@\_addr\_index\_int} \\
%   - & \ain  & \texttt{g\_@@\_byte\_index\_int} \\
%   - & \aout & \texttt{g\_@@\_last\_addr\_node\_tl} \\
% \end{args}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_generate_byte_node:nn #1 #2
{
%    \end{macrocode}
% Construct the nodename only once so it can be reused later
%    \begin{macrocode}
  \tl_gset:Ne
    \g_@@_last_byte_node_tl
    {
      hexdumptikz-in-
      \int_use:N \g_@@_addr_index_int
      -
      \int_use:N \g_@@_byte_index_int
    }
%    \end{macrocode}
%
% Draw the node depending on its position:
% \begin{itemize}
%   \item[pos=$0$] needs special positioning
%   \item[$x \bmod m = 0$] add gap for separation
%   \item normal node
% \end{itemize}
%    \begin{macrocode}
  \int_compare:nNnTF { \g_@@_byte_index_int } = { 0 }
  {
    \node[right=of~hexdumptikz-in- \int_use:N \g_@@_addr_index_int ,/hexdumptikz/byte~node,#2] % noqa: S103
    ( \tl_use:N \g_@@_last_byte_node_tl )
    { #1 }
    ;
  }
  {
    \int_compare:nNnTF
    {
      \int_mod:nn
      { \g_@@_byte_index_int }
      { \l_hexdumptikz_draw_byte_sep_int }
    }
    =
    { 0 }
    {
      \node[ xshift = \tl_use:N \l_hexdumptikz_draw_byte_sep_tl ,/hexdumptikz/byte~node,#2] % noqa: S103
      ( \tl_use:N \g_@@_last_byte_node_tl )
      { #1 }
      ;
    } {
      \node[/hexdumptikz/byte~node,#2]
      ( \tl_use:N \g_@@_last_byte_node_tl )
      { #1 }
      ;
    }
  }
}
\cs_generate_variant:Nn \@@_generate_byte_node:nn { ev }
%    \end{macrocode}
% \end{fn}
%
% \subsubsection{Main drawing functions}
% \begin{fn}{\hexdumptikz_draw_init:nn}
% Initialize the drawing logic (necessary as it is stateful)
% \begin{sideeffects}
%   \sclobber & \sdir &  all kinds of variables, see the source-code\\
% \end{sideeffects}
% \begin{args}
%   1 & \ain  & pgfkeys for the whole hexdump \\
%   2 & \ain  & row-selector \\
% \end{args}
%    \begin{macrocode}
\cs_new_protected:Npn \hexdumptikz_draw_init:nn #1 #2
{
%    \end{macrocode}
% Clear and initialize the selector contexts
%    \begin{macrocode}
  \hexdumptikz_selector_parse:Ne
    \l_@@_print_selector_ctx_tl
    { #2 }
  \hexdumptikz_selector_ctx_clear_iter:N
    \l_@@_print_selector_ctx_tl
  \hexdumptikz_selector_ctx_clear_storage:N
    \l_@@_print_styled_ctx_tl
%    \end{macrocode}
%
% Clear the variables with global state.
%    \begin{macrocode}
  \bool_gset_true:N \g_@@_first_addr_node_bool
  \int_gzero:N \g_@@_addr_index_int
  \int_gzero:N \g_@@_addr_used_index_int
%    \end{macrocode}
%
% handle the pgfkeys.
% Needs to be after clearing the \texttt{print\_styled} logic.
%    \begin{macrocode}
  \pgfkeys {
    /hexdumptikz,
    #1
  }
  \hexdumptikz_selector_ctx_clear_iter:N
    \l_@@_print_styled_ctx_tl
%    \end{macrocode}
% Start the tikz-scope which holds the entire hexdump
%    \begin{macrocode}
  \begin{ scope } [
    start~chain = hexdumptikz-rows~going~{ below=of~\tikzchainprevious.south~east,anchor=north~east }, % noqa: S103
    node~distance = .3ex~and~.2em,
    font = \ttfamily\small,
    /hexdumptikz/next~scope,
    ]
}
%    \end{macrocode}
% \end{fn}
%
% \begin{fn}{\hexdumptikz_draw:NNNN}
% Draw-callback which is passed to the parser.
% Draws one line / row of the hexdump.
% \begin{sideeffects}
%   \sclobber & \sdir & \texttt{l\_tmpa\_int} \\
%   \sclobber & \sdir & \texttt{l\_tmpa\_tl} \\
% \end{sideeffects}
% \begin{args}
%   1 & \ain  & index of the line (in the input) (int) \\
%   2 & \ain  & offset / address (tl) \\
%   3 & \ain  & bytes (seq) \\
%   4 & \aout & backchannel for signaling the parser to stop \\
% \end{args}
% TODO: \texttt{g\_@@\_addr\_index\_int} is \texttt{\#1} (ok there are differences regarding empty lines) $\to$ simplify
%    \begin{macrocode}
\cs_new_protected:Npn \hexdumptikz_draw:NNNN #1 #2 #3 #4
{
%    \end{macrocode}
% Create a working copy of the address, padd it and make a proper string out of it
%    \begin{macrocode}
  \tl_set:Ne \l_@@_cur_addr_tl { #2 }
  \hexdumptikz_common_pad_address:N #2
  \str_set:Ne
    \l_@@_cur_addr_padded_str
    { \tl_to_str:N #2 }
%    \end{macrocode}
%
% Query the user-supplied row selector whether this row should be present in the output
%    \begin{macrocode}
  \hexdumptikz_selector_match_rows:NnnN
    \l_@@_print_selector_ctx_tl
    { \g_@@_addr_index_int } % y
    { 0 } % x
    \l_@@_cur_addr_padded_str
%    \end{macrocode}
%
% Only show the row when the selector said so
%    \begin{macrocode}
  \bool_if:cT
  {
    \hexdumptikz_selector_show_bool:N
    \l_@@_print_selector_ctx_tl
  }
  {
%    \end{macrocode}
% Place the address in a lookup-table which allows translating \texttt{addr$\to$idx}.
% This may then later used for annotating the hexdump.
%    \begin{macrocode}
    \prop_gput:Nee
      \g_hexdumptikz_common_cur_offsets_prop
      { \l_@@_cur_addr_padded_str }
      { \int_use:N \g_@@_addr_used_index_int }
%    \end{macrocode}
%
% The row-selector might have encountered gaps before the current range $\to$ draw them
%    \begin{macrocode}
    \int_set_eq:Nc
      \l_tmpa_int
      {
        \hexdumptikz_selector_gap_int:N
        \l_@@_print_selector_ctx_tl
      }
    \int_step_function:nnnN
      { 1 }
      { 1 }
      { \l_tmpa_int }
      \@@_generate_gap_node:n
    \int_gzero:c
    {
      \hexdumptikz_selector_gap_int:N
        \l_@@_print_selector_ctx_tl
    }
%    \end{macrocode}
%
% Determine how the address should be presented (padded or unpadded) (avoids having to use more branches later)
%    \begin{macrocode}
    \bool_if:NTF \l_hexdumptikz_draw_show_addr_padded_bool
      { \tl_set:Ne \l_tmpa_tl { \l_@@_cur_addr_padded_str } }
      { \tl_set:Ne \l_tmpa_tl { \l_@@_cur_addr_tl } }
%    \end{macrocode}
%
% Remove the leading \texttt{0x} if the user does not want it to be present in the output
%    \begin{macrocode}
    \bool_if:NF \l_hexdumptikz_draw_show_addr_base_bool
    {
      \regex_replace_once:NnN
      \c_hexdumptikz_common_leading_hex_base_regex
      { }
      \l_tmpa_tl
    }

    \@@_generate_addr_node:e { \l_tmpa_tl }
%    \end{macrocode}
%
% Create various node-aliases encoding additional information about the node.
%    \begin{macrocode}
    \pgfnodealias
      { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl hexdumptikz-    \str_use:N \l_@@_cur_addr_padded_str }
      { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl \tl_use:N \g_@@_last_addr_node_tl }
    \pgfnodealias
      { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl hexdumptikz-out- \int_use:N \g_@@_addr_used_index_int }
      { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl \tl_use:N \g_@@_last_addr_node_tl }
%    \end{macrocode}
%
% Start a new tikz-\texttt{scope} + chain for the row which started with the address containing the byte values
%    \begin{macrocode}
    \begin{ scope } [start~chain=hexdumptikz-row~going~right]
      \int_zero:N \g_@@_byte_index_int
      \seq_map_inline:Nn #3
      {
%    \end{macrocode}
%
% Determine what style to apply to the node
%    \begin{macrocode}
        \hexdumptikz_selector_match_styles:NnnN
          \l_@@_print_styled_ctx_tl
          { \g_@@_addr_used_index_int } % y
          { \g_@@_byte_index_int } % x
          \l_@@_cur_addr_padded_str

        \@@_generate_byte_node:ev
          { ##1 }
          {
            \hexdumptikz_selector_style_tl:N
            \l_@@_print_styled_ctx_tl
          }
%    \end{macrocode}
%
% Create various node-aliases encoding additional information about the node.
%    \begin{macrocode}
        \pgfnodealias
          { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl hexdumptikz- \str_use:N \l_@@_cur_addr_padded_str - \int_use:N \g_@@_byte_index_int } % noqa: S103
          { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl \tl_use:N \g_@@_last_byte_node_tl }
        \pgfnodealias
          { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl hexdumptikz-out- \int_use:N \g_@@_addr_used_index_int - \int_use:N \g_@@_byte_index_int } % noqa: S103
          { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl \tl_use:N \g_@@_last_byte_node_tl }
%    \end{macrocode}
%
% Count the byte nodes for indexing
%    \begin{macrocode}
        \int_gincr:N \g_@@_byte_index_int
      }
%    \end{macrocode}
%
% Row finished $\to$ create more node-aliases for easier drawing later
%    \begin{macrocode}
      \pgfnodealias
        { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl hexdumptikz-in- \int_use:N \g_@@_addr_index_int -end }
        { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl \tl_use:N \g_@@_last_byte_node_tl }
      \pgfnodealias
        { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl hexdumptikz-out- \int_use:N \g_@@_addr_used_index_int -end } % noqa: S103
        { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl \tl_use:N \g_@@_last_byte_node_tl }
      \pgfnodealias
        { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl hexdumptikz- \str_use:N \l_@@_cur_addr_padded_str -end } % noqa: S103
        { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl \tl_use:N \g_@@_last_byte_node_tl }
    \end{ scope }
  }
%    \end{macrocode}
%
% Count the selected rows for indexing
%    \begin{macrocode}
      \int_gincr:N \g_@@_addr_used_index_int
%    \end{macrocode}
%
% Forward the row-selector's decision whether the parser should continue parsing
%    \begin{macrocode}
  \bool_set_eq:Nc
    \l_hexdumptikz_parser_finished_bool
    {
      \hexdumptikz_selector_finished_bool:N
      \l_@@_print_selector_ctx_tl
    }
%    \end{macrocode}
%
% Count the parsed rows for indexing
%    \begin{macrocode}
  \int_gincr:N \g_@@_addr_index_int
}
%    \end{macrocode}
% \end{fn}
%
% \begin{fn}{\hexdumptikz_draw_fin:}
% Finalize the drawing logic (necessary as it is stateful)
%    \begin{macrocode}
\cs_new_protected:Npn \hexdumptikz_draw_fin:
{
%    \end{macrocode}
%
% Hexdump finished $\to$ create more node-aliases for easier drawing later
%    \begin{macrocode}
  \pgfnodealias
    { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl hexdumptikz-end }
    { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl \g_@@_last_addr_node_tl }
  \pgfnodealias
    { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl hexdumptikz-end-end }
    { \tl_use:N \l_hexdumptikz_common_nodename_prefix_tl \g_@@_last_byte_node_tl }
  \end{ scope }
  \pgfkeys { /hexdumptikz/next~scope/.style = { } }
%    \end{macrocode}
%
% Cleanup the created state (additional hexdump might be drawn and the information might leak)
%    \begin{macrocode}
  \hexdumptikz_selector_ctx_clear_storage:N
    \l_@@_print_styled_ctx_tl
  \hexdumptikz_selector_ctx_clear_storage:N
    \l_@@_print_selector_ctx_tl
}
%    \end{macrocode}
% \end{fn}
%
% \subsection{Usual entrance point}
% \begin{fn}{\hexdumptikz_draw_print:nn}
% Usual entry-point handling the complete drawing state logic and the incovation of the selected parser.
% \begin{args}
%   1 & \ain  & pgfkeys for the whole hexdump \\
%   2 & \ain  & row-selector (tl) \\
% \end{args}
%    \begin{macrocode}
\cs_new_protected:Npn \hexdumptikz_draw_print:nn #1 #2
{
%    \end{macrocode}
% Note, this handling the pgfkeys can still select a different parser.
%    \begin{macrocode}
  \hexdumptikz_draw_init:nn { #1 } { #2 }

  \hexdumptikz_parser_parse:nN
    { \l_hexdumptikz_common_input_file_str }
    \hexdumptikz_draw:NNNN

  \hexdumptikz_draw_fin:
}
%    \end{macrocode}
% \end{fn}
% \iffalse
%</package>
% \fi
%
% \Finale
