3
iZ             8   @   s  d Z ddlmZ dZdZdZ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 g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k	reZyeZW n   eZY nX e
j
d"jd#krd"Zn4e
j
d$jd#krd$Zne
j
d%jd#krd%Zned&ye W n ek
r    eZY nX d'Zejd d(k r<d)Znd!Zejd* fd+d,Zed-Z d.d	 Z!d/Z"d0Z#d1Z$d2Z%d3Z&d4Z'd0Z(d4Z)dZ*d*Z+d5Z,d(Z-d#Z.d6Z/d7Z0dZ1d*Z2d5Z3d(Z4d#Z5d6Z6d8Z7d9Z8d:Z9d;Z:d<Z;d=Z<d>Z=d?Z>d@Z?dAZ@dBZAdCZBdDZCdEZDdFZEdGZFdHZGdIZHdJZIdKZJdLZKdMZLdNZMdOZNdPZOdQZPdRZQdSZRdTZSdUZTdVZUdWZVdXZWdYZXdZZYi ZZx6e[e\ j] D ]$\Z^Z_e^d!d( d[krVe^eZe_< qVW d\Z`d<ZadEZbdOZcd]Zdd^Zed_d Zfeekrd`da Zgndbda ZgddcddZhddedfZidgdh Zjdidj ZkG dkd dZlG dldm dmejmZnG dndo doZoG dpd dZpeqdqkrdd!lZdd!lrZrdrZsejtejuejvejwejdsZxdtZyerjzeyduZ{e{j|dvdwdxdydz e{j|d{dwd|d}dz e{j|d~dddesdd e{j} \Z~Zedeef  eedkree  e{j  ej  e~jrde~_ejexe~j dd e!  xeD ]ZyepeZeddU  ee eddU  ej   xej D  ]Zed d dkrTede  yejed'dZeej] ZxxeD ]p\ZZeeeefreedkred!d Zeeerx"dD ]ZeeekrdZP qW edee qW W n   e jde  Y nX qTW e~jred xjej D ]^Zededjeddd ejeZee,kredeje  eje nede  qLW e  ed x6ejD ],Zed!k	redejej ej f  qW e  yej Zej  W n   e jd Y nX e  ej Zede  ejdred edejd edejd ejdred ed ejrx0ejD ]\ZZedejqef  qW ned W n   e jde  Y nX qW 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-01-25z0.45.1z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kr&t j| }|j| |S t j| }|jt j  |j| |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levelZlogger r)   1/usr/lib/python3/dist-packages/olefile/olefile.py
get_logger   s    



r+   olefilec               C   s   t j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    s   ࡱl    l    l    l    l          i         	   
                                                               @   A   B   C   D   E   F   G   H   i   ZVT_z$00020900-0000-0000-C000-000000000046(   i   c          
   C   s   t | dr$| jtt}| jd nLt| trLt| tkrL| dtt }n$t| d}|jtt}W dQ R X |tkr|dS d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)	hasattrrS   lenr   seek
