o
    Eb                     @   s  d 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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mZmZmZ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%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z- dd	l.m/Z/ d
d Z0dd Z1dd Z2dd Z3G dd deZ4dd Z5G dd dZ6dd Z7ee d d Z8ee d d Z9ee d d Z:ee d d Z;G dd  d Z<G d!d" d"Z=dS )#z Classes for read / write of matlab (TM) 5 files

The matfile specification last found here:

https://www.mathworks.com/access/helpdesk/help/pdf_doc/matlab/matfile_format.pdf

(as of December 5 2008)
    N)BytesIO   )native_codeswapped_code)	MatFileReader	docfillermatdims
read_dtypearr_to_charsarr_dtype_numberMatWriteErrorMatReadErrorMatReadWarning)
VarReader5)MatlabObjectMatlabFunctionMDTYPESNP_TO_MTYPESNP_TO_MXTYPESmiCOMPRESSEDmiMATRIXmiINT8miUTF8miUINT32mxCELL_CLASSmxSTRUCT_CLASSmxOBJECT_CLASSmxCHAR_CLASSmxSPARSE_CLASSmxDOUBLE_CLASSmclass_info
mat_struct)ZlibInputStreamc                 C   s$   t | tjo| jdkot | d tS )zBDetermine if elem is an array and if first array item is a struct.r   )
isinstancenpndarraysizer!   )elem r(   7/usr/lib/python3/dist-packages/scipy/io/matlab/_mio5.py_has_structj   s   r*   c                 C   sN   g }| D ] }t |tr|t| qt|r|t| q|| q|S )zyConstruct lists from cell arrays (loaded as numpy ndarrays), recursing
    into items if they contain mat_struct objects.)r#   r!   append_matstruct_to_dictr*   _inspect_cell_array)r%   Z	elem_listZsub_elemr(   r(   r)   r-   p   s   
r-   c                 C   sT   i }| j D ]"}| j| }t|trt|||< qt|r#t|||< q|||< q|S )z/Construct nested dicts from mat_struct objects.)Z_fieldnames__dict__r#   r!   r,   r*   r-   )Zmatobjdfr'   r(   r(   r)   r,   ~   s   



r,   c                 C   sJ   | D ] }t | | trt| | | |< qt| | r"t| | | |< q| S )z,Convert mat objects in dict to nested dicts.)r#   r!   r,   r*   r-   )r/   keyr(   r(   r)   _simplify_cells   s   r2   c                       st   e Zd ZdZe									d fdd	Zdd Zd	d
 Zdd Zdd Z	dddZ
dddZdd Z  ZS )MatFile5Readera   Reader for Mat 5 mat files
    Adds the following attribute to base class

    uint16_codec - char codec to use for uint16 char arrays
        (defaults to system default codec)

    Uses variable reader that has the following stardard interface (see
    abstract class in ``miobase``::

       __init__(self, file_reader)
       read_header(self)
       array_from_header(self)

    and added interface::

       set_stream(self, stream)
       read_full_tag(self)

    NFTc                    s>   t  |||||||||
	 |	st }	|	| _d| _d| _dS )zInitializer for matlab 5 file format reader

    %(matstream_arg)s
    %(load_args)s
    %(struct_arg)s
    uint16_codec : {None, string}
        Set codec to use for uint16 char arrays (e.g., 'utf-8').
        Use system default codec if None
        N)super__init__sysgetdefaultencodinguint16_codec_file_reader_matrix_reader)self
mat_stream
byte_orderZ	mat_dtypeZ
squeeze_meZchars_as_stringsZmatlab_compatibleZstruct_as_record verify_compressed_data_integrityr8   simplify_cells	__class__r(   r)   r5      s    
zMatFile5Reader.__init__c                 C   s4   | j d | j d}| j d |dkrdpdS )z4 Guess byte order.
        Sets stream pointer to 0 ~      r   s   IM<>)r<   seekread)r;   mir(   r(   r)   guess_byte_order   s   zMatFile5Reader.guess_byte_orderc                 C   sd   i }t | j d d }t| j|}|d  d|d< |d d? }|d d@ }d	||f |d
< |S )z Read in mat 5 file header dtypesfile_headerdescriptions    	
 Z
