o
    6[_                    @   s  d Z ddlmZ dZdZdZg 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ZddlZeeur4eZzeZW n   eZY e

djd	krJdZne

d
jd	krUd
Zne

djd	kr`dZnedze W n eys   eZY nw dZejd dk rdZndZejd fddZedZ dd Z!dZ"dZ#dZ$dZ%dZ&dZ'dZ(dZ)dZ*dZ+dZ,dZ-d	Z.dZ/dZ0dZ1dZ2dZ3dZ4d	Z5dZ6dZ7d Z8d!Z9d"Z:d#Z;d$Z<d%Z=d&Z>d'Z?d(Z@d)ZAd*ZBd+ZCd,ZDd-ZEd.ZFd/ZGd0ZHd1ZId2ZJd3ZKd4ZLd5ZMd6ZNd7ZOd8ZPd9ZQd:ZRd;ZSd<ZTd=ZUd>ZVd?ZWd@ZXdAZYdBZZd#Z[d,Z\d6Z]dCZ^dDZ_dEdF Z`eeu rdGdH ZandIdH Zad]dJdKZbd]dLdMZcdNdO ZddPdQ ZeG dRdS dSZfG dTdU dUejgZhG dVdW dWZiG dXdY dYZjdZd[ Zkeld\kr_ek  dS dS )^a:  
olefile (formerly OleFileIO_PL)

Module to read/write Microsoft OLE2 files (also called Structured Storage or
Microsoft Compound Document File Format), such as Microsoft Office 97-2003
documents, Image Composer and FlashPix files, Outlook messages, ...
This version is compatible with Python 2.7 and 3.4+

Project website: https://www.decalage.info/olefile

olefile is copyright (c) 2005-2018 Philippe Lagadec
(https://www.decalage.info)

olefile is based on the OleFileIO module from the PIL library v1.1.7
See: http://www.pythonware.com/products/pil/index.htm
and http://svn.effbot.org/public/tags/pil-1.1.7/PIL/OleFileIO.py

The Python Imaging Library (PIL) is
Copyright (c) 1997-2009 by Secret Labs AB
Copyright (c) 1995-2009 by Fredrik Lundh

See source code and LICENSE.txt for information on usage and redistribution.
    )print_functionz
2018-09-09z0.46zPhilippe Lagadec)	isOleFile	OleFileIOOleMetadataenable_loggingMAGICSTGTY_EMPTYKEEP_UNICODE_NAMESSTGTY_STREAMSTGTY_STORAGE
STGTY_ROOTSTGTY_PROPERTYSTGTY_LOCKBYTESMINIMAL_OLEFILE_SIZEDEFECT_UNSUREDEFECT_POTENTIALDEFECT_INCORRECTDEFECT_FATALDEFAULT_PATH_ENCODING
MAXREGSECTDIFSECTFATSECT
ENDOFCHAINFREESECT	MAXREGSIDNOSTREAMUNKNOWN_SIZE
WORD_CLSIDNL   Iiz>Need to fix a bug with 32 bit arrays, please contact author...T   zutf-8   c                 C   sL   | t jjjv rt | }|| |S t | }|t   || |S )an  
    Create a suitable logger object for this module.
    The goal is not to change settings of the root logger, to avoid getting
    other modules' logs on the screen.
    If a logger exists with same name, reuse it. (Else it would have duplicate
    handlers and messages would be doubled.)
    The level is set to CRITICAL+1 by default, to avoid any logging.
    )loggingZLoggermanagerZ
loggerDictZ	getLoggersetLevelZ
addHandlerZNullHandler)namelevellogger r*   1/usr/lib/python3/dist-packages/olefile/olefile.py
get_logger   s   



r,   olefilec                   C   s   t tj dS )z
    Enable logging for this module (disabled by default).
    This will set the module-specific logger level to NOTSET, which
    means the main application controls the actual logging level.
    N)logr&   r$   ZNOTSETr*   r*   r*   r+   r      s   r   s   ࡱl    l    l    l              i         	   
                                                               @   A   B   C   D   E   F   G   H      z$00020900-0000-0000-C000-000000000046(   i   c                 C   s   t | dr| tt}| d n0t| tr&t| tkr&| dtt }nt| d}|tt}W d   n1 s=w   Y  |tkrHdS dS )aJ  
    Test if a file is an OLE container (according to the magic bytes in its header).

    .. note::
        This function only checks the first 8 bytes of the file, not the
        rest of the OLE structure.

    .. versionadded:: 0.16

    :param filename: filename, contents or file-like object of the OLE file (string-like or file-like object)

        - if filename is a string smaller than 1536 bytes, it is the path
          of the file to open. (bytes or unicode string)
        - if filename is a string longer than 1535 bytes, it is parsed
          as the content of an OLE file in memory. (bytes type only)
        - if filename is a file-like object (with read and seek methods),
          it is parsed as-is.

    :type filename: bytes or str or unicode or file
    :returns: True if OLE, False otherwise.
    :rtype: bool
    readr   NrbTF)	hasattrrV   lenr   seek
isinstancebytesr   open)filenameheaderfpr*   r*   r+   r     s   
r   c                 C   s   t | S N)ordcr*   r*   r+   i8?  s   re   c                 C   s   | j tu r| S | d S Nr   )	__class__intrc   r*   r*   r+   re   C  s   c                 C      t d| ||d  d S )z
    Converts a 2-bytes (16 bits) string to an integer.

    :param c: string containing bytes to convert
    :param o: offset of bytes to convert in string
    z<Hr0   r   structunpackrd   or*   r*   r+   i16G     ro   c                 C   ri   )z
    Converts a 4-bytes (32 bits) string to an integer.

    :param c: string containing bytes to convert
    :param o: offset of bytes to convert in string
    z<Ir   r   rj   rm   r*   r*   r+   i32Q  rp   rq   c                 C   sT   t | dksJ | dsdS dt| dt| dt| dfttt| dd   S )	z^
    Converts a CLSID to a human-readable string.

    :param clsid: string of length 16.
    r;        z0%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02Xr   r   r2   r4   )rY   striprq   ro   tuplemapre   )clsidr*   r*   r+   _clsid[  s   
rx   c                 C   s(   t  dddddd}|t j| d d S )zL
        convert FILETIME (64 bits int) to Python datetime.datetime
        A  r#   r   r6   Zmicroseconds)datetime	timedelta)Zfiletime_FILETIME_null_dater*   r*   r+   filetime2datetimel  s   r~   c                   @   s8   e Zd ZdZg dZg dZdd Zdd Zdd	 Zd
