summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfdict.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfdict.dtx')
-rw-r--r--Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfdict.dtx591
1 files changed, 591 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfdict.dtx b/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfdict.dtx
new file mode 100644
index 00000000000..558b721ca57
--- /dev/null
+++ b/Master/texmf-dist/source/latex/pdfmanagement-testphase/l3pdfdict.dtx
@@ -0,0 +1,591 @@
+% \iffalse meta-comment
+%
+%% File: l3pdfdict.dtx
+%
+% Copyright (C) 2018-2021 The LaTeX Project
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This file is part of the "LaTeX PDF management testphase bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+% https://github.com/latex3/pdfresources
+%
+% for those people who are interested.
+%
+%<*driver>
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{pdfstandard=A-2b}
+\makeatletter
+\declare@file@substitution{doc.sty}{doc-v3beta.sty}
+\makeatother
+\documentclass[full]{l3doc}
+\usepackage{array,booktabs,hyperxmp}
+\hypersetup{pdfauthor=The LaTeX Project,
+ pdftitle=l3pdfdict (LaTeX PDF management testphase bundle)}
+
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+% \title{^^A
+% The \pkg{l3pdfdict} module---tools for PDF dictionaries ^^A
+% \\
+% \LaTeX{} PDF management testphase bundle
+% }
+%
+% \author{^^A
+% The \LaTeX{} Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Version 0.95a, released 2021-02-22}
+%
+% \maketitle
+% \begin{documentation}
+%
+% \section{\pkg{l3pdfdict} documentation}
+% Many PDF objects are or contain dictionaries---structures
+% containing a number of \mbox{(pdf-)}name/value pairs.
+% Examples are attributes of links,
+% filespec dictionaries, xform dictionaries, the catalog, the info dictionary.
+% The commands in this module offer an number of
+% tools to handle such dictionaries. The module setups a name space for the
+% dictionary names and offers some commands to output dictionaries.
+%
+% The dictionaries work in many respects
+% like property lists with a few PDF specific changes:
+% \begin{itemize}
+% \item The keys are always converted with \cs{str_convert_pdfname:n}
+% to get a correct PDF name;
+% \item a key with a empty value can not be added, it will be ignored;
+% \item there is a dedicated function to output the property as space
+% separated list with keys with slash: \texttt{/key1 value1 /key2 value2}.
+% \end{itemize}
+% Local and global dictionaries can be created.
+%
+% \subsection{User Commands}
+% \begin{function}[updated = 2020-12-03]
+% {\pdfdict_new:n}
+% \begin{syntax}
+% \cs{pdfdict_new:n} \Arg{dictionary name}
+% \end{syntax}
+% This function create a new local or global dictionary. Which one depends on
+% \meta{dictionary name}: If it begins with the standard |g| the dictionary is global,
+% with |l| the dictionary is local, other starting chars will give an error.
+% It is recommended to begin the name in the standard expl3 naming scheme
+% with one or two underscores and a module name,
+% so |g_module_XXXX| or |g__module_XXXX|.
+% \end{function}
+%
+% \begin{function}[added = 2020-06-16,updated = 2020-12-03]
+% {\pdfdict_set_eq:nn,\pdfdict_gset_eq:nn}
+% \begin{syntax}
+% \cs{pdfdict_set_eq:nn} \Arg{local dictionary name_1} \Arg{dictionary name_2}\\
+% \cs{pdfdict_gset_eq:nn} \Arg{global dictionary name_1}\Arg{dictionary name_2}
+% \end{syntax}
+% This functions copy \meta{dictionary name_2} into
+% \meta{local/global dictionary name_1} locally or globally. If the
+% dictionary \meta{local/global dictionary name_1} doesn't exist yet, it will be created.
+% If \meta{dictionary name_2} doesn't exist yet, an error will be raised.
+% \end{function}
+%
+% \begin{function}[added = 2020-04-06]
+% {\pdfdict_put:nnn, \pdfdict_gput:nnn}
+% \begin{syntax}
+% \cs{pdfdict_put:nnn} \Arg{local dictionary} \Arg{name} \Arg{value} \\
+% \cs{pdfdict_gput:nnn} \Arg{global dictionary} \Arg{name} \Arg{value}
+% \end{syntax}
+% This function puts key \meta{name} and value \meta{value} locally or globally in the
+% \meta{dictionary} created with \cs{pdfdict_new:n}.
+% \Arg{name} should be a PDF Name without the starting slash. It will be stored
+% with \cs{str_convert_pdfname:n}, so will be automatically correctly escaped in case
+% it contains slashes, spaces or other chars not allowed in a PDF name.
+% \meta{value} should be a valid PDF value for this name in the
+% target dictionary. The value is \emph{neither} converted \emph{nor} escaped automatically.
+% If the value is blank nothing is added to the dictionary.
+%
+% When adding a value keep in mind that the expansion behaviour
+% of the backends differ. Some backends expand a
+% value always fully when writing to the PDF, with other backends commands
+% could end as strings in the PDF. This makes controlling the
+% expansion quite tricky. It is better to not rely on
+% \meta{value} to be expanded nor not expanded by the backend commands.
+% \end{function}
+%
+% \begin{function}[EXP,added = 2020-12-04]
+% { \pdfdict_item:nn, \pdfdict_item:ne }
+% \begin{syntax}
+% \cs{pdfdict_item:nn} \Arg{key} \Arg{value}
+% \end{syntax}
+% A simple command to output key-value as |/key value|. This is
+% needed to output dictionaries in mapping commands. The command doesn't
+% do any escaping, it expects that the name has been escaped when the value
+% has been stored into the dictionary.
+% If the value is blank nothing is output.
+% The command is expandable if the content is it.
+% \end{function}
+%
+% \begin{function}[EXP,updated = 2020-12-03]
+% { \pdfdict_use:n }
+% \begin{syntax}
+% \cs{pdfdict_use:n} \Arg{dictionary}
+% \end{syntax}
+% This outputs the property list of the dictionary as a list of
+% |/key value| pairs.
+% This can be used e.g. when writing a dictionary object with
+% \cs{pdf_object_write:nx}
+% \end{function}
+%
+% \begin{function}[updated = 2020-12-03]
+% {\pdfdict_show:n }
+% \begin{syntax}
+% \cs{pdfdict_show:n} \Arg{dictionary}
+% \end{syntax}
+% This shows the content of \meta{dictionary} in the log and on the terminal.
+% \end{function}
+%\begin{function}[EXP, pTF,updated = 2020-12-03]
+% { \pdfdict_if_exist:n }
+% \begin{syntax}
+% \cs{pdfdict_if_exist:n} \Arg{dictionary}
+% \end{syntax}
+% This tests if the dictionary exists.
+% \end{function}
+% \begin{function}[EXP, pTF,updated = 2020-12-03]
+% { \pdfdict_if_empty:n }
+% \begin{syntax}
+% \cs{pdfdict_if_empty:n} \Arg{dictionary}
+% \end{syntax}
+% This tests if the dictionary is empty. The result is false if the
+% dictionary doesn't exist.
+% \end{function}
+% \begin{function}[added = 2020-07-06]
+% {\pdfdict_get:nnN }
+% \begin{syntax}
+% \cs{pdfdict_get:nnN} \Arg{dictionary} \Arg{name} \meta{tl var}
+% \end{syntax}
+% Recovers the \meta{value} stored by \cs{pdfdict_put:nnn} or
+% \cs{pdfdict_gput:nnn}
+% for \meta{name} and places this in the \meta{token list
+% variable}. If \meta{name} is not found
+% then the \meta{token list variable} is set
+% to the special marker \cs{q_no_value}. \meta{name} is first converted
+% with \cs{str_convert_pdfname:n}. The \meta{token list
+% variable} is set within the current \TeX{} group.
+% \end{function}
+%
+% \begin{function}[updated = 2020-12-03]
+% {
+% \pdfdict_remove:nn, \pdfdict_gremove:nn
+% }
+% \begin{syntax}
+% \cs{pdfdict_remove:nn} \Arg{local dictionary} \Arg{name}\\
+% \cs{pdfdict_gremove:nn} \Arg{global dictionary} \Arg{name}
+% \end{syntax}
+% Removes \meta{name} and its associated \meta{value} from
+% the \Arg{dictionary}
+% The removal is local from local dictionaries
+% and global from global dictionaries.
+% If \meta{name} is not found no change occurs,
+% \emph{i.e}~there is no need to test for the existence of a name before
+% trying to remove it. \meta{name} is first converted
+% with \cs{str_convert_pdfname:n}.
+% \end{function}
+% \end{documentation}
+%
+% \begin{implementation}
+% \section{\pkg{l3pdfdict} implementation}
+% \begin{macrocode}
+%<@@=pdfdict>
+%<*header>
+\ProvidesExplPackage {l3pdfdict} {2021-02-22} {0.95a}
+ {Tools for PDF dictionaries (LaTeX PDF management testphase bundle)}
+%</header>
+% \end{macrocode}
+% \subsection{messages}
+% \begin{macrocode}
+%<*package>
+\cs_new:Npn \@@_get_type:n #1
+ {
+ \str_case_e:nn { \str_head:n{#1} }
+ {
+ {g}{global}
+ {l}{local}
+ }
+ }
+\msg_new:nnn { pdfdict } { show-dict }
+ { %#1: name of the dictionary
+ %#2: expanded content
+ %#3: type
+ The~#3~dictionary~'#1'~
+ \tl_if_empty:nTF {#2}
+ { is~empty \\>~ . }
+ { contains~the~pairs~(without~outer~braces): #2 . }
+ }
+\msg_new:nnn { pdfdict } { unknown-dict }
+ {
+ The~dictionary~'#1'~is~unknown.
+ }
+\msg_new:nnn { pdfdict } { dict-already-defined }
+ {
+ The~#2~dictionary~'#1'~is~already~defined.
+ }
+\msg_new:nnn { pdfdict } { empty-value }
+ { The~value~#1~for~#2~is~blank~and~will~be~ignored }
+
+\msg_new:nnn { pdfdict } { invalid-name }
+ { Name~'#1'~is~not~valid\\
+ Names~of~dictionaries~should~start~with~'g_'~or~'l_' }
+
+% \end{macrocode}
+%
+
+% \subsection{Creating dictionaries}
+% \begin{variable}
+% {\g_@@_names_seq,\g_@@_gnames_seq}
+% Two seq to store the used names for diagnostics.
+% \begin{macrocode}
+\seq_new:N \g_@@_lnames_seq
+\seq_new:N \g_@@_gnames_seq
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}
+% {
+% \@@_name:n, \__kernel_pdfdict_name:n,
+% \@@_new:n, \pdfdict_new:n,
+% }
+%
+% This are the commands to create new dictionaries and to access their internal
+% name. All internal names start with |g__pdfdict_/| or |l__pdfdict_/|.
+%
+% For the other modules we also need a kernel command to access the internal
+% name to speed up the code and allow the use standard commands
+% of the \texttt{prop} module to deal with the dictionaries. For example\\
+% |\prop_clear:c { \__kernel_pdfdict_name:n { name }}|
+%
+% \begin{macrocode}
+\cs_new:Npn \@@_name:n #1 % #1 dictionary name
+ {
+ \str_head:n{#1}_@@_/#1_prop
+ }
+\cs_set_eq:NN \__kernel_pdfdict_name:n \@@_name:n
+
+\cs_new_protected:Npn \@@_new:n #1
+ {
+ \@@_if_exist:nTF { #1 }
+ {
+ \msg_error:nnxx
+ { pdfdict }
+ { dict-already-defined }
+ { \tl_to_str:n {#1} }
+ { \@@_get_type:n{#1} }
+ }
+ {
+ \str_case_e:nnF { \str_head:n{#1} }
+ {
+ {g}
+ {
+ \prop_new:c { \@@_name:n { #1 } }
+ \seq_gput_right:cn {g_@@_gnames_seq} { #1 }
+ }
+ {l}
+ {
+ \prop_new:c { \@@_name:n { #1 } }
+ \seq_gput_right:cn {g_@@_lnames_seq} { #1 }
+ }
+ }
+ {
+ \msg_error:nnx{pdfdict}{invalid-name}{\tl_to_str:n{#1}}
+ }
+ }
+ }
+
+\cs_set_eq:NN \pdfdict_new:n \@@_new:n
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \@@_set_eq:nn,\pdfdict_set_eq:nn,
+% \@@_gset_eq:nn,\pdfdict_gset_eq:nn
+% }
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_set_eq:nn #1 #2
+ {
+ \@@_if_exist:nTF { #2 }
+ {
+ \@@_if_exist:nF { #1 }
+ {
+ \@@_new:n { #1 }
+ }
+ \prop_set_eq:cc { \@@_name:n {#1} }{ \@@_name:n {#2} }
+ }
+ {
+ \msg_error:nnn { pdfdict } { unknown-dict } { #1 }
+ }
+ }
+
+\cs_set_eq:NN \pdfdict_set_eq:nn \@@_set_eq:nn
+
+\cs_new_protected:Npn \@@_gset_eq:nn #1 #2
+ {
+ \@@_if_exist:nTF { #2 }
+ {
+ \@@_if_exist:nF { #1 }
+ {
+ \@@_new:n { #1 }
+ }
+ \prop_gset_eq:cc { \@@_name:n {#1} }{ \@@_name:n {#2} }
+ }
+ {
+ \msg_error:nnn { pdfdict } { unknown-dict } { #1 }
+ }
+ }
+
+\cs_set_eq:NN \pdfdict_gset_eq:nn \@@_gset_eq:nn
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}
+% {
+% \@@_if_exist:n, \pdfdict_if_exist:n,
+% }
+%
+% Existence tests.
+% \begin{macrocode}
+%local
+\prg_new_conditional:Npnn \@@_if_exist:n #1 { p , T , F , TF }
+ {
+ \prop_if_exist:cTF
+ { \@@_name:n { #1 } }
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+\prg_set_eq_conditional:NNn
+ \pdfdict_if_exist:n \@@_if_exist:n { p , T , F , TF }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}
+% {
+% \@@_if_empty:n, \pdfdict_if_empty:n,
+% }
+%
+% Tests for emptiness.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_if_empty:n #1 { p , T , F , TF }
+ {
+ \prop_if_empty:cTF
+ { \@@_name:n { #1 } }
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+
+\prg_set_eq_conditional:NNn
+ \pdfdict_if_empty:n \@@_if_empty:n { p , T , F , TF }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}
+% {
+% \@@_put:nnn, \pdfdict_put:nnn,
+% \@@_gput:nnn,\pdfdict_gput:nnn
+% }
+% These are the commands to store values into the dictionaries.
+% The main difference to adding values to a normal property list is,
+% that the keys are converted with \cs{str_convert_pdfname:n}
+% and that empty values are ignored.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_put:nnn #1 #2 #3 %#1 (local) dict, #2 name, #3 value
+ {
+ \tl_if_blank:nTF { #3 }
+ {
+ \msg_warning:nnnn { pdfdict }{ empty-value }{ #2 } { #1 }
+ }
+ {
+ \@@_if_exist:nTF { #1 }
+ {
+ \exp_args:Nnx \prop_put:cnn
+ { \@@_name:n { #1 } }{ \str_convert_pdfname:n { #2 } } { #3 }
+ }
+ {
+ \msg_error:nnn { pdfdict } { unknown-dict } { #1 }
+ }
+ }
+ }
+
+\cs_set_eq:NN \pdfdict_put:nnn \@@_put:nnn
+\cs_generate_variant:Nn \pdfdict_put:nnn {nnx,nno}
+
+\cs_new_protected:Npn \@@_gput:nnn #1 #2 #3 %#1 global dict, #2 name, #3 value
+ {
+ \tl_if_empty:nTF { #3 }
+ {
+ \msg_warning:nnnn { pdfdict }{ empty-value }{ #2 } { #1 }
+ }
+ {
+ \@@_if_exist:nTF { #1 }
+ {
+ \exp_args:Nnx \prop_gput:cnn
+ { \@@_name:n { #1 } }{ \str_convert_pdfname:n { #2 } } { #3 }
+ }
+ {
+ \msg_error:nnn { pdfdict } { unknown-dict } { #1 }
+ }
+ }
+ }
+
+\cs_set_eq:NN \pdfdict_gput:nnn \@@_gput:nnn
+\cs_generate_variant:Nn \pdfdict_gput:nnn {nnx,nno}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \@@_get:nnN, \pdfdict_get:nnN,
+% }
+% Recover the values. The name must be first escaped to match the stored name.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_get:nnN #1 #2 #3 %dict,key,macro
+ {
+ \@@_if_exist:nTF { #1 }
+ {
+ \exp_args:Nnx \prop_get:cnN
+ { \@@_name:n { #1 } }
+ { \str_convert_pdfname:n { #2 } } #3
+ }
+ {
+ \msg_error:nnn { pdfdict } { unknown-dict } { #1 }
+ }
+ }
+
+\cs_set_eq:NN \pdfdict_get:nnN \@@_get:nnN
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \@@_remove:nn, \pdfdict_remove:nn,
+% \@@_gremove:nn,\pdfdict_gremove:nn
+% }
+% This removes a name/value pair from a dictionary.
+% The name has to be passed through the escaping.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_remove:nn #1 #2 %dict,name
+ {
+ \@@_if_exist:nTF { #1 }
+ {
+ \exp_args:Nnx \prop_remove:cn
+ { \@@_name:n { #1 } }{ \str_convert_pdfname:n { #2 } }
+ }
+ {
+ \msg_error:nnn { pdfdict } { unknown-dict } { #1 }
+ }
+ }
+\cs_set_eq:NN \pdfdict_remove:nn \@@_remove:nn
+
+\cs_new_protected:Npn \@@_gremove:nn #1 #2 %dict,name
+ {
+ \@@_if_exist:nTF { #1 }
+ {
+ \exp_args:Nnx \prop_gremove:cn
+ { \@@_name:n { #1 } }{ \str_convert_pdfname:n { #2 } }
+ }
+ {
+ \msg_error:nnn { pdfdict } { unknown-dict } { #1 }
+ }
+ }
+
+\cs_set_eq:NN \pdfdict_gremove:nn \@@_gremove:nn
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% { \@@_show:Nn, \pdfdict_show:n }
+% This allows to show the content of dictionaries. It also displays if a
+% dictionary is local or global. If both exists both are shown.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_show:Nn #1#2 %#1 message command, #2 dict
+ {
+ \prop_if_exist:cTF { \@@_name:n { #2 } }
+ {
+ #1
+ { pdfdict }
+ { show-dict }
+ { \tl_to_str:n {#2} }
+ { \prop_map_function:cN {\@@_name:n { #2 }} \msg_show_item:nn }
+ { \@@_get_type:n{#2} }
+ { }
+ }
+ {
+ #1 { pdfdict } { unknown-dict } { #2 } {}{}{}
+ }
+ }
+\cs_new_protected:Npn \pdfdict_show:n #1
+ {
+ \@@_show:Nn \msg_show:nnxxxx {#1}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@@_item:nn, \@@_item:ne}
+% \begin{macro}{\pdfdict_item:nn, \pdfdict_item:ne}
+% \begin{macrocode}
+\cs_new:Npn \@@_item:nn #1 #2 %#1 name, #2 value
+ {
+ \tl_if_blank:nF {#2} { /#1~#2~ }
+ }
+\cs_generate_variant:Nn \@@_item:nn {ne}
+\cs_set_eq:NN \pdfdict_item:nn \@@_item:nn
+\cs_generate_variant:Nn \pdfdict_item:nn {ne}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%
+% \begin{macro}
+% {
+% \@@_use:n,\pdfdict_use:n
+% }
+% \cs{@@_use:n} outputs a prop as needed in a dictionary:
+% as a list of /\meta{key} \meta{value} pairs.
+% \begin{NOTE}{UF}
+% !! is e-expansion the right thing?
+% \end{NOTE}
+% \begin{macrocode}
+\cs_new:Npn \@@_use:n #1 %#1 dict
+ {
+ \prop_map_function:cN { \@@_name:n { #1 } } \@@_item:ne
+ }
+
+\cs_set_eq:NN \pdfdict_use:n \@@_use:n
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex