%\iffalse
% makeindex -s gglo.ist -o web.gls web.glo
%<*copyright>
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% aebxmp.sty package,                  2012-01-10      %%
%% Copyright (C) 2006--2012 D. P. Story                 %%
%%   dpstory@uakron.edu                                 %%
%%                                                      %%
%% This program can redistributed and/or modified under %%
%% the terms of the LaTeX Project Public License        %%
%% Distributed from CTAN archives in directory          %%
%% macros/latex/base/lppl.txt; either version 1 of the  %%
%% License, or (at your option) any later version.      %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%</copyright>
%<package>\NeedsTeXFormat{LaTeX2e}[1997/12/01]
%<package>\ProvidesPackage{aebxmp}
%<package> [2012/01/10 v2.3 Populate advanced metadata (dps)]
%<*driver>
\documentclass{ltxdoc}
\usepackage[colorlinks,hyperindex]{hyperref}
%\pdfstringdefDisableCommands{\let\\\textbackslash}
%\EnableCrossrefs \CodelineIndex
\RecordChanges
\begin{document}
\def\CMD#1{\textbackslash#1}
  \GetFileInfo{aebxmp.sty}
  \title{AeBXMP: Updating XMP using E4X and {\LaTeX}}
  \author{D. P. Story\\
    Email: \texttt{dpstory@uakron.edu}}
  \date{processed \today}
  \maketitle
  \tableofcontents
  \let\Email\texttt
  \renewenvironment{theglossary}{%
    \let\efill\relax
    \begin{itemize}}{\end{itemize}}
   \value{GlossaryColumns}=1
  \DocInput{aebxmp.dtx}
  \PrintIndex
\end{document}
%</driver>
% \fi
% \MakeShortVerb{|}
% \StopEventually{}
%
% \DoNotIndex{\def,\edef,\gdef,\xdef,\global,\long,\let}
% \DoNotIndex{\expandafter,\string,\the,\ifx,\else,\fi}
% \DoNotIndex{\csname,\endcsname,\relax,\begingroup,\endgroup}
% \DoNotIndex{\DeclareTextCommand,\DeclareTextCompositeCommand}
% \DoNotIndex{\space,\@empty,\special}
%
%    \begin{macrocode}
%<*package>
%    \end{macrocode}
% \textbf{Changes}
% \begin{itemize}
% \item v2.3 (2012/01/09) All XMP elements now is inserted by E4X.
% \item v2.2 (2012/01/04) Added the \cs{Keywords} command for creating an array
%       of keywords that can be accessed individually using the JavaScript function
%       \texttt{aKeyWords}, also defined in this package.
% \item v2.1a (2011/12/30) More code efficiencies
% \item v2.1 (2011/12/30) Cleaned up the code, fixed a bug.
% \item v2.0 (2011/12/30) Defined commands to producing custom document properties,
%   defined the \cs{Authors} command.
% \item v1.0 (2011/12/29) Made a proper DTX file for this package; added
% \cs{authortitle} and \cs{descriptionwriter}; support for \texttt{xmp:CreateDate}.
% \item v0.2 (2007/03/13) Added support for unicode escape sequences in the
%      \cs{copyrightNotice} and \cs{copyrightInfoURL} fields.
% \item v0.1 Original distribution
% \end{itemize}
%    \begin{macrocode}
\RequirePackage{xkeyval}
\ProcessOptionsX
\@ifpackageloaded{insdljs}{\let\execjs=y}
    {\RequirePackage[execJS]{insdljs}}