S )r   aT  
    class to parse and store metadata from standard properties of OLE files.

    Available attributes:
    codepage, title, subject, author, keywords, comments, template,
    last_saved_by, revision_number, total_edit_time, last_printed, create_time,
    last_saved_time, num_pages, num_words, num_chars, thumbnail,
    creating_application, security, codepage_doc, category, presentation_target,
    bytes, lines, paragraphs, slides, notes, hidden_slides, mm_clips,
    scale_crop, heading_pairs, titles_of_parts, manager, company, links_dirty,
    chars_with_spaces, unused, shared_doc, link_base, hlinks, hlinks_changed,
    version, dig_sig, content_type, content_status, language, doc_version

    Note: an attribute is set to None when not present in the properties of the
    OLE file.

    References for SummaryInformation stream:

    - https://msdn.microsoft.com/en-us/library/dd942545.aspx
    - https://msdn.microsoft.com/en-us/library/dd925819%28v=office.12%29.aspx
    - https://msdn.microsoft.com/en-us/library/windows/desktop/aa380376%28v=vs.85%29.aspx
    - https://msdn.microsoft.com/en-us/library/aa372045.aspx
    - http://sedna-soft.de/articles/summary-information-stream/
    - https://poi.apache.org/apidocs/org/apache/poi/hpsf/SummaryInformation.html

    References for DocumentSummaryInformation stream:

    - https://msdn.microsoft.com/en-us/library/dd945671%28v=office.12%29.aspx
    - https://msdn.microsoft.com/en-us/library/windows/desktop/aa380374%28v=vs.85%29.aspx
    - https://poi.apache.org/apidocs/org/apache/poi/hpsf/DocumentSummaryInformation.html

    new in version 0.25
    )codepagetitlesubjectauthorkeywordscommentstemplatelast_saved_byrevision_numbertotal_edit_timelast_printedcreate_timelast_saved_time	num_pages	num_words	num_chars	thumbnailcreating_applicationsecurity)codepage_doccategorypresentation_targetr\   lines
paragraphsslidesnoteshidden_slidesmm_clips
scale_cropheading_pairstitles_of_partsr%   companylinks_dirtychars_with_spacesunused
shared_doc	link_basehlinkshlinks_changedversiondig_sigcontent_typecontent_statuslanguagedoc_versionc                 C   s  d| _ d| _d| _d| _d| _d| _d| _d| _d| _d| _	d| _
d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _ d| _!d| _"d| _#d| _$d| _%d| _&d| _'d| _(d| _)d| _*d| _+d| _,d| _-d| _.dS )z_
        Constructor for OleMetadata
        All attributes are set to None by default
        N)/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   r   r   r   r%   r   r   r   r   r   r   r   r   r   r   r   r   r   r   selfr*   r*   r+   __init__  s^   
zOleMetadata.__init__c                 C   s   | j | j D ]}t| |d q|dr8|jdddgd}tt| j D ]}||d d}t| | j | | q$|dr_|jddd}tt| jD ]}||d d}t| | j| | qKdS dS )	a=  
        Parse standard properties of an OLE file, from the streams
        ``\x05SummaryInformation`` and ``\x05DocumentSummaryInformation``,
        if present.
        Properties are converted to strings, integers or python datetime objects.
        If a property is not present, its value is set to None.
        NzSummaryInformationTr6   )convert_timeno_conversionr#   zDocumentSummaryInformationr   )SUMMARY_ATTRIBSDOCSUM_ATTRIBSsetattrexistsgetpropertiesrangerY   get)r   r-   Zattribpropsr!   valuer*   r*   r+   parse_properties  s$   	

zOleMetadata.parse_propertiesc                 C   sh   t d | jD ]}t| |}t d|t|f  qt d | jD ]}t| |}t d|t|f  q dS )z<
        Dump all metadata, for debugging purposes.
        z*Properties from SummaryInformation stream:- %s: %sz2Properties from DocumentSummaryInformation stream:N)printr   getattrreprr   )r   Zpropr   r*   r*   r+   dump  s   



zOleMetadata.dumpN)	__name__
__module____qualname____doc__r   r   r   r   r   r*   r*   r*   r+   r   z  s    $8 r   c                   @   s   e Zd ZdZdd ZdS )	OleStreama  
    OLE2 Stream

    Returns a read-only file object which can be used to read
    the contents of a OLE stream (instance of the BytesIO class).
    To open a stream, use the openstream method in the OleFile class.

    This function can be used with either ordinary streams,
    or ministreams, depending on the offset, sectorsize, and
    fat table arguments.

    Attributes:

        - size: actual size of data stream, after it was opened.
    c	                 C   s"  t d t d|||||t|t|f  || _| jjjr#tdd}	|tkr6t|| }d}	t d ||d  | }
t d|
  |
t|krR| j	t
d	 g }|d
krh|tkrht d | j	t
d t|
D ]}t d||f  |tkr|	rt d  nt d | j	t
d |d
k s|t|krt d||t|f  t d||
f  | j	t
d  nz||||   W n   t d||||  |f  | j	t
d Y  n_||}t||kr|t|d krt d|t||||  |t|f  t d|||  t|   | j	t
d || z|| d@ }W ql ty=   | j	t
d Y  nw d|}t||kr_t dt||f  |d| }|| _n)|	rqt dt|  t|| _nt dt||f  t|| _| j	t
d tj| | dS ) a_  
        Constructor for OleStream class.

        :param fp: file object, the OLE container or the MiniFAT stream
        :param sect: sector index of first sector in the stream
        :param size: total size of the stream
        :param offset: offset in bytes for the first FAT or MiniFAT sector
        :param sectorsize: size of one sector
        :param fat: array/list of sector indexes (FAT or MiniFAT)
        :param filesize: size of OLE file (for debugging)
        :param olefileio: OleFileIO object containing this stream
        :returns: a BytesIO instance containing the OLE stream
        zOleStream.__init__:zE  sect=%d (%X), size=%d, offset=%d, sectorsize=%d, len(fat)=%d, fp=%sz2Attempting to open a stream from a closed OLE FileFTz  stream with UNKNOWN SIZEr#   nb_sectors = %dz(malformed OLE document, stream too larger   z!size == 0 and sect != ENDOFCHAIN:z+incorrect OLE sector index for empty streamzReading stream sector[%d] = %Xhz6Reached ENDOFCHAIN sector for stream with unknown sizez$sect=ENDOFCHAIN before expected sizezincomplete OLE streamzsect=%d (%X) / len(fat)=%dzi=%d / nb_sectors=%d,incorrect OLE FAT, sector index out of rangezsect=%d, seek=%d, filesize=%dOLE sector index out of rangez9sect=%d / len(fat)=%d, seek=%d / filesize=%d, len read=%dzseek+len(read)=%dincomplete OLE sectorr/       z3Read data of length %d, truncated to stream size %dNz3Read data of length %d, the stream size was unknownz9Read data of length %d, less than expected stream size %dz%OLE stream size is less than declared)r.   debugrY   r   oler`   closedOSErrorr   _raise_defectr   r   r   rZ   rV   append
