%%
%% This is file `tagpdf.sty',
%% generated with the docstrip utility.
%%
%% The original source files were:
%%
%% tagpdf.dtx  (with options: `package')
%% tagpdf-checks.dtx  (with options: `package')
%% tagpdf-mc-shared.dtx  (with options: `shared')
%% tagpdf.dtx  (with options: `mcloading')
%% tagpdf-tree.dtx  (with options: `package')
%% tagpdf-roles.dtx  (with options: `package')
%% tagpdf-struct.dtx  (with options: `package')
%% tagpdf-space.dtx  (with options: `package')
%% tagpdf-user.dtx  (with options: `package')
%% 
%% Copyright (C) 2019-2022 Ulrike Fischer
%% 
%% 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:
%% 
%%    https://www.latex-project.org/lppl.txt
%% 
%% This file is part of the "tagpdf bundle" (The Work in LPPL)
%% and all files in that bundle must be distributed together.
%% 
%% File: tagpdf.dtx
\ProvidesExplPackage {tagpdf} {2022-01-13} {0.93}
  { A package to experiment with pdf tagging }

\bool_if:nF
  {
    \bool_lazy_and_p:nn
      {\cs_if_exist_p:N \pdfmanagement_if_active_p:}
      { \pdfmanagement_if_active_p: }
  }
  {  %error for now, perhaps warning later.
    \PackageError{tagpdf}
     {
       PDF~resource~management~is~no~active!\MessageBreak
       tagpdf~will~no~work.
     }
     {
       Activate~it~with \MessageBreak
       \string\RequirePackage{pdfmanagement-testphase}\MessageBreak
       \string\DeclareDocumentMetadata{<options>}\MessageBreak
       before~\string\documentclass
     }
  }
\prop_gput:Nnn \g_msg_module_name_prop { tag }{ tagpdf }
\bool_new:N\g__tag_mode_lua_bool
\DeclareOption {luamode}    { \sys_if_engine_luatex:T { \bool_gset_true:N \g__tag_mode_lua_bool } }
\DeclareOption {genericmode}{ \bool_gset_false:N\g__tag_mode_lua_bool }
\ExecuteOptions{luamode}
\ProcessOptions
\RequirePackage{l3ref-tmp}
 \cs_new_protected:Npn \__tag_lastpagelabel:
   {
     \legacy_if:nT { @filesw }
       {
         \exp_args:NNnx \exp_args:NNx\iow_now:Nn \@auxout
            {
              \token_to_str:N \newlabeldata
                {__tag_LastPage}
                {
                  {abspage} { \int_use:N \g_shipout_readonly_int}
                  {tagmcabs}{ \int_use:N \c@g__tag_MCID_abs_int }
                }
            }
       }
   }

 \AddToHook{enddocument/afterlastpage}
  {\__tag_lastpagelabel:}
 \cs_if_exist:NF \ref_value:nnn
   {
     \cs_new:Npn \ref_value:nnn #1#2#3
       {
         \exp_args:Nee
           \__ref_value:nnn
            { \tl_to_str:n {#1} } { \tl_to_str:n {#2} } {#3}
       }
     \cs_new:Npn \__ref_value:nnn #1#2#3
       {
         \tl_if_exist:cTF { g__ref_label_ #1 _ #2 _tl }
           { \tl_use:c { g__ref_label_ #1 _ #2 _tl } }
           {
             #3
           }
       }
   }

\tl_new:N    \l__tag_tmpa_tl
\str_new:N   \l__tag_tmpa_str
\prop_new:N  \l__tag_tmpa_prop
\seq_new:N   \l__tag_tmpa_seq
\seq_new:N   \l__tag_tmpb_seq
\clist_new:N \l__tag_tmpa_clist
\int_new:N   \l__tag_tmpa_int
\box_new:N   \l__tag_tmpa_box
\box_new:N   \l__tag_tmpb_box
\clist_const:Nn \c__tag_refmc_clist     {tagabspage,tagmcabs,tagmcid}
\clist_const:Nn \c__tag_refstruct_clist {tagstruct,tagstructobj}
\int_new:N  \l__tag_loglevel_int
\bool_new:N \g__tag_active_space_bool
\bool_new:N \g__tag_active_mc_bool
\bool_new:N \g__tag_active_tree_bool
\bool_new:N \g__tag_active_struct_bool
\bool_new:N \g__tag_active_struct_dest_bool
\bool_gset_true:N \g__tag_active_struct_dest_bool

\bool_new:N \l__tag_active_mc_bool
\bool_set_true:N \l__tag_active_mc_bool
\bool_new:N \l__tag_active_struct_bool
\bool_set_true:N \l__tag_active_struct_bool
\bool_new:N \g__tag_tagunmarked_bool
\prg_generate_conditional_variant:Nnn \pdf_object_if_exist:n {e}{T,F}
\cs_generate_variant:Nn \pdf_object_ref:n {e}
\cs_generate_variant:Nn \pdfannot_dict_put:nnn {nnx}
\cs_generate_variant:Nn \pdffile_embed_stream:nnn {nxx,oxx}
\cs_generate_variant:Nn \prop_gput:Nnn {Nxx}
\cs_generate_variant:Nn \prop_put:Nnn  {Nxx}
\cs_generate_variant:Nn \ref_label:nn { nv }
\cs_generate_variant:Nn \seq_set_split:Nnn{Nne}
\cs_generate_variant:Nn \str_set_convert:Nnnn {Nonn, Noon, Nnon }

\ref_attribute_gset:nnnn { tagstruct } {0} { now }
  { \int_use:N \c@g__tag_struct_abs_int }
\ref_attribute_gset:nnnn { tagstructobj } {} { now }
  {
    \pdf_object_if_exist:eT {__tag/struct/\int_use:N \c@g__tag_struct_abs_int}
      {
        \pdf_object_ref:e{__tag/struct/\int_use:N \c@g__tag_struct_abs_int}
      }
  }
\ref_attribute_gset:nnnn { tagabspage } {0} { shipout }
  { \int_use:N \g_shipout_readonly_int }
\ref_attribute_gset:nnnn { tagmcabs } {0} { now }
  { \int_use:N \c@g__tag_MCID_abs_int }
\ref_attribute_gset:nnnn {tagmcid }  {0} { now }
  { \int_use:N \g__tag_MCID_tmp_bypage_int }
\cs_new_protected:Npn \__tag_ref_label:nn #1 #2 %#1 label, #2 name of list mc or struct
  {
    \@bsphack
    \ref_label:nv {#1}{c__tag_ref#2_clist}
    \@esphack
  }
\cs_generate_variant:Nn \__tag_ref_label:nn {en}
\cs_new:Npn \__tag_ref_value:nnn #1 #2 #3 %#1 label, #2 attribute, #3 default
  {
    \ref_value:nnn {#1}{#2}{#3}
  }
\cs_generate_variant:Nn \__tag_ref_value:nnn {enn}
\cs_new:Npn \__tag_ref_value_lastpage:nn #1 #2
  {
    \ref_value:nnn {__tag_LastPage}{#1}{#2}
  }

\cs_set_eq:NN \__tag_prop_new:N        \prop_new:N
\cs_set_eq:NN \__tag_seq_new:N         \seq_new:N
\cs_set_eq:NN \__tag_prop_gput:Nnn     \prop_gput:Nnn
\cs_set_eq:NN \__tag_seq_gput_right:Nn \seq_gput_right:Nn
\cs_set_eq:NN \__tag_seq_item:cn       \seq_item:cn
\cs_set_eq:NN \__tag_prop_item:cn      \prop_item:cn
\cs_set_eq:NN \__tag_seq_show:N        \seq_show:N
\cs_set_eq:NN \__tag_prop_show:N       \prop_show:N

\cs_generate_variant:Nn \__tag_prop_gput:Nnn      { Nxn , Nxx, Nnx , cnn, cxn, cnx, cno}
\cs_generate_variant:Nn \__tag_seq_gput_right:Nn  { Nx  , No, cn, cx }
\cs_generate_variant:Nn \__tag_prop_new:N   { c }
\cs_generate_variant:Nn \__tag_seq_new:N    { c }
\cs_generate_variant:Nn \__tag_seq_show:N   { c }
\cs_generate_variant:Nn \__tag_prop_show:N  { c }

\cs_new_protected:Npn \tag_stop_group_begin:
  {
    \group_begin:
    \bool_set_false:N \l__tag_active_struct_bool
    \bool_set_false:N \l__tag_active_mc_bool
  }
\cs_set_eq:NN \tag_stop_group_end: \group_end:

\keys_define:nn { __tag / setup }
  {
    activate-space  .bool_gset:N = \g__tag_active_space_bool,
    activate-mc     .bool_gset:N = \g__tag_active_mc_bool,
    activate-tree   .bool_gset:N = \g__tag_active_tree_bool,
    activate-struct .bool_gset:N = \g__tag_active_struct_bool,
    activate-all    .meta:n =
      {activate-mc={#1},activate-tree={#1},activate-struct={#1}},
    activate-all  .default:n = true,
    no-struct-dest .bool_gset_inverse:N = \g__tag_active_struct_dest_bool,
 %    \end{macrocode}
    log             .choice:,
    log / none      .code:n = {\int_set:Nn \l__tag_loglevel_int { 0 }},
    log / v         .code:n =
      {
        \int_set:Nn \l__tag_loglevel_int { 1 }
        \cs_set_protected:Nn \__tag_check_typeout_v:n { \iow_term:x {##1} }
      },
    log / vv        .code:n = {\int_set:Nn \l__tag_loglevel_int { 2 }},
    log / vvv       .code:n = {\int_set:Nn \l__tag_loglevel_int { 3 }},
    log / all       .code:n = {\int_set:Nn \l__tag_loglevel_int { 10 }},
    tagunmarked     .bool_gset:N = \g__tag_tagunmarked_bool,
    tagunmarked     .initial:n  = true,
    tabsorder       .choice:,
    tabsorder / row       .code:n =
      \pdfmanagement_add:nnn { Page } {Tabs}{/R},
    tabsorder / column    .code:n =
      \pdfmanagement_add:nnn { Page } {Tabs}{/C},
    tabsorder / structure .code:n =
      \pdfmanagement_add:nnn { Page } {Tabs}{/S},
    tabsorder / none      .code:n =
      \pdfmanagement_remove:nn {Page} {Tabs},
    tabsorder       .initial:n = structure,
    uncompress      .code:n = { \pdf_uncompress:  },
  }
\sys_if_engine_luatex:T
  {
    \file_input:n {tagpdf-luatex.def}
  }
%% File: tagpdf-checks.dtx
\msg_new:nnn { tag } {mc-nested} { nested~marked~content~found~-~mcid~#1 }
\msg_new:nnn { tag } {mc-tag-missing} { required~tag~missing~-~mcid~#1 }
\msg_new:nnn { tag } {mc-label-unknown}
  { label~#1~unknown~or~has~been~already~used.\\
    Either~rerun~or~remove~one~of~the~uses. }
\msg_new:nnn { tag } {mc-used-twice} { mc~#1~has~been~already~used }
\msg_new:nnn { tag } {mc-not-open} { there~is~no~mc~to~end~at~#1 }
\msg_new:nnn { tag } {mc-pushed} { #1~has~been~pushed~to~the~mc~stack}
\msg_new:nnn { tag } {mc-popped} { #1~has~been~removed~from~the~mc~stack }
\msg_new:nnn { tag } {mc-current}
  { current~MC:~
    \bool_if:NTF\g__tag_in_mc_bool
      {abscnt=\__tag_get_mc_abs_cnt:,~tag=\g__tag_mc_key_tag_tl}
      {no~MC~open,~current~abscnt=\__tag_get_mc_abs_cnt:"}
  }
\msg_new:nnn { tag } {struct-no-objnum} { objnum~missing~for~structure~#1 }
\msg_new:nnn { tag }
  {struct-faulty-nesting}
  { there~is~no~open~structure~on~the~stack }
\msg_new:nnn { tag } {struct-missing-tag} { a~structure~must~have~a~tag! }
\msg_new:nnn { tag } {struct-used-twice}
  { structure~with~label~#1~has~already~been~used}
\msg_new:nnn { tag } {struct-label-unknown}
  { structure~with~label~#1~is~unknown~rerun}
\msg_new:nnn { tag } {struct-show-closing}
  { closing~structure~#1~tagged~\prop_item:cn{g__tag_struct_#1_prop}{S} }
\msg_new:nnn { tag } {attr-unknown}  { attribute~#1~is~unknown}
\msg_new:nnn { tag } {role-missing}     { tag~#1~has~no~role~assigned  }
\msg_new:nnn { tag } {role-unknown}     { role~#1~is~not~known  }
\msg_new:nnn { tag } {role-unknown-tag} { tag~#1~is~not~known  }
\msg_new:nnn { tag } {role-tag}         { mapping~tag~#1~to~role~#2  }
\msg_new:nnn { tag } {new-tag}          { adding~new~tag~#1 }
\msg_new:nnn { tag } {tree-mcid-index-wrong}
  {something~is~wrong~with~the~mcid--rerun}
\msg_new:nnn { tag } {sys-no-interwordspace}
  {engine/output~mode~#1~doesn't~support~the~interword~spaces}
\cs_set_eq:NN \__tag_check_typeout_v:n \use_none:n
\msg_new:nnnn { tag } {para-hook-count-wrong}
  {The~number~of~automatic~begin~(#1)~and~end~(#2)~para~hooks~differ!}
  {This~quite~probably~a~coding~error~and~the~structure~will~be~wrong!}
\cs_new:Npn \tag_get:n #1   { \use:c {__tag_get_data_#1: } }
\prg_new_conditional:Npnn \tag_if_active: { p , T , TF, F }
  {
     \bool_lazy_all:nTF
       {
         {\g__tag_active_struct_bool}
         {\g__tag_active_mc_bool}
         {\g__tag_active_tree_bool}
         {\l__tag_active_struct_bool}
         {\l__tag_active_mc_bool}
       }
       {
         \prg_return_true:
       }
       {
         \prg_return_false:
       }
  }
\prg_new_conditional:Npnn \__tag_check_if_active_mc: {T,F,TF}
  {
    \bool_lazy_and:nnTF { \g__tag_active_mc_bool } { \l__tag_active_mc_bool }
      {
         \prg_return_true:
      }
      {
         \prg_return_false:
      }
  }
\prg_new_conditional:Npnn \__tag_check_if_active_struct: {T,F,TF}
  {
    \bool_lazy_and:nnTF { \g__tag_active_struct_bool } { \l__tag_active_struct_bool }
      {
         \prg_return_true:
      }
      {
         \prg_return_false:
      }
  }
\cs_new_protected:Npn \__tag_check_structure_has_tag:n #1 %#1 struct num
  {
    \prop_if_in:cnF { g__tag_struct_#1_prop }
      {S}
      {
        \msg_error:nn { tag } {struct-missing-tag}
      }
  }
\cs_new_protected:Npn \__tag_check_structure_tag:N #1
  {
    \prop_if_in:NoF \g__tag_role_tags_prop {#1}
      {
        \msg_warning:nnx { tag } {role-unknown-tag} {#1}
      }
  }
\cs_new_protected:Npn \__tag_check_info_closing_struct:n #1 %#1 struct num
  {
    \int_compare:nNnT {\l__tag_loglevel_int} > { 0 }
      {
        \msg_info:nnn { tag } {struct-show-closing} {#1}
      }
  }

\cs_generate_variant:Nn \__tag_check_info_closing_struct:n {o,x}
\cs_new_protected:Npn \__tag_check_no_open_struct:
  {
    \msg_error:nn { tag } {struct-faulty-nesting}
  }
\cs_new_protected:Npn \__tag_check_struct_used:n #1 %#1 label
  {
    \prop_get:cnNT
      {g__tag_struct_\__tag_ref_value:enn{tagpdfstruct-#1}{tagstruct}{unknown}_prop}
      {P}
      \l_tmpa_tl
      {
        \msg_warning:nnn { tag } {struct-used-twice} {#1}
      }
  }
\cs_new_protected:Npn \__tag_check_add_tag_role:nn #1 #2 %#1 tag, #2 role
  {
    \tl_if_empty:nTF {#2}
      {
        \msg_warning:nnn { tag } {role-missing} {#1}
      }
      {
        \prop_get:NnNTF \g__tag_role_tags_prop {#2} \l_tmpa_tl
          {
            \int_compare:nNnT {\l__tag_loglevel_int} > { 0 }
              {
                \msg_info:nnnn { tag } {role-tag} {#1} {#2}
              }
          }
          {
            \msg_warning:nnn { tag } {role-unknown} {#2}
          }
      }
  }
\cs_new_protected:Npn \__tag_check_mc_if_nested:
  {
    \__tag_mc_if_in:T
      {
        \msg_warning:nnx { tag } {mc-nested} { \__tag_get_mc_abs_cnt: }
      }
  }

\cs_new_protected:Npn \__tag_check_mc_if_open:
  {
    \__tag_mc_if_in:F
      {
        \msg_warning:nnx { tag } {mc-not-open} { \__tag_get_mc_abs_cnt: }
      }
  }
\cs_new_protected:Npn \__tag_check_mc_pushed_popped:nn #1 #2
  {
    \int_compare:nNnT
      { \l__tag_loglevel_int } ={ 2 }
      { \msg_info:nnx {tag}{mc-#1}{#2} }
    \int_compare:nNnT
      { \l__tag_loglevel_int } > { 2 }
      {
        \msg_info:nnx {tag}{mc-#1}{#2}
        \seq_log:N \g__tag_mc_stack_seq
      }
  }
\cs_new_protected:Npn \__tag_check_mc_tag:N #1  %#1 is var with a tag name in it
  {
    \tl_if_empty:NT #1
      {
        \msg_error:nnx { tag } {mc-tag-missing} { \__tag_get_mc_abs_cnt: }
      }
   \prop_if_in:NoF \g__tag_role_tags_NS_prop {#1}
     {
       \msg_warning:nnx { tag } {role-unknown-tag} {#1}
     }
  }
\cs_new_protected:Npn \__tag_check_init_mc_used:
  {
    \intarray_new:Nn \g__tag_check_mc_used_intarray { 65536 }
    \cs_gset_eq:NN \__tag_check_init_mc_used: \prg_do_nothing:
  }
\cs_new_protected:Npn \__tag_check_mc_used:n #1 %#1 mcid abscnt
  {
    \int_compare:nNnT {\l__tag_loglevel_int} > { 2 }
      {
        \__tag_check_init_mc_used:
        \intarray_gset:Nnn \g__tag_check_mc_used_intarray
          {#1}
          { \intarray_item:Nn \g__tag_check_mc_used_intarray {#1} + 1 }
        \int_compare:nNnT
          {
            \intarray_item:Nn \g__tag_check_mc_used_intarray {#1}
          }
          >
          { 1 }
          {
            \msg_warning:nnn { tag } {mc-used-twice} {#1}
          }
      }
  }
\cs_new_protected:Npn \__tag_check_show_MCID_by_page:
  {
    \tl_set:Nx \l__tag_tmpa_tl
      {
        \__tag_ref_value_lastpage:nn
          {abspage}
          {-1}
      }
    \int_step_inline:nnnn {1}{1}
      {
        \l__tag_tmpa_tl
      }
      {
        \seq_clear:N \l_tmpa_seq
        \int_step_inline:nnnn
          {1}
          {1}
          {
            \__tag_ref_value_lastpage:nn
              {tagmcabs}
              {-1}
          }
          {
            \int_compare:nT
              {
                \__tag_ref_value:enn
                  {mcid-####1}
                  {tagabspage}
                  {-1}
                =
                ##1
             }
             {
               \seq_gput_right:Nx \l_tmpa_seq
                 {
                   Page##1-####1-
                   \__tag_ref_value:enn
                     {mcid-####1}
                     {tagmcid}
                     {-1}
                 }
             }
          }
          \seq_show:N \l_tmpa_seq
      }
  }
\prg_new_conditional:Npnn \__tag_check_if_mc_in_galley: { T,F,TF }
 {
   \tl_if_eq:NNTF \l__tag_mc_firstmarks_seq \l__tag_mc_botmarks_seq
    { \prg_return_false: }
    { \prg_return_true: }
 }

\prg_new_conditional:Npnn \__tag_check_if_mc_tmb_missing: { T,F,TF }
 {
  \bool_if:nTF
    {
      \str_if_eq_p:ee {\seq_item:Nn \l__tag_mc_firstmarks_seq {1}}{e-}
      ||
      \str_if_eq_p:ee {\seq_item:Nn \l__tag_mc_firstmarks_seq {1}}{b+}
    }
    { \prg_return_true: }
    { \prg_return_false: }
 }

\prg_new_conditional:Npnn \__tag_check_if_mc_tme_missing: { T,F,TF }
 {
   \str_if_eq:eeTF {\seq_item:Nn \l__tag_mc_botmarks_seq {1}}{b+}
    { \prg_return_true: }
    { \prg_return_false: }
 }
%% File: tagpdf-mc.dtx

\newcounter { g__tag_MCID_abs_int }
\cs_new:Npn \__tag_get_mc_abs_cnt: { \int_use:N \c@g__tag_MCID_abs_int }
\int_new:N \g__tag_MCID_tmp_bypage_int
\bool_new:N \g__tag_in_mc_bool
\__tag_prop_new:N \g__tag_mc_parenttree_prop
\seq_new:N \g__tag_mc_stack_seq
\tl_new:N \l__tag_mc_artifact_type_tl
\bool_new:N \l__tag_mc_key_stash_bool
\bool_new:N \l__tag_mc_artifact_bool
\tl_new:N \l__tag_mc_key_tag_tl
\tl_new:N \g__tag_mc_key_tag_tl
\tl_new:N \l__tag_mc_key_label_tl
\tl_new:N \l__tag_mc_key_properties_tl
\cs_new:Nn \__tag_mc_handle_mc_label:n
  {
    \__tag_ref_label:en{tagpdf-#1}{mc}
  }
\cs_new_protected:Npn \__tag_mc_set_label_used:n #1 %#1 labelname
  {
    \tl_new:c { g__tag_mc_label_\tl_to_str:n{#1}_used_tl }
  }
\cs_new_protected:Npn \tag_mc_use:n #1 %#1: label name
  {
    \__tag_check_if_active_struct:T
      {
        \tl_set:Nx  \l__tag_tmpa_tl { \__tag_ref_value:nnn{tagpdf-#1}{tagmcabs}{} }
        \tl_if_empty:NTF\l__tag_tmpa_tl
          {
            \msg_warning:nnn {tag} {mc-label-unknown} {#1}
          }
          {
            \cs_if_free:cTF { g__tag_mc_label_\tl_to_str:n{#1}_used_tl }
              {
                \__tag_mc_handle_stash:x { \l__tag_tmpa_tl }
                \__tag_mc_set_label_used:n {#1}
              }
              {
                 \msg_warning:nnn {tag}{mc-used-twice}{#1}
              }
          }
       }
  }
\cs_new_protected:Npn \tag_mc_artifact_group_begin:n #1
 {
  \tag_mc_end_push:
  \tag_mc_begin:n {artifact=#1}
  \tag_stop_group_begin:
 }

\cs_new_protected:Npn \tag_mc_artifact_group_end:
 {
  \tag_stop_group_end:
  \tag_mc_end:
  \tag_mc_begin_pop:n{}
 }
\cs_new_protected:Npn \tag_mc_end_push:
  {
    \__tag_check_if_active_mc:T
      {
        \__tag_mc_if_in:TF
          {
            \seq_gpush:Nx \g__tag_mc_stack_seq { \tag_get:n {mc_tag} }
            \__tag_check_mc_pushed_popped:nn
              { pushed }
              { \tag_get:n {mc_tag} }
            \tag_mc_end:
          }
          {
            \seq_gpush:Nn \g__tag_mc_stack_seq {-1}
            \__tag_check_mc_pushed_popped:nn { pushed }{-1}
          }
      }
  }

\cs_new_protected:Npn \tag_mc_begin_pop:n #1
  {
    \__tag_check_if_active_mc:T
      {
        \seq_gpop:NNTF \g__tag_mc_stack_seq \l__tag_tmpa_tl
          {
            \tl_if_eq:NnTF \l__tag_tmpa_tl {-1}
              {
                \__tag_check_mc_pushed_popped:nn {popped}{-1}
              }
              {
                \__tag_check_mc_pushed_popped:nn {popped}{\l__tag_tmpa_tl}
                \tag_mc_begin:n {tag=\l__tag_tmpa_tl,#1}
              }
          }
          {
            \__tag_check_mc_pushed_popped:nn {popped}{empty~stack,~nothing}
          }
      }
  }
\keys_define:nn { __tag / mc }
  {
    stash                    .bool_set:N    = \l__tag_mc_key_stash_bool,
    __artifact-bool          .bool_set:N    = \l__tag_mc_artifact_bool,
    __artifact-type          .choice:,
    __artifact-type / pagination .code:n    =
      {
        \tl_set:Nn \l__tag_mc_artifact_type_tl { Pagination }
      },
    __artifact-type / pagination/header .code:n    =
      {
        \tl_set:Nn \l__tag_mc_artifact_type_tl { Pagination/Subtype/Header }
      },
    __artifact-type / pagination/footer .code:n    =
      {
        \tl_set:Nn \l__tag_mc_artifact_type_tl { Pagination/Subtype/Footer }
      },
    __artifact-type / layout     .code:n    =
      {
        \tl_set:Nn \l__tag_mc_artifact_type_tl { Layout }
      },
    __artifact-type / page       .code:n    =
      {
        \tl_set:Nn \l__tag_mc_artifact_type_tl { Page }
      },
    __artifact-type / background .code:n    =
      {
        \tl_set:Nn \l__tag_mc_artifact_type_tl { Background }
      },
    __artifact-type / notype     .code:n    =
      {
        \tl_set:Nn \l__tag_mc_artifact_type_tl {}
      },
    __artifact-type /      .code:n    =
      {
        \tl_set:Nn \l__tag_mc_artifact_type_tl {}
      },
  }
%% File: tagpdf.dtx
\bool_if:NTF \g__tag_mode_lua_bool
  {
   \RequirePackage {tagpdf-mc-code-lua}
  }
  {
   \RequirePackage {tagpdf-mc-code-generic} %
  }
%% File: tagpdf-tree.dtx
\hook_gput_code:nnn{begindocument}{tagpdf}
  {
    \bool_if:NT \g__tag_active_tree_bool
      {
        \sys_if_output_pdf:TF
          {
            \AddToHook{enddocument/end} { \__tag_finish_structure: }
          }
          {
            \AddToHook{shipout/lastpage} { \__tag_finish_structure: }
          }
      }
  }
\pdf_object_new:nn { __tag/struct/0 }{ dict }
\hook_gput_code:nnn{shipout/lastpage}{tagpdf}
  {
    \bool_if:NT \g__tag_active_tree_bool
      {
        \pdfmanagement_add:nnn { Catalog / MarkInfo } { Marked } { true }
        \pdfmanagement_add:nnx
          { Catalog }
          { StructTreeRoot }
          { \pdf_object_ref:n { __tag/struct/0 } }
      }
  }
\cs_new_protected:Npn \__tag_tree_write_structtreeroot:
  {
     \__tag_prop_gput:cnx
       { g__tag_struct_0_prop }
       { ParentTree }
       { \pdf_object_ref:n { __tag/tree/parenttree } }
     \__tag_prop_gput:cnx
       { g__tag_struct_0_prop }
       { RoleMap }
       { \pdf_object_ref:n { __tag/tree/rolemap } }
     \__tag_struct_write_obj:n { 0 }
  }
\cs_new_protected:Npn \__tag_tree_write_structelements:
  {
    \int_step_inline:nnnn {1}{1}{\c@g__tag_struct_abs_int}
      {
        \__tag_struct_write_obj:n { ##1 }
      }
  }
\pdf_object_new:nn { __tag/tree/parenttree }{ dict }
\newcounter  { g__tag_parenttree_obj_int }
\hook_gput_code:nnn{begindocument}{tagpdf}
  {
    \int_gset:Nn
      \c@g__tag_parenttree_obj_int
      { \__tag_ref_value_lastpage:nn{abspage}{100}  }
  }
\tl_new:N \g__tag_parenttree_objr_tl
\cs_new_protected:Npn \__tag_parenttree_add_objr:nn #1 #2 %#1 StructParent number, #2 objref
  {
    \tl_gput_right:Nx \g__tag_parenttree_objr_tl
      {
        #1 \c_space_tl #2 ^^J
      }
  }
\tl_new:N \l__tag_parenttree_content_tl

\cs_new_protected:Npn \__tag_tree_fill_parenttree:
  {
    \int_step_inline:nnnn{1}{1}{\__tag_ref_value_lastpage:nn{abspage}{-1}} %not quite clear if labels are needed. See lua code
      { %page ##1
        \prop_clear:N \l__tag_tmpa_prop
        \int_step_inline:nnnn{1}{1}{\__tag_ref_value_lastpage:nn{tagmcabs}{-1}}
          {
            %mcid####1
            \int_compare:nT
              {\__tag_ref_value:enn{mcid-####1}{tagabspage}{-1}=##1} %mcid is on current page
              {% yes
                \prop_put:Nxx
                  \l__tag_tmpa_prop
                  {\__tag_ref_value:enn{mcid-####1}{tagmcid}{-1}}
                  {\prop_item:Nn \g__tag_mc_parenttree_prop {####1}}
              }
          }
        \tl_put_right:Nx\l__tag_parenttree_content_tl
          {
            \int_eval:n {##1-1}\c_space_tl
            [\c_space_tl %]
          }
        \int_step_inline:nnnn
          {0}
          {1}
          { \prop_count:N \l__tag_tmpa_prop -1 }
          {
            \prop_get:NnNTF \l__tag_tmpa_prop {####1} \l__tag_tmpa_tl
              {% page#1:mcid##1:\l__tag_tmpa_tl :content
                \tl_put_right:Nx \l__tag_parenttree_content_tl
                  {
                    \pdf_object_if_exist:eT { __tag/struct/\l__tag_tmpa_tl }
                     {
                       \pdf_object_ref:e { __tag/struct/\l__tag_tmpa_tl }
                     }
                    \c_space_tl
                  }
              }
              {
                \msg_warning:nn { tag } {tree-mcid-index-wrong}
              }
          }
        \tl_put_right:Nn
          \l__tag_parenttree_content_tl
          {%[
            ]^^J
          }
      }
  }
\cs_new_protected:Npn \__tag_tree_lua_fill_parenttree:
  {
    \tl_set:Nn \l__tag_parenttree_content_tl
      {
        \lua_now:e
          {
            ltx.__tag.func.output_parenttree
              (
                \int_use:N\g_shipout_readonly_int
              )
          }
      }
  }
\cs_new_protected:Npn \__tag_tree_write_parenttree:
  {
    \bool_if:NTF \g__tag_mode_lua_bool
      {
        \__tag_tree_lua_fill_parenttree:
      }
      {
        \__tag_tree_fill_parenttree:
      }
    \tl_put_right:NV \l__tag_parenttree_content_tl\g__tag_parenttree_objr_tl
    \pdf_object_write:nx  { __tag/tree/parenttree }
      {
        /Nums\c_space_tl [\l__tag_parenttree_content_tl]
      }
  }
\pdf_object_new:nn { __tag/tree/rolemap }{ dict }
\cs_new_protected:Npn \__tag_tree_write_rolemap:
  {
    \pdf_object_write:nx  { __tag/tree/rolemap }
      {
        \pdfdict_use:n{g__tag_role/RoleMap_dict}
      }
  }
\cs_new_protected:Npn \__tag_tree_write_classmap:
  {
    \tl_clear:N \l__tag_tmpa_tl
    \seq_gremove_duplicates:N \g__tag_attr_class_used_seq
    \seq_set_map:NNn \l__tag_tmpa_seq \g__tag_attr_class_used_seq
      {
        /##1\c_space_tl
        <<
          \prop_item:Nn
            \g__tag_attr_entries_prop
            {##1}
        >>
      }
    \tl_set:Nx \l__tag_tmpa_tl
      {
        \seq_use:Nn
          \l__tag_tmpa_seq
          { \iow_newline: }
      }
    \tl_if_empty:NF
      \l__tag_tmpa_tl
      {
        \pdf_object_new:nn { __tag/tree/classmap }{ dict }
        \pdf_object_write:nx
          { __tag/tree/classmap }
          { \l__tag_tmpa_tl }
        \__tag_prop_gput:cnx
          { g__tag_struct_0_prop }
          { ClassMap }
          { \pdf_object_ref:n { __tag/tree/classmap }  }
      }
  }
\pdf_object_new:nn{ __tag/tree/namespaces }{array}
\cs_new_protected:Npn \__tag_tree_write_namespaces:
  {
    \prop_map_inline:Nn \g__tag_role_NS_prop
      {
        \pdfdict_if_empty:nF {g__tag_role/RoleMapNS_##1_dict}
          {
            \pdf_object_write:nx {__tag/RoleMapNS/##1}
              {
                \pdfdict_use:n {g__tag_role/RoleMapNS_##1_dict}
              }
            \pdfdict_gput:nnx{g__tag_role/Namespace_##1_dict}
              {RoleMapNS}{\pdf_object_ref:n {__tag/RoleMapNS/##1}}
          }
        \pdf_object_write:nx{tag/NS/##1}
          {
             \pdfdict_use:n {g__tag_role/Namespace_##1_dict}
          }
      }
    \pdf_object_write:nx {__tag/tree/namespaces}
      {
        \prop_map_tokens:Nn \g__tag_role_NS_prop{\use_ii:nn}
      }
  }
\cs_new_protected:Npn \__tag_finish_structure:
  {
    \bool_if:NT\g__tag_active_tree_bool
      {
        \hook_use:n {tagpdf/finish/before}
        \__tag_tree_write_parenttree:
        \__tag_tree_write_rolemap:
        \__tag_tree_write_classmap:
        \__tag_tree_write_namespaces:
        \__tag_tree_write_structelements: %this is rather slow!!
        \__tag_tree_write_structtreeroot:
      }
  }
\hook_gput_code:nnn{begindocument}{tagpdf}
  {
    \bool_if:NT\g__tag_active_tree_bool
      {
       \hook_gput_code:nnn{shipout/before} { tagpdf/structparents }
         {
           \pdfmanagement_add:nnx
             { Page }
             { StructParents }
             { \int_eval:n { \g_shipout_readonly_int} }
         }
      }
  }
%% File: tagpdf-roles.dtx
\__tag_seq_new:N  \g__tag_role_tags_seq  %to get names (type/NS) from numbers
\__tag_prop_new:N \g__tag_role_tags_prop %to get numbers  from names (type/NS)
\prop_new:N    \g__tag_role_tags_NS_prop %to namespace info
\prop_new:N \g__tag_role_NS_prop % collect namespaces
\tl_new:N \l__tag_role_tag_tmpa_tl
\tl_new:N \l__tag_role_tag_namespace_tmpa_tl
\tl_new:N \l__tag_role_role_tmpa_tl
\tl_new:N \l__tag_role_role_namespace_tmpa_tl
\cs_new_protected:Npn \__tag_role_NS_new:nnn #1 #2 #3
  {
    \pdf_object_new:nn {tag/NS/#1}{dict}
    \pdfdict_new:n     {g__tag_role/Namespace_#1_dict}
    \pdf_object_new:nn {__tag/RoleMapNS/#1}{dict}
    \pdfdict_new:n     {g__tag_role/RoleMapNS_#1_dict}
    \pdfdict_gput:nnn
      {g__tag_role/Namespace_#1_dict}
      {Type}
      {/Namespace}
    \pdf_string_from_unicode:nnN{utf8/string}{#2}\l_tmpa_str
    \tl_if_empty:NF \l_tmpa_str
      {
        \pdfdict_gput:nnx
          {g__tag_role/Namespace_#1_dict}
          {NS}
          {\l_tmpa_str}
      }
    %RoleMapNS is added in tree
    \tl_if_empty:nF  {#3}
     {
       \pdfdict_gput:nnx{g__tag_role/Namespace_#1_dict}
        {Schema}{#3}
     }
    \prop_gput:Nnx \g__tag_role_NS_prop {#1}{\pdf_object_ref:n{tag/NS/#1}~}
  }
\str_const:Nx \c__tag_role_userNS_id_str
  { data:,
    \int_to_Hex:n{\int_rand:n {65535}}
    \int_to_Hex:n{\int_rand:n {65535}}
    -
    \int_to_Hex:n{\int_rand:n {65535}}
    -
    \int_to_Hex:n{\int_rand:n {65535}}
    -
    \int_to_Hex:n{\int_rand:n {65535}}
    -
    \int_to_Hex:n{\int_rand:n {16777215}}
    \int_to_Hex:n{\int_rand:n {16777215}}
  }
\pdf_version_compare:NnT > {1.9}
  {
    \__tag_role_NS_new:nnn {pdf}   {http://iso.org/pdf/ssn}{}
    \__tag_role_NS_new:nnn {pdf2}  {http://iso.org/pdf2/ssn}{}
    \__tag_role_NS_new:nnn {mathml}{http://www.w3.org/1998/Math/MathML}{}
    \exp_args:Nnx
    \__tag_role_NS_new:nnn {user}{\c__tag_role_userNS_id_str}{}
  }
\clist_const:Nn \c__tag_role_sttags_pdf_pdfII_clist
  {
    Document,   %A complete document. This is the root element
                %of any structure tree containing
                %multiple parts or multiple articles.
    Part,       %A large-scale division of a document.
    Sect,       %A container for grouping related content elements.
    Div,        %A generic block-level element or group of elements
    Caption,    %A brief portion of text describing a table or figure.
    Index,
    NonStruct,  %probably not needed
    H,
    H1,
    H2,
    H3,
    H4,
    H5,
    H6,
    P,
    L,           %list
    LI,          %list item (around label and list item body)
    Lbl,         %list label
    LBody,       %list item body
    Table,
    TR,          %table row
    TH,          %table header cell
    TD,          %table data cell
    THead,       %table header (n rows)
    TBody,       %table rows
    TFoot,       %table footer
    Span,        %generic inline marker
    Link,        %
    Annot,
    Figure,
    Formula,
    Form,
    % ruby warichu etc ..
    Ruby,
    RB,
    RT,
    Warichu,
    WT,
    WP,
    Artifact % only MC-tag ?...
  }

\clist_const:Nn \c__tag_role_sttags_only_pdf_clist
 {
   Art,        %A relatively self-contained body of text
               %constituting a single narrative or exposition
   BlockQuote, %A portion of text consisting of one or more paragraphs
               %attributed to someone other than the author of the
               %surrounding text.
   TOC,        %A list made up of table of contents item entries
               %(structure tag TOCI; see below) and/or other
               %nested table of contents entries
   TOCI,       %An individual member of a table of contents.
               %This entry's children can be any of the following structure  tags:
               %Lbl,Reference,NonStruct,P,TOC
   Index,
   Private,
   Quote,       %inline quote
   Note,        %footnote, endnote. Lbl can be child
   Reference,   %A citation to content elsewhere in the document.
   BibEntry,    %bibentry
   Code
 }

\clist_const:Nn \c__tag_role_sttags_only_pdfII_clist
 {
   DocumentFragment
   ,Aside
   ,H7
   ,H8
   ,H9
   ,H10
   ,Title
   ,FENote
   ,Sub
   ,Em
   ,Strong
   ,Artifact
 }

\clist_const:Nn \c__tag_role_sttags_mathml_clist
 {
   abs
   ,and
   ,annotation
   ,apply
   ,approx
   ,arccos
   ,arccosh
   ,arccot
   ,arccoth
   ,arccsc
   ,arccsch
   ,arcsec
   ,arcsech
   ,arcsin
   ,arcsinh
   ,arctan
   ,arctanh
   ,arg
   ,bind
   ,bvar
   ,card
   ,cartesianproduct
   ,cbytes
   ,ceiling
   ,cerror
   ,ci
   ,cn
   ,codomain
   ,complexes
   ,compose
   ,condition
   ,conjugate
   ,cos
   ,cosh
   ,cot
   ,coth
   ,cs
   ,csc
   ,csch
   ,csymbol
   ,curl
   ,declare
   ,degree
   ,determinant
   ,diff
   ,divergence
   ,divide
   ,domain
   ,domainofapplication
   ,emptyset
   ,eq
   ,equivalent
   ,eulergamma
   ,exists
   ,exp
   ,exponentiale
   ,factorial
   ,factorof
   ,false
   ,floor
   ,fn
   ,forall
   ,gcd
   ,geq
   ,grad
   ,gt
   ,ident
   ,image
   ,imaginary
   ,imaginaryi
   ,implies
   ,in
   ,infinity
   ,int
   ,integers
   ,intersect
   ,interval
   ,inverse
   ,lambda
   ,laplacian
   ,lcm
   ,leq
   ,limit
   ,ln
   ,log
   ,logbase
   ,lowlimit
   ,lt
   ,maction
   ,maligngroup
   ,malignmark
   ,math
   ,matrix
   ,matrixrow
   ,max
   ,mean
   ,median
   ,menclose
   ,merror
   ,mfenced
   ,mfrac
   ,mglyph
   ,mi
   ,min
   ,minus
   ,mlabeledtr
   ,mlongdiv
   ,mmultiscripts
   ,mn
   ,mo
   ,mode
   ,moment
   ,momentabout
   ,mover
   ,mpadded
   ,mphantom
   ,mprescripts
   ,mroot
   ,mrow
   ,ms
   ,mscarries
   ,mscarry
   ,msgroup
   ,msline
   ,mspace
   ,msqrt
   ,msrow
   ,mstack
   ,mstyle
   ,msub
   ,msubsup
   ,msup
   ,mtable
   ,mtd
   ,mtext
   ,mtr
   ,munder
   ,munderover
   ,naturalnumbers
   ,neq
   ,none
   ,not
   ,notanumber
   ,notin
   ,notprsubset
   ,notsubset
   ,or
   ,otherwise
   ,outerproduct
   ,partialdiff
   ,pi
   ,piece
   ,piecewise
   ,plus
   ,power
   ,primes
   ,product
   ,prsubset
   ,quotient
   ,rationals
   ,real
   ,reals
   ,reln
   ,rem
   ,root
   ,scalarproduct
   ,sdev
   ,sec
   ,sech
   ,selector
   ,semantics
   ,sep
   ,set
   ,setdiff
   ,share
   ,sin
   ,sinh
   ,subset
   ,sum
   ,tan
   ,tanh
   ,tendsto
   ,times
   ,transpose
   ,true
   ,union
   ,uplimit
   ,variance
   ,vector
   ,vectorproduct
   ,xor
 }

\prop_const_from_keyval:Nn \c__tag_role_sttags_pdfII_to_pdf_prop
  {
    DocumentFragment = Art,
    Aside = Note,
    Title = H1,
    Sub   = Span,
    H7    = H6 ,
    H8    = H6 ,
    H9    = H6 ,
    H10   = H6,
    FENote= Note,
    Em    = Span,
    Strong= Span,
  }

\clist_map_inline:Nn \c__tag_role_sttags_pdf_pdfII_clist
  {
    \__tag_seq_gput_right:Nn \g__tag_role_tags_seq { #1 }
    \prop_gput:Nnn \g__tag_role_tags_NS_prop    { #1 }{ pdf2 }
  }
\clist_map_inline:Nn \c__tag_role_sttags_only_pdf_clist
  {
    \__tag_seq_gput_right:Nn \g__tag_role_tags_seq { #1 }
    \prop_gput:Nnn \g__tag_role_tags_NS_prop    { #1 }{ pdf }
  }
\clist_map_inline:Nn \c__tag_role_sttags_only_pdfII_clist
  {
    \__tag_seq_gput_right:Nn \g__tag_role_tags_seq { #1 }
    \prop_gput:Nnn \g__tag_role_tags_NS_prop    { #1 }{ pdf2 }
  }
\pdf_version_compare:NnT > {1.9}
  {
     \clist_map_inline:Nn \c__tag_role_sttags_mathml_clist
       {
         \__tag_seq_gput_right:Nn \g__tag_role_tags_seq { #1 }
         \prop_gput:Nnn \g__tag_role_tags_NS_prop    { #1 }{ mathml }
       }
  }
\int_step_inline:nnnn { 1 }{ 1 }{ \seq_count:N \g__tag_role_tags_seq }
  {
    \__tag_prop_gput:Nxn \g__tag_role_tags_prop
      {
        \seq_item:Nn \g__tag_role_tags_seq  { #1 }
      }
      { #1 }
  }
\pdfdict_new:n {g__tag_role/RoleMap_dict}
\cs_new_protected:Nn \__tag_role_add_tag:nn %(new) name, reference to old
  {
    \prop_if_in:NnF \g__tag_role_tags_prop {#1}
      {
        \int_compare:nNnT {\l__tag_loglevel_int} > { 0 }
          {
            \msg_info:nnn { tag }{new-tag}{#1}
          }
         \__tag_seq_gput_right:Nn \g__tag_role_tags_seq { #1 }
         \__tag_prop_gput:Nnx \g__tag_role_tags_prop    { #1 }
           {
             \seq_count:N \g__tag_role_tags_seq
           }
         \prop_gput:Nnn \g__tag_role_tags_NS_prop    { #1 }{ user }
      }
    \__tag_check_add_tag_role:nn {#1}{#2}
    \tl_if_empty:nF { #2 }
      {
        \pdfdict_gput:nnx {g__tag_role/RoleMap_dict}
          {#1}
          {\pdf_name_from_unicode_e:n{#2}}
      }
  }
\cs_generate_variant:Nn \__tag_role_add_tag:nn {VV}

\pdf_version_compare:NnT < {2.0}
  {
     \prop_map_inline:Nn \c__tag_role_sttags_pdfII_to_pdf_prop
       {
         \__tag_role_add_tag:nn {#1}{#2}
       }
  }

\cs_new_protected:Nn \__tag_role_add_tag:nnnn %tag/namespace/role/namespace
  {
    \int_compare:nNnT {\l__tag_loglevel_int} > { 0 }
      {
        \msg_info:nnn { tag }{new-tag}{#1}
      }
    \__tag_seq_gput_right:Nn \g__tag_role_tags_seq { #1 }
    \__tag_prop_gput:Nnx \g__tag_role_tags_prop    { #1 }
       {
         \seq_count:N \g__tag_role_tags_seq
       }
    \prop_gput:Nnn \g__tag_role_tags_NS_prop    { #1 }{ #2 }
    \__tag_check_add_tag_role:nn {#1}{#3}
    \pdfdict_gput:nnx {g__tag_role/RoleMapNS_#2_dict}{#1}
       {
         [
           \pdf_name_from_unicode_e:n{#3}
           \c_space_tl
           \pdf_object_ref:n {tag/NS/#4}
         ]
       }
   }
\cs_generate_variant:Nn \__tag_role_add_tag:nnnn {VVVV}
\keys_define:nn { __tag / tag-role }
  {
    ,tag .tl_set:N = \l__tag_role_tag_tmpa_tl
    ,tag-namespace  .tl_set:N = \l__tag_role_tag_namespace_tmpa_tl
    ,role .tl_set:N = \l__tag_role_role_tmpa_tl
    ,role-namespace .tl_set:N = \l__tag_role_role_namespace_tmpa_tl
  }

\keys_define:nn { __tag / setup }
  {
    add-new-tag .code:n =
     {
       \keys_set_known:nnnN
         {__tag/tag-role}
         {
           tag-namespace=user,
           role-namespace=, %so that we can test for it.
          #1
         }{__tag/tag-role}\l_tmpa_tl
       \tl_if_empty:NF \l_tmpa_tl
         {
           \exp_args:NNno \seq_set_split:Nnn \l_tmpa_seq { / } {\l_tmpa_tl/}
           \tl_set:Nx \l__tag_role_tag_tmpa_tl  { \seq_item:Nn \l_tmpa_seq {1} }
           \tl_set:Nx \l__tag_role_role_tmpa_tl { \seq_item:Nn \l_tmpa_seq {2} }
         }
      \tl_if_empty:NT \l__tag_role_role_namespace_tmpa_tl
         {
           \prop_get:NVNTF
             \g__tag_role_tags_NS_prop
             \l__tag_role_role_tmpa_tl
             \l__tag_role_role_namespace_tmpa_tl
             {
                \prop_if_in:NVF\g__tag_role_NS_prop \l__tag_role_role_namespace_tmpa_tl
                 {
                   \tl_set:Nn \l__tag_role_role_namespace_tmpa_tl {user}
                 }
             }
             {
               \tl_set:Nn \l__tag_role_role_namespace_tmpa_tl {user}
             }
         }
      \pdf_version_compare:NnTF < {2.0}
       {
        %TODO add check for emptyness?
          \__tag_role_add_tag:VV
              \l__tag_role_tag_tmpa_tl
              \l__tag_role_role_tmpa_tl
       }
       {
         \__tag_role_add_tag:VVVV
           \l__tag_role_tag_tmpa_tl
           \l__tag_role_tag_namespace_tmpa_tl
           \l__tag_role_role_tmpa_tl
           \l__tag_role_role_namespace_tmpa_tl
       }
    }
  }
%% File: tagpdf-struct.dtx
\newcounter  { g__tag_struct_abs_int }
\int_gzero:N \c@g__tag_struct_abs_int
\__tag_seq_new:N  \g__tag_struct_objR_seq

\__tag_prop_new:N  \g__tag_struct_cont_mc_prop
\seq_new:N    \g__tag_struct_stack_seq
\seq_gpush:Nn \g__tag_struct_stack_seq {0}
\seq_new:N    \g__tag_struct_tag_stack_seq
\seq_gpush:Nn \g__tag_struct_tag_stack_seq {Root}
\tl_new:N     \g__tag_struct_stack_current_tl
\tl_new:N     \l__tag_struct_stack_parent_tmpa_tl

\seq_const_from_clist:Nn \c__tag_struct_StructTreeRoot_entries_seq
  {%p. 857/858
    Type,              % always /StructTreeRoot
    K,                 % kid, dictionary or array of dictionaries
    IDTree,            % currently unused
    ParentTree,        % required,obj ref to the parent tree
    ParentTreeNextKey, % optional
    RoleMap,
    ClassMap,
    Namespaces,
    AF                 %pdf 2.0
  }

\seq_const_from_clist:Nn \c__tag_struct_StructElem_entries_seq
  {%p 858 f
    Type,              %always /StructElem
    S,                 %tag/type
    P,                 %parent
    ID,                %optional
    Ref,               %optional, pdf 2.0 Use?
    Pg,                %obj num of starting page, optional
    K,                 %kids
    A,                 %attributes, probably unused
    C,                 %class ""
    %R,                %attribute revision number, irrelevant for us as we
                       % don't update/change existing PDF and (probably)
                       % deprecated in PDF 2.0
    T,                 %title, value in () or <>
    Lang,              %language
    Alt,               % value in () or <>
    E,                 % abreviation
    ActualText,
    AF,                 %pdf 2.0, array of dict, associated files
    NS,                 %pdf 2.0, dict, namespace
    PhoneticAlphabet,   %pdf 2.0
    Phoneme             %pdf 2.0
  }
\tl_new:N \g__tag_struct_tag_tl
\tl_new:N \g__tag_struct_tag_NS_tl
\tl_new:N \l__tag_struct_key_label_tl
\bool_new:N \l__tag_struct_elem_stash_bool
\cs_new:Npn \__tag_struct_output_prop_aux:nn #1 #2 %#1 num, #2 key
  {
    \prop_if_in:cnT
      { g__tag_struct_#1_prop }
      { #2 }
      {
        \c_space_tl/#2~ \prop_item:cn{ g__tag_struct_#1_prop } { #2 }
      }
  }

\cs_new_protected:Npn \__tag_new_output_prop_handler:n #1
  {
    \cs_new:cn { __tag_struct_output_prop_#1:n }
      {
        \__tag_struct_output_prop_aux:nn {#1}{##1}
      }
  }
\tl_gset:Nn \g__tag_struct_stack_current_tl {0}

\__tag_prop_new:c { g__tag_struct_0_prop }
\__tag_new_output_prop_handler:n {0}
\__tag_seq_new:c  { g__tag_struct_kids_0_seq }

\__tag_prop_gput:cnn
  { g__tag_struct_0_prop }
  { Type }
  { /StructTreeRoot }

\__tag_prop_gput:cnx
  { g__tag_struct_0_prop }
  { Namespaces }
  { \pdf_object_ref:n { __tag/tree/namespaces } }
\cs_new:Npn \__tag_struct_mcid_dict:n #1 %#1 MCID absnum
  {
     <<
      /Type \c_space_tl /MCR \c_space_tl
      /Pg
        \c_space_tl
      \pdf_pageobject_ref:n { \__tag_ref_value:enn{mcid-#1}{tagabspage}{1} }
       /MCID \c_space_tl \__tag_ref_value:enn{mcid-#1}{tagmcid}{1}
     >>
  }
\cs_new_protected:Npn \__tag_struct_kid_mc_gput_right:nn #1 #2 %#1 structure num, #2 MCID absnum%
  {
    \__tag_seq_gput_right:cx
      { g__tag_struct_kids_#1_seq }
      {
        \__tag_struct_mcid_dict:n {#2}
      }
    \__tag_seq_gput_right:cn
      { g__tag_struct_kids_#1_seq }
      {
        \prop_item:Nn \g__tag_struct_cont_mc_prop {#2}
      }
  }
\cs_generate_variant:Nn \__tag_struct_kid_mc_gput_right:nn {nx}

\cs_new_protected:Npn\__tag_struct_kid_struct_gput_right:nn #1 #2 %#1 num of parent struct, #2 kid struct
  {
    \__tag_seq_gput_right:cx
      { g__tag_struct_kids_#1_seq }
      {
        \pdf_object_ref:n { __tag/struct/#2 }
      }
 }

\cs_generate_variant:Nn \__tag_struct_kid_struct_gput_right:nn {xx}
\cs_new_protected:Npn\__tag_struct_kid_OBJR_gput_right:nn #1 #2 %#1 num of parent struct,
                                                             %#2 obj reference
  {
    \pdf_object_unnamed_write:nn
      { dict }
      {
        /Type/OBJR/Obj~#2
      }
    \__tag_seq_gput_right:cx
      { g__tag_struct_kids_#1_seq }
      {
        \pdf_object_ref_last:
      }
  }

\cs_generate_variant:Nn\__tag_struct_kid_OBJR_gput_right:nn { xx }

\cs_new_protected:Npn\__tag_struct_exchange_kid_command:N #1 %#1 = seq var
  {
    \seq_gpop_left:NN #1 \l__tag_tmpa_tl
    \regex_replace_once:nnN
      { \c{\__tag_mc_insert_mcid_kids:n} }
      { \c{\__tag_mc_insert_mcid_single_kids:n} }
      \l__tag_tmpa_tl
    \seq_gput_left:NV #1 \l__tag_tmpa_tl
  }

\cs_generate_variant:Nn\__tag_struct_exchange_kid_command:N { c }
\cs_new_protected:Npn \__tag_struct_fill_kid_key:n #1 %#1 is the struct num
  {
    \bool_if:NF\g__tag_mode_lua_bool
     {
        \seq_clear:N \l__tag_tmpa_seq
        \seq_map_inline:cn { g__tag_struct_kids_#1_seq }
         { \seq_put_right:Nx \l__tag_tmpa_seq { ##1 } }
        %\seq_show:c { g__tag_struct_kids_#1_seq }
        %\seq_show:N \l__tag_tmpa_seq
        \seq_remove_all:Nn \l__tag_tmpa_seq {}
        %\seq_show:N \l__tag_tmpa_seq
        \seq_gset_eq:cN { g__tag_struct_kids_#1_seq } \l__tag_tmpa_seq
     }

    \int_case:nnF
      {
        \seq_count:c
          {
            g__tag_struct_kids_#1_seq
          }
      }
      {
        { 0 }
         { } %no kids, do nothing
        { 1 } % 1 kid, insert
         {
           % in this case we need a special command in
           % luamode to get the array right. See issue #13
           \bool_if:NT\g__tag_mode_lua_bool
             {
               \__tag_struct_exchange_kid_command:c
                {g__tag_struct_kids_#1_seq}
             }
           \__tag_prop_gput:cnx { g__tag_struct_#1_prop } {K}
             {
               \seq_item:cn
                 {
                   g__tag_struct_kids_#1_seq
                 }
                 {1}
             }
         } %
      }
      { %many kids, use an array
        \__tag_prop_gput:cnx { g__tag_struct_#1_prop } {K}
          {
            [
              \seq_use:cn
                {
                  g__tag_struct_kids_#1_seq
                }
                {
                  \c_space_tl
                }
            ]
          }
      }
  }

\cs_new_protected:Npn \__tag_struct_get_dict_content:nN #1 #2 %#1: stucture num
  {
    \tl_clear:N #2
    \seq_map_inline:cn
      {
        c__tag_struct_
         \int_compare:nNnTF{#1}={0}{StructTreeRoot}{StructElem}
         _entries_seq
      }
      {
        \tl_put_right:Nx
          #2
          {
             \prop_if_in:cnT
               { g__tag_struct_#1_prop }
               { ##1 }
               {
                 \c_space_tl/##1~\prop_item:cn{ g__tag_struct_#1_prop } { ##1 }
               }
          }
      }
  }
\cs_new_protected:Npn \__tag_struct_write_obj:n #1 % #1 is the struct num
  {
    \pdf_object_if_exist:nTF { __tag/struct/#1 }
      {
        \__tag_struct_fill_kid_key:n { #1 }
        \__tag_struct_get_dict_content:nN { #1 } \l__tag_tmpa_tl
        \exp_args:Nx
          \pdf_object_write:nx
            { __tag/struct/#1 }
            {
              \l__tag_tmpa_tl
            }
      }
      {
        \msg_error:nnn { tag } { struct-no-objnum } { #1}
      }
  }
\cs_new_protected:Npn \__tag_struct_insert_annot:nn #1 #2 %#1 object reference to the annotation/xform
                                                       %#2 structparent number
  {
    \bool_if:NT \g__tag_active_struct_bool
      {
        %get the number of the parent structure:
        \seq_get:NNF
          \g__tag_struct_stack_seq
          \l__tag_struct_stack_parent_tmpa_tl
          {
            \msg_error:nn { tag } { struct-faulty-nesting }
          }
        %put the obj number of the annot in the kid entry, this also creates
        %the OBJR object
        \__tag_struct_kid_OBJR_gput_right:xx
          {
            \l__tag_struct_stack_parent_tmpa_tl
          }
          {
            #1 %
          }
        % add the parent obj number to the parent tree:
        \exp_args:Nnx
        \__tag_parenttree_add_objr:nn
          {
            #2
          }
          {
            \pdf_object_ref:e { __tag/struct/\l__tag_struct_stack_parent_tmpa_tl }
          }
        % increase the int:
        \stepcounter{ g__tag_parenttree_obj_int }
      }
  }
\cs_new:Npn \__tag_get_data_struct_tag:
  {
    \exp_args:Ne
    \tl_tail:n
     {
       \prop_item:cn {g__tag_struct_\g__tag_struct_stack_current_tl _prop}{S}
     }
  }
\keys_define:nn { __tag / struct }
  {
    label .tl_set:N      = \l__tag_struct_key_label_tl,
    stash .bool_set:N    = \l__tag_struct_elem_stash_bool,
    tag   .code:n        = % S property
      {
        \seq_set_split:Nne \l__tag_tmpa_seq { / } {#1/\prop_item:Nn\g__tag_role_tags_NS_prop{#1}}
        \tl_gset:Nx \g__tag_struct_tag_tl    { \seq_item:Nn\l__tag_tmpa_seq {1} }
        \tl_gset:Nx \g__tag_struct_tag_NS_tl { \seq_item:Nn\l__tag_tmpa_seq {2} }
        \__tag_check_structure_tag:N \g__tag_struct_tag_tl
        \__tag_prop_gput:cnx
         { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop }
         { S }
         { \pdf_name_from_unicode_e:n{ \g__tag_struct_tag_tl} } %
       \prop_get:NVNT \g__tag_role_NS_prop\g__tag_struct_tag_NS_tl\l__tag_tmpa_tl
         {
           \__tag_prop_gput:cnx
            { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop }
            { NS }
            { \l__tag_tmpa_tl } %
         }
      },
    title .code:n        = % T property
      {
        \str_set_convert:Nnon
          \l__tag_tmpa_str
          { #1 }
          { default }
          { utf16/hex }
        \__tag_prop_gput:cnx
          { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop }
          { T }
          { <\l__tag_tmpa_str> }
      },
    title-o .code:n        = % T property
      {
        \str_set_convert:Nnon
          \l__tag_tmpa_str
          { #1 }
          { default }
          { utf16/hex }
        \__tag_prop_gput:cnx
          { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop }
          { T }
          { <\l__tag_tmpa_str> }
      },
    alttext .code:n      = % Alt property
      {
        \str_set_convert:Noon
          \l__tag_tmpa_str
          { #1 }
          { default }
          { utf16/hex }
        \__tag_prop_gput:cnx
          { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop }
          { Alt }
          { <\l__tag_tmpa_str> }
      },
    actualtext .code:n  = % ActualText property
      {
        \str_set_convert:Noon
          \l__tag_tmpa_str
          { #1 }
          { default }
          { utf16/hex }
        \__tag_prop_gput:cnx
          { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop }
          { ActualText }
          { <\l__tag_tmpa_str>}
      },
    lang .code:n        = % Lang property
      {
        \__tag_prop_gput:cnx
          { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop }
          { Lang }
          { (#1) }
      },
    ref .code:n        = % Lang property
      {
        \tl_clear:N\l__tag_tmpa_tl
        \clist_map_inline:nn {#1}
          {
            \tl_put_right:Nx \l__tag_tmpa_tl
              {~\ref_value:nn{tagpdfstruct-##1}{tagstructobj} }
          }
        \__tag_prop_gput:cnx
          { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop }
          { Ref }
          { [\l__tag_tmpa_tl] }
      },
    E .code:n        = % E property
      {
        \str_set_convert:Nnon
          \l__tag_tmpa_str
          { #1 }
          { default }
          { utf16/hex }
        \__tag_prop_gput:cnx
          { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop }
          { E }
          { <\l__tag_tmpa_str> }
      },
  }
\cs_new_protected:Npn \__tag_struct_add_AF:nn #1 #2 % #1 struct num #2 object name
  {
     \tl_if_exist:cTF
       {
         g__tag_struct_#1_AF_tl
       }
       {
         \tl_gput_right:cx
           { g__tag_struct_#1_AF_tl }
           {  ~ \pdf_object_ref:n {#2} }
       }
       {
          \tl_new:c
            { g__tag_struct_#1_AF_tl }
          \tl_gset:cx
            { g__tag_struct_#1_AF_tl }
            { \pdf_object_ref:n {#2} }
       }
  }
\cs_generate_variant:Nn \__tag_struct_add_AF:nn {en,ee}
\keys_define:nn { __tag / struct }
 {
    AF .code:n        = % AF property
      {
        \pdf_object_if_exist:nTF {#1}
          {
            \__tag_struct_add_AF:en { \int_eval:n {\c@g__tag_struct_abs_int} }{#1}
            \__tag_prop_gput:cnx
             { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop }
             { AF }
             {
               [
                 \tl_use:c
                   { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_AF_tl }
               ]
             }
          }
          {

          }
      },
   ,AFinline .code:n =
     {
       \group_begin:
       \pdf_object_if_exist:eF {__tag/fileobj\int_use:N\c@g__tag_struct_abs_int}
         {
           \pdffile_embed_stream:nxx
             {#1}
             {tag-AFfile\int_use:N\c@g__tag_struct_abs_int.txt}
             {__tag/fileobj\int_use:N\c@g__tag_struct_abs_int}
           \__tag_struct_add_AF:ee
             { \int_eval:n {\c@g__tag_struct_abs_int} }
             { __tag/fileobj\int_use:N\c@g__tag_struct_abs_int }
           \__tag_prop_gput:cnx
             { g__tag_struct_\int_use:N\c@g__tag_struct_abs_int _prop }
             { AF }
             {
               [
                 \tl_use:c
                  { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_AF_tl }
               ]
             }
         }
       \group_end:
     }
   ,AFinline-o .code:n =
     {
       \group_begin:
       \pdf_object_if_exist:eF {__tag/fileobj\int_use:N\c@g__tag_struct_abs_int}
        {
          \pdffile_embed_stream:oxx
            {#1}
            {tag-AFfile\int_use:N\c@g__tag_struct_abs_int.txt}
            {__tag/fileobj\int_use:N\c@g__tag_struct_abs_int}
          \__tag_struct_add_AF:ee
             { \int_eval:n {\c@g__tag_struct_abs_int} }
             { __tag/fileobj\int_use:N\c@g__tag_struct_abs_int }
           \__tag_prop_gput:cnx
             { g__tag_struct_\int_use:N\c@g__tag_struct_abs_int _prop }
             { AF }
             {
               [
                 \tl_use:c
                  { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_AF_tl }
               ]
             }
        }
       \group_end:
     }
 }
\keys_define:nn { __tag / setup }
  {
    root-AF .code:n =
     {
        \pdf_object_if_exist:nTF {#1}
          {
            \__tag_struct_add_AF:en { 0 }{#1}
            \__tag_prop_gput:cnx
             { g__tag_struct_0_prop }
             { AF }
             {
               [
                 \tl_use:c
                   { g__tag_struct_0_AF_tl }
               ]
             }
          }
          {

          }
      },
  }
\cs_new_protected:Npn \tag_struct_begin:n #1 %#1 key-val
  {
\__tag_check_if_active_struct:T
      {
        \group_begin:
        \int_gincr:N \c@g__tag_struct_abs_int
        \__tag_prop_new:c  { g__tag_struct_\int_eval:n { \c@g__tag_struct_abs_int }_prop }
        \__tag_new_output_prop_handler:n {\int_eval:n { \c@g__tag_struct_abs_int }}
        \__tag_seq_new:c  { g__tag_struct_kids_\int_eval:n { \c@g__tag_struct_abs_int }_seq}
        \exp_args:Ne
          \pdf_object_new:nn
            { __tag/struct/\int_eval:n { \c@g__tag_struct_abs_int } }
            { dict }
        \__tag_prop_gput:cno
          { g__tag_struct_\int_eval:n { \c@g__tag_struct_abs_int }_prop }
          { Type }
          { /StructElem }
        \keys_set:nn { __tag / struct} { #1 }
        \__tag_check_structure_has_tag:n { \int_eval:n {\c@g__tag_struct_abs_int} }
        \tl_if_empty:NF
          \l__tag_struct_key_label_tl
          {
            \__tag_ref_label:en{tagpdfstruct-\l__tag_struct_key_label_tl}{struct}
          }
        %get the potential parent from the stack:
        \seq_get:NNF
          \g__tag_struct_stack_seq
          \l__tag_struct_stack_parent_tmpa_tl
          {
            \msg_error:nn { tag } { struct-faulty-nesting }
          }
        \seq_gpush:NV \g__tag_struct_stack_seq        \c@g__tag_struct_abs_int
        \seq_gpush:NV \g__tag_struct_tag_stack_seq    \g__tag_struct_tag_tl
        \tl_gset:NV   \g__tag_struct_stack_current_tl \c@g__tag_struct_abs_int
        %\seq_show:N   \g__tag_struct_stack_seq
        \bool_if:NF
          \l__tag_struct_elem_stash_bool
          {%set the  parent
            \__tag_prop_gput:cnx
              { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop }
              { P }
              {
                \pdf_object_ref:e { __tag/struct/\l__tag_struct_stack_parent_tmpa_tl }
              }
            %record this structure as kid:
            %\tl_show:N \g__tag_struct_stack_current_tl
            %\tl_show:N \l__tag_struct_stack_parent_tmpa_tl
            \__tag_struct_kid_struct_gput_right:xx
               { \l__tag_struct_stack_parent_tmpa_tl }
               { \g__tag_struct_stack_current_tl }
            %\prop_show:c { g__tag_struct_\g__tag_struct_stack_current_tl _prop }
            %\seq_show:c {g__tag_struct_kids_\l__tag_struct_stack_parent_tmpa_tl _seq}
          }
        %\prop_show:c { g__tag_struct_\g__tag_struct_stack_current_tl _prop }
        %\seq_show:c {g__tag_struct_kids_\l__tag_struct_stack_parent_tmpa_tl _seq}
        \group_end:
     }
  }
\cs_new_protected:Nn \tag_struct_end:
  { %take the current structure num from the stack:
    %the objects are written later, lua mode hasn't all needed info yet
    %\seq_show:N \g__tag_struct_stack_seq
\__tag_check_if_active_struct:T
      {
        \seq_gpop:NN   \g__tag_struct_tag_stack_seq \l__tag_tmpa_tl
        \seq_gpop:NNTF \g__tag_struct_stack_seq \l__tag_tmpa_tl
          {
            \__tag_check_info_closing_struct:o { \g__tag_struct_stack_current_tl }
          }
          { \__tag_check_no_open_struct: }
        % get the previous one, shouldn't be empty as the root should be there
        \seq_get:NNTF \g__tag_struct_stack_seq \l__tag_tmpa_tl
          {
            \tl_gset:NV   \g__tag_struct_stack_current_tl \l__tag_tmpa_tl
          }
          {
            \__tag_check_no_open_struct:
          }
       \seq_get:NNT \g__tag_struct_tag_stack_seq \l__tag_tmpa_tl
          {
            \tl_gset:NV \g__tag_struct_tag_tl \l__tag_tmpa_tl
          }
      }
  }
\cs_new_protected:Nn \tag_struct_use:n %#1 is the label
  {
    \__tag_check_if_active_struct:T
      {
        \prop_if_exist:cTF
          { g__tag_struct_\__tag_ref_value:enn{tagpdfstruct-#1}{tagstruct}{unknown}_prop } %
          {
            \__tag_check_struct_used:n {#1}
            %add the label structure as kid to the current structure (can be the root)
            \__tag_struct_kid_struct_gput_right:xx
              { \g__tag_struct_stack_current_tl }
              { \__tag_ref_value:enn{tagpdfstruct-#1}{tagstruct}{0} }
            %add the current structure to the labeled one as parents
            \__tag_prop_gput:cnx
              { g__tag_struct_\__tag_ref_value:enn{tagpdfstruct-#1}{tagstruct}{0}_prop }
              { P }
              {
                \pdf_object_ref:e { __tag/struct/\g__tag_struct_stack_current_tl }
              }
          }
          {
            \msg_warning:nnn{ tag }{struct-label-unknown}{#1}
          }
      }
  }
\cs_new_protected:Npn \tag_struct_insert_annot:nn #1 #2 %#1 should be an object reference
                                                        %#2 struct parent num
  {
    \__tag_check_if_active_struct:T
      {
        \__tag_struct_insert_annot:nn {#1}{#2}
      }
  }

\cs_generate_variant:Nn \tag_struct_insert_annot:nn {xx}
\cs_new:Npn \tag_struct_parent_int: {\int_use:c { c@g__tag_parenttree_obj_int }}


\prop_new:N \g__tag_attr_entries_prop
\seq_new:N  \g__tag_attr_class_used_seq
\tl_new:N   \l__tag_attr_value_tl
\prop_new:N \g__tag_attr_objref_prop %will contain obj num of used attributes
\cs_new_protected:Npn \__tag_attr_new_entry:nn #1 #2 %#1:name, #2: content
  {
    \prop_gput:Nnn \g__tag_attr_entries_prop
      {#1}{#2}
  }

\keys_define:nn { __tag / setup }
  {
    newattribute .code:n =
      {
        \__tag_attr_new_entry:nn #1
      }
  }
\keys_define:nn { __tag / struct }
  {
    attribute-class .code:n =
     {
       \clist_set:No \l__tag_tmpa_clist { #1 }
       \seq_set_from_clist:NN \l__tag_tmpa_seq \l__tag_tmpa_clist
       \seq_map_inline:Nn \l__tag_tmpa_seq
         {
           \prop_if_in:NnF \g__tag_attr_entries_prop {##1}
             {
               \msg_error:nnn { tag } { attr-unknown } { ##1 }
             }
           \seq_gput_left:Nn\g__tag_attr_class_used_seq { ##1}
         }
       \seq_set_map:NNn \l__tag_tmpb_seq \l__tag_tmpa_seq
         {
           /##1
         }
       \tl_set:Nx \l__tag_tmpa_tl
         {
           \int_compare:nT { \seq_count:N \l__tag_tmpa_seq > 1 }{[}
           \seq_use:Nn \l__tag_tmpb_seq  { \c_space_tl  }
           \int_compare:nT { \seq_count:N \l__tag_tmpa_seq > 1 }{]}
         }
       \int_compare:nT { \seq_count:N \l__tag_tmpa_seq > 0 }
         {
           \__tag_prop_gput:cnx
             { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop }
             { C }
             { \l__tag_tmpa_tl }
          %\prop_show:c  { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop }
         }
     }
  }
\keys_define:nn { __tag / struct }
  {
    attribute .code:n  = % A property (attribute, value currently a dictionary)
      {
        \clist_set:No          \l__tag_tmpa_clist { #1 }
        \seq_set_from_clist:NN \l__tag_tmpa_seq \l__tag_tmpa_clist
        \tl_set:Nx \l__tag_attr_value_tl
          {
            \int_compare:nT { \seq_count:N \l__tag_tmpa_seq > 1 }{[}%]
          }
        \seq_map_inline:Nn \l__tag_tmpa_seq
          {
            \prop_if_in:NnF \g__tag_attr_entries_prop {##1}
              {
                \msg_error:nnn { tag } { attr-unknown } { ##1 }
              }
            \prop_if_in:NnF \g__tag_attr_objref_prop {##1}
              {%\prop_show:N \g__tag_attr_entries_prop
                \pdf_object_unnamed_write:nx
                  { dict }
                  {
                    \prop_item:Nn\g__tag_attr_entries_prop {##1}
                  }
                \prop_gput:Nnx \g__tag_attr_objref_prop {##1} {\pdf_object_ref_last:}
              }
            \tl_put_right:Nx \l__tag_attr_value_tl
              {
                \c_space_tl
                \prop_item:Nn \g__tag_attr_objref_prop {##1}
              }
 %     \tl_show:N \l__tag_attr_value_tl
          }
        \tl_put_right:Nx \l__tag_attr_value_tl
          { %[
            \int_compare:nT { \seq_count:N \l__tag_tmpa_seq > 1 }{]}%
          }
 %     \tl_show:N \l__tag_attr_value_tl
        \__tag_prop_gput:cnx
          { g__tag_struct_\int_eval:n {\c@g__tag_struct_abs_int}_prop }
          { A }
          { \l__tag_attr_value_tl }
    },
  }
%% File: tagpdf-space.dtx
\sys_if_engine_pdftex:T
  {
    \sys_if_output_pdf:TF
      {
        \pdfglyphtounicode{space}{0020}
        \keys_define:nn { __tag / setup }
          {
            interwordspace .choices:nn = { true, on }  { \pdfinterwordspaceon },
            interwordspace .choices:nn = { false, off }{ \pdfinterwordspaceon },
            interwordspace .default:n = true,
            show-spaces .bool_set:N = \l__tag_showspaces_bool
          }
      }
      {
        \keys_define:nn { __tag / setup }
          {
            interwordspace .choices:nn = { true, on, false, off }
              { \msg_warning:nnn {tag}{sys-no-interwordspace}{dvi}  },
            interwordspace .default:n = true,
            show-spaces .bool_set:N = \l__tag_showspaces_bool
          }
      }
  }

\sys_if_engine_luatex:T
  {
    \keys_define:nn { __tag / setup }
      {
        interwordspace .choices:nn =
                                 { true, on }
                                 {
                                   \bool_gset_true:N \g__tag_active_space_bool
                                   \lua_now:e{ltx.__tag.func.markspaceon()}
                                 },
        interwordspace .choices:nn =
                                 { false, off }
                                 {
                                  \bool_gset_false:N \g__tag_active_space_bool
                                  \lua_now:e{ltx.__tag.func.markspaceoff()}
                                 },
        interwordspace .default:n = true,
        show-spaces      .choice:,
        show-spaces  / true  .code:n =
                                 {\lua_now:e{ltx.__tag.trace.showspaces=true}},
        show-spaces  / false .code:n =
                                 {\lua_now:e{ltx.__tag.trace.showspaces=nil}},
        show-spaces .default:n = true
      }
  }

\sys_if_engine_xetex:T
  {
    \keys_define:nn { __tag / setup }
      {
        interwordspace .choices:nn = { true, on }
          { \msg_warning:nnn {tag}{sys-no-interwordspace}{xetex}  },
        interwordspace .choices:nn = { false, off }
          { \msg_warning:nnn {tag}{sys-no-interwordspace}{xetex}  },
        interwordspace .default:n = true,
        show-spaces .bool_set:N = \l__tag_showspaces_bool
      }
  }
\sys_if_engine_luatex:T
  {
    \cs_new_protected:Nn \__tag_fakespace:
      {
        \group_begin:
        \lua_now:e{ltx.__tag.func.fakespace()}
        \skip_horizontal:n{\c_zero_skip}
        \group_end:
      }
  }
%% File: tagpdf-user.dtx


\NewDocumentCommand \tagpdfsetup { m }
  {
    \keys_set:nn { __tag / setup } { #1 }
  }

\NewDocumentCommand \tagmcbegin { m }
  {
    \tag_mc_begin:n {#1}%\ignorespaces
  }

\NewDocumentCommand \tagmcend {  }
  {
    %\if_mode_horizontal: \unskip \fi: %
    \tag_mc_end:
  }

\NewDocumentCommand \tagmcuse { m }
  {
    \tag_mc_use:n {#1}
  }


\NewDocumentCommand \tagmcifinTF { m m }
  {
    \tag_mc_if_in:TF { #1 } { #2 }
  }
\NewDocumentCommand \tagstructbegin { m }
  {
    \tag_struct_begin:n {#1}
  }

\NewDocumentCommand \tagstructend {  }
  {
   \tag_struct_end:
  }

\NewDocumentCommand \tagstructuse { m }
  {
    \tag_struct_use:n {#1}
  }
\NewDocumentCommand\ShowTagging { m }
  {
    \keys_set:nn { __tag / show }{ #1}

  }
\keys_define:nn { __tag / show }
  {
    mc-data .code:n =
      {
        \sys_if_engine_luatex:T
          {
            \lua_now:e{ltx.__tag.trace.show_all_mc_data(#1,\__tag_get_mc_abs_cnt:,0)}
          }
      }
    ,mc-data .default:n = 1
  }

\keys_define:nn { __tag / show }
  { mc-current .code:n =
     {
       \bool_if:NTF \g__tag_mode_lua_bool
         {
           \sys_if_engine_luatex:T
             {
               \int_compare:nNnTF
                 { -2147483647 }
                  =
                 {
                   \lua_now:e
                     {
                        tex.print
                         (tex.getattribute
                           (luatexbase.attributes.g__tag_mc_cnt_attr))
                     }
                 }
                 {
                   \lua_now:e
                     {
                       ltx.__tag.trace.log
                        (
                          "mc-current:~no~MC~open,~current~abscnt
                           =\__tag_get_mc_abs_cnt:"
                          ,0
                        )
                       texio.write_nl("")
                     }
                 }
                 {
                   \lua_now:e
                     {
                       ltx.__tag.trace.log
                        (
                          "mc-current:~abscnt=\__tag_get_mc_abs_cnt:=="
                           ..
                           tex.getattribute(luatexbase.attributes.g__tag_mc_cnt_attr)
                           ..
                           "~=>tag="
                           ..
                           tostring
                             (ltx.__tag.func.get_tag_from
                               (tex.getattribute
                                 (luatexbase.attributes.g__tag_mc_type_attr)))
                           ..
                           "="
                           ..
                           tex.getattribute
                            (luatexbase.attributes.g__tag_mc_type_attr)
                           ,0
                        )
                       texio.write_nl("")
                     }
                 }
             }
         }
         {
          \msg_note:nn{ tag }{ mc-current }
         }
     }
  }
\keys_define:nn { __tag / show }
  {
    mc-marks .choice: ,
    mc-marks / show .code:n =
      {
        \__tag_mc_get_marks:
        \__tag_check_if_mc_in_galley:TF
         {
          \iow_term:n {Marks~from~this~page:~}
         }
         {
           \iow_term:n {Marks~from~a~previous~page:~}
         }
        \seq_show:N \l__tag_mc_firstmarks_seq
        \seq_show:N \l__tag_mc_botmarks_seq
        \__tag_check_if_mc_tmb_missing:T
         {
           \iow_term:n {BDC~missing~on~this~page!}
         }
        \__tag_check_if_mc_tme_missing:T
         {
           \iow_term:n {EMC~missing~on~this~page!}
         }
      },
    mc-marks / use .code:n =
      {
        \__tag_mc_get_marks:
        \__tag_check_if_mc_in_galley:TF
         { Marks~from~this~page:~}
         { Marks~from~a~previous~page:~}
        \seq_use:Nn \l__tag_mc_firstmarks_seq {,~}\quad
        \seq_use:Nn \l__tag_mc_botmarks_seq {,~}\quad
        \__tag_check_if_mc_tmb_missing:T
         {
           BDC~missing~
         }
        \__tag_check_if_mc_tme_missing:T
         {
           EMC~missing
         }
      },
   mc-marks .default:n = show
  }
\keys_define:nn { __tag / show }
  {
     struct-stack .choice:
    ,struct-stack / log .code:n = \seq_log:N \g__tag_struct_tag_stack_seq
    ,struct-stack / show .code:n = \seq_show:N \g__tag_struct_tag_stack_seq
    ,struct-stack .default:n = show
  }
\cs_new_protected:Npn \__tag_add_document_structure:n #1
 {
   \hook_gput_code:nnn{begindocument}{tagpdf}{\tagstructbegin{tag=#1}}
   \hook_gput_code:nnn{tagpdf/finish/before}{tagpdf}{\tagstructend}
 }
\keys_define:nn { __tag / setup}
 {
   activate   .code:n =
    {
      \keys_set:nn { __tag / setup }
        { activate-mc,activate-tree,activate-struct }
      \__tag_add_document_structure:n {#1}
    },
  activate .default:n = Document
 }
\AddToHook{begindocument/before}
  {
    \bool_lazy_all:nT
      {
        { \g__tag_active_struct_dest_bool }
        { \g__tag_active_struct_bool }
        { \cs_if_exist_p:N \pdf_activate_structure_destination: }
        { ! \pdf_version_compare_p:Nn < {2.0} }
      }
      {
        \tl_set:Nn \l_pdf_current_structure_destination_tl { __tag/struct/\g__tag_struct_stack_current_tl }
        \pdf_activate_structure_destination:
      }
   }

\sys_if_engine_luatex:T
  {
    \NewDocumentCommand\pdffakespace { }
     {
       \__tag_fakespace:
     }
  }
\bool_new:N \l__tag_para_bool
\bool_new:N \l__tag_para_show_bool
\int_new:N  \g__tag_para_begin_int
\int_new:N  \g__tag_para_end_int
\keys_define:nn { __tag / setup }
  {
    paratagging      .bool_set:N = \l__tag_para_bool,
    paratagging-show .bool_set:N = \l__tag_para_show_bool,
  }

\AddToHook{para/begin}
  {
   \bool_if:NT \l__tag_para_bool
     {
       \int_gincr:N \g__tag_para_begin_int
       \tag_struct_begin:n {tag=P}
       \bool_if:NT \l__tag_para_show_bool
        { \tag_mc_begin:n{artifact}
          \llap{\color_select:n{red}\tiny\int_use:N\g__tag_para_begin_int\ }
          \tag_mc_end:
        }
       \tag_mc_begin:n {tag=P}
     }
  }
\AddToHook{para/end}
  {
    \bool_if:NT \l__tag_para_bool
      {
        \int_gincr:N \g__tag_para_end_int
        \tag_mc_end:
        \bool_if:NT \l__tag_para_show_bool
          { \tag_mc_begin:n{artifact}
            \rlap{\color_select:n{red}\tiny\ \int_use:N\g__tag_para_end_int}
            \tag_mc_end:
          }
        \tag_struct_end:
      }
  }
\AddToHook{enddocument/info}
  {
    \int_compare:nNnF {\g__tag_para_begin_int}={\g__tag_para_end_int}
      {
        \msg_error:nnxx
          {tag}
          {para-hook-count-wrong}
          {\int_use:N\g__tag_para_begin_int}
          {\int_use:N\g__tag_para_end_int}
      }
  }
\AddToHook{begindocument/before}
 {
   \bool_if:NF \g__tag_mode_lua_bool
     {
        \cs_if_exist:NT \@kernel@before@footins
         {
           \tl_put_right:Nn \@kernel@before@footins
             { \__tag_add_missing_mcs_to_stream:Nn \footins {footnote} }
           \tl_put_right:Nn \@kernel@before@cclv
             {
               \__tag_check_typeout_v:n {====>~In~\token_to_str:N \@makecol\c_space_tl\the\c@page}
               \__tag_add_missing_mcs_to_stream:Nn \@cclv {main}
             }
           \tl_put_right:Nn \@mult@ptagging@hook
             {
               \__tag_check_typeout_v:n {====>~In~\string\page@sofar}
               \process@cols\mult@firstbox
                {
                  \__tag_add_missing_mcs_to_stream:Nn \count@ {multicol}
                }
               \__tag_add_missing_mcs_to_stream:Nn \mult@rightbox {multicol}
             }
         }
     }
  }
\newcommand\tagpdfparaOn {\bool_set_true:N \l__tag_para_bool}
\newcommand\tagpdfparaOff{\bool_set_false:N \l__tag_para_bool}
\NewDocumentCommand\tagpdfsuppressmarks{m}
  {{\use:c{__tag_mc_disable_marks:} #1}}
\cs_new_protected:Npn\__tag_hook_kernel_before_head:{}
\cs_new_protected:Npn\__tag_hook_kernel_after_head:{}
\cs_new_protected:Npn\__tag_hook_kernel_before_foot:{}
\cs_new_protected:Npn\__tag_hook_kernel_after_foot:{}

\AddToHook{begindocument}
 {
  \cs_if_exist:NT \@kernel@before@head
   {
     \tl_put_right:Nn \@kernel@before@head {\__tag_hook_kernel_before_head:}
     \tl_put_left:Nn  \@kernel@after@head  {\__tag_hook_kernel_after_head:}
     \tl_put_right:Nn \@kernel@before@foot {\__tag_hook_kernel_before_foot:}
     \tl_put_left:Nn  \@kernel@after@foot  {\__tag_hook_kernel_after_foot:}
   }
 }

\bool_new:N \g__tag_saved_in_mc_bool
\cs_new_protected:Npn \__tag_exclude_headfoot_begin:
 {
    \bool_set_false:N  \l__tag_para_bool
    \bool_if:NTF \g__tag_mode_lua_bool
     {
      \tag_mc_end_push:
     }
     {
       \bool_gset_eq:NN   \g__tag_saved_in_mc_bool \g__tag_in_mc_bool
       \bool_gset_false:N \g__tag_in_mc_bool
     }
    \tag_mc_begin:n {artifact}
 }
\cs_new_protected:Npn \__tag_exclude_headfoot_end:
 {
    \tag_mc_end:
    \bool_if:NTF \g__tag_mode_lua_bool
     {
      \tag_mc_begin_pop:n{}
     }
     {
       \bool_gset_eq:NN \g__tag_in_mc_bool\g__tag_saved_in_mc_bool
     }
 }
\__tag_attr_new_entry:nn {__tag/attr/pagination}{/O/Artifact/Type/Pagination}
\cs_new_protected:Npn \__tag_exclude_struct_headfoot_begin:n #1
 {
    \bool_set_false:N  \l__tag_para_bool
    \bool_if:NTF \g__tag_mode_lua_bool
     {
      \tag_mc_end_push:
     }
     {
       \bool_gset_eq:NN   \g__tag_saved_in_mc_bool \g__tag_in_mc_bool
       \bool_gset_false:N \g__tag_in_mc_bool
     }
    \tag_struct_begin:n{tag=Artifact,attribute-class=__tag/attr/#1}
    \tag_mc_begin:n {artifact=#1}
 }

\cs_new_protected:Npn \__tag_exclude_struct_headfoot_end:
 {
    \tag_mc_end:
    \tag_struct_end:
    \bool_if:NTF \g__tag_mode_lua_bool
     {
      \tag_mc_begin_pop:n{}
     }
     {
       \bool_gset_eq:NN \g__tag_in_mc_bool\g__tag_saved_in_mc_bool
     }
 }
\keys_define:nn { __tag / setup }
  {
    exclude-header-footer .choice:,
    exclude-header-footer / true .code:n =
     {
       \cs_set_eq:NN \__tag_hook_kernel_before_head: \__tag_exclude_headfoot_begin:
       \cs_set_eq:NN \__tag_hook_kernel_before_foot: \__tag_exclude_headfoot_begin:
       \cs_set_eq:NN \__tag_hook_kernel_after_head:  \__tag_exclude_headfoot_end:
       \cs_set_eq:NN \__tag_hook_kernel_after_foot:  \__tag_exclude_headfoot_end:
     },
    exclude-header-footer / pagination .code:n =
     {
       \cs_set:Nn \__tag_hook_kernel_before_head: { \__tag_exclude_struct_headfoot_begin:n {pagination} }
       \cs_set:Nn \__tag_hook_kernel_before_foot: { \__tag_exclude_struct_headfoot_begin:n {pagination} }
       \cs_set_eq:NN \__tag_hook_kernel_after_head:  \__tag_exclude_struct_headfoot_end:
       \cs_set_eq:NN \__tag_hook_kernel_after_foot:  \__tag_exclude_struct_headfoot_end:
     },
    exclude-header-footer / false .code:n =
     {
       \cs_set_eq:NN \__tag_hook_kernel_before_head: \prg_do_nothing:
       \cs_set_eq:NN \__tag_hook_kernel_before_foot: \prg_do_nothing:
       \cs_set_eq:NN \__tag_hook_kernel_after_head:  \prg_do_nothing:
       \cs_set_eq:NN \__tag_hook_kernel_after_foot:  \prg_do_nothing:
     },
   exclude-header-footer .default:n = true,
   exclude-header-footer .initial:n = true
  }
\hook_gput_code:nnn
  {pdfannot/link/URI/before}
  {tagpdf}
  {
    \tag_mc_end_push:
    \tag_struct_begin:n { tag=Link }
    \tag_mc_begin:n { tag=Link }
    \pdfannot_dict_put:nnx
      { link/URI }
      { StructParent }
      { \tag_struct_parent_int: }
  }

\hook_gput_code:nnn
  {pdfannot/link/URI/after}
  {tagpdf}
  {
     \tag_struct_insert_annot:xx {\pdfannot_link_ref_last:}{\tag_struct_parent_int:}
     \tag_mc_end:
     \tag_struct_end:
     \tag_mc_begin_pop:n{}
  }

\hook_gput_code:nnn
  {pdfannot/link/GoTo/before}
  {tagpdf}
  {
     \tag_mc_end_push:
     \tag_struct_begin:n{tag=Link}
     \tag_mc_begin:n{tag=Link}
     \pdfannot_dict_put:nnx
       { link/GoTo }
       { StructParent }
       { \tag_struct_parent_int: }
  }

\hook_gput_code:nnn
  {pdfannot/link/GoTo/after}
  {tagpdf}
  {
    \tag_struct_insert_annot:xx {\pdfannot_link_ref_last:}{\tag_struct_parent_int:}
    \tag_mc_end:
    \tag_struct_end:
    \tag_mc_begin_pop:n{}

  }

\pdfannot_dict_put:nnn
 { link/URI }
 { Contents }
 { (url) }

\pdfannot_dict_put:nnn
 { link/GoTo }
 { Contents }
 { (ref) }

%% 
%%
%% End of file `tagpdf.sty'.