isinstancebytesr   open)filenameheaderfpr)   r)   r*   r     s    
c             C   s   t | S )N)ord)cr)   r)   r*   i8@  s    r`   c             C   s   | j tkr| S | d S )Nr   )	__class__int)r_   r)   r)   r*   r`   D  s    c             C   s   t j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<Hr.   r   )structunpack)r_   or)   r)   r*   i16H  s    rf   c             C   s   t jd| ||d  d S )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   )rc   rd   )r_   re   r)   r)   r*   i32R  s    rg   c             C   s\   t | dkst| jdsdS dd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.
    r9        z%08X-%04X-%04X-%02X%02X-z%02Xr0   r   r   r2   )rV   AssertionErrorstriprg   rf   tuplemapr`   )clsidr)   r)   r*   _clsid\  s    

ro   c             C   s(   t j dddddd}|t j| d d S )zL
        convert FILETIME (64 bits int) to Python datetime.datetime
        iA  r#   r   r4   )microseconds)datetime	timedelta)Zfiletime_FILETIME_null_dater)   r)   r*   filetime2datetimem  s    rt   c               @   s   e Zd ZdZdddddddd	d
ddddddddddgZ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/d0gZd1d2 Zd3d4 Zd5d6 Zd7S )8r   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_targetrY   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)/ru   rv   rw   rx   ry   rz   r{   r|   r}   r~   r   r   r   r   r   r   r   r   r   r   r   r   rY   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   x | j | j D ]}t| |d qW |jdrx|jdddgd}x8tt| j D ]&}|j|d d}t| | j | | qNW |jdr|jddd}x8tt| jD ]&}|j|d d}t| | j| | qW 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SummaryInformationTr4   )convert_timeno_conversionr#   zDocumentSummaryInformation)r   )SUMMARY_ATTRIBSDOCSUM_ATTRIBSsetattrexistsgetpropertiesrangerV   get)r   r,   Zattribpropsr!   valuer)   r)   r*   parse_properties  s    	

zOleMetadata.parse_propertiesc             C   sp   t d x,| jD ]"}t| |}t d|t|f  qW t d x,| jD ]"}t| |}t d|t|f  qFW dS )z<
        Dump all metadata, for debugging purposes.
        z*Properties from SummaryInformation stream:z- %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   {  s   !

8 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   s6  t jd t jd|||||t|t|f  || _| jjjrFtdd}	|tkrlt|| }d}	t jd ||d  | }
t jd|
  |
t|kr| jj	t
d	 g }|d
kr|tkrt jd | jj	t
d xt|
D ]}t jd||f  |tkr*|	rt jd P nt jd | jj	t
d |d
k sB|t|kr|t jd||t|f  t jd||
f  | jj	t
d P y|j|||   W n8   t jd||||  |f  | jj	t
d P Y nX |j|}t||krJ|t|d krJt jd|t||||  |t|f  t jd|||  t|   | jj	t
d |j| y|| d@ }W q tk
r   | jj	t
d P Y qX qW dj|}t||krt jdt||f  |d| }|| _nR|	rt jdt|  t|| _n.t jdt||f  t|| _| jj	t
d tj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#   z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=%dz,incorrect OLE FAT, sector index out of rangezsect=%d, seek=%d, filesize=%dzOLE sector index out of rangez9sect=%d / len(fat)=%d, seek=%d / filesize=%d, len read=%dzseek+len(read)=%dzincomplete OLE sectorl        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-   debugrV   r   oler]   closedOSErrorr   _raise_defectr   r   r   rW   rS   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jeeks&t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   sj  || _ || _g | _i | _d| _tjtj|\| _	| _
| _| _| _| _| _}| _| _| _| _| _| _| jttttgkr|jtd | jtkr|dkr|jtd |dkr| jtkr|jtd | j
dkr|jtd d| _
| j	d| j
d	  | _|j| j| _tj d
| j t!| jf  tj d| j  tj d| j  tj d| j| j| jf  |j"dkr| jdkr| jdkrtj d|j"| j| j| jf  |jt#d | j| _$n| jt%| jd>  | _$tj d| j$| j| jf  t&|| _'| jtkr| j$dkr|jt(d d| _)| jttfkr`| j$dkr`| j$|j*k rJ| jtkrJd| _)nd| _)|j+| 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 entryrI   z(incorrect DirEntry name length >64 bytesNr.   zDirEntry SID=%d: %sz - type: %dz - sect: %Xhz% - SID left: %d, right: %d, child: %di   l    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usedrc   rd   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   longro   rn   r   
is_minifatminisectorcutoff_check_duplicate_stream
sect_chain)r   entryr   r,   rn   r)   r)   r*   r     sR    	D



zOleDirectoryEntry.__init__c             C   s   | j r
d S | jttfks"| jdkr&d S t | _ | jrD|j rD|j  | j	}x4|t
kr~| j j| | jrr|j| }qL|j| }qLW d S )Nr   )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   sB   t jd| jt| j| jf  | jtkr>| j| j | jj	  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   sort)r   r)   r)   r*   build_storage_treeA  s
    
	z$OleDirectoryEntry.build_storage_treec             C   s   t jd|  |tkrdS |dk s2|t| jjkrB| jjtd n| jj|}t jd|j	t
|j|j|j|jf  | j|j |jj }|| jkr| jjtd | jj| || j|< |jr| jjtd 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!Duplicate filename in OLE storagez#OLE Entry referenced more than onceT)r-   r   r   rV   r,   
direntriesr   r   _load_direntryr   r   r'   r   r   r   r   lowerr   r   r   r   r   )r   Z	child_sidZchildZ
name_lowerr)   r)   r*   r   Y  s*     


zOleDirectoryEntry.append_kidsc             C   s   | j |j kS )zCompare entries by name)r'   )r   otherr)   r)   r*   __eq__  s    zOleDirectoryEntry.__eq__c             C   s   | j |j k S )zCompare entries by name)r'   )r   r   r)   r)   r*   __lt__  s    zOleDirectoryEntry.__lt__c             C   s   | j | S )N)r   )r   r   r)   r)   r*   __ne__  s    zOleDirectoryEntry.__ne__c             C   s   | j |p| j|S )N)r   r   )r   r   r)   r)   r*   __le__  s    zOleDirectoryEntry.__le__r   c             C   s   ddddddg}t d| t| j || j dd | jttfkrPt | jd	dd t   | jttfkr| jrt d| d
| j   x| j	D ]}|j
|d  qW dS )zADump this entry, and all its subentries (for debug purposes only)z	(invalid)z	(storage)z(stream)z(lockbytes)z
(property)z(root) )endrY   z{%s}r.   N)r   r   r'   r   r
   r   r   r   rn   r   r   )r   tabZTYPESkidr)   r)   r*   r     s    "zOleDirectoryEntry.dumpc             C   s   | 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   rt   )r   r)   r)   r*   getmtime  s    	
zOleDirectoryEntry.getmtimec             C   s   | j dkrdS t| j S )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   rt   )r   r)   r)   r*   getctime  s    	
zOleDirectoryEntry.getctimeN)r   )r   r   r   r   r   ZDIRENTRY_SIZErc   calcsizerj   r   r   r   r   r   r   r   r   r   r   r   r)   r)   r)   r*   r     s   b.	
r   c               @   sJ  e Zd ZdZdeddefddZefddZdLd	d
Z	dMddZ
dd ZdNddZdOddZdPddZdd Zdd Zdd Zdd Zdd ZdQd!d"ZdRd#d$Zd%d& Zd'd( Zd)d* Zedfd+d,ZdSd.d/ZdTd0d1Zd2d3 Zd4d5 Zd6d7 Zd8d9 Z d:d; Z!d<d= Z"d>d? Z#d@dA Z$dBdC Z%dDdE Z&dFdG Z'dUdHdIZ(dJdK 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 )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_numberrZ   )r   r[   Zraise_defectsr   r   r   r)   r)   r*   r     sT    zOleFileIO.__init__c             C   s<   || j krtj| ||n| jj||f tj| 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   2  s
    


zOleFileIO._raise_defectreplacec             C   s(   |j d|}| jr |j| j|S |S d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-16LEN)decoder   encode)r   Z	utf16_strerrorsZunicode_strr)   r)   r*   r   L  s    
zOleFileIO._decode_utf16_strc       	      C   s  || _ t|dr|| _n@t|tr<t|tkr<tj|| _n| j rHd}nd}t	||| _d}| jj
dtj z| jj }W d| jj
d X || _tjd| j| jf  g | _g | _| jjd}t|dks|dd tkrtjd	|dd tf  | jtd
 d}tj|}tjd||d2 f  |d| }tj||\| _| _| _| _| _| _| _ | _!| _"| _#| _$| _%| _&| _'| _(| _)| _*| _+tjtj|| | jtkr| jtd | jt,dkr| jt-d tjd| j  tjd| j  | jd3kr| jt-d tjd| j  | jdkr,| jt-d d| j | _.tjd| j.  | j.d4kr`| jt-d | jdkrx| j.dks| jdkr| j.dkr| jt-d d| j  | _/tjd| j/  | j/d5kr| jt-d  | j!dks| j"dkr| jt-d! tjd"| j#  | j.dkr(| j#dkr(| jt-d# tjd$| j$  tjd%| j%  tjd&| j&  | j&dkrp| jt0d' tjd(| j'  | j'dkr| jt-d) tj1d*| j'  d| _'tjd+| j(  tjd,| j)  tjd-| j*  tjd.| j+  || j. d/ | j. d/ | _2tjd0| j2| j2f  t3|dd1 | _| j.| _4| j/| _5| j'| _6| j7| j% | j)rh| j7| j( | j+r|| j7| j* | j8| | j9| j% | j(| _:dS )6a  
        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)
        rS   zr+brT   r   NzFile size: %d bytes (%Xh)   r2   zMagic = %r instead of %rz#not an OLE2 structured storage filez<8s16sHHHHHHLLLLLLLLLLzfmt_header size = %d, +FAT = %dm   r   zincorrect OLE signaturer9   zincorrect CLSID in OLE headerzMinor Version = %dz%DLL Version   = %d (expected: 3 or 4)r"   z"incorrect DllVersion in OLE headerz#Byte Order    = %X (expected: FFFE)i  z!incorrect ByteOrder in OLE headerr.   z0Sector Size   = %d bytes (expected: 512 or 4096)   z#incorrect sector_size in OLE headerz3sector_size does not match DllVersion in OLE headerz/MiniFAT Sector Size   = %d bytes (expected: 64)rI   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)rA   i  )r"   r   )r"  r$  )rI   );r   rU   r]   rX   rY   rV   r   r   r   rZ   rW   osSEEK_ENDtellr   r-   r   r   r   rS   r   r   r   rc   r   rd   r  r  r  r  r  r  r
  r  r  r  r  r  r  r  r  r  r  r  	bytearrayr   r  r  r   r  r  ro   r   r  r   r   loadfatloaddirectoryr  )	r   r[   r   moder   r\   Z
fmt_headerZheader_sizeZheader1r)   r)   r*   rZ   _  s    
'
T

