3
VmWi                 @   s@  d Z ddlmZmZ ddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlmZmZ ddlmZmZmZmZ ddlmZmZmZ ddlmZ dd	lmZ d
d ZG dd de	jZ e  j!Z"G dd de#Z$G dd de#Z%d$ddZ&dd Z'dd Z(dd Z)dd Z*dd Z+dd Z,d d! Z-d"d# Z.dS )%aW  
    weasyprint.pdf
    --------------

    Post-process the PDF files created by cairo and add metadata such as
    hyperlinks and bookmarks.


    Rather than trying to parse any valid PDF, we make some assumptions
    that hold for cairo in order to simplify the code:

    * All newlines are '\n', not '\r' or '\r\n'
    * Except for number 0 (which is always free) there is no "free" object.
    * Most white space separators are made of a single 0x20 space.
    * Indirect dictionary objects do not contain '>>' at the start of a line
      except to mark the end of the object, followed by 'endobj'.
      (In other words, '>>' markers for sub-dictionaries are indented.)
    * The Page Tree is flat: all kids of the root page node are page objects,
      not page tree nodes.

    However the code uses a lot of assert statements so that if an assumptions
    is not true anymore, the code should (hopefully) fail with an exception
    rather than silently behave incorrectly.


    :copyright: Copyright 2011-2014 Simon Sapin and contributors, see AUTHORS.
    :license: BSD, see LICENSE for details.

    )divisionunicode_literalsN   )VERSION_STRING
Attachment)xrange	iteritemsizipunquote)
iri_to_uriurlsplitURLFetchingError)W3C_DATE_RE)LOGGERc             C   s&   t | tr| jd} | jddddS )zlEscape parentheses and backslashes in ``value``.

    ``value`` must be unicode, or latin1 bytestring.

    latin1z\(z\)z\\)(   )   \   )
isinstancebytesdecode	translate)value r   N/var/www/html/enquirykeeper_venv/lib/python3.6/site-packages/weasyprint/pdf.py
pdf_escape4   s    

r   c                   s,   e Zd ZdZ fddZ fddZ  ZS )PDFFormatterzLike str.format except:

    * Results are byte strings
    * The new !P conversion flags encodes a PDF string.
      (UTF-16 BE with a BOM, then backslash-escape parentheses.)

    Except for fields marked !P, everything should be ASCII-only.

    c                s<   |dkr&dj td| jdjdS tt| j||S d S )NPz({0})u   ﻿z	utf-16-ber   )formatr   encoder   superr   convert_field)selfr   