IndexErrorjoinsizeioBytesIOr   )r   r`   sectr   offset
sectorsizefatfilesize	olefileioZunknown_size
nb_sectorsdatar!   Zsector_datar*   r*   r+   r   *  s   






 


zOleStream.__init__N)r   r   r   r   r   r*   r*   r*   r+   r     s    r   c                   @   s   e Zd ZdZdZdZeeeksJ 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dZdd Zdd ZdS )OleDirectoryEntryz
    OLE2 Directory Entry
    z<64sHBBIII16sIQQIII   c                 C   s`  || _ || _g | _i | _d| _ttj|\| _	| _
| _| _| _| _| _}| _| _| _| _| _| _| jttttfvr@|td | jtkrO|dkrO|td |dkr^| jtkr^|td | j
dkrl|td d| _
| j	d| j
d	  | _|| j| _t d
| j t!| jf  t d| j  t d| j  t d| j| j| jf  |j"dkr| jdkr| jdkrt d|j"| j| j| jf  |t#d | j| _$n| jt%| jd>  | _$t d| j$| j| jf  t&|| _'| jtkr| j$dkr|t(d d| _)| jttfv r+| j$dkr+| j$|j*k r | jtkr d| _)nd| _)|+| j| j) d| _,dS )aI  
        Constructor for an OleDirectoryEntry object.
        Parses a 128-bytes entry from the OLE Directory stream.

        :param entry  : string (must be 128 bytes long)
        :param sid    : index of this directory entry in the OLE file directory
        :param olefile: OleFileIO containing this directory entry
        Fzunhandled OLE storage typer   zduplicate OLE root entryzincorrect OLE root entryrK   z(incorrect DirEntry name length >64 bytesNr0   zDirEntry SID=%d: %sz - type: %dz - sect: %Xhz% - SID left: %d, right: %d, child: %d   r/   z+sectorsize=%d, sizeLow=%d, sizeHigh=%d (%X)zincorrect OLE stream size    z% - size: %d (sizeLow=%d, sizeHigh=%d)zOLE storage with size>0T)-sidr-   kids	kids_dictusedrk   rl   r   STRUCT_DIRENTRYZname_rawZ
namelength
entry_typeZcolorsid_left	sid_right	sid_childZdwUserFlags
createTime
modifyTime
isectStartZsizeLowZsizeHighr   r   r
   r   r   r   Z
name_utf16_decode_utf16_strr'   r.   r   r   r   r   r   longrx   rw   r   
is_minifatminisectorcutoff_check_duplicate_stream
sect_chain)r   entryr   r-   rw   r*   r*   r+   r     sv   	





zOleDirectoryEntry.__init__c                 C   s   | j rd S | jttfvs| jdkrd S t | _ | jr!|js!|  | j	}|t
krB| j | | jr7|j| }n|j| }|t
ks(d S d S rf   )r   r   r   r
   r   listr   minifatloadminifatr   r   r   r   )r   r-   Z	next_sectr*   r*   r+   build_sect_chain-  s   
z"OleDirectoryEntry.build_sect_chainc                 C   sF   t d| jt| j| jf  | jtkr!| | j | j	  dS dS )z
        Read and build the red-black tree attached to this OleDirectoryEntry
        object, if it is a storage.
        Note that this method builds a tree of all subentries, so it should
        only be called for the root object once.
        z.build_storage_tree: SID=%d - %s - sid_child=%dN)
r.   r   r   r   r'   r   r   append_kidsr   sortr   r*   r*   r+   build_storage_tree@  s   
	z$OleDirectoryEntry.build_storage_treec                 C   s   t d|  |tkrdS |dk s|t| jjkr"| jtd dS | j|}t d|j	t
|j|j|j|jf  |jrG| jtd dS d|_| |j |j }|| jv ra| jtd | j| || j|< | |j |  dS )	a)  
        Walk through red-black tree of children of this directory entry to add
        all of them to the kids list. (recursive method)

        :param child_sid: index of child directory entry to use, or None when called
            first time for the root. (only used during recursion)
        zappend_kids: child_sid=%dNr   zOLE DirEntry index out of rangezHappend_kids: child_sid=%d - %s - sid_left=%d, sid_right=%d, sid_child=%dz#OLE Entry referenced more than onceTz!Duplicate filename in OLE storage)r.   r   r   rY   r-   
direntriesr   r   _load_direntryr   r   r'   r   r   r   r   r   lowerr   r   r   r   )r   Z	child_sidchildZ
name_lowerr*   r*   r+   r   X  s2   


zOleDirectoryEntry.append_kidsc                 C   s   | j |j kS zCompare entries by namer'   r   otherr*   r*   r+   __eq__     zOleDirectoryEntry.__eq__c                 C   s   | j |j k S r   r  r  r*   r*   r+   __lt__  r  zOleDirectoryEntry.__lt__c                 C   s   |  | S ra   )r  r  r*   r*   r+   __ne__     zOleDirectoryEntry.__ne__c                 C   s   |  |p	| |S ra   )r  r  r  r*   r*   r+   __le__  s   zOleDirectoryEntry.__le__r   c                 C   s   g d}z|| j  }W n ty   d}Y nw td| t| j |dd | j ttfv r4t| jddd t  | j ttfv rL| j	rLtd| d| j	   | j
D ]	}||d  qOdS )	zADump this entry, and all its subentries (for debug purposes only))z	(invalid)z	(storage)z(stream)z(lockbytes)z
(property)z(root)z	(UNKNOWN) endr\   z{%s}r0   N)r   r   r   r   r'   r
   r   r   r   rw   r   r   )r   tabZTYPES	type_namekidr*   r*   r+   r     s   
zOleDirectoryEntry.dumpc                 C      | j dkrdS t| j S )z
        Return modification time of a directory entry.

        :returns: None if modification time is null, a python datetime object
            otherwise (UTC timezone)

        new in version 0.26
        r   N)r   r~   r   r*   r*   r+   getmtime     
	
zOleDirectoryEntry.getmtimec                 C   r  )z
        Return creation time of a directory entry.

        :returns: None if modification time is null, a python datetime object
            otherwise (UTC timezone)

        new in version 0.26
        r   N)r   r~   r   r*   r*   r+   getctime  r  zOleDirectoryEntry.getctimeNr   )r   r   r   r   r   ZDIRENTRY_SIZErk   calcsizer   r   r   r   r  r  r  r	  r   r  r  r*   r*   r*   r+   r     s     b/
	r   c                   @   sZ  e Zd ZdZdeddefddZdd Zdd	 Ze	fd