zOleFileIO.openc             C   s   | j j  dS )z@
        close the OLE file, to release the file object
        N)r]   close)r   r)   r)   r*   r,  ?  s    zOleFileIO.closec             C   sf   |rt jd|  | j}n(t jd|  |ttttfkr<dS | j}||krX| jt	d n
|j
| 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   F  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	 x t|D ]}td
| dd	 qFW t  xt|D ]}|| }	td||	  dd	 xht|	|	| D ]V}||krP || }
|
d@ }||kr|| }n|
|d krd}nd
|
 }t|dd	 qW t  qnW dS )zU
        Display a part of FAT in human-readable form for debugging purposes
        r2   z..free..z[ END. ]zFATSECT zDIFSECT r#   indexr   )r   z%8Xz%6X:l    z    --->N)r   r   r   r   rV   r   r   )r   r   
firstindexVPLZfatnamesnbsectnlinesr!   lr-  r   Zauxr'   r)   r)   r*   dumpfat`  s4    
zOleFileIO.dumpfatc             C   s   d}t j t|}tjdkr"|j  t|}|| d | }tddd x t|D ]}td| dd qPW t  xpt|D ]d}|| }	td||	  dd x<t|	|	| D ]*}||krP || }
d|
 }t|dd qW t  qxW d	S )