conversion)	__class__r   r   r!   I   s    zPDFFormatter.convert_fieldc                s   t t| j|||}|jdS )Nr   )r    r   vformatr   )r"   format_stringargskwargsresult)r$   r   r   r%   S   s    zPDFFormatter.vformat)__name__
__module____qualname____doc__r!   r%   __classcell__r   r   )r$   r   r   ?   s   	
r   c               @   s@   e Zd Zdd Zdd Zi Zdd Zdd Zd	d
 Zdd Z	dS )PDFDictionaryc             C   s   || _ || _d S )N)object_numberbyte_string)r"   r0   r1   r   r   r   __init__\   s    zPDFDictionary.__init__c             C   s   | j jt| j| jf S )N)r$   r*   reprr0   r1   )r"   r   r   r   __repr__`   s    zPDFDictionary.__repr__c             C   sF   | j j||f}|s4tjtd||}|| j ||f< |j| jjdS )Nz/{0} {1}r   )	_re_cachegetrecompile
pdf_formatsearchr1   group)r"   keyZvalue_reZregexr   r   r   	get_valuef   s
    zPDFDictionary.get_valuec             C   s   | j ddjdS )z9
        :returns: the value for the /Type key.

        ZTypez/(\w+)ascii)r=   r   )r"   r   r   r   get_typem   s    zPDFDictionary.get_typec             C   s$   t | j|d}t| ||j|S )zRead the value for `key` and follow the reference, assuming
        it is an indirect dictionary object.

        :return: a new PDFDictionary instance.

        z	(\d+) 0 R)intr=   typeread_object)r"   r<   pdf_filer0   r   r   r   get_indirect_dictu   s    zPDFDictionary.get_indirect_dictc                sP   | j |djd}|j }|j  s(tt|  |j fddtt|D S )zRead the value for `key` and follow the references, assuming
        it is an array of indirect dictionary objects.

        :return: a list of new PDFDictionary instance.

        z	\[(.+?)\]s    0 Rc                s   g | ]} ||qS r   r   ).0n)class_readr   r   
<listcomp>   s    z9PDFDictionary.get_indirect_dict_array.<locals>.<listcomp>)	r=   splitpopstripAssertionErrorrA   rB   mapr@   )r"   r<   rC   partstrailr   )rG   rH   r   get_indirect_dict_array   s    z%PDFDictionary.get_indirect_dict_arrayN)
r*   r+   r,   r2   r4   r5   r=   r?   rD   rQ   r   r   r   r   r/   [   s   
r/   c               @   sf   e Zd ZdZejdejZdd Zdd Z	dd Z
d	d
 Zdd Zdd Zdd Zdd Zdd ZdS )PDFFilezc
    :param fileobj:
        A seekable binary file-like object for a PDF generated by cairo.

    s%   
trailer
(.+)
startxref
(\d+)
%%EOF
$c             C   sf  |j dtj | jj|j j \}}td |}t|}|j | t	|}|dksVt
t	|}|j \}}|dksvt
t|}t	|}|dkst
d g}xDtd|D ]6}t	|}|dd  dkst
|jt|d d  qW || _|| _|jd| }	|jd	| }
|
jd
| }|jd| }tdd |D s2t
|| _|	| _|
| _|| _|| _d| _i | _g | _d S )N   s   xref
   0s   0000000000 65535 f 
r   
   s
    00000 n 
ZInfoZRootZPagesZKidsc             s   s   | ]}|j  d kV  qdS )ZPageN)r?   )rE   pr   r   r   	<genexpr>   s    z#PDFFile.__init__.<locals>.<genexpr>Fi8)seekosSEEK_END
trailer_rer:   rH   groupsr/   r@   nextrM   rJ   r   appendfileobjobjects_offsetsrD   rQ   all	startxrefinfocatalog	page_treepagesfinishedoverwritten_objects_offsetsnew_objects_offsets)r"   r_   trailerrb   lineZfirst_objectZtotal_objectsr`   r0   rc   rd   re   rf   r   r   r   r2      sB    

zPDFFile.__init__c             C   s   | j }|j| j|  t|}|jds,tt|dd |ksDtg }xB|D ]:}|dkr~t|dksjt|jd dj|S |j| qNW dS )	z
        :param object_number:
            An integer N so that 1 <= N < len(self.objects_offsets)
        :returns:
            The object content as a byte string.

        s    0 obj
N   s   >>
s   endobj
s   >>    i)	r_   rX   r`   r]   endswithrM   r@   r^   join)r"   r0   r_   rk   Zobject_linesr   r   r   rB      s    


zPDFFile.read_objectc             C   s   | j ||| j|< dS )a  Write the new content for an existing object at the end of the file.

        :param object_number:
            An integer N so that 1 <= N < len(self.objects_offsets)
        :param byte_string:
            The new object content as a byte string.

        N)_write_objectrh   )r"   r0   r1   r   r   r   overwrite_object   s    
zPDFFile.overwrite_objectc             C   s4   |j jdst| j|j|j dd | d  dS )zaOverwrite a dictionary object after adding content inside
        the << >> delimiters.

        s   >>N   s   
>>)r1   rn   rM   rq   r0   )r"   
dictionaryZnew_contentr   r   r   extend_dict   s    zPDFFile.extend_dictc             C   s   t | jt | j S )zKReturn the object number that would be used by write_new_object().
        )lenr`   ri   )r"   r   r   r   next_object_number   s    zPDFFile.next_object_numberc             C   s    | j  }| jj| j|| |S )zWrite a new object at the end of the file.

        :param byte_string:
            The object content as a byte string.
        :return:
            The new object number.

        )rw   ri   r^   rp   )r"   r1   r0   r   r   r   write_new_object   s    	zPDFFile.write_new_objectc          	   C   s   | j  \}}d| _|d x&t| jD ]\}}|td|| q&W | jrt| j}|td|t| j x(t| j|dD ]\}}|td| qxW |td| j	 | j
