o
    vh                     @   s  d Z ddlZddlmZmZmZmZmZmZ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 dd	lmZ eeZg d
Zeeej eej f Zdd Zdedeeddf fddZdedejdejdeedef fddZe	dddZ e	dddZ!e	dedZ"e	deddZ#dedee"de f deeee"f de f fd d!Z$dedee!de f d"ee!ge#f deeee#f de f fd#d$Z%e& dfdee dee d%ee' de(fd&d'Z)dS )(z
Module defining common helpers for use by rules and policies.

In principle, these aren't relevant to the high-level validation API.
    N)Callable	FrozenSet	GeneratorOptionalSetTupleTypeVar)genericmisc)	PdfObject	Reference)HistoricalResolver   )ModificationLevelSuspiciousModification)ReferenceUpdate)qualifyqualify_transformingsafe_whitelistcompare_key_refscompare_dictsassert_not_streamc                 C   s"   t | tjrtd| j ddS )zT
    Throw :class:`.SuspiciousModification` if the argument is a stream object.
    z!Unexpected stream encountered at !N)
isinstancer	   StreamObjectr   container_ref)obj r   `/var/www/html/hyperkenya/venv/lib/python3.10/site-packages/pyhanko/sign/diff_analysis/commons.pyr      s
   r   oldreturnc                 c   sT    |r	t |  ||krt |  |V  dS | |r"|V  dS td| d)a~  
    Checks whether an indirect reference in a PDF structure
    can be updated without clobbering an older object in a way
    that causes ramifications at the PDF syntax level.

    The following are verified:

     - Does the old reference point to a non-stream object?
     - If the new reference is equal to the old one, does the new reference point
       to a non-stream object?
     - If the new reference is not equal to the old one,
       is the new reference a newly defined object?

    This is a generator for syntactical convenience and integration
    with internal APIs, but it will always yield at most one element.
    zUpdate clobbers or reuses z in an unexpected way.N)r   
get_objectis_ref_availabler   )r   old_refnew_refr   r   r   r   )   s   



r   old_dictnew_dictc                 c   s    z| | }t|tjr|j}| }nd}W n ty%   d }}Y nw z| | }t|tjr:|j}| }nd}W n tyS   |durPtd|  dY dS w |durat|||E dH  ||fS )a  
    Ensure that updating a key in a dictionary has no undesirable side effects.
    The following scenarios are allowed:

    0. replacing a direct value with another direct value
    1. adding a key in new_dict
    2. replacing a direct value in old_dict with a reference in new_dict
    3. the reverse (allowed by default)
    4. replacing a reference with another reference (that doesn't override
       anything else)

    The restrictions of `safe_whitelist` apply to this function as well.

    Note: this routine is only safe to use if the structure of the resulting
    values is also checked. Otherwise, it can lead to reference leaks if
    one is not careful.
    NzKey z was deleted from dictionary)NN)	raw_getr   r	   IndirectObject	referencer!   KeyErrorr   r   )keyr   r%   r&   	old_valueold_value_ref	new_valuenew_value_refr   r   r   r   K   s8   




r   RT)	covariant	QualifyIn)contravariantRefToUpd)bound	OutRefUpd)r5   r1   levelrule_resultc                 C   s   t | |dd dS )a  
    This is a helper function for rule implementors.
    It attaches a fixed modification level to an existing reference update
    generator, respecting the original generator's return value (if relevant).

    A prototypical use would be of the following form:

    .. code-block:: python

        def some_generator_function():
            # do stuff
            for ref in some_list:
                # do stuff
                yield ref

            # do more stuff
            return summary_value

        # ...

        def some_qualified_generator_function():
            summary_value = yield from qualify(
                ModificationLevel.FORM_FILLING,
                some_generator_function()
            )

    Provided that ``some_generator_function`` yields
    :class:`~.generic.ReferenceUpdate` objects, the yield type of the resulting
    generator will be tuples of the form ``(level, ref)``.

    :param level:
        The modification level to set.
    :param rule_result:
        A generator that outputs references to be whitelisted.
    :return:
        A converted generator that outputs references qualified at the
        modification level specified.
    c                 S   s   | S Nr   )xr   r   r   <lambda>   s    zqualify.<locals>.<lambda>)	transform)r   )r7   r8   r   r   r   r      s   *r   r<   c                    s   t | fddS )a  
    This is a version of :func:`.qualify` that additionally allows
    a transformation to be applied to the output of the rule.

    :param level:
        The modification level to set.
    :param rule_result:
        A generator that outputs references to be whitelisted.
    :param transform:
        Function to apply to the reference object before appending
        the modification level and yielding it.
    :return:
        A converted generator that outputs references qualified at the
        modification level specified.
    c                    s    | fS r9   r   )refr7   r<   r   r   r;      s    z&qualify_transforming.<locals>.<lambda>)r
   map_with_return)r7   r8   r<   r   r>   r   r      s   r   ignoredc           	      C   s   t | tjstdt |tjstdt|  t| t| | }t|  | }||kr@|r>td| d| ddS |D ]"}|	|}| 	|}||krd|ratd| d| d	|  dS qBd
S )zP
    Compare entries in two dictionaries, optionally ignoring certain keys.
    z?Encountered unexpected non-dictionary object in prior revision.z.Dict is overridden by non-dict in new revisionzDict keys differ: z vs. .FzValues for dict key z differ:z changed to T)
r   r	   DictionaryObjectr
   PdfReadErrorr   r   setkeysr'   )	r%   r&   r@   	raise_excnew_dict_keysold_dict_keysknew_valold_valr   r   r   r      sB   


	r   )*__doc__loggingtypingr   r   r   r   r   r   r   pyhanko.pdf_utilsr	   r
   pyhanko.pdf_utils.genericr   r   pyhanko.pdf_utils.readerr   
policy_apir   r   	rules_apir   	getLogger__name__logger__all__TwoVersionsr   r   rB   r   r0   r2   r4   r6   r   r   	frozensetstrboolr   r   r   r   r   <module>   sr    $
	

"
6
-