zS
        Display a sector in a human-readable form, for debugging purposes
        r2   bigr#   r-  r   )r   z%8Xz%6X:N)arrayUINT32sys	byteorderbyteswaprV   r   r   )r   sectorr.  r/  r   r0  r1  r!   r2  r-  r   r'   r)   r)   r*   dumpsect  s(    
zOleFileIO.dumpsectc             C   s"   t j t|}tjdkr|j  |S )z
        convert a sector to an array of 32 bits unsigned integers,
        swapping bytes on big endian CPUs such as PowerPC (old Macs)
        r4  )r5  r6  r7  r8  r9  )r   r   ar)   r)   r*   
sect2array  s    
zOleFileIO.sect2arrayc             C   s   t |tjr|}n | j|}tjtjr2| j| d}x^|D ]V}|d@ }tjd|  |t	ksf|t
krrtjd P | j|}| j|}| j| | _q<W |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.
        Nl    z
isect = %Xzfound end of sector chain)rX   r5  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 jd |dd }t jdt|t|d f  tjt| _| j| | jdkrrt jd | jdkrv| j	t
d	 | j| jkr| j	td
 t jd | jd d }| jd | d | }t jd|  | j|krtd| j}xvt|D ]j}t jd||f  | j|}| j|}t jtjr.| j| | j|d|  || }t jd|  qW |ttgkr|tdn