dZ
dPddZdQddZdd ZdQddZdRddZdRddZdd Zdd Zdd Zd d! Zd"d# ZdSd%d&ZdSd'd(Zd)d* Zd+d, Zd-d. Zedfd/d0ZdTd2d3ZdTd4d5Zd6d7 Zd8d9 Z d:d; Z!d<d= Z"d>d? Z#d@dA Z$dBdC Z%dDdE Z&dFdG Z'dHdI Z(dJdK Z)dUdLdMZ*dNdO Z+dS )Vr   a  
    OLE container object

    This class encapsulates the interface to an OLE 2 structured
    storage file.  Use the listdir and openstream methods to
    access the contents of this file.

    Object names are given as a list of strings, one for each subentry
    level.  The root entry should be omitted.  For example, the following
    code extracts all image streams from a Microsoft Image Composer file::

        ole = OleFileIO("fan.mic")

        for entry in ole.listdir():
            if entry[1:2] == "Image":
                fin = ole.openstream(entry)
                fout = open(entry[0:1], "wb")
                while True:
                    s = fin.read(8192)
                    if not s:
                        break
                    fout.write(s)

    You can use the viewer application provided with the Python Imaging
    Library to view the resulting files (which happens to be standard
    TIFF files).
    NFc                 C   s
  || _ g | _|| _|| _d| _d| _g | _g | _d| _d| _	d| _
d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _ d| _!d| _"d| _#d| _$d| _%d| _&|r| j'||d dS dS )a  
        Constructor for the OleFileIO class.

        :param filename: file to open.

            - if filename is a string smaller than 1536 bytes, it is the path
              of the file to open. (bytes or unicode string)
            - if filename is a string longer than 1535 bytes, it is parsed
              as the content of an OLE file in memory. (bytes type only)
            - if filename is a file-like object (with read, seek and tell methods),
              it is parsed as-is.

        :param raise_defects: minimal level for defects to be raised as exceptions.
            (use DEFECT_FATAL for a typical application, DEFECT_INCORRECT for a
            security-oriented application, see source code for details)

        :param write_mode: bool, if True the file is opened in read/write mode instead
            of read-only by default.

        :param debug: bool, set debug mode (deprecated, not used anymore)

        :param path_encoding: None or str, name of the codec to use for path
            names (streams and storages), or None for Unicode.
            Unicode by default on Python 3+, UTF-8 on Python 2.x.
            (new in olefile 0.42, was hardcoded to Latin-1 until olefile v0.41)
        N)
write_mode)(_raise_defects_levelparsing_issuesr  path_encoding	_filesize
ministream_used_streams_fat_used_streams_minifat
byte_orderdirectory_fpr   dll_versionr   first_difat_sectorfirst_dir_sectorfirst_mini_fat_sectorr`   header_clsidheader_signaturemetadatamini_sector_shiftmini_sector_sizemini_stream_cutoff_sizer   minifatsectr   minisectorsizeminor_versionnb_sectnum_difat_sectorsnum_dir_sectorsnum_fat_sectorsnum_mini_fat_sectors	reserved1	reserved2rootsector_shiftsector_sizetransaction_signature_numberr]   )r   r^   Zraise_defectsr  r   r  r*   r*   r+   r     sV   zOleFileIO.__init__c                 C   s   | S ra   r*   r   r*   r*   r+   	__enter__6  s   zOleFileIO.__enter__c                 G   s   |    d S ra   )close)r   argsr*   r*   r+   __exit__:  r  zOleFileIO.__exit__c                 C   s:   || j krt| ||| j||f t| dS )a  
        This method should be called for any defect found during file parsing.
        It may raise an IOError exception according to the minimal level chosen
        for the OleFileIO object.

        :param defect_level: defect level, possible values are:

            - DEFECT_UNSURE    : a case which looks weird, but not sure it's a defect
            - DEFECT_POTENTIAL : a potential defect
            - DEFECT_INCORRECT : an error according to specifications, but parsing can go on
            - DEFECT_FATAL     : an error which cannot be ignored, parsing is impossible

        :param message: string describing the defect, used with raised exception.
        :param exception_type: exception class to be raised, IOError by default
        N)r  r.   errorr  r   warning)r   Zdefect_levelmessageZexception_typer*   r*   r+   r   >  s
   

zOleFileIO._raise_defectreplacec                 C   s$   | d|}| jr|| j|S |S )a  
        Decode a string encoded in UTF-16 LE format, as found in the OLE
        directory or in property streams. Return a string encoded
        according to the path_encoding specified for the OleFileIO object.

        :param utf16_str: bytes string encoded in UTF-16 LE format
        :param errors: str, see python documentation for str.decode()
        :return: str, encoded according to path_encoding
        zUTF-16LE)decoder  encode)r   Z	utf16_strerrorsZunicode_strr*   r*   r+   r   X  s   
zOleFileIO._decode_utf16_strc           	      C   s  || _ t|dr|| _n t|trt|tkrt|| _n| j r$d}nd}t	||| _d}| j
dtj z| j }W | j
d n| j
d w || _td| j| jf  g | _g | _| jd}t|dkss|dd tkrtd	|dd tf  | td
 d}t|}td||d f  |d| }t||\| _| _| _| _| _| _| _ | _!| _"| _#| _$| _%| _&| _'| _(| _)| _*| _+tt|| | jtkr| td | jt,dkr| t-d td| j  td| j  | jdvr| t-d td| j  | jdkr| t-d d| j | _.td| j.  | j.dvr3| t-d | jdkr?| j.dksK| jdkrQ| j.dkrQ| t-d d| j  | _/td | j/  | j/d!vrk| t-d" | j!dksw| j"dkr}| t-d# td$| j#  | j.dkr| j#dkr| t-d% td&| j$  td'| j%  td(| j&  | j&dkr| t0d) td*| j'  | j'dkr| t-d+ t1d,| j'  d| _'td-| j(  td.| j)  td/| j*  td0| j+  || j. d1 | j. d1 | _2td2| j2| j2f  t3|dd3 | _| j.| _4| j/| _5| j'| _6| 7| j% | j)r7| 7| j( | j+rA| 7| j* | 8| | 9| j% | j(| _:dS )4a  
        Open an OLE2 file in read-only or read/write mode.
        Read and parse the header, FAT and directory.

        :param filename: string-like or file-like object, OLE file to parse

            - if filename is a string smaller than 1536 bytes, it is the path
              of the file to open. (bytes or unicode string)
            - if filename is a string longer than 1535 bytes, it is parsed
              as the content of an OLE file in memory. (bytes type only)
            - if filename is a file-like object (with read, seek and tell methods),
              it is parsed as-is.

        :param write_mode: bool, if True the file is opened in read/write mode instead
            of read-only by default. (ignored if filename is not a path)
        rV   zr+brW   r   zFile size: %d bytes (%Xh)r   Nr4   zMagic = %r instead of %rz#not an OLE2 structured storage filez<8s16sHHHHHHLLLLLLLLLLzfmt_header size = %d, +FAT = %di  zincorrect OLE signaturer;   zincorrect CLSID in OLE headerzMinor Version = %dz%DLL Version   = %d (expected: 3 or 4))r"   r   z"incorrect DllVersion in OLE headerz#Byte Order    = %X (expected: FFFE)i  z!incorrect ByteOrder in OLE headerr0   z0Sector Size   = %d bytes (expected: 512 or 4096))r   rT   z#incorrect sector_size in OLE headerr"   r   rT   z3sector_size does not match DllVersion in OLE headerz/MiniFAT Sector Size   = %d bytes (expected: 64))rK   z(incorrect mini_sector_size in OLE headerz.incorrect OLE header (non-null reserved bytes)z Number of Directory sectors = %dz3incorrect number of directory sectors in OLE headerzNumber of FAT sectors = %dzFirst Directory sector  = %Xhz$Transaction Signature Number    = %dz5incorrect OLE header (transaction_signature_number>0)z/Mini Stream cutoff size = %Xh (expected: 1000h)z/incorrect mini_stream_cutoff_size in OLE headerzJFixing the mini_stream_cutoff_size to 4096 (mandatory value) instead of %dzFirst MiniFAT sector      = %XhzNumber of MiniFAT sectors = %dzFirst DIFAT sector        = %XhzNumber of DIFAT sectors   = %dr#   z/Maximum number of sectors in the file: %d (%Xh)rC   );r  rX   r`   r[   r\   rY   r   r   r   r]   rZ   osSEEK_ENDtellr  r.   r   r  r  rV   r   r   r   rk   r  rl   r%  r$  r,  r   r  r5  r'  r2  r3  r/  r0  r"  r7  r)  r#  r1  r!  r.  	bytearrayr   r6  r(  r   r=  r-  rx   r   r+  r   r   loadfatloaddirectoryr*  )	r   r^   r  moder   r_   Z
fmt_headerheader_sizeZheader1r*   r*   r+   r]   k  s   
'



