o
    ij                     @   s  d Z ddlZddlm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 ddlmZ ddl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 ddlmZ ddl m!Z! ddl"m#Z#m$Z$m%Z% ddl&Zddl'Zddl'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z/m0Z0 erddl1Z1ddl'm2Z2 edZ3	d^de4dee4ge3f dB de3ee3 B fddZ5d_de6de7de8de%fddZ9	d^de6de7de4dB de4ee4 B fddZ:	d^de6de7de4dB de%ee% B fd d!Z;d"e4de(fd#d$Z<	d^de6de7de4dB de4e(B ee4 B ee( B fd%d&Z=	d^de6de7de4dB deej>j?eej>j? d'd(f fd)d*Z@d"e4de)fd+d,ZA	d^de6de7de4dB de4e)B ee4 B ee) B fd-d.ZB	d^de6de7de4dB dee,ee, d/d(f fd0d1ZCde6de7de4de4e8B eDB ee8 B eeD B fd2d3ZE	d^de6de7de4dB de6fd4d5ZF	d^de6de7de4dB de6fd6d7ZG	d^de6de7de4dB de6fd8d9ZH	d^de6d:eIe4 dB de2ee2 B fd;d<ZJ	d^de6de7de4dB de4ee4 B fd=d>ZK	d`de6d:eIe4 dB d?e4dB de4ee4 B fd@dAZL		d`de6d:eIe4 dB d?e4dB de4fdBdCZM		dade6dDe7de7dEeIe4 dB de8de!fdFdGZNd"e4de*fdHdIZO	d^de6de7de4dB de4e*B ee4 B ee* B fdJdKZP	d^de6de7de4dB dejQjReejQjR B fdLdMZS	d^de6de7de4dB de6fdNdOZT	d^de6de7de4dB de4fdPdQZU	d^dRe4dSed:e4ee4 B dB de
ee
 B fdTdUZVe/jWe/jXe/jYe/jZe/j[e/j\e/j]e/j^e/j_e/j`e/j(e/j*e/jae/j,e/jbe/jce/jde/jee/jfe/jge/j)e/jhgZii e/jje:e/jkeKe/jfe;e/jleKe/j(e=e/jbe@e/j)eBe/j]eEdVfe/j\eEdWfe/j,eCe/jmeLe/jceMe/j_eFe/jneFe/j^eGe/joeFe/jgeGi e/jpeHe/jaeJe/jWeLe/jYeEdXfe/jdeNe/j[eEdYfe/jqeMe/jreEdZfe/j*ePe/jseLe/j`eSe/jXeEd[fe/jeeTe/jteUe/jZeEd\fe/jheMe/jueEd]fe/jveFe/jweGe/jxeGe/jyeGiZzdS )bzQFunctions for converting values of DICOM
   data elements to proper python types
    N)BytesIO)unpackcalcsize)UnioncastAnyTypeVar)MutableSequenceCallable)config)default_encodingdecode_bytes)logger
have_numpy)empty_value_for_VRRawDataElement)BytesLengthException)read_sequence)
MultiValue)Sequence)TagTupleTagBaseTag)DADTTMTEXT_VR_DELIMSISCUSTOMIZABLE_CHARSET_VRVRvalidate_value)
PersonName_Tvalvaltypereturnc                 C   sN   |du rt ttgtf t}| dd}t|dkr"||d S t||S )a  Split a string by delimiters if there are any

    Parameters
    ----------
    val : str
        The string to split up.
    valtype : type or callable, optional
        Default :class:`str`, but can be e.g. :class:`~pydicom.uid.UID` to
        overwrite to a specific type.

    Returns
    -------
    valtype or MultiValue[valtype]
        The split value as `valtype` or a :class:`~pydicom.multival.MultiValue`
        of `valtype`.
    Nz  \   r   )r   r
   strr"   rstripsplitlenr   )r#   r$   items r-   D/mnt/sdb/aimis/docanh/lib/python3.10/site-packages/pydicom/values.pymulti_string-   s   "r/   byte_stringis_little_endianoffsetc                 C   sL   t | dk r
