U
    NfnN                     @   s  U d Z dZd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	 ddl
m
Z
mZ ddlmZmZ ddlmZ dd	lmZmZmZmZmZmZmZmZmZmZ ejdd
 dkrddlmZ nddlmZ ddlm Z m!Z!m"Z" eee#e#e#f ee#e#e#f ee#e#e#f f Z$ee%d< ee#e#e#e#e#e#f Z&ee%d< ee Z'ee(e'f Z)dZ*dZ+dZ,dZ-ee( ee
 dddZ.e(e(e(dddZ/die'ee0 e1dddZ2e'e1ddd Z3e'e4dd!d"Z5e1e4d#d$d%Z6e'ddd&d'Z7e'ee1 e1d(d)d*Z8e'e0e1d+d,d-Z9e'e1dd.d/Z:e$e$e$d0d1d2Z;e'ddd3d4Z<i Z=eee(e1f e1f e%d5< ee(e1f e1d6d7d8Z>ee(d9d:d;Z?ee(e0d9d<d=Z@ee1e1d9d>d=Z@ee0e0d9d?d=Z@ee0e(e1f ee0e1f d9d@d=Z@dAZAdBZBe0e0e0e0dCdDdEZCdje(e0ddGdHdIZDe(ddJdKdLZEe(e(e(ddMdNdOZFe(e(e(ddMdPdQZGe(e(ddRdSdTZHe(e(ddRdUdVZIe(e(ddWdXdYZJe(e(ddWdZd[ZKdke(ee(ef ee(e(f e4dd]d^d_ZLe0e(d`dadbZMe	G dcdd ddZNe	G dedf dfeNZOejPG dgdh dhZQdS )lz"Utility functions for PDF library.zMathieu Fenniakzbiziqe@mathieu.fenniak.net    N)	dataclass)datetimetimezone)DEFAULT_BUFFER_SIZEBytesIO)SEEK_CUR)
IOAnyDictListOptionalPatternTupleUnioncastoverload   )   
   )	TypeAlias   )STREAM_TRUNCATED_PREMATURELYDeprecationErrorPdfStreamErrorTransformationMatrixTypeCompressedTransformationMatrixz1{} is deprecated and will be removed in pypdf {}.z-{} is deprecated and was removed in pypdf {}.zA{} is deprecated and will be removed in pypdf {}. Use {} instead.z={} is deprecated and was removed in pypdf {}. Use {} instead.)textreturnc              	   C   s   | }| d krd S | d   r$d|  } | dr6| d7 } | dddddd	} t| d| d
}|dkr|t| d kr| d7 } dD ]T}zt| |}W n tk
r   Y qY qX | dd  dkr|jt	j
d}|  S qtd| d S )Nr   zD:)ZzZ0000r   +r   ' -   Z00)zD:%YzD:%Y%mzD:%Y%m%dz
D:%Y%m%d%HzD:%Y%m%d%H%MzD:%Y%m%d%H%M%SzD:%Y%m%d%H%M%S%zz+0000)tzinfozCan not convert date: )isdigitendswithreplacemaxfindlenr   strptime
ValueErrorr   utc)r   Zorgtextifd r3   0/tmp/pip-unpacked-wheel-zevpxvmc/pypdf/_utils.pyparse_iso8824_dateR   s(    
	

r5   )header1header2r   c                 C   sf   d}g }| |kr | ||  ||kr8| || t|dkrZtd| d|d|t| S )N)z%PDF-1.3z%PDF-1.4z%PDF-1.5z%PDF-1.6z%PDF-1.7z%PDF-2.0r   zneither z nor z are proper headers)appendindexr,   r.   r*   )r6   r7   versionsZpdf_header_indicesr3   r3   r4   _get_max_pdf_version_headerr   s    r;   )streammaxcharsr   c                 C   s8   d}|  d}| s4|sq4||7 }t||krq4q|S )a;  
    Read non-whitespace characters and return them.

    Stops upon encountering whitespace or when maxchars is reached.

    Args:
        stream: The data stream from which was read.
        maxchars: The maximum number of bytes returned; by default unlimited.

    Returns:
        The data which was read.
        r   )readisspacer,   )r<   r=   txttokr3   r3   r4   read_until_whitespace   s    