zOleFileIO.openc                 C      | j   dS )z@
        close the OLE file, to release the file object
        N)r`   r9  r   r*   r*   r+   r9  K     zOleFileIO.closec                 C   sh   |rt d|  | j}nt d|  |ttttfv rdS | j}||v r-| t	d dS |
| dS )ag  
        Checks if a stream has not been already referenced elsewhere.
        This method should only be called once for each known stream, and only
        if stream size is not null.

        :param first_sect: int, index of first sector of the stream in FAT
        :param minifat: bool, if True, stream is located in the MiniFAT, else in the FAT
        z,_check_duplicate_stream: sect=%Xh in MiniFATz(_check_duplicate_stream: sect=%Xh in FATNzStream referenced twice)r.   r   r  r   r   r   r   r  r   r   r   )r   Z
first_sectr   Zused_streamsr*   r*   r+   r   R  s   	z!OleFileIO._check_duplicate_streamr   c                 C   s   d}t dtdtdtdi}t|}|| d | }tddd	 t|D ]
}td
| dd	 q"t  t|D ]G}|| }	td||	  dd	 t|	|	| D ],}||krS n%|| }
|
d@ }||v rd|| }n|
|d krmd}nd
|
 }t|dd	 qKt  q4dS )zU
        Display a part of FAT in human-readable form for debugging purposes
        r4   z..free..z[ END. ]zFATSECT zDIFSECT r#   indexr
  r  %8X%6X:r/   z    --->N)r   r   r   r   rY   r   r   )r   r   
firstindexVPLZfatnamesnbsectnlinesr!   lrM  r   Zauxr'   r*   r*   r+   dumpfatl  s8   
zOleFileIO.dumpfatc                 C   s   d}t  t|}tjdkr|  t|}|| d | }tddd t|D ]
}td| dd q't  t|D ]1}|| }	td||	  dd t|	|	| D ]}||krX n|| }
d|
 }t|dd qPt  q9d	S )
zS
        Display a sector in a human-readable form, for debugging purposes
        r4   bigr#   rM  r
  r  rN  rO  N)arrayUINT32sys	byteorderbyteswaprY   r   r   )r   sectorrP  rQ  r  rR  rS  r!   rT  rM  r   r'   r*   r*   r+   dumpsect  s*   
zOleFileIO.dumpsectc                 C   s"   t  t|}tjdkr|  |S )z
        convert a sector to an array of 32 bits unsigned integers,
        swapping bytes on big endian CPUs such as PowerPC (old Macs)
        rV  )rW  rX  rY  rZ  r[  )r   r   ar*   r*   r+   
sect2array  s   
zOleFileIO.sect2arrayc                 C   s   t |tjr	|}n| |}ttjr| | d}|D ]-}|d@ }td|  |t	ks2|t
kr:td  |S | |}| |}| j| | _q|S )z
        Adds the indexes of the given sector to the FAT

        :param sect: string containing the first FAT sector, or array of long integers
        :returns: index of last FAT sector.
        Nr/   z
isect = %Xzfound end of sector chain)r[   rW  r_  r.   isEnabledForr$   DEBUGr]  r   r   r   getsectr   )r   r   Zfat1ZisectsZnextfatr*   r*   r+   loadfat_sect  s"   




zOleFileIO.loadfat_sectc           	      C   s  t d |dd }t dt|t|d f  tt| _| | | jdkrt d | jdkr:| 	t
d	 | j| jkrF| 	td
 t d | jd d }| jd | d | }t d|  | j|krmtd| j}t|D ]4}t d||f  | |}| |}t tjr| | | |d|  || }t d|  qt|ttfvrtdnt d t| j| jkrt dt| j| jf  | jd| j | _t dt| j| jf  t tjrt d | | j dS dS )z%
        Load the FAT table.
        zDLoading the FAT table, starting with the 1st sector after the headerL   r   zlen(sect)=%d, so %d integersr   r   z)DIFAT is used, because file size > 6.8MB.m   z#incorrect DIFAT, not enough sectorsz)incorrect DIFAT, first index out of rangezDIFAT analysis...r#   znb_difat = %dzincorrect DIFATzDIFAT block %d, sector %XNznext DIFAT sector: %Xzincorrect end of DIFATz$No DIFAT, because file size < 6.8MB.z!len(fat)=%d, shrunk to nb_sect=%dz6FAT references %d sectors / Maximum %d sectors in filez
FAT:)r.   r   rY   rW  rX  r   rd  r.  r0  r   r   r!  r-  r   r   IOError	iterrangerb  r_  r`  r$   ra  r]  r   r   rU  )	r   r_   r   Znb_difat_sectorsZnb_difatZisect_difatr!   Zsector_difatZdifatr*   r*   r+   rG    sN   
	