td|rdnd}ttttf t|| ||d  }t|S )a(  Return a decoded :class:`BaseTag<pydicom.tag.BaseTag>` from the encoded
    `byte_string`. `byte_string` must be at least 4 bytes long.

    Parameters
    ----------
    byte_string : bytes
        The encoded tag.
    is_little_endian : bool
        ``True`` if the encoding is little endian, ``False`` otherwise.
    offset : int, optional
        The byte offset in `byte_string` to the start of the tag.

    Returns
    -------
    BaseTag
        The decoded tag.

    Raises
    ------
    ValueError
        If `byte_string` is too short.
       z6byte string too short - must be at least 4 bytes long.z<HHz>HH)r+   
ValueErrorr   tupleintr   r   )r0   r1   r2   fmtvaluer-   r-   r.   convert_tagI   s
   $r9   struct_formatc                 C   s<   |  td}dd |D }t|dkr|d S tt|S )a  Return a decoded 'AE' value.

    Elements with VR of 'AE' have non-significant leading and trailing spaces.

    Parameters
    ----------
    byte_string : bytes
        The encoded 'AE' element value.
    is_little_endian : bool
        ``True`` if the value is encoded as little endian, ``False`` otherwise.
    struct_format : str, optional
        Not used.

    Returns
    -------
    str
        The decoded 'AE' value without non-significant spaces.
    r&   c                 S   s   g | ]}|  qS r-   )strip).0sr-   r-   r.   
<listcomp>~       z%convert_AE_string.<locals>.<listcomp>r'   r   )decoder   r*   r+   r   r(   )r0   r1   r:   valuesr-   r-   r.   convert_AE_stringg   s
   
rB   c                    sd   t  }|dkrt S |d dkr!td|  ||d 8 }tt fddtd|dD S )a|  Return a decoded 'AT' value.

    Parameters
    ----------
    byte_string : bytes
        The encoded 'AT' element value.
    is_little_endian : bool
        ``True`` if the value is encoded as little endian, ``False`` otherwise.
    struct_format : str, optional
        Not used.

    Returns
    -------
    BaseTag or MultiValue of BaseTag
        The decoded value(s).
    r3   r   z<Expected length to be multiple of 4 for VR 'AT', got length c                    s   g | ]	}t  |d qS ))r2   )r9   )r<   xr0   r1   r-   r.   r>      s    z#convert_ATvalue.<locals>.<listcomp>)r+   r9   r   warningr   r   range)r0   r1   r:   lengthr-   rD   r.   convert_ATvalue   s   

rH   r8   c                 C   s   t |  S N)r   r)   )r8   r-   r-   r.   _DA_from_str   s   rJ   c                 C   D   t jr| td}t|dkrt|d S tt|S t| ||S )ad  Return a decoded 'DA' value.

    Parameters
    ----------
    byte_string : bytes
        The encoded 'DA' element value.
    is_little_endian : bool
        ``True`` if the value is encoded as little endian, ``False`` otherwise.
    struct_format : str, optional
        Not used.

    Returns
    -------
    str or MultiValue of str or valuerep.DA or MultiValue of valuerep.DA
        If
        :attr:`~pydicom.config.datetime_conversion` is ``True`` then returns
        either :class:`~pydicom.valuerep.DA` or a :class:`list` of ``DA``,
        otherwise returns :class:`str` or ``list`` of ``str``.
    r&   r'   r   )	r   datetime_conversionr@   r   r*   r+   rJ   r   convert_stringr0   r1   r:   splitupr-   r-   r.   convert_DA_string      
