[tex-k] HyperTeX tags

Heiko Oberdiek oberdiek at uni-freiburg.de
Tue Feb 28 09:38:32 CET 2006

On Mon, Feb 27, 2006 at 02:03:36PM +0200, Oleg Katsitadze wrote:

> ---------------------to.tex---------------------
> {\catcode`\#=11
> \gdef\hash{#}}
> \null\vfill\eject % Empty first page.
> \noindent
> \special{html:<a name="dest">}%
>   Destination in to.pdf%
> \special{html:</a>}
> \vfill
> \noindent
> \special{html:<a href="\hash dest">}Reference to force
> creation of the target anchor\special{html:</a>}
> \bye
> ---------------------to.tex---------------------

> The first problem:  the link from from.pdf opens to.pdf on
> the _first_ page (both in Xpdf and Acrobat Reader).  When I
> look at the `raw' from.pdf, I see:
> Alright.  Now I open to.pdf and see:

>   13 0 obj
>   <</Type/Annot
>   /T(dest)
>   /Rect [72 437 279 449]
>   /Border [1 1 1[]]
>   /C [0 0 1]
>   /Dest [10 0 R /FitH 841]
>   /Subtype/Link>>endobj
>   14 0 obj
> This is the link on the second page of to.pdf to the
> destination on the same page, but instead of creating a
> named destination "dest" and linking to it, ps2pdf created
> link using explicit destination.  There is no destination
> named "dest" defined in to.pdf,

I agree with your analysis and found a bug in dvips (hps.lpro):

dvips puts the destinations in a dictionary /TargetAnchors and
applies the procedure targetdump-hook on the dictionary.
The default definition of targetdump-hook in hps.lpro:

   {dup mark exch gsave initmat setmatrix 
    {{ mark /Dest 4 2 roll 
        {aload pop exch pop
         /Page 3 1 roll /View exch [ exch /FitH exch ]
         /DEST pdfmark}
        ifelse} forall} stackstopped pop
    grestore} bind def

It calls targetvalidate that is the cause of the problem:

/tempstring 256 string def

 {1 index dup length 255 gt exch
  dup (/) search 
    {pop pop pop exch pop true exch}
  cvn tempstring cvs
  token pop pop length 0 ne or 
  not} bind def

I do not know the purpose of this procedure. Perhaps it want to
sort out names that does not work with some Distiller/older
Ghostscript versions? It throws away names longer than 255
characters, names that contain "/" or white space. This might
be a problem with very old Distiller programs for PDF < 1.2,
but for PDF-1.2 any character except null (code 0) can be part
of a name.

"1 index" at the beginning of targetvalidate gets the key
of the entry in the dictionary TargetAnchors. The original
type was string. The entry in the dictionary was defined
with the key as string. That is possible in PostScript where
string or name (or any other type) can be used as key.
But the forall loop produces the type name for the key
(perhaps older versions of ghostscript/distiller behaved differently
returning a string?). Thus the key has the type name!
The length test works for both string and name, but search
expects a string only. Thus the conversion to the string must
be done *before* search, not after.

Also the PDF specification (Version 1.6) says in appendix C
"Implemenation Limits", table C.1 "Architectural limits":
  quantitiy: name
  limit: 127
  description: Maximum length of a name, in bytes.

The next bug: token also can return false. This case is not checked.
For example, this case is triggered by an empty name. This is valid
for PDF, but perhaps it is intended to prevent this case for
older distiller versions? The patch below assumes yes.

*** hps.lpro.org	2006-02-28 09:31:13.000000000 +0100
--- hps.lpro	2006-02-28 09:35:41.000000000 +0100
*** 69,84 ****
  bind def
! /tempstring 256 string def
!  {1 index dup length 255 gt exch
    dup (/) search 
      {pop pop pop exch pop true exch}
!   cvn tempstring cvs
!   token pop pop length 0 ne or 
    not} bind def
  /targetdump-hook where 
--- 69,87 ----
  bind def
! % PDF implementation limit for names is 127, see PDF specification,
! % version 1.6, appendix C "Implementation Limits,
! % table C.1 "Architectural limits", page 920.
! /tempstring 128 string def
!  {1 index dup length 127 gt exch
!   tempstring cvs
    dup (/) search 
      {pop pop pop exch pop true exch}
!   token {pop length 0 ne} {true} ifelse or 
    not} bind def
  /targetdump-hook where 

Next problem is dvips itself:

  \special{html:<a name="abc)def">}%

The PS file is then invalid:

  (abc)def) [2 [72 719 183 721] 841] def

The name should be quoted to get a valid PostScript string:

  (abc\)def) ...

Yours sincerely
  Heiko <oberdiek at uni-freiburg.de>

More information about the tex-k mailing list