rC   )r<   r   c                 C   s"   |  d}|tkr|  d}q
|S )z
    Find and read the next non-whitespace character (ignores whitespace).

    Args:
        stream: The data stream from which was read.

    Returns:
        The data which was read.
    r   )r?   WHITESPACESr<   rB   r3   r3   r4   read_non_whitespace   s    

rF   c                 C   s0   t d }d}|t kr(| d}|d7 }q|dkS )a  
    Similar to read_non_whitespace, but return a boolean if more than one
    whitespace character was read.

    Args:
        stream: The data stream from which was read.

    Returns:
        True if more than one whitespace was skipped, otherwise return False.
    r   r   )rD   r?   )r<   rB   Zcntr3   r3   r4   skip_over_whitespace   s    

rG   )valuer   c                 C   s4   t t| D ]"}| ||d  }|tkr dS qdS )z
    Check if the given value consists of whitespace characters only.

    Args:
        value: The bytes to check.

    Returns:
        True if the value only has whitespace characters, otherwise return False.
    r   FT)ranger,   rD   )rH   r9   currentr3   r3   r4   check_if_whitespace_only   s
    
rK   c                 C   s6   |  d}| dd |dkr2|dkr2|  d}qd S )Nr      %)   
   )r?   seekrE   r3   r3   r4   skip_over_comment   s
    
rQ   )r<   regexr   c                 C   sp   d}|  d}|s|S ||| }|dk	rb| | t|t|  d || d|  }ql||7 }q|S )z
    Read until the regular expression pattern matched (ignore the match).
    Treats EOF on the underlying stream as the end of the token to be matched.

    Args:
        regex: re.Pattern

    Returns:
        The read bytes.
    r>      Nr   )r?   searchrP   startr,   )r<   rR   namerB   mr3   r3   r4   read_until_regex   s    
 
rX   )r<   to_readr   c                 C   s>   |   |k rtd| | t | |}| | t |S )a  
    Given a stream at position X, read a block of size to_read ending at position X.

    This changes the stream's position to the beginning of where the block was
    read.

    Args:
        stream:
        to_read:

    Returns:
        The data which was read.
    z!Could not read malformed PDF file)tellr   rP   r   r?   )r<   rY   r?   r3   r3   r4   read_block_backwards   s    
r[   c                 C   s   g }d}|   dkrtttt|   }|dkr4qt| |}t|d }|sx|dkrl|| dkrl|d8 }qN|dkrxd}|r|||d d  |dkr|| dkr|d8 }qn
|| |dkr| |d t	 qqd
|ddd S )	a   
    Given a byte stream with current position X, return the previous line.

    All characters between the first CR/LF byte found before X
    (or, the start of the file, if no such byte is found) and position X
    After this call, the stream will be positioned one byte after the
    first non-CRLF character found beyond the first CR/LF byte before X,
    or, if no such byte is found, at the beginning of the stream.

    Args:
        stream: StreamType:

    Returns:
        The data which was read.
    Fr   r   s   
TNr>   rL   )rZ   r   r   minr   r[   r,   r8   rP   r   join)r<   Zline_contentZ
found_crlfrY   blockidxr3   r3   r4   read_previous_line
  s.    