__header__version      z%d.%d__version__)r   r=   r	   r<   itemstrip)r;   ZhdictZ	hdr_dtypehdrZv_majorZv_minorr(   r(   r)   read_file_header   s   zMatFile5Reader.read_file_headerc                 C   s   t | | _t | | _dS )za Run when beginning read of variables

        Sets up readers from parameters in `self`
        N)r   r9   r:   r;   r(   r(   r)   initialize_read   s   
zMatFile5Reader.initialize_readc                 C   s   | j  \}}|dkstd| j | }|tkr1t| j|}| j| | j	}| j \}}n	d}| j| j |t
ksDtd| | j|}||fS )a   Read header, return header, next position

        Header has to define at least .name and .is_global

        Parameters
        ----------
        None

        Returns
        -------
        header : object
           object that can be passed to self.read_var_array, and that
           has attributes .name and .is_global
        next_position : int
           position in stream of next variable
        r   zDid not read any bytesFz$Expecting miMATRIX type here, got %d)r9   Zread_full_tag
ValueErrorr<   tellr   r"   r:   Z
set_streamr>   r   	TypeErrorZread_header)r;   mdtype
byte_countZnext_posstreamZcheck_stream_limitheaderr(   r(   r)   read_var_header   s   zMatFile5Reader.read_var_headerc                 C   s   | j ||S )a   Read array, given `header`

        Parameters
        ----------
        header : header object
           object with fields defining variable header
        process : {True, False} bool, optional
           If True, apply recursive post-processing during loading of
           array.

        Returns
        -------
        arr : array
           array with post-processing applied or not according to
           `process`.
        )r:   Zarray_from_header)r;   r]   processr(   r(   r)   read_var_array  s   zMatFile5Reader.read_var_arrayc           	   
   C   s|  t |tr	|g}n|durt|}| jd |   |  }g |d< |  s|  \}}|j	du r4dn|j	
d}||v rHtjd| tdd |d	krQd
}d}nd}|durb||vrb| j| q#z| ||}W n" ty } ztjd||f tdd d| }W Y d}~nd}~ww | j| |||< |jr|d | |dur|| t|dkrn|  r'| jrt|S |S )z get variables from stream as dictionary

        variable_names   - optional list of variable names to get

        If variable_names is None, then get all variables in file
        Nr   __globals__Nonelatin1zDuplicate variable name "%s" in stream - replacing previous with new
Consider mio5.varmats_from_mat to split file into single variable filesrC   )
stacklevel __function_workspace__FTz&Unreadable variable "%s", because "%s"zRead error: %s)r#   strlistr<   rF   rV   rT   end_of_streamr^   namedecodewarningswarnr   r`   r   Warning	is_globalr+   removelenr?   r2   )	r;   Zvariable_namesmdictrS   next_positionrj   r_   reserrr(   r(   r)   get_variables&  s`   

$zMatFile5Reader.get_variablesc                 C   s   | j d |   |   g }|  sR|  \}}|jdu r!dn|jd}|dkr-d}| j	|}|j
r9d}nt|jd}||||f | j | |  r|S )	z list variables from stream r   Nrb   rc   re   rf   Zlogicalunknown)r<   rF   rV   rT   ri   r^   rj   rk   r:   Zshape_from_header
is_logicalr    getmclassr+   )r;   varsrS   rs   rj   shapeinfor(   r(   r)   list_variables`  s"   zMatFile5Reader.list_variables)	NFFTFTTNF)TN)__name__
__module____qualname____doc__r   r5   rI   rT   rV   r^   r`   rv   r~   __classcell__r(   r(   r@   r)   r3      s(    &
#
:r3   c                 C   s   t | }| d tt d d j}| |}| d |  |  |  }g }|	 sn|}|
 \}}|jdu r=dn|jd}| | || }	| |	}
t }|| ||
 |d |||f |	 r.|S )a   Pull variables out of mat 5 file as a sequence of mat file objects

    This can be useful with a difficult mat file, containing unreadable
    variables. This routine pulls the variables out in raw form and puts them,
    unread, back into a file stream for saving or reading. Another use is the
    pathological case where there is more than one variable of the same name in
    the file; this routine returns the duplicates, whereas the standard reader
    will overwrite duplicates in the returned dictionary.

    The file pointer in `file_obj` will be undefined. File pointers for the
    returned file-like objects are set at 0.

    Parameters
    ----------
    file_obj : file-like
        file object containing mat file

    Returns
    -------
    named_mats : list
        list contains tuples of (name, BytesIO) where BytesIO is a file-like
        object containing mat file contents as for a single variable. The
        BytesIO contains a string with the original header and a single var. If
        ``var_file_obj`` is an individual BytesIO instance, then save as a mat
        file with something like ``open('test.mat',
        'wb').write(var_file_obj.read())``

    Examples
    --------
    >>> import scipy.io

    BytesIO is from the ``io`` module in Python 3, and is ``cStringIO`` for
    Python < 3.

    >>> mat_fileobj = BytesIO()
    >>> scipy.io.savemat(mat_fileobj, {'b': np.arange(10), 'a': 'a string'})
    >>> varmats = varmats_from_mat(mat_fileobj)
    >>> sorted([name for name, str_obj in varmats])
    ['a', 'b']
    r   rJ   rK   Nrb   rc   )r3   rF   r   r   itemsizerG   rV   rT   rX   ri   r^   rj   rk   r   writer+   )Zfile_objZrdrZhdr_lenZraw_hdrrs   Z