t jd t| j| jkrt jdt| j| jf  | jd| j | _t jdt| j| jf  t jtjrt jd | j| j dS )z%
        Load the FAT table.
        zDLoading the FAT table, starting with the 1st sector after the headerL   i   zlen(sect)=%d, so %d integersr   r   z)DIFAT is used, because file size > 6.8MB.r#  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   rV   r5  r6  r   rB  r  r  r   r   r  r  r   r   IOError	iterranger@  r=  r>  r$   r?  r;  r   r   r3  )	r   r\   r   Znb_difat_sectorsZnb_difatZisect_difatr!   Zsector_difatZdifatr)   r)   r*   r)    sJ    	












zOleFileIO.loadfatc             C   s   | j | j }| jj| j d | j }|d }tjd| j| j |||f  ||kr\| jt	d | j
| j|ddj }| j|| _tjdt| j|f  | jd| | _tjd	t| j  tjtjrtjd
 | j| j 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:)r  r  r  r   r  r-   r   r  r   r   _openrS   r=  r   rV   r>  r$   r?  r3  )r   Zstream_sizeZnb_minisectorsZ	used_sizerA  r)   r)   r*   r   "  s    
zOleFileIO.loadminifatc             C   s   y| j j| j|d   W n8   tjd|| j|d  | jf  | jtd Y nX | j j| j}t	|| jkrtjd|t	|| jf  | j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=%dzOLE sector index out of rangez*getsect(): sect=%X, read=%d, sectorsize=%dzincomplete OLE sector)
r]   rW   r   r-   r   r   r   r   rS   rV   )r   r   r:  r)   r)   r*   r@  F  s    zOleFileIO.getsectrh   c             C   s   t |tstdt |t s*t|dkr2tdy| jj| j|d   W n8   tjd|| j|d  | j	f  | j
td Y nX t|| jk r||| jt|  7 }nt|| jk rtd| j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=%dzOLE sector index out of rangezData is larger than sector sizeN)rX   rY   	TypeErrorrV   r]   rW   r   r-   r   r   r   r   
ValueErrorwrite)r   r   r   paddingr)   r)   r*   
write_sectf  s    
zOleFileIO.write_sectc          
   C   s   t |tstdt |t s*t|dkr2tdy| jj| W n,   tjd|| jf  | j	t
d Y nX t|}|| jk r||| j|  7 }| j|k rtd| j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=%dzOLE sector index out of rangezData is larger than sector sizeN)rX   rY   rH  rV   r]   rW   r-   r   r   r   r   r  rI  rJ  )r   fp_posr   rK  Zlen_datar)   r)   r*   _write_mini_sect  s     


zOleFileIO._write_mini_sectc             C   sl   t jd | j|dd| _| jjd }t jd| jj|f  dg| | _| jd}| jd | _| jj  dS )z]
        Load the directory.

        :param sect: sector index of directory stream.
        zLoading the Directory:T)rF  r   z&loaddirectory: size=%d, max_entries=%dNr   )	r-   r   rG  r  r   r   r   r  r   )r   r   Zmax_entriesZ
root_entryr)   r)   r*   r*    s    

zOleFileIO.loaddirectoryc             C   s~   |dk s|t | jkr"| jtd | j| dk	rF| jtd | j| S | jj|d  | j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   )	rV   r   r   r   r   r  rW   rS   r   )r   r   r   r)   r)   r*   r     s    
zOleFileIO._load_direntryc             C   s   | j j  dS )z5
        Dump directory (for debugging only)
        N)r  r   )r   r)   r)   r*   dumpdirectory  s    zOleFileIO.dumpdirectoryc          
   C   s   t jd||t|f  || jk r| r| jsj| j  | jj}t j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 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=%dT)rF  r   )r]   r   r   r   r   r   r   r   N)r-   r   strr   r   r   r  r   r   rG  r   r  r   r]   r   r   r   )r   startr   rF  Zsize_ministreamr)   r)   r*   rG    s&    