rP   znumpy.float64numpy.ndarrayc                 C   s   |  t}tjr<tstdd}t||du r(td	t
|dd d|tj|ddd	}t|d
kr:|d S |S t| tjjdS )a  Return a decoded 'DS' value.

    .. versionchanged:: 2.0

        The option to return numpy values was added.

    Parameters
    ----------
    byte_string : bytes
        The encoded 'DS' element value.
    is_little_endian : bool
        ``True`` if the value is encoded as little endian, ``False`` otherwise.
    struct_format : str, optional
        Not used.

    Returns
    -------
    :class:`~pydicom.valuerep.DSfloat`, :class:`~pydicom.valuerep.DSdecimal`, :class:`numpy.float64`, MultiValue of DSfloat/DSdecimal or :class:`numpy.ndarray` of :class:`numpy.float64`

        If :attr:`~pydicom.config.use_DS_decimal` is ``False`` (default),
        returns a :class:`~pydicom.valuerep.DSfloat` or list of them

        If :attr:`~pydicom.config.use_DS_decimal` is ``True``,
        returns a :class:`~pydicom.valuerep.DSdecimal` or list of them

        If :data:`~pydicom.config.use_DS_numpy` is ``True``,
        returns a :class:`numpy.float64` or a :class:`numpy.ndarray` of them

    Raises
    ------
    ValueError
        If :data:`~pydicom.config.use_DS_numpy` is ``True`` and the string
        contains non-valid characters

    ImportError
        If :data:`~pydicom.config.use_DS_numpy` is ``True`` and numpy is not
        available
    z(use_DS_numpy set but numpy not installedz[ \\0-9\.+eE-]*\ZNz#DS: char(s) not in repertoire: '{}' f8r&   dtypesepr'   r   r$   )r@   r   r   use_DS_numpyr   ImportErrorrematchr4   formatsubnumpy
fromstringr+   r/   r;   pydicomvaluerepDSclassr0   r1   r:   
num_stringregexr8   r-   r-   r.   convert_DS_string   s    
.rh   c                 C   s8   |   } t| }|dk s|dkrtd|  t| S )Nr3      z-Expected length between 4 and 26, got length )r)   r+   r   rE   r   r8   rG   r-   r-   r.   _DT_from_str  s
   rk   c                 C   rK   )aT  Return a decoded 'DT' value.

    Parameters
    ----------
    byte_string : bytes
        The encoded 'DT' element value.
    is_little_endian : bool
        ``True`` if the value is encoded as little endian, ``False`` otherwise.
    struct_format : str, optional
        Not used.

    Returns
    -------
    str or MultiValue of str or valuerep.DT or MultiValue of DT
        If
        :attr:`~pydicom.config.datetime_conversion` is ``True`` then returns
        :class:`~pydicom.valuerep.DT` or a :class:`list` of ``DT``, otherwise
        returns :class:`str` or ``list`` of ``str``.
    r&   r'   r   )	r   rL   r@   r   r*   r+   rk   r   rM   rN   r-   r-   r.   convert_DT_string  rQ   rl   numpy.int64c                 C   s   |  t}tjrDtstdd}t||du r(td	t