zOleFileIO.loadfatc                 C   s   | j | j }| jj| j d | j }|d }td| j| j |||f  ||kr.| t	d | j
| j|dd }| || _tdt| j|f  | jd| | _td	t| j  ttjrptd
 | | j dS dS )z)
        Load the MiniFAT table.
        r#   r   zaloadminifat(): minifatsect=%d, nb FAT sectors=%d, used_size=%d, stream_size=%d, nb MiniSectors=%dz%OLE MiniStream is larger than MiniFATT	force_FATz$MiniFAT shrunk from %d to %d sectorsNzloadminifat(): len=%dz	
MiniFAT:)r1  r6  r4  r   r(  r.   r   r*  r   r   _openrV   r_  r   rY   r`  r$   ra  rU  )r   Zstream_sizeZnb_minisectorsZ	used_sizerc  r*   r*   r+   r   .  s"   
zOleFileIO.loadminifatc              
   C   s   z| j | j|d   W n   td|| j|d  | jf  | td Y | j | j}t	|| jkrItd|t	|| jf  | td |S )z
        Read given sector from file on disk.

        :param sect: int, sector index
        :returns: a string containing the sector data.
        r#   z(getsect(): sect=%X, seek=%d, filesize=%dr   z*getsect(): sect=%X, read=%d, sectorsize=%dr   )
r`   rZ   r   r.   r   r  r   r   rV   rY   )r   r   r\  r*   r*   r+   rb  R  s   zOleFileIO.getsectrr   c              
   C   s   t |ts	tdt |trt|dkrtdz| j| j|d   W n   td|| j|d  | j	f  | 
td Y t|| jk rS||| jt|  7 }nt|| jk r^td| j| dS )z
        Write given sector to file on disk.

        :param sect: int, sector index
        :param data: bytes, sector data
        :param padding: single byte, padding character if data < sector size
        z'write_sect: data must be a bytes stringr#   z4write_sect: padding must be a bytes string of 1 charz+write_sect(): sect=%X, seek=%d, filesize=%dr   Data is larger than sector sizeN)r[   r\   	TypeErrorrY   r`   rZ   r   r.   r   r  r   r   
ValueErrorwrite)r   r   r   paddingr*   r*   r+   
write_sectr  s    
zOleFileIO.write_sectc                 C   s   t |ts	tdt |trt|dkrtdz| j| W n   td|| jf  | 	t
d Y t|}|| jk rG||| j|  7 }| j|k rPtd| j| dS )z
        Write given sector to file on disk.

        :param fp_pos: int, file position
        :param data: bytes, sector data
        :param padding: single byte, padding character if data < sector size
        z,write_mini_sect: data must be a bytes stringr#   z9write_mini_sect: padding must be a bytes string of 1 charz)write_mini_sect(): fp_pos=%d, filesize=%dr   rl  N)r[   r\   rm  rY   r`   rZ   r.   r   r  r   r   r(  rn  ro  )r   fp_posr   rp  Zlen_datar*   r*   r+   _write_mini_sect  s"   


zOleFileIO._write_mini_sectc                 C   sl   t d | j|dd| _| jjd }t d| jj|f  dg| | _| d}| jd | _| j  dS )z]
        Load the directory.

        :param sect: sector index of directory stream.
        zLoading the Directory:Tri  r   z&loaddirectory: size=%d, max_entries=%dNr   )	r.   r   rk  r  r   r   r   r4  r   )r   r   Zmax_entriesZ
root_entryr*   r*   r+   rH    s   


zOleFileIO.loaddirectoryc                 C   s~   |dk s|t | jkr| td | j| dur#| td | j| S | j|d  | jd}t||| | j|< | j| S )aY  
        Load a directory entry from the directory.
        This method should only be called once for each storage/stream when
        loading the directory.

        :param sid: index of storage/stream in the directory.
        :returns: a OleDirectoryEntry object

        :exception IOError: if the entry has always been referenced.
        r   z OLE directory index out of rangeNz'double reference for OLE stream/storager   )	rY   r   r   r   r   r  rZ   rV   r   )r   r   r   r*   r*   r+   r     s   

zOleFileIO._load_direntryc                 C   rK  )z5
        Dump directory (for debugging only)
        N)r4  r   r   r*   r*   r+   dumpdirectory  rL  zOleFileIO.dumpdirectoryc              
   C   s   t d||t|f  || jk rE|sE| js4|   | jj}t d| jj|f  | j	| jj|dd| _t
| j||d| j| j| jj| dS t
| j||| j| j| j| j| dS )a|  
        Open a stream, either in FAT or MiniFAT according to its size.
        (openstream helper)

        :param start: index of first sector
        :param size: size of stream (or nothing if size is unknown)
        :param force_FAT: if False (default), stream will be opened in FAT or MiniFAT
            according to size. If True, it will always be opened in FAT.
        z1OleFileIO.open(): sect=%Xh, size=%d, force_FAT=%sz%Opening MiniStream: sect=%Xh, size=%dTri  r   )r`   r   r   r   r   r   r   r   )r.   r   strr   r  r   r4  r   r   rk  r   r+  r   r`   r   r   r  )r   startr   rj  Zsize_ministreamr*   r*   r+   rk    s0   





zOleFileIO._openTc                 C   s   ||j g }|jD ];}|jtkr)|r||dd |j g  | ||||| q	|jtkr>|r=||dd |j g  q	| td q	dS )a  
        listdir helper

        :param files: list of files to fill in
        :param prefix: current location in storage tree (list of names)
        :param node: current node (OleDirectoryEntry object)
        :param streams: bool, include streams if True (True by default) - new in v0.26
        :param storages: bool, include storages if True (False by default) - new in v0.26
            (note: the root storage is never included)
        r#   NzIThe directory tree contains an entry which is not a stream nor a storage.)	r'   r   r   r   r   _listr
   r   r   )r   filesprefixnodestreamsstoragesr   r*   r*   r+   rw    s   