named_matsZstart_positionrS   rj   r[   Zvar_strZout_objr(   r(   r)   varmats_from_maty  s.   )







r   c                   @   s   e Zd ZdZdS )EmptyStructMarkerz= Class to indicate presence of empty matlab struct on output N)r   r   r   r   r(   r(   r(   r)   r     s    r   c                 C   s  t | tjr| S | du rdS t| dot| dot| d}t | tjr$n|s9t| dr9tdd | j D } d}|rng }g }|  D ]\}}t |tr`|d	 d
vr`|	t|t
f |	| qC|rltt|g|S tS t| }|jjt
tjfv r|jdkr|| krdS |S )a   Convert input object ``source`` to something we can write

    Parameters
    ----------
    source : object

    Returns
    -------
    arr : None or ndarray or EmptyStructMarker
        If `source` cannot be converted to something we can write to a matfile,
        return None.  If `source` is equivalent to an empty dictionary, return
        ``EmptyStructMarker``.  Otherwise return `source` converted to an
        ndarray with contents for writing to matfile.
    Nkeysvaluesitemsr.   c                 s   s&    | ]\}}| d s||fV  qdS )_N)
startswith).0r1   valuer(   r(   r)   	<genexpr>  s   
 zto_writeable.<locals>.<genexpr>Tr   Z_0123456789r(   )r#   r$   r%   hasattrZgenericdictr.   r   rg   r+   objectarraytupler   Z
asanyarraydtypetypeZobject_r|   )sourceZ
is_mappingr   r   Zfieldr   narrr(   r(   r)   to_writeable  sB   



r   rJ   rK   Ztag_fullZtag_smalldataZarray_flagsc                   @   s   e Zd ZdZedeZeed< dd Z	dd Z
dd	 Zd,ddZdd Zdd Z			d-ddZdd Zdd Zdd Zdd Zd.ddZd d! Zd"d# Zd$d% Zd&d' Zd(d) Zd*d+ Zd
S )/
VarWriter5z% Generic matlab matrix writing class r(   rZ   c                 C   s0   |j | _ |j| _|j| _|j| _d | _d| _d S )NF)file_streamunicode_stringslong_field_namesoned_as	_var_name_var_is_global)r;   Zfile_writerr(   r(   r)   r5     s   
zVarWriter5.__init__c                 C   s   | j |jdd d S )NFZorder)r   r   tobytesr;   arrr(   r(   r)   write_bytes
  s   zVarWriter5.write_bytesc                 C   s   | j | d S r   )r   r   )r;   sr(   r(   r)   write_string  s   zVarWriter5.write_stringNc                 C   sl   |du rt |jjdd  }|jjtkr|  }|j|j }|dkr-| 	||| dS | 
||| dS )z write tag and data Nr      )r   r   rg   	byteorderr   ZbyteswapZnewbyteorderr&   r   write_smalldata_elementwrite_regular_element)r;   r   rZ   r[   r(   r(   r)   write_element  s   zVarWriter5.write_elementc                 C   s:   t dt}|d> | |d< |jdd|d< | | d S )Nr(      Zbyte_count_mdtyper   r   data)r$   zerosNDT_TAG_SMALLr   r   )r;   r   rZ   r[   tagr(   r(   r)   r     s   z"VarWriter5.write_smalldata_elementc                 C   sX   t dt}||d< ||d< | | | | |d }|r*| jdd|   d S d S )Nr(   rZ   r[   rN       )r$   r   NDT_TAG_FULLr   r   r   )r;   r   rZ   r[   r   Zbc_mod_8r(   r(   r)   r   %  s   

z VarWriter5.write_regular_elementFr   c           
      C   s   | j }| j}| j | _| | j tdt	}t