|dd d|tj|dtdd	}t|d
kr?td|d S td|S t|tjjdS )a)  Return a decoded 'IS' value.

    .. versionchanged:: 2.0

        The option to return numpy values was added.

    Parameters
    ----------
    byte_string : bytes
        The encoded 'IS' element value.
    is_little_endian : bool
        ``True`` if the value is encoded as little endian, ``False`` otherwise.
    struct_format : str, optional
        Not used.

    Returns
    -------
    :class:`~pydicom.valuerep.IS` or MultiValue of them, or :class:`numpy.int64` or :class:`~numpy.ndarray` of them

        If :data:`~pydicom.config.use_IS_numpy` is ``False`` (default), returns
        a single :class:`~pydicom.valuerep.IS` or a list of them

        If :data:`~pydicom.config.use_IS_numpy` is ``True``, returns
        a single :class:`numpy.int64` or a :class:`~numpy.ndarray` of them

    Raises
    ------
    ValueError
        If :data:`~pydicom.config.use_IS_numpy` is ``True`` and the string
        contains non-valid characters
    ImportError
        If :data:`~pydicom.config.use_IS_numpy` is ``True`` and numpy is not
        available
    z(use_IS_numpy set but numpy not installedz[ \\0-9\.+-]*\ZNz#IS: char(s) not in repertoire: '{}'rS   rT   i8\   rV   r'   rm   r   rR   rY   )r@   r   r   use_IS_numpyr   r[   r\   r]   r4   r^   r_   r`   ra   chrr+   r   r/   rb   rc   r   re   r-   r-   r.   convert_IS_string?  s    
%
rr   c              
   C   s   d| }t d| }t| }|| dkr/tdt| dkr t| nd d| d| d	| d
	| ||  | }t|| }t|dkrFdS t|dkrP|d S t|S )ak  Return a decoded numerical VR value.

    Given an encoded DICOM Element value, use `struct_format` and the
    endianness of the data to decode it.

    Parameters
    ----------
    byte_string : bytes
        The encoded numerical VR element value.
    is_little_endian : bool
        ``True`` if the value is encoded as little endian, ``False`` otherwise.
    struct_format : str
        The format of the numerical data encoded in `byte_string`. Should be a
        valid format for :func:`struct.unpack()` without the endianness.

    Returns
    -------
    str
        If there is no encoded data in `byte_string` then an empty string will
        be returned.
    value
        If `byte_string` encodes a single value then it will be returned.
    list
        If `byte_string` encodes multiple values then a list of the decoded
        values will be returned.
    z><=r   zQExpected total bytes to be an even multiple of bytes per value. Instead received    bytesz with length z and struct format 'z*' which corresponds to bytes per value of .rT   r'   )r   r+   r   reprr   list)r0   r1   r:   
endianCharbytes_per_valuerG   format_stringr8   r-   r-   r.   convert_numbersz  s,   	
r|   c                 C      | S )z,Return encoded 'OB' value as :class:`bytes`.r-   r0   r1   r:   r-   r-   r.   convert_OBvalue     r   c                 C   
   t | |S )z^Return the encoded 'OW' value as :class:`bytes`.

    No byte swapping will be performed.
    r   r~   r-   r-   r.   convert_OWvalue     
r   c                 C   r   )z^Return the encoded 'OV' value as :class:`bytes`.

    No byte swapping will be performed.
    r   r~   r-   r-   r.   convert_OVvalue  r   r   	encodingsc                    sb    pt g dtdtf fdd}| d}t| t}|d}t|dkr,||d S t||S )	af  Return a decoded 'PN' value.

    Parameters
    ----------
    byte_string : bytes
        The encoded 'PN' element value.
    encodings : list of str, optional
        A list of the character encoding schemes used to encode the 'PN' value.

    Returns
    -------
    valuerep.PersonName or MultiValue of PersonName
        The decoded 'PN' value(s).
    rC   r%   c                    s   t |  }|  | S rI   )r!   encoder@   )rC   person_namer   r-   r.   get_valtype  s   
zconvert_PN.<locals>.get_valtypes     r&   r'   r   )	r   r(   r!   r)   r   r   r*   r+   r   )r0   r   r   stripped_stringdecoded_valuevalue_splitr-   r   r.   
convert_PN  s   



r   c                 C   s   t | tS )a  Return a decoded string VR value.

    String VRs are 'AE', AS', 'CS' and optionally (depending on
    :ref:`pydicom.config <api_config>`) 'DA', 'DT', and 'TM'.

    Parameters
    ----------
    byte_string : bytes
        The encoded text VR element value.
    is_little_endian : bool
        ``True`` if the value is encoded as little endian, ``False`` otherwise.
    struct_format : str, optional
        Not used.

    Returns
    -------
    str or MultiValue of str
        The decoded value(s).
    )r/   r@   r   r~   r-   r-   r.   rM        rM   vrc                    sf   dt dt ffdd |ptg}t| |t}|d} fdd|D }t|dkr.|d	 S tt |S )