zOleFileIO._listc                 C   s   g }|  |g | j|| |S )am  
        Return a list of streams and/or storages stored in this file

        :param streams: bool, include streams if True (True by default) - new in v0.26
        :param storages: bool, include storages if True (False by default) - new in v0.26
            (note: the root storage is never included)
        :returns: list of stream and/or storage paths
        )rw  r4  )r   r{  r|  rx  r*   r*   r+   listdir3  s   	zOleFileIO.listdirc                 C   sX   t |tr
|d}| j}|D ]}|jD ]}|j | kr! nqtd|}q|jS )a*  
        Returns directory entry of given filename. (openstream helper)
        Note: this method is case-insensitive.

        :param filename: path of stream in storage tree (except root entry), either:

            - a string using Unix path syntax, for example:
              'storage_1/storage_1.2/stream'
            - or a list of storage filenames, path to the desired stream/storage.
              Example: ['storage_1', 'storage_1.2', 'stream']

        :returns: sid of requested filename
        :exception IOError: if file not found
        /zfile not found)	r[   
basestringsplitr4  r   r'   r   rg  r   )r   r^   rz  r'   r  r*   r*   r+   _findA  s   


zOleFileIO._findc                 C   s6   |  |}| j| }|jtkrtd| |j|jS )a;  
        Open a stream as a read-only file object (BytesIO).
        Note: filename is case-insensitive.

        :param filename: path of stream in storage tree (except root entry), either:

            - a string using Unix path syntax, for example:
              'storage_1/storage_1.2/stream'
            - or a list of storage filenames, path to the desired stream/storage.
              Example: ['storage_1', 'storage_1.2', 'stream']

        :returns: file object (read-only)
        :exception IOError: if filename not found, or if this is not a stream.
        zthis file is not a stream)r  r   r   r
   rg  rk  r   r   r   r^   r   r   r*   r*   r+   
openstreama  s
   


zOleFileIO.openstreamc                 C   s   |j s||  t|j }| jj s| j|  | j| j }t|j D ]@\}}|| }|| }| jj | d | j || j  }	||d k rS||| j |d | j  }
n	||| j d  }
| |	|
 q"d S )Nr#   )r   r   rY   r4  r6  r(  	enumeraters  )r   r   data_to_writer   Z
block_sizeidxr   Z	sect_baseZsect_offsetrr  Zdata_per_sectorr*   r*   r+   _write_mini_streamv  s   

 zOleFileIO._write_mini_streamc           
   	   C   sz  t |ts	td| |}| j| }|jtkrtd|j}|t	|kr)t
d|| jk r:|jtkr:| j||dS |j}|| jd  | j }td|  t|D ]`}||d k rr||| j |d | j  }	t	|	| jksqJ n(||| j d }	td|| jt	|	|| j f  t	|	| j || j ksJ | ||	 z| j| }W qR ty   td	w |tkrtd
dS )aD  
        Write a stream to disk. For now, it is only possible to replace an
        existing stream by data of the same size.

        :param stream_name: path of stream in storage tree (except root entry), either:

            - a string using Unix path syntax, for example:
              'storage_1/storage_1.2/stream'
            - or a list of storage filenames, path to the desired stream/storage.
              Example: ['storage_1', 'storage_1.2', 'stream']

        :param data: bytes, data to be written, must be the same size as the original
            stream.
        z)write_stream: data must be a bytes stringzthis is not a streamz?write_stream: data must be the same size as the existing stream)r   r  r#   r   NzGwrite_stream: size=%d sectorsize=%d data_sector=%Xh size%%sectorsize=%dr   z)incorrect last sector index in OLE stream)r[   r\   rm  r  r   r   r
   rg  r   rY   rn  r   r   r  r   r   r.   r   r   rq  r   r   r   )
r   Zstream_namer   r   r   r   r   r   r!   Zdata_sectorr*   r*   r+   write_stream  s@   



zOleFileIO.write_streamc                 C   s*   z|  |}| j| }|jW S    Y dS )a  
        Test if given filename exists as a stream or a storage in the OLE
        container, and return its type.

        :param filename: path of stream in storage tree. (see openstream for syntax)
        :returns: False if object does not exist, its entry type (>0) otherwise:

            - STGTY_STREAM: a stream
            - STGTY_STORAGE: a storage
            - STGTY_ROOT: the root entry
        F)r  r   r   r  r*   r*   r+   get_type  s   

zOleFileIO.get_typec                 C   s   |  |}| j| }|jS )a  
        Return clsid of a stream/storage.

        :param filename: path of stream/storage in storage tree. (see openstream for
            syntax)
        :returns: Empty string if clsid is null, a printable representation of the clsid otherwise

        new in version 0.44
        )r  r   rw   r  r*   r*   r+   getclsid  s   


zOleFileIO.getclsidc                 C      |  |}| j| }| S )a9  
        Return modification time of a stream/storage.

        :param filename: path of stream/storage in storage tree. (see openstream for
            syntax)
        :returns: None if modification time is null, a python datetime object
            otherwise (UTC timezone)

        new in version 0.26
        )r  r   r  r  r*   r*   r+   r       

zOleFileIO.getmtimec                 C   r  )a1  
        Return creation time of a stream/storage.

        :param filename: path of stream/storage in storage tree. (see openstream for
            syntax)
        :returns: None if creation time is null, a python datetime object
            otherwise (UTC timezone)

        new in version 0.26
        )r  r   r  r  r*   r*   r+   r    r  zOleFileIO.getctimec                 C   s   z|  |}W dS    Y dS )a  
        Test if given filename exists as a stream or a storage in the OLE
        container.
        Note: filename is case-insensitive.

        :param filename: path of stream in storage tree. (see openstream for syntax)
        :returns: True if object exist, else False.
        TF)r  )r   r^   r   r*   r*   r+   r   	  s
   	
zOleFileIO.existsc                 C   s,   |  |}| j| }|jtkrtd|jS )a2  
        Return size of a stream in the OLE container, in bytes.

        :param filename: path of stream in storage tree (see openstream for syntax)
        :returns: size in bytes (long integer)
        :exception IOError: if file not found
        :exception TypeError: if this is not a stream.
        zobject is not an OLE stream)r  r   r   r
   rm  r   r  r*   r*   r+   get_size  s
   
	

zOleFileIO.get_sizec                 C   s   | j jS )zp
        Return root entry name. Should usually be 'Root Entry' or 'R' in most
        implementations.
        )r4  r'   r   r*   r*   r+   get_rootentry_name*  s   zOleFileIO.get_rootentry_namec                 C   s2  |dkrg }|}t |tsd|}| |}i }z7|d}t|dd }|d}t|dd }	|t|d d|t|d	d	  }t|d	}
W n% tyu } zd
t	||f }| 
t|t| |W  Y d}~S d}~ww t|
tt|d }
t|
D ]}d}zft|d|d  }t|d|d  }t||}td|||f  |tkrt||d	 }|dkr|d }n*|tkrt||d	 }n|tttfv rt||d	 }n|ttfv rt||d	 }n|ttfv rt||d	 }||d |d | d  }|dd}n|tkr)t||d	 }||d |d |  }n|tkrGt||d	 }|  ||d |d |d   }n|t!krt"t||d	 t"t||d d>  }|r||vrtd||t#|d f  t$$dddddd}td|d   |t$j%|d d }nX|d }nS|t&krt'||d	  }nE|t(krt||d	 |d  }n3|t)krt||d	 }||d |d |  }n|t*krt+t||d	 }nd}td||f  |||< W q ty } zd|t	||f }| 
t|t| W Y d}~qd}~ww |S )a  
        Return properties described in substream.

        :param filename: path of stream in storage tree (see openstream for syntax)
        :param convert_time: bool, if True timestamps will be converted to Python datetime
        :param no_conversion: None or list of int, timestamps not to be converted
            (for example total editing time is not a real timestamp)

        :returns: a dictionary of values indexed by id (integer)
        Nr~  rG   r4   rC   r?   r;   s   ****r   z6Error while parsing properties header in stream %s: %sr   r8   z!property id=%d: type=%d offset=%Xi   i   r#   rr   r   r0   r   z8Converting property #%d to python datetime, value=%d=%fsi ry   ztimedelta days=%dl    @T$r6   rz   z5property id=%d: type=%d not implemented in parser yetz3Error while parsing property id %d in stream %s: %s),r[   ru  r   r  rV   rx   rZ   rq   BaseExceptionr   r   r   typeminrh   rY   rh  r.   r   VT_I2ro   VT_UI2VT_I4VT_INTVT_ERRORVT_UI4VT_UINTVT_BSTRVT_LPSTRr?  VT_BLOB	VT_LPWSTRr   VT_FILETIMEr   floatr{   r|   VT_UI1re   VT_CLSIDVT_CFVT_BOOLbool)r   r^   r   r   Z
streampathr`   r   rc  rw   ZfmtidZ	num_propsexcmsgr!   Zproperty_idr   Zproperty_typer   countr}   r*   r*   r+   r   2  s   