|d< d|d< |d> |d> B |d> B }	||	d> B |d< ||d	< | | | tj|d
d t|}|dkrX| |td n| |t d| _ d| _dS )a   Write header for given data options
        shape : sequence
           array shape
        mclass      - mat5 matrix class
        is_complex  - True if matrix is complex
        is_logical  - True if matrix is logical
        nzmax        - max non zero elements for sparse arrays

        We get the name and the global flag from the object, and reset
        them to defaults after we've used them
        r(   Z	data_typerN   r[      rC   r   Zflags_classnzmaxi4r   re   r   FN)r   r   r   rX   Z_mat_tag_posr   mat_tagr$   r   NDT_ARRAY_FLAGSr   r   r   Zasarrayr   r   )
r;   r|   rz   
is_complexrx   r   rj   ro   afflagsr(   r(   r)   write_header1  s$   


zVarWriter5.write_headerc                 C   sX   | j  }| j | || d }|dkrtd|| jd< | | j | j | d S )NrN   l        z-Matrix too large to save with Matlab 5 formatr[   )r   rX   rF   r   r   r   )r;   Z	start_posZcurr_posr[   r(   r(   r)   update_matrix_tag\  s   

zVarWriter5.update_matrix_tagc                 C   s   || _ || _| | dS )a   Write variable at top level of mat file

        Parameters
        ----------
        arr : array_like
            array-like object to create writer for
        name : str, optional
            name as it will appear in matlab workspace
            default is empty string
        is_global : {False, True}, optional
            whether variable will be global on load into matlab
        N)r   r   r   )r;   r   rj   ro   r(   r(   r)   	write_topg  s   zVarWriter5.write_topc                 C   s   | j  }tj|r| | | | dS t|}|du r)td|t	|f t
|tr4| | n@t
|tr=td|tu rF|   n.|jjrP| | n$|jjrZ| | n|jjdv ro| jrfd}nd}| || n| | | | dS )z Write `arr` to stream at top and sub levels

        Parameters
        ----------
        arr : array_like
            array-like object to create writer for
        Nz'Could not convert %s (type %s) to arrayzCannot write matlab functions)USZUTF8ascii)r   rX   scipyZsparseZissparsewrite_sparser   r   rY   r   r#   r   write_objectr   r   r   write_empty_structr   Zfieldswrite_structZ	hasobjectwrite_cellskindr   
write_charwrite_numeric)r;   r   Zmat_tag_posr   codecr(   r(   r)   r   {  s6   
	






zVarWriter5.writec                 C   s   |j jdk}|j jdk}zt|j jdd   }W n  ty8   |r'|d}n|r/|d}n|d}t}Y nw | jt|| j	|||d |rV| 
|j | 
|j d S | 
| d S )Ncbr   Zc128Zi1Zf8)r   rx   )r   r   r   rg   KeyErrorastyper   r   r   r   r   realimag)r;   r   ZimagfZlogifrz   r(   r(   r)   r     s*   

zVarWriter5.write_numericr   c                 C   s   |j dkst|dkr%dt|jdg }| |t | |td dS t	|}|j
}| |t |jjdkr`|j r`t|}tjdt|||j d}| |}tjt|fd	|d}| j|td
 dS )z5 Write string array `arr` with given `codec`
        r   re   r   rC   Nr   r(   r|   r   bufferZS1rZ   )r&   r$   allmaxndimr   r   r   r   r
   r|   r   r   Zprodr%   r   TcopyrQ   encoderq   r   )r;   r   r   r|   Zn_charsZst_arrstr(   r(   r)   r     s(   

zVarWriter5.write_charc                 C   s   |  }|  |jjdk}|jjdk}|j}| jt|| jt|||dkr'dn|d | 	|j
d | 	|jd | 	|jj |rO| 	|jj dS dS )z  Sparse matrices are 2D
        r   r   r   r   )r   rx   r   r   N)ZtocscZsort_indicesr   r   Znnzr   r   r   r   r   indicesr   Zindptrr   r   r   )r;   r   Ar   rx   Znzr(   r(   r)   r     s"   zVarWriter5.write_sparsec                 C   s<   |  t|| jt t|d}|D ]}| | qd S )Nr   )r   r   r   r   r$   
atleast_2dflattenr   )r;   r   r   elr(   r(   r)   r     s   zVarWriter5.write_cellsc                 C   s<   |  dt | tjdtjd | tjg tjd d S )N)r   r   r   r   )r   r   r   r$   r   Zint32Zint8rU   r(   r(   r)   r     s   zVarWriter5.write_empty_structc                 C   s"   |  t|| jt | | d S r   )r   r   r   r   _write_itemsr   r(   r(   r)   r   
  s   zVarWriter5.write_structc                 C   s   dd |j jD }tdd |D d }| jrdpd}||kr'td|d  | tj|gdd	 | jtj|d