a  Return a decoded text VR value.

    Text VRs are 'SH', 'LO' and 'UC'.

    Parameters
    ----------
    byte_string : bytes
        The encoded text VR element value.
    encodings : list of str, optional
        A list of the character encoding schemes used to encode the value.
    vr : str
        The value representation of the element. Needed for validation.

    Returns
    -------
    str or list of str
        The decoded value(s).
    vr%   c                    s"    d urt  | tjj | dS )N  )r    r   settingsreading_validation_moder)   )r   )r   r-   r.   handle_value%  s   
z"convert_text.<locals>.handle_valuer&   c                    s   g | ]} |qS r-   r-   )r<   r8   )r   r-   r.   r>   -  r?   z convert_text.<locals>.<listcomp>r'   r   )r(   r   r   r   r*   r+   r   )r0   r   r   decoded_stringrA   
as_stringsr-   )r   r   r.   convert_text  s   


r   c                 C   s8   |pt g}t| |t}|durt||tjj |dS )a  Return decoded text, ignoring backslashes and trailing spaces.

    Parameters
    ----------
    byte_string : bytes
        The encoded string.
    encodings : list of str, optional
        A list of the character encoding schemes used to encode the text.
    vr : str
        The value representation of the element. Needed for validation.

    Returns
    -------
    str
        The decoded text.
    Nr   )r   r   r   r    r   r   r   r)   )r0   r   r   r8   r-   r-   r.   convert_single_string3  s
   

r   is_implicit_VRencodingc                 C   s,   |pt g}t| }t|||t| ||}|S )a  Return a decoded 'SQ' value.

    Parameters
    ----------
    byte_string : bytes
        The encoded 'SQ' element value.
    is_implicit_VR : bool
        ``True`` if the value is encoded as implicit VR, ``False`` otherwise.
    is_little_endian : bool
        ``True`` if the value is encoded as little endian, ``False`` otherwise.
    encoding : list of str, optional
        The character encoding scheme(s) used to encoded any text VR elements
        within the sequence value. ``'iso8859'`` is used by default.
    offset : int, optional
        The byte offset in `byte_string` to the start of the sequence value.

    Returns
    -------
    sequence.Sequence
        The decoded sequence.
    )r   r   r   r+   )r0   r   r1   r   r2   r   fpseqr-   r-   r.   
convert_SQO  s   
r   c                 C   s@   |   } t| }|dk s|dkr|dkrtd|  t| S )N      r   z-Expected length between 2 and 16, got length )r)   r+   r   rE   r   rj   r-   r-   r.   _TM_from_strs  s
   r   c                 C   sB   t jr| td}t|dkrt|d S tt|S t| |S )aX  Return a decoded 'TM' value.

    Parameters
    ----------
    byte_string : bytes
        The encoded 'TM' element value.
    is_little_endian : bool
        ``True`` if the value is encoded as little endian, ``False`` otherwise.
    struct_format : str, optional
        Not used.

    Returns
    -------
    str or list of str or valuerep.TM or list of valuerep.TM
        If
        :attr:`~pydicom.config.datetime_conversion` is ``True`` then returns
        either :class:`~pydicom.valuerep.TM` or a :class:`list` of ``TM``,
        otherwise returns :class:`str` or ``list`` of ``str``.
    r&   r'   r   )	r   rL   r@   r   r*   r+   r   r   rM   rN   r-   r-   r.   convert_TM_string|  s   