r`   )abr   c                    s   t  fdd| D S )Nc                 3   s(   | ]  t  fd dt D V  qdS )c                 3   s&   | ]}t d d t |D V  qdS )c                 s   s"   | ]\}}t |t | V  qd S N)float).0r0   jr3   r3   r4   	<genexpr>G  s     z6matrix_multiply.<locals>.<genexpr>.<genexpr>.<genexpr>N)sumzip)re   colrowr3   r4   rg   G  s     z,matrix_multiply.<locals>.<genexpr>.<genexpr>N)tupleri   )re   rb   rk   r4   rg   F  s   z"matrix_multiply.<locals>.<genexpr>)rm   )ra   rb   r3   rn   r4   matrix_multiplyC  s    ro   c              	   C   sd   d}|  | d tdd0}|| | |d || | W 5 Q R X |  | d dS )z5Create text file showing current location in context.i  r   zpypdf_pdfLocation.txtwbs   HEREN)rP   openwriter?   )r<   ZradiusZ	output_fhr3   r3   r4   mark_locationL  s    
rs   B_CACHE)sr   c                 C   s   t | tr| S t}| |kr"||  S z$| d}t| dk rB||| < |W S  tk
r|   | d}t| dk rt||| < | Y S X d S )Nlatin-1r   zutf-8)
isinstancebytesrt   encoder,   	Exception)ru   Zbcrr3   r3   r4   b_[  s    


r|   )rb   r   c                 C   s    t | tr| dS t| S d S )Nrv   )rw   rx   decodestrrn   r3   r3   r4   str_m  s    

r   c                 C   s   d S rc   r3   rn   r3   r3   r4   ord_t  s    r   c                 C   s   d S rc   r3   rn   r3   r3   r4   r   y  s    c                 C   s   d S rc   r3   rn   r3   r3   r4   r   ~  s    c                 C   s   t | trt| S | S rc   )rw   r~   ordrn   r3   r3   r4   r     s    
)    rN   rO      	    s   [ 
	 ])leftupup_leftr   c                 C   sX   | | | }t ||  }t || }t || }||krD||krD| S ||krP|S |S d S rc   )abs)r   r   r   pZ	dist_leftZdist_upZdist_up_leftr3   r3   r4   paeth_predictor  s    r   r   )msg
stacklevelr   c                 C   s   t j| t|d d S )N)r   )warningswarnDeprecationWarning)r   r   r3   r3   r4   	deprecate  s    r   )r   r   c                 C   s   t | d S rc   )r   )r   r3   r3   r4   deprecation  s    r   )old_namenew_name
removed_inr   c                 C   s   t t| ||d dS )zIRaise an exception that a feature will be removed, but has a replacement.   N)r   DEPR_MSGformatr   r   r   r3   r3   r4   deprecate_with_replacement  s    r   c                 C   s   t t| || dS )zMRaise an exception that a feature was already removed, but has a replacement.N)r   DEPR_MSG_HAPPENEDr   r   r3   r3   r4   deprecation_with_replacement  s    r   )rV   r   r   c                 C   s   t t| |d dS )zFRaise an exception that a feature will be removed without replacement.r   N)r   DEPR_MSG_NO_REPLACEMENTr   rV   r   r3   r3   r4   deprecate_no_replacement  s    r   c                 C   s   t t| | dS )zJRaise an exception that a feature was already removed without replacement.N)r    DEPR_MSG_NO_REPLACEMENT_HAPPENEDr   r   r3   r3   r4   deprecation_no_replacement  s    r   )r   srcr   c                 C   s   t ||  dS )z
    Use this instead of logger.error directly.

    That allows people to overwrite it more easily.

    See the docs on when to use which:
    https://pypdf.readthedocs.io/en/latest/user/suppress-warnings.html
    N)logging	getLoggererrorr   r   r3   r3   r4   logger_error  s    	r   c                 C   s   t ||  dS )a  
    Use this instead of logger.warning directly.

    That allows people to overwrite it more easily.

    ## Exception, warnings.warn, logger_warning
    - Exceptions should be used if the user should write code that deals with
      an error case, e.g. the PDF being completely broken.
    - warnings.warn should be used if the user needs to fix their code, e.g.
      DeprecationWarnings
    - logger_warning should be used if the user needs to know that an issue was
      handled by pypdf, e.g. a non-compliant PDF being read in a way that
      pypdf could apply a robustness fix to still read it. This applies mainly
      to strict=False mode.
    N)r   r   warningr   r3   r3   r4   logger_warning  s    r   F)	func_namekwargsaliasesfailr   c                 C   s   |  D ]~\}}||kr|r0t| d| d||kr^t|  d| d| d| d| d
||||< tj| d| dtd qd	S )
z
    Helper function to deprecate arguments.

    Args:
        func_name: Name of the function to be deprecated
        kwargs:
        aliases:
        fail:
    z# is deprecated as an argument. Use z insteadz received both z and z as an argument. z is deprecated. Use z	 instead.)messagecategoryN)itemsr   	TypeErrorpopr   r   r   )r   r   r   r   Zold_termZnew_termr3   r3   r4   rename_kwargs  s     r   )rx   r   c                 C   sV   | dk r|  dS | dk r*| d ddS | dk rB| d ddS | d ddS d S )	Ni  z Bytei@B z.1fz kBi ʚ;z MBz GBr3   )rx   r3   r3   r4   _human_readable_bytes  s    
r   c                   @   sf   e Zd ZU ddlmZ eed< eed< dZe	e
 ed< dZe	e ed< edd	d
ZedddZdS )Filer   IndirectObjectrV   dataNimageindirect_reference)r   c                 C   s&   | j j d| j dtt| j dS )Nz(name=z, data: ))	__class____name__rV   r   r,   r   selfr3   r3   r4   __str__  s    zFile.__str__c                 C   s"   |   d d dt| j d S )NrL   z, hash: r   )r   hashr   r   r3   r3   r4   __repr__  s    zFile.__repr__)r   
__module____qualname__genericr   r~   __annotations__rx   r   r   r	   r   r   r   r3   r3   r3   r4   r     s   
r   c                   @   sL   e Zd ZU ddlmZ dZee ed< dZ	ee ed< eeddddZ
dS )		ImageFiler   r   Nr   r   )	new_imager   r   c                 K   s8  ddl m} ddlm} ddlm} ddlm}m} | j	dkrFt
dt| j	jd	s\t
d
t||jspt
dt }|j|df| ||}	|	jd jd j	dk	st|	jd jd j	 | j	jj| j	jd < | j	t|| j	 _	|t|| j	 \}
}}|
dk	st| jd| jd |
 | _|| _|| _dS )a  
        Replace the Image with a new PIL image.

        Args:
            new_image (PIL.Image.Image): The new PIL image to replace the existing image.
            **kwargs: Additional keyword arguments to pass to `Image.Image.save()`.

        Raises:
            TypeError: If the image is inline or in a PdfReader.
            TypeError: If the image does not belong to a PdfWriter.
            TypeError: If `new_image` is not a PIL Image.

        Note:
            This method replaces the existing image with a new image.
            It is not allowed for inline images or images within a PdfReader.
            The `kwargs` parameter allows passing additional parameters
            to `Image.Image.save()`, such as quality.
        r   )Imager   )	PdfReader)_xobj_to_image)DictionaryObject	PdfObjectNzCan not update an inline imageZ_id_translatedz4Can not update an image not belonging to a PdfWriterznew_image shall be a PIL ImageZPDF.)ZPILr   Z_readerr   filtersr   r   r   r   r   r   hasattrZpdfrw   r   saveZpagesZimagesAssertionErrorZ
get_object_objectsZidnumr   rV   rfindr   r   )r   r   r   r   r   r   r   r   rb   reader	extensionZbyte_streamimgr3   r3   r4   r)     s8    
 
zImageFile.replace)r   r   r   r   r   r   r   r	   r   r   r)   r3   r3   r3   r4   r     s   
r   c                   @   sb   e Zd ZedZeddddZeee	e
ef  dddZeedd	d
ZeedddZdS )Versionz^(\d+)(.*)$N)version_strr   c                 C   s   || _ | || _d S rc   )r   _parse_version
components)r   r   r3   r3   r4   __init__R  s    zVersion.__init__c                 C   sn   | d}g }|D ]V}tj|}|s6|d|f q|d}|d}|d krVd}|t||f q|S )Nr   r   r   r   )splitr   COMPONENT_PATTERNmatchr8   groupint)r   r   r   Zparsed_components	componentr   Zinteger_prefixsuffixr3   r3   r4   r   V  s    


zVersion._parse_version)otherr   c                 C   s   t |tsdS | j|jkS )NF)rw   r   r   )r   r   r3   r3   r4   __eq__e  s    
zVersion.__eq__c                 C   s   t |tstdt| tt| jt|j}t|D ]X}| j| \}}|j| \}}||k rh dS ||krv dS ||k r dS ||kr: dS q:t| jt|jk S )Nz#Version cannot be compared against TF)rw   r   r.   typer\   r,   r   rI   )r   r   Zmin_lenr0   Z
self_valueZself_suffixZother_valueZother_suffixr3   r3   r4   __lt__j  s    
zVersion.__lt__)r   r   r   recompiler   r~   r   r   r   r   r   objectboolr   r	   r   r3   r3   r3   r4   r   N  s
   
r   )N)r   )F)R__doc__
__author____author_email__	functoolsr   r   sysr   Zdataclassesr   r   r   ior   r   osr   typingr   r	   r
   r   r   r   r   r   r   r   version_infor   Ztyping_extensionserrorsr   r   r   rd   r   r   r   Z
StreamTyper~   ZStrByteTyper   r   r   r   r5   r;   r   rx   rC   rF   r   rG   rK   rQ   rX   r[   r`   ro   rs   rt   r|   r   r   rD   ZWHITESPACES_AS_REGEXPr   r   r   r   r   r   r   r   r   r   r   r   r   total_orderingr   r3   r3   r3   r4   <module>   s   0& : 	"  
 
 !;