zOleFileIO._openTc             C   s   ||j g }x|jD ]v}|jtkrT|r@|j|dd |j g  | j||||| q|jtkr~|r|j|dd |j g  q| jtd qW 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*   rR  
  s    

zOleFileIO._listc             C   s   g }| j |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
        )rR  r  )r   rV  rW  rS  r)   r)   r*   listdir'  s    	zOleFileIO.listdirc             C   s^   t |tr|jd}| j}x<|D ]4}x*|jD ]}|jj |j kr,P q,W td|}q W |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)	rX   
basestringsplitr  r   r'   r   rD  r   )r   r[   rU  r'   r   r)   r)   r*   _find5  s    


zOleFileIO._findc             C   s6   | j |}| j| }|jtkr&td| j|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
   rD  rG  r   r   )r   r[   r   r   r)   r)   r*   
openstreamU  s
    


zOleFileIO.openstreamc             C   s   |j s|j|  t|j }| jj s.| jj|  | j| j }xt|j D ]\}}|| }|| }| jj | d | j || j  }	||d k r||| j |d | j  }
n||| j d  }
| j|	|
 qFW d S )Nr#   )r   r   rV   r  r  r  	enumeraterN  )r   r   data_to_writer   Z
block_sizeidxr   Z	sect_baseZsect_offsetrM  Zdata_per_sectorr)   r)   r*   _write_mini_streamj  s    

 zOleFileIO._write_mini_streamc       
      C   s  t |tstd| j|}| j| }|jtkr8td|j}|t	|krRt
d|| jk rt|jtkrt| j||dS |j}|| jd  | j }tjd|  xt|D ]}||d k r||| j |d | j  }	t	|	| jkstnR||| j d }	tjd|| jt	|	|| j f  t	|	| j || j ks8t| j||	 y| j| }W q tk
rp   td	Y qX qW |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#   znb_sectors = %dNzGwrite_stream: size=%d sectorsize=%d data_sector=%Xh size%%sectorsize=%dz,incorrect OLE FAT, sector index out of rangez)incorrect last sector index in OLE stream)rX   rY   rH  r\  r   r   r
   rD  r   rV   rI  r   r   ra  r   r   r-   r   r   rj   rL  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*   y| j |}| j| }|jS    dS 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
        FN)r\  r   r   )r   r[   r   r   r)   r)   r*   get_type  s    

zOleFileIO.get_typec             C   s   | j |}| 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   rn   )r   r[   r   r   r)   r)   r*   getclsid  s    


zOleFileIO.getclsidc             C   s   | j |}| j| }|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)   r)   r*   r     s    

zOleFileIO.getmtimec             C   s   | j |}| j| }|j S )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)   r*   r     s    

zOleFileIO.getctimec          	   C   s   y| j |}dS    dS 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.
        TFN)r\  )r   r[   r   r)   r)   r*   r     s
    	
zOleFileIO.existsc             C   s,   | j |}| 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
   rH  r   )r   r[   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.
        )r  r'   )r   r)   r)   r*   get_rootentry_name  s    zOleFileIO.get_rootentry_namec              C   s@  |dkrg }|}t |ts$dj|}| j|}i }yn|jd}t|dd }|jd}t|dd }	|jt|d d|jt|jd	d	  }t|d	}