j| jj| j|d d	S )
z
        Write the cross-reference table and the trailer for the new and
        overwritten objects. This makes `fileobj` a valid (updated) PDF file.

        Ts   xref
z{0} 1
{1:010} 00000 n 
z{0} {1}
)startz{0:010} 00000 n 
zftrailer
<< /Size {size} /Root {root} 0 R /Info {info} 0 R /Prev {prev} >>
startxref
{startxref}
%%EOF
)sizerootrc   prevrb   N)_start_writingrg   r   rh   r9   ri   rv   r`   	enumeraterw   rd   r0   rc   rb   )r"   Znew_startxrefwriter0   offsetZfirst_new_objectr   r   r   finish  s*    
zPDFFile.finishc             C   s.   | j  \}}|td| || |d |S )Nz
{0} 0 obj
s   
endobj
)r}   r9   )r"   r0   r1   r   r   r   r   r   rp   +  s
    zPDFFile._write_objectc             C   s.   | j  st| j}|jdtj |j |jfS )Nr   )rg   rM   r_   rX   rY   rZ   tellr   )r"   r_   r   r   r   r}   2  s    zPDFFile._start_writingN)r*   r+   r,   r-   r7   r8   DOTALLr[   r2   rB   rq   ru   rw   rx   r   rp   r}   r   r   r   r   rR      s   
/
#rR   c             c   sB   x<| D ]4\}}}|||fV  xt ||d D ]
}|V  q,W qW d S )Nr   )flatten_bookmarks)	bookmarksdepthlabeltargetchildrenr)   r   r   r   r   9  s    r   c          
      s   fdd| j D }g }xt| j |D ]\}}g }x|D ]\}}	}
|dkrl|	\}}}|f|| j|| }	|
\}}}}|j||\}}|j||\}}|||| || f}
|j||	|
f q:W |j| q(W ddi}g }|g}|g}xtt| j |d D ]\}\}}	}|	\}}}|f|| j|| }	ddddd||d  ||	d}|t	|d krp|||d  d	< n,|| |d
< ||| d< ||d= ||d= x&t
|D ]}|| d  d7  < qW |||d  d< |j| |j| |j| q W |||fS )ay  Change metadata into data structures closer to the PDF objects.

    In particular, convert from WeasyPrint units (CSS pixels from
    the top-left corner) to PDF units (points from the bottom-left corner.)

    :param scale:
        PDF points per CSS pixels.
        Defaults to 0.75, but is affected by `zoom` in
        :meth:`weasyprint.document.Document.write_pdf`.

    c                s$   g | ]}t j   |j  d qS ))ZxxyyZy0)cairoZMatrixheight)rE   page)scaler   r   rI   M  s   z$prepare_metadata.<locals>.<listcomp>internalCountr   r   N)r   FirstLastPrevNextParentr   r   r   r   r   r   )rf   r	   Zresolve_linksZtransform_pointZtransform_distancer^   r~   r   Zmake_bookmark_treerv   range)documentbookmark_root_idr   Zmatriceslinks
page_linksZmatrixZnew_page_links	link_typer   	rectangleZtarget_pageZtarget_xZtarget_yZrect_xZrect_ywidthr   bookmark_rootZbookmark_listZlast_id_by_depthZlast_by_depthZbookmark_idr   r   bookmarkir   )r   r   prepare_metadata@  sT    










r   c                sJ  | j  }|d }|d }|d }|d }| j \}}|td| |td||| |d d}	d}
tj }tj }xNt fd	d
dD ]8}|	t|7 }	|j	| |j
|}|
t|7 }
|| qW |jtj}|
t|7 }
|| |d |d | jj| | jtd|
 | jtd|j  | jtd|	 | j  |ksFt|S )a  
    Write a file like object as ``/EmbeddedFile``, compressing it with deflate.
    In fact, this method writes multiple PDF objects to include length,
    compressed length and MD5 checksum.

    :return:
        the object number of the compressed file stream object
       r   rr      z
{0} 0 obj
zm<< /Type /EmbeddedFile /Length {0} 0 R /Filter /FlateDecode /Params << /CheckSum {1} 0 R /Size {2} 0 R >> >>
s   stream
r   c                  s
    j dS )Ni   )rH   r   )filer   r   <lambda>  s    z/_write_compressed_file_object.<locals>.<lambda>rm   s   
endstream
s   endobj
z{0}z<{0}>)rw   r}   r9   hashlibmd5zlibcompressobjiterrv   updatecompressflushZ_FINISHri   r^   rx   	hexdigestrM   )pdfr   r0   Zexpected_next_object_numberZlength_numberZ
md5_numberZuncompressed_length_numberr   r   Zuncompressed_lengthZcompressed_lengthr   r   data
compressedr   )r   r   _write_compressed_file_object  s@    


r   c             C   s   d}|r|j d}|r|S | rLt| }|jdkrL|jjdd }|dkrLd}|dkrd}|r|j d}|dkrtd	}qtj|pd
}nd
}d| }n>tjd dk rt	|}t
|ts|jd}|jd}nt	|}|S )z
    Derives a filename from a fetched resource. This is either the filename
    returned by the URL fetcher, the last URL path component or a synthetic
    name if the URL has no path
    Nfilenamer   /r    	mime_typez
text/plainz.txtz.bin
attachmentr   r   r   zutf-8)r6   r   schemepathrJ   	mimetypesZguess_extensionsysversion_infor
   r   r   r   r   )urlr)   r   rJ   	extensionr   r   r   r   _get_filename_from_result  s6    






r   c             C   s~   g }x*|D ]"}t | ||}|dk	r
|j| q
W t|dkr@dS dg}x|D ]}|jtd| qLW |jd | jdj|S )z
    Writes attachments as embedded files (document attachments).

    :return:
        the object number of the name dictionary or :obj:`None`
    Nr   s   << /Names [z
(attachment{0}) {0} 0 R s   
] >>rm   )_write_pdf_attachmentr^   rv   r9   rx   ro   )r   attachmentsurl_fetcherZfile_spec_idsr   Zfile_spec_idcontentfsr   r   r   _write_pdf_embedded_files  s    


r   c             C   s   ytt |tr$|\}}t|||d}nt |ts:t||d}|j,\}}}}t |tr^tj|}t| |}W dQ R X W n, tk
r }	 zt	j
d|	 dS d}	~	X nX t|d}
| jtd|
||jpdS )z
    Writes an attachment to the PDF stream

    :return:
        the object number of the ``/Filespec`` object or :obj:`None` if the
        attachment couldn't be read.
    )r   r   description)Zguessr   NzFailed to load attachment: %szF<< /Type /Filespec /F () /UF {0!P} /EF << /F {1} 0 R >> /Desc {2!P}
>>r   )r   tupler   sourcer   ioBytesIOr   r   r   warningr   rx   r9   r   )r   r   r   r   r   Zsource_typer   _Zfile_stream_idexcr   r   r   r   r     s(    




r   c             C   sN   i }xD|D ]<}x6|D ].\}}}|dkr||krt | |df|||< qW q
W |S )z
    Write all annotation attachments to the PDF file.

    :return:
        a dictionary that maps URLs to PDF object numbers, which can be
        :obj:`None` if the resource failed to load.
    r   N)r   )r   r   r   annot_filesr   r   r   r   r   r   r   _write_pdf_annotation_files=  s    
r   c             C   s  t |}|j }t| ||\}}	}
|	r|jtd|d |d |d  x|	D ]}td|d g}|d \}}}|jtd|j| j|| |d r|jtd	|d  x*d3D ]"}|| r|jtd|||  qW |jd |jdj| qLW t	||j
|p g  |}|	s|dk	rVd}|	r0|td|7 }|dk	rH|td|7 }|j|j| t||
|}x*t|j|
D ]\}}g }x|D ]\}}}td4| g}|dks|| dkr|jd |dkr|jtd5|  n|jtdtt| nD|| dk	s
t|jtd6| }|jd |jtd|| | |jd |j|jdj| qW |rr|j|tddjdd |D  qrW td tg}x8d:D ]0\}}t||}|dk	r|jtd'|| qW x>d=D ]6\}}t||}|dk	r|jtd'|d,j| qW x>d@D ]6\}}tt|||}|dk	r|jtd1|| qW |jd2 |j|jjdj| |j  dS )Az:Append to a seekable file-like object to add PDF metadata.z=<< /Type /Outlines /Count {0} /First {1} 0 R /Last {2} 0 R
>>r   r   r   z<< /Title {0!P}
r   r   z@/A << /Type /Action /S /GoTo /D [{0} 0 R /XYZ {1:f} {2:f} 0] >>
z/Count {0}
r   r   r   z/{0} {1} 0 R
s   >>rm   Nz) /Outlines {0} 0 R /PageMode /UseOutlinesz$ /Names << /EmbeddedFiles {0} 0 R >>@<< /Type /Annot /Rect [{0:f} {1:f} {2:f} {3:f}] /Border [0 0 0]
r   s   /Subtype /Link r   </A << /Type /Action /S /GoTo /D [{0} /XYZ {1:f} {2:f} 0] >>
z*/A << /Type /Action /S /URI /URI ({0}) >>
^<< /Type /XObject /Subtype /Form /BBox [{0:f} {1:f} {2:f} {3:f}] /Length 0 >>
stream
endstreams   /Subtype /FileAttachment z&/T () /FS {0} 0 R /AP << /N {1} 0 R >>z/Annots [{0}] c             s   s   | ]}d j |V  qdS )z{0} 0 RN)r   )rE   rF   r   r   r   rW     s    z%write_pdf_metadata.<locals>.<genexpr>z<< /Producer {0!P}
titleTitler   Subject	generatorCreatorz
/{0} {1!P}authorsAuthorkeywordsKeywordsz, createdCreationDatemodifiedModDatez/{0} (D:{1})s    >>)r   r   r   r   r   )r   )r   )r   r   r   r   r   r   r   )r   r   r   r   r   r   r   )r   r   r   r   r   r   )r   r   )rR   rw   r   rx   r9   r^   rf   r0   ro   r   r   ru   rd   r   zipr   r   rM   r   getattrw3c_date_to_pdfrq   rc   r   )r   r_   r   metadatar   r   r   r   r   r   r   r   r   Zpage_numZpos_xZpos_yr<   Zembedded_files_idparamsr   r   r   annotationsr   r   r   Zlink_aprc   attrr   r   r   r   write_pdf_metadataO  s    















r   c             C   s   | dkrdS t j| }|dkr0tjd||  dS |j }|d |d pHd |d pTd |d p`d |d pld |d	 pxd }|d r|d st|d	 s|d
7 }|d r|d jdst|d st|d|d |d f 7 }n|d7 }|S )z 
    YYYYMMDDHHmmSSOHH'mm'

    NzInvalid %s date: %ryearmonthr   dayhourminutesecondZ00Ztz_hour+-Z	tz_minutez%s'%s'Z)r   r   )r   matchr   r   	groupdictrM   
startswith)string	attr_namer   r\   Zpdf_dater   r   r   r     s&    
6r   )r   )/r-   
__future__r   r   r   r   r   rY   r7   r   r   r   Z	cairocffir   r   r   r   compatr   r   r	   r
   Zurlsr   r   r   htmlr   loggerr   r   	Formatterr   r   r9   objectr/   rR   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>   s<   6 )
D;>&v