r   c                 C   s   |  t}t|dtjjS )a  Return a decoded 'UI' value.

    Elements with VR of 'UI' may have a non-significant trailing null ``0x00``.

    Parameters
    ----------
    byte_string : bytes
        The encoded 'UI' element value.
    is_little_endian : bool
        ``True`` if the value is encoded as little endian, ``False`` otherwise.
    struct_format : str, optional
        Not used.

    Returns
    -------
    uid.UID or list of uid.UID
        The decoded 'UI' element value without trailing nulls or spaces.
    r   )r@   r   r/   r)   rb   uidUID)r0   r1   r:   r8   r-   r-   r.   
convert_UI  s   
r   c                 C   r}   )z0Return the encoded 'UN' value as :class:`bytes`.r-   r~   r-   r-   r.   
convert_UN  r   r   c                 C   s   |  t S )a  Return a decoded 'UR' value.

    Elements with VR of 'UR' may not be multi-valued and trailing spaces are
    non-significant.

    Parameters
    ----------
    byte_string : bytes
        The encoded 'UR' element value.
    is_little_endian : bool
        ``True`` if the value is encoded as little endian, ``False`` otherwise.
    struct_format : str, optional
        Not used.

    Returns
    -------
    bytes or str
        The encoded 'UR' element value without any trailing spaces.
    )r@   r   r)   r~   r-   r-   r.   convert_UR_string  r   r   r   raw_data_elementc           
   	      s   t vr4ttddttdd }t d |vs"t d |vr,ddd	  D  td
  d|jdkr=t S tt	  t
t   trSttt   \}}nt   }d}|p]tg}t
|trf|g}|j}|j}|j}z, t	jkr{|||W S  tv r||| W S  t	jkr||||W S ||||||jW S  ty   tjjtjkr Y nw td|j d  d  fdd	tD D ]}	z	t|	||W   S  ty   Y qw td|j d |jS )a  Return the element value decoded using the appropriate decoder.

    Parameters
    ----------
    VR : str
        The element's VR.
    raw_data_element : pydicom.dataelem.RawDataElement
        The encoded element value.
    encodings : list of str, optional
        A list of the character encoding schemes used to encode any text
        elements.

    Returns
    -------
    type or MultiValue of type
        The element value decoded using the appropriate decoder.
    A   [   a   {   r   r'    c                 S   s   g | ]
}d t |dqS )0x02x)ord)r<   chr-   r-   r.   r>     s    z!convert_value.<locals>.<listcomp>zUnknown Value Representation ''NzUnable to convert tag z	 with VR z# using the standard value converterc                    s   g | ]}| kr|qS r-   r-   )r<   r#   r   r-   r.   r>   (  s    z Could not convert value for tag z1 with any VR in the 'convert_retry_VR_order' list) 
convertersrx   rF   r   joinNotImplementedErrorrG   r   r   VR_
isinstancer5   r   r(   r8   r1   r   PNr   SQ
value_tellr4   r   r   r   RAISEr   debugtagconvert_retry_VR_orderconvert_value	Exception)
r   r   r   
char_range	converter
num_formatr0   r1   r   r   r-   r   r.   r     sd    





r   dflhqLHQrI   )r   )NN)Nr   ){__doc__r\   ior   structr   r   typingr   r   r   r   collections.abcr	   r
   rb   r   pydicom.charsetr   r   pydicom.configr   r   pydicom.dataelemr   r   pydicom.errorsr   pydicom.filereaderr   pydicom.multivalr   pydicom.sequencer   pydicom.tagr   r   r   pydicom.uidpydicom.valuerepr   r   r   r   r   r   r   r   r    r`   r!   r"   r(   r/   ru   boolr6   r9   rB   rH   rJ   rP   rc   rd   rh   rk   rl   rr   floatr|   r   r   r   rx   r   rM   r   r   r   r   r   r   r   r   r   r   r   SHULSLUSSSFLFDOFOBUIr   DSLTr   UNATOWUTr   AEASCSLOODOLOVSTSVUCURUVOB_OWUS_SSUS_OWUS_SS_OWr   r-   r-   r-   r.   <module>   s  (





&
!

G

!
;
=





$




&

 

$

!




`

	





 !
"#