W nB tk
r } z&d
t	||f }| j
t|t| |S d}~X nX t|
t|d }
xBt|
D ]4}d}yt|d|d  }t|d|d  }t||}tjd|||f  |tkrt||d	 }|dkr|d }nb|tkrt||d	 }nF|tttfkrt||d	 }n$|ttfkrt||d	 }n|ttfkr&t||d	 }||d |d | d  }|jdd}n|tkrZt||d	 }||d |d |  }n|tkrt||d	 }| j||d |d |d   }nJ|t kr<t!t||d	 t!t||d d>  }|r2||kr2tjd||t"|d f  t#j#dddddd}tjd|d!   |t#j$|d d }n|d }n|t%krXt&||d	  }n|t'kr|t||d	 |d  }nf|t(krt||d	 }||d |d |  }n4|t)krt*t||d	 }nd}tjd||f  |||< W nH tk
r4 } z*d|t	||f }| j
t|t| W Y dd}~X nX q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)
        NrY  rE   r2   rA   r=   r9   s   ****r   z6Error while parsing properties header in stream %s: %sr   r6   z!property id=%d: type=%d offset=%Xi   i   r#   rh   r   r.   r   z8Converting property #%d to python datetime, value=%d=%fsi iA  ztimedelta days=%dr4   i@B i  )rp   z5property id=%d: type=%d not implemented in parser yetz3Error while parsing property id %d in stream %s: %si l    hC! l    @T$)+rX   rP  r   r]  rS   ro   rW   rg   BaseExceptionr   r   r   typeminrV   rE  r-   r   VT_I2rf   VT_UI2VT_I4VT_INTVT_ERRORVT_UI4VT_UINTVT_BSTRVT_LPSTRr  VT_BLOB	VT_LPWSTRr   VT_FILETIMEr   floatrq   rr   VT_UI1r`   VT_CLSIDVT_CFVT_BOOLbool)r   r[   r   r   Z
streampathr]   r   rA  rn   ZfmtidZ	num_propsexcmsgr!   Zproperty_idr   Zproperty_typer   countrs   r)   r)   r*   r   &  s    










&
(




*zOleFileIO.getpropertiesc             C   s   t  | _| j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  )F)F)r   )r   )rh   )rh   )TF)TF)FN)*r   r   r   r   r   r   r   rD  r   r   rZ   r,  r   r3  r;  r=  rB  r)  r   r@  rL  rN  r*  r   rO  r   rG  rR  rX  r\  r]  ra  rb  rc  rd  r   r   r   re  rf  r   r  r)   r)   r)   r*   r     sL   L

 a

%
$T$ 

)&

 >
 __main__r  )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loglevelZ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(   format-z%r: properties)r   2      z(binary data)z   z&Error while parsing property stream %rz
Checking streams...rY  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:z- %s: %sNonezError while parsing file %r)r   )r   )r#   r.   r"   r   r/   r0   r1   r5   r6   r8   r  r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   rE   rF   rG   rH   )r   Z
__future__r   Z__date____version__
__author____all__r   r7  rc   r5  os.pathr%  rq   r$   rP  rY   rb   r   ZxrangerE  r   itemsizer6  rI  rZ  	NameErrorr	   version_infor   ZCRITICALr+   r-   r   r   r   r   r   r   r   r   r   r   r   r
   r   r   r   r   ZVT_EMPTYZVT_NULLrj  rl  ZVT_R4ZVT_R8ZVT_CYZVT_DATErq  ZVT_DISPATCHrn  rz  Z
VT_VARIANTZ
VT_UNKNOWNZ
VT_DECIMALZVT_I1rw  rk  ro  ZVT_I8ZVT_UI8rm  rp  ZVT_VOIDZ
VT_HRESULTZVT_PTRZVT_SAFEARRAYZ	VT_CARRAYZVT_USERDEFINEDrr  rt  ru  rs  Z	VT_STREAMZ
VT_STORAGEZVT_STREAMED_OBJECTZVT_STORED_OBJECTZVT_BLOB_OBJECTry  rx  Z	VT_VECTORZVTr   varsitemskeywordvarr   r   r   r   r   r   r   r`   rf   rg   ro   rt   r   r   r   r   r   r   ZoptparseZDEFAULT_LOG_LEVELr?  INFOZWARNINGZERRORZ
LOG_LEVELSr  ZOptionParserparserZ
add_option
parse_argsZoptionsargsr   rV   Z
print_helpexitr  r  ZbasicConfigr[   r   rO  rX  Z
streamnamer   r   sortedkvrX   r_   r(  Z	exceptionr  r   r   rc  Zst_typere  r]  r   r   r'   r   r   r  metar   rf  r  r   r   exctyper}  r)   r)   r)   r*   <module>   s  <
(

                                *





              