$
(





zOleFileIO.getpropertiesc                 C   s   t  | _| j|  | jS )z
        Parse standard properties streams, return an OleMetadata object
        containing all the available metadata.
        (also stored in the metadata attribute of the OleFileIO object)

        new in version 0.25
        )r   r&  r   r   r*   r*   r+   get_metadata  s   zOleFileIO.get_metadata)r?  )Fr  )rr   )TF)FN),r   r   r   r   r   r   r   r8  r;  rg  r   r   r]   r9  r   rU  r]  r_  rd  rG  r   rb  rq  rs  rH  r   rt  r   rk  rw  r}  r  r  r  r  r  r  r  r  r   r  r  r   r  r*   r*   r*   r+   r     sT    
M

 a


%$T$
 
)
&
 >
 r   c               	   C   s  ddl } ddl}d}tjtjtjtjtjd}d}|j|d}|j	ddd	d
d |j	ddddd |j	dddd|dd |
 \}}tdttf  t|dkr\tt |  |   |jrbd|_tj||j dd t  |D ]M}z>t|}	td t| td |	  |	 D ]`}
|
d d dkrtd|
  zC|	j|
dd}t| }|D ]1\}}t|ttfrt|dkr|dd }t|trd D ]}|t|v rd!} nqtd"|| qW q   t !d#|
  Y qq|j"r-td$ |	 D ].}
td%t#d&$|
d%d'd( |	%|
}|t&kr#td)|	'|
  |	(|
 qtd*|  qt  td+ |	j)D ]}|durItd,|j*|+ |, f  q4t  z
|	- }|.  W n	   t !d- Y t  |	/ }td.|  |	0d/rtd0 td1|	%d/ td2|	'd/ |	0d3rtd4 td5 |	j1r|	j1D ]\}}td6|j2|f  qntd7 W qq   t !d8|  Y qqdS )9z
    Main function when olefile is runs as a script from the command line.
    This will open an OLE2 file and display its structure and properties
    :return: nothing
    r   Nr=  )r   infor=  r<  Zcriticalz1usage: %prog [options] <filename> [filename2 ...])usagez-c
store_truecheck_streamsz*check all streams (for debugging purposes))actiondesthelpz-d
debug_modez\debug mode, shortcut for -l debug (displays a lot of debug information, for developers only)z-lz
--loglevelloglevelstorezBlogging level debug/info/warning/error/critical (default=%default))r  r  defaultr  z=olefile version %s %s - https://www.decalage.info/en/olefile
r   z%(levelname)-8s %(message)s)r(   formatzD--------------------------------------------------------------------z%r: propertiesTr   2   )r#   r0   r"   r   r1   r2   r3   r7   r8   r:      r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   rE   rF   rG   rH   rI   rJ   z(binary data)z   z&Error while parsing property stream %rz
Checking streams...-r~  r
  r  zsize %dzNOT a stream : type=%dz5Modification/Creation times of all directory entries:z- %s: mtime=%s ctime=%szError while parsing metadatazRoot entry name: "%s"ZworddocumentzThis is a Word document.ztype of stream 'WordDocument':zsize :z
macros/vbaz%This document may contain VBA macros.z(
Non-fatal issues raised during parsing:r   NonezError while parsing file %r)3rY  optparser$   ra  INFOZWARNINGZERRORCRITICALZOptionParserZ
add_option
parse_argsr   __version____date__rY   r   
print_helpexitr  r  ZbasicConfigr   r   rt  r}  r   sorteditemsr[   r  r\   rF  r.   Z	exceptionr  r   r   r  r
   r  r  r   r'   r  r  r  r   r  r   r  r   )rY  r  ZDEFAULT_LOG_LEVELZ
LOG_LEVELSr  parseroptionsr:  r^   r   Z
streamnamer   kvrd   Zst_typer   metar4  exctyper  r*   r*   r+   main  s   







r  __main__r  )mr   Z
__future__r   r  r  
__author____all__r   rY  rk   rW  os.pathrC  r{   r$   ru  r\   rh   r   Zxrangerh  r   itemsizerX  rn  r  	NameErrorr	   version_infor   r  r,   r.   r   r   r   r   r   r   r   r   r   r   r   r
   r   r   r   r   ZVT_EMPTYZVT_NULLr  r  ZVT_R4ZVT_R8ZVT_CYZVT_DATEr  ZVT_DISPATCHr  r  Z
VT_VARIANTZ
VT_UNKNOWNZ
VT_DECIMALZVT_I1r  r  r  ZVT_I8ZVT_UI8r  r  ZVT_VOIDZ
VT_HRESULTZVT_PTRZVT_SAFEARRAYZ	VT_CARRAYZVT_USERDEFINEDr  r  r  r  Z	VT_STREAMZ
VT_STORAGEZVT_STREAMED_OBJECTZVT_STORED_OBJECTZVT_BLOB_OBJECTr  r  Z	VT_VECTORr   r   r   r   r   r   r   re   ro   rq   rx   r~   r   r   r   r   r   r  r   r*   r*   r*   r+   <module>   s    <
(
*




    "           