%    \end{macrocode}
% \section{Top-level Interface to Metadata}
% Through this package, the author can specify certain ``Advance Metadata''
% items: copyright notice; copyright notice; copyright url; author title;
% and writer description.\par\medskip\noindent
% The basic user interface is a series of commands listed below.
% Each of the commands takes one argument.
%    \begin{macro}{\copyrightStatus}
%If \texttt{\#1} is \texttt{True}, the \textsf{Copyright Status} is set to
%\texttt{Copyrighted}; if \texttt{False}, \textsf{Copyright Status} is set
%to \textsf{Public Domain}. If left empty, the status is set to
%\textsf{Unknown}.
%    \begin{macro}{\copyrightNotice}
% The argument \texttt{\#1} is the text of the \textsf{Copyright Notice}.
%    \begin{macro}{\copyrightInfoURL}
% The argument \texttt{\#1} is the \textsf{URL} to the copyright information
%    \begin{macro}{\authortitle}
% The \texttt{<text>} (argument \texttt{\#1}) appears in the
% \textsf{Author Title} line on the \textsf{Advanced Metadata} dialog box.
% This is a \textbf{Photoshop} property. (See the Advanced category in the left
% panel.)
%    \begin{macro}{\descriptionwriter}
% The \texttt{<text>} (argument \texttt{\#1}) appears in the
%\textsf{Description Writer} line on the \textsf{Advanced Metadata} dialog box.
%This is a \textbf{Photoshop} property. (See the Advanced category in the left
%panel.)
%    \begin{macrocode}
\newcommand{\copyrightStatus}[1]{\def\xmpcopyrightStatus{#1}}
\let\xmpcopyrightStatus\@empty
\newcommand{\copyrightNotice}[1]{\def\xmpcopyrightNotice{#1}}
\let\xmpcopyrightNotice\@empty
\newcommand{\copyrightInfoURL}[1]{\def\xmpcopyrightInfoURL{#1}}
\let\xmpcopyrightInfoURL\@empty
\newcommand{\authortitle}[1]{\def\xmpauthortitle{#1}}
\let\xmpauthortitle\@empty
\newcommand{\descriptionwriter}[1]{\def\xmpdescriptionwriter{#1}}
\let\xmpdescriptionwriter\@empty
%    \end{macrocode}
%    \begin{macro}{\Authors}
% Enter multiple authors using a token list
%\begin{verbatim}
%\Authors
%{%
%   {D. P. Story}
%   {A. P. Story}
%   ...
%}
%\end{verbatim}
% We use \cs{@tfor} to build an array of authors, and use the simple mechanism
% of \texttt{this.info.Authors} to set the multiple authors.
%    \begin{macrocode}
\let\arrayOfAuthors\@empty
\let\xmpAuthors\@empty
\newcommand{\Authors}[1]{\def\xmpAuthors{#1}%
    \begingroup\let\u\relax
    \ifx\xmpAuthors\@empty\else
        \let\arrayOfAuthors\@gobble
        \@tfor\xmpAuthor:=#1\do{%
            \xdef\arrayOfAuthors{\arrayOfAuthors,"\xmpAuthor"}%
        }%
%    \end{macrocode}
% We build a JavaScript array of authors.
%    \begin{macrocode}
        \xdef\arrayOfAuthors{[\arrayOfAuthors];}%
    \fi
    \endgroup
}
%    \end{macrocode}
% \cs{insertAuthors} does what the other ``insert'' commands do, insert the
% code, only if there are multiple authors.
%    \begin{macrocode}
\def\insertAuthors{\ifx\arrayOfAuthors\@empty\else
    this.info.Authors=\arrayOfAuthors^^J\fi}
%    \end{macrocode}
%    \end{macro}
%    \end{macro}
%    \end{macro}
%    \end{macro}
%    \end{macro}
%    \end{macro}
%    \begin{macrocode}
\def\insertCopyrightNotice{\ifx\xmpcopyrightNotice\@empty\else
^^Jp.aebdc::rights.aebrdf::Alt.aebrdf::li[0]="\xmpcopyrightNotice";
^^Jp.aebdc::rights.aebrdf::Alt.aebrdf::li[0].@xml::lang="en";\fi}
%    \end{macrocode}
%    \begin{macro}{\Keywords}
% We try to implement keywords in a manner similar to \cs{Authors}; that is,
% we want to reference each key word. The individual keywords are listed in
% \texttt{dc:subject}, in a \texttt{Bag}, an unordered array.
%    \begin{macrocode}
\let\arrayOfKeywords\@empty
\let\aKeywords\@empty
\let\xmpKeywords\@empty
\newcommand{\Keywords}[1]{\def\xmpKeywords{#1}%
    \begingroup\let\u\relax\count0=0
    \def\insBagItem{%
    p.aebdc::subject.aebrdf::Bag.aebrdf::li}%
    \ifx\xmpKeywords\@empty\else
        \let\arrayOfKeywords\@gobble
        \let\aKeywords\@gobbletwo
        \@for\xmpKeyword:=#1\do{%
            \xdef\arrayOfKeywords{\arrayOfKeywords^^J%
            \insBagItem[\the\count0]="\xmpKeyword";}%
            \xdef\aKeywords{\aKeywords;\space\xmpKeyword}%
            \advance\count0by1
        }%
        \xdef\aKeywords{"\aKeywords"}%
    \fi
    \endgroup
}
%    \end{macrocode}
% \cs{insertKeywords} does what the other ``insert'' commands do, insert the
% code, we use the \texttt{dc:subject} tag, which corresponds to keywords.
%    \begin{macrocode}
\def\insertKeywords{\ifx\arrayOfKeywords\@empty\else
    \arrayOfKeywords\fi}
%    \end{macrocode}
% We set the keywords using the JavaScript property \texttt{Doc.in}, rather
% than a pdfmark.
%    \begin{macrocode}
\def\insertaKeywords{\ifx\aKeywords\@empty\else
%    this.info.Keywords=\aKeywords.toString();^^J%
    this.info.Keywords=\aKeywords;^^J%
    this.addScript("Array of Keywords", '\akeywordsJS');^^J\fi}
%    \end{macrocode}
% This is the definition of the function \texttt{aKeywords}, it is imported
% using the JavaScript method \texttt{Doc.addScript}, see above.
%    \begin{macrocode}
\begin{defineJS}[\catcode`\@=0\relax]{\akeywordsJS}
function aKeywords(i) {
    var uriRdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
    var uriDc="http://purl.org/dc/elements/1.1/";
    var meta=this.metadata;
    var aebXMPData=new XML(meta);
    var aebrdf=@xNNS(uriRdf);
    var aebdc=@xNNS(uriDc);
    var p=aebXMPData.aebrdf::RDF.aebrdf::Description;
    return p.aebdc::subject.aebrdf::Bag.aebrdf::li[i];
}
aKeywords.doc=this;
%    \end{macrocode}
% \texttt{aKeywords.toString()} displays a sting listing of the keywords;
% the string it displays \texttt{this.info.Keywords}.
%    \begin{macrocode}
aKeywords.toString=function() {return aKeywords.doc.info.Keywords;}
\end{defineJS}
%    \end{macrocode}
%    \end{macro}
%    \begin{macro}{\customProperties}
%\begin{verbatim}
%\customProperties
%{
%   {name=dps,value=5}
%   {name=jg,value=good}
%   ...
%}
%\end{verbatim}
%    \begin{macrocode}
\let\insertCusProps\@empty
\newcommand\customProperties[1]{\def\pdfx@cusProps{#1}%
    \begingroup\let\u\relax
    \@tfor\thisproperty:=#1\do{%
    \edef\tmp@exp{\noexpand
    \setkeys{pdfx@cusPropKV}{name,value,\thisproperty}}\tmp@exp
    \xdef\insertCusProps{\insertCusProps^^J%
%    \end{macrocode}
% We permit the use of \cs{u} the the value of the custom property,
% the name of the custom property should be a restricted XML name, basically
% \texttt{A-Z},\texttt{a-z}, and \texttt{0-9}.
%    \begin{macrocode}
        p.aebpdfx::\pdfx@KName="\pdfx@VValue";}
    }%
    \endgroup
}
%    \end{macrocode}
% The \texttt{pdfx@cusPropKV} family has two keys, \texttt{name} and \texttt{value}.
% These keys are used in the command \cs{customProperties} defined above.
%    \begin{macrocode}
\define@key{pdfx@cusPropKV}{name}[]{\def\pdfx@KName{#1}}
\define@key{pdfx@cusPropKV}{value}[]{\def\pdfx@VValue{#1}}
%    \end{macrocode}
%    \end{macro}
% We define a simple tabbing command \cs{tabiv} to use within the JavaScript.
%    \begin{macrocode}
\bgroup\obeyspaces
\gdef\tabiv{    }%
\egroup
%    \end{macrocode}
% These are some helper macros that conditionally fill in metadata when it exists.
% All these commands are using internally; the document author has no reason to use them.
%    \begin{macrocode}
\def\insertMarked{\ifx\xmpcopyrightStatus\@empty
    \else^^Jp.aebxapRights::Marked="\xmpcopyrightStatus";\fi}
\def\insertWebStatement{\ifx\xmpcopyrightInfoURL\@empty
    \else^^Jp.aebxapRights::WebStatement="\xmpcopyrightInfoURL";\fi}
\def\insertAuthorTitle{\ifx\xmpauthortitle\@empty
    \else^^Jp.aebphotoshop::AuthorsPosition="\xmpauthortitle";\fi}
\def\insertDescriptionWriter{\ifx\xmpdescriptionwriter\@empty
    \else^^Jp.aebphotoshop::CaptionWriter="\xmpdescriptionwriter";\fi}
\def\insertCreateDate{^^Jp.aebxap::CreateDate=createDateStr;}
\def\xmpnEOL{\string\n\string\^^J}
%    \end{macrocode}
% \section{Disposable JavaScript}
% Most of this package consists of a few new commands to populate the ``disposable''
% JavaScript that is input as an \textsf{FDF} when the PDF file is first opened after distilling.
% This code does all the work.
%    \begin{macrocode}
\def\xNNS{new Namespace}
\def\xAdbNS{http://ns.adobe.com}
\def\xWiiiNS{http://www.w3.org}
\begin{execJS}{execXMP}
var meta=this.metadata;
var aebXMPData=new XML(meta);
var aebx=\xNNS("x","adobe:ns:meta/");
var xmlns=\xNNS("xmlns","\xWiiiNS/2000/xmlns/");
var xml=\xNNS("xml", "\xWiiiNS/XML/1998/namespace");
var aebrdf=\xNNS("rdf","\xWiiiNS/1999/02/22-rdf-syntax-ns#");
var aebdc=\xNNS("dc","http://purl.org/dc/elements/1.1/");
var aebpdf=\xNNS("pdf","\xAdbNS/pdf/1.3/");
var aebxap=\xNNS("xmp","\xAdbNS/xap/1.0/");
var aebxapRights=\xNNS("xmpRights","\xAdbNS/xap/1.0/rights/");
var aebphotoshop=\xNNS("photoshop","\xAdbNS/photoshop/1.0/");
var aebpdfx=\xNNS("pdfx","\xAdbNS/pdfx/1.3/");
%    \end{macrocode}
%    \begin{macrocode}
var p=aebXMPData.aebrdf::RDF.aebrdf::Description;
%    \end{macrocode}
%    \begin{macrocode}
p.@xmlns::pdfx=aebpdfx.uri;
p.@xmlns::photoshop=aebphotoshop.uri;
p.@xmlns::xmpRights=aebxapRights.uri;
%    \end{macrocode}
% The creation date shall be the time this \textsf{FDF} is imported into the document.
%    \begin{macrocode}
var d=new Date();
var createDateStr=util.printd("yyyy-mm-ddTHH:MM:ss",d);
%    \end{macrocode}
% We delete the element, in case it already has a value (unlikely), the  we
% assign it our value.
%    \begin{macrocode}
delete p.@aebdc::rights.aebrdf::Alt.aebrdf::li;
%    \end{macrocode}
% \paragraph*{Dublin Core Properties
% (\texttt{dc}, \begin{NoHyper}\url{http://purl.org/dc/elements/1.1/}\end{NoHyper})}\strut\\
% Core properties include \texttt{dc:format}, \texttt{dc:title},
% \texttt{dc:rights}, \texttt{dc:creator}, and \texttt{dc:subject} (aka, keywords).
% Here, we set \texttt{dc:rights}, called \textsf{Copyright Notice} in the user interface.
%    \begin{macrocode}
\insertKeywords%
\insertCopyrightNotice
%    \end{macrocode}
% We delete all old values of \texttt{xapRights:Marked} and \texttt{xap:WebStatement},
% and replace them with the new values.
%    \begin{macrocode}
delete p.@aebxapRights::Marked;
delete p.@aebxapRights::WebStatement;
%    \end{macrocode}
% Ditto for \texttt{photoshop:AuthorsPosition} and
% \texttt{photoshop:CaptionWriter}.
%    \begin{macrocode}
delete p.@aebphotoshop::AuthorsPosition;
delete p.@aebphotoshop::CaptionWriter;
delete p.@aebxap::CreateDate;%
%    \end{macrocode}
% Now we insert additional properties, if there are any
%    \begin{macrocode}
%    \end{macrocode}
% \paragraph*{XMP Rights Management}\strut\\(\texttt{xmpRights},
% \begin{NoHyper}\url{http://ns.adobe.com/xap/1.0/rights/}\end{NoHyper})\\
% These include \texttt{xmpRights:Marked} and \texttt{xmpRights:WebStatement}, both of which
% are set.
%    \begin{macrocode}
\insertMarked%
\insertWebStatement%
%    \end{macrocode}
% \paragraph*{Adobe Photoshop Properties}\strut\\(\texttt{photoshop},
% \begin{NoHyper}\url{http://ns.adobe.com/photoshop/1.0/}\end{NoHyper})\\
% These include \texttt{photoshop:AuthorsPosition} and \texttt{photoshop:CaptionWriter}, both of which
% are set.
%    \begin{macrocode}
\insertAuthorTitle%
\insertDescriptionWriter%
%    \end{macrocode}
% \paragraph*{Acrobat Custom Properties} (\texttt{pdfx},
% \begin{NoHyper}\url{http://ns.adobe.com/pdfx/1.3/}\end{NoHyper})\\
% Adobe allows the creation of custom properties that are accessible
% through the \texttt{Doc.info} object.
%    \begin{macrocode}
\insertCusProps%
%    \end{macrocode}
% \paragraph*{XMP Core Properties} (\texttt{xmp},
% \begin{NoHyper}\url{http://ns.adobe.com/xap/1.0/}\end{NoHyper})\\
% These properties include \texttt{xmp:CreatorTool},
% \texttt{xmp:ModifyDate}, \texttt{xmp:CreateDate}, and \texttt{xmp:MetadataDate}.
% Here we set only \texttt{CreateDate}.
%    \begin{macrocode}
\insertCreateDate
%%</rdf:Description>
%    \end{macrocode}
% Convert \texttt{aebXMPData} into a string
%    \begin{macrocode}
var aebNewXMPStr=aebXMPData.toXMLString();
%    \end{macrocode}
% and assign it to the document metadata
%    \begin{macrocode}
this.metadata=aebNewXMPStr;
%    \end{macrocode}
% Now, we update the metadata by inserting the \texttt{info.Authors}
%    \begin{macrocode}
\insertAuthors%
%    \end{macrocode}
% This next command uses \texttt{this.info.Keywords} to insert the keywords
% into the \textbf{Info} dictionary and into \texttt{pdf:Keywords}. It also
% inserts the document-level JavaScript function \texttt{aKeywords()}.
%    \begin{macrocode}
\insertaKeywords%
\end{execJS}
%    \end{macrocode}
%    \begin{macrocode}
%</package>
%    \end{macrocode}
\endinput