| d	td t	|
d}|D ]}|D ]	}| ||  qNqJd S )Nc                 S   s   g | ]}|d  qS r   r(   )r   r0   r(   r(   r)   
<listcomp>      z+VarWriter5._write_items.<locals>.<listcomp>c                 S   s   g | ]}t |qS r(   )rq   )r   Z	fieldnamer(   r(   r)   r     r   r   @       z+Field names are restricted to %d charactersr   r   zS%dr   r   )r   Zdescrr   r   rW   r   r$   r   r   r   r   r   )r;   r   Z
fieldnameslengthZ
max_lengthr   r   r0   r(   r(   r)   r     s$   zVarWriter5._write_itemsc                 C   s<   |  t|| jt | jtj|jddtd | 	| dS )zmSame as writing structs, except different mx class, and extra
        classname element after header
        r   r   r   N)
r   r   r   r   r   r$   r   Z	classnamer   r   r   r(   r(   r)   r      s   zVarWriter5.write_objectr   )FFr   )r   )r   r   r   r   r$   r   r   r   r   r5   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r(   r(   r(   r)   r     s2    	

+(
+r   c                   @   s:   e Zd ZdZe					dddZdd Zdd	d
ZdS )MatFile5Writerz Class for writing mat5 files FNrowc                 C   s:   || _ || _|| _|r|| _ng | _|| _|| _d| _dS )a<   Initialize writer for matlab 5 format files

        Parameters
        ----------
        %(do_compression)s
        %(unicode_strings)s
        global_vars : None or sequence of strings, optional
            Names of variables to be marked as global for matlab
        %(long_fields)s
        %(oned_as)s
        N)r   do_compressionr   global_varsr   r   _matrix_writer)r;   r   r   r   r   r   r   r(   r(   r)   r5   .  s   
zMatFile5Writer.__init__c                 C   sX   t dt}dtjt f |d< d|d< t jddt dd|d	< | j	
|  d S )
Nr(   z0MATLAB 5.0 MAT-file Platform: %s, Created on: %srL      rM   ZS2iIM  r   Zendian_test)r$   r   NDT_FILE_HDRosrj   timeasctimer%   Zuint16r   r   r   )r;   rS   r(   r(   r)   write_file_headerK  s   
z MatFile5Writer.write_file_headerc           	      C   s   |du r| j  dk}|r|   t| | _| D ]V\}}|d dkr%q|| jv }| jret }|| j_ | j	||
d| t| }tdt}t|d< t||d< | j |  | j | q| j	||
d| qdS )a   Write variables in `mdict` to stream

        Parameters
        ----------
        mdict : mapping
           mapping with method ``items`` returns name, contents pairs where
           ``name`` which will appear in the matlab workspace in file load, and
           ``contents`` is something writeable to a matlab file, such as a NumPy
           array.
        write_header : {None, True, False}, optional
           If True, then write the matlab file header before writing the
           variables. If None (the default) then write the file header
           if we are at position 0 in the stream. By setting False
           here, and setting the stream position to the end of the file,
           you can append variables to a matlab file
        Nr   r   rc   r(   rZ   r[   )r   rX   r   r   r   r   r   r   r   r   r   zlibcompressgetvaluer$   emptyr   r   rq   r   r   )	r;   rr   r   rj   varro   r\   Zout_strr   r(   r(   r)   put_variablesV  s*   

zMatFile5Writer.put_variables)FFNFr   r   )r   r   r   r   r   r5   r   r   r(   r(   r(   r)   r   +  s    r   )>r   r   r   r6   r   ior   rl   Znumpyr$   Zscipy.sparser   Z_byteordercodesr   r   Z_miobaser   r   r   r	   r
   r   r   r   r   Z_mio5_utilsr   Z_mio5_paramsr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r!   Z_streamsr"   r*   r-   r,   r2   r3   r   r   r   r   r   r   r   r   r   r(   r(   r(   r)   <module>   s@    A,P
 dE4  1