B
    0#˜[_› ã               @   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	ršeZyeZW n   eZY nX e
 
d"¡jd#krÊd"Zn4e
 
d$¡jd#kràd$Zne
 
d%¡jd#kröd%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@dBZAdCZBdDZCdEZDdFZEdGZFdHZGdIZHdJZIdKZJdLZKdMZLdNZMdOZNdPZOdQZPdRZQdSZRdTZSdUZTdVZUdWZVdXZWdYZXdZZYd[ZZd<Z[dEZ\dOZ]d\Z^d]Z_d^d„ Z`eekrvd_d`„ Zandad`„ Zadsdbdc„Zbdtddde„Zcdfdg„ Zddhdi„ ZeG djd„ dƒZfG dkdl„ dlejgƒZhG dmdn„ dnƒZiG dod„ dƒZjdpdq„ Zkeldrkröekƒ  d!S )ua:  
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k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ÚlevelZlogger© r)   ú.lib/python3.7/site-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    s   ÐÏà¡±ál   úÿ l   üÿ l   ýÿ l   þÿ l   ÿÿ é   é   iÿÿÿé   é   é   é	   é
   é   é   é   é   é   é   é   é   é   é   é   é   é   é   é   é   é   é   é   é   é@   éA   éB   éC   éD   éE   éF   éG   éH   i   z$00020900-0000-0000-C000-000000000046é(   i   c          	   C   s„   t | dƒr$|  ttƒ¡}|  d¡ nLt| tƒrLt| ƒtkrL| dttƒ… }n$t| dƒ}| 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`   C  s    c             C   s   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<Hr.   r   )ÚstructÚunpack)r_   Úor)   r)   r*   Úi16G  s    rf   c             C   s   t  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*   Úi32Q  s    rg   c             C   sT   t | ƒdkst‚|  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.
    r9   ó    Ú z0%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02Xr   r   r0   r2   )rV   ÚAssertionErrorÚstriprg   rf   ÚtupleÚmapr`   )Úclsidr)   r)   r*   Ú_clsid[  s    
ro   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
        iA  r#   r   r4   )Úmicroseconds)ÚdatetimeÚ	timedelta)ZfiletimeÚ_FILETIME_null_dater)   r)   r*   Úfiletime2datetimel  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 | d¡rx|jdddgd}x8tt| j ƒƒD ]&}| |d d¡}t| | j | |ƒ qNW | d¡rÊ|jddd}x8tt| jƒƒD ]&}| |d d¡}t| | j| |ƒ q W 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   z  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  d¡ t  d|||||t|ƒt|ƒf ¡ || _| jjjrFtdƒ‚d}	|tkrlt|ƒ| }d}	t  d¡ ||d  | }
t  d|
 ¡ |
t|ƒkr¤| j 	t
d	¡ g }|d
krÐ|tkrÐt  d¡ | j 	t
d¡ x¼t|
ƒD ]®}t  d||f ¡ |tkr*|	rt  d¡ P nt  d¡ | j 	t
d¡ |d
k sB|t|ƒkr|t  d||t|ƒf ¡ t  d||
f ¡ | j 	t
d¡ P y| |||  ¡ W n8   t  d||||  |f ¡ | j 	t
d¡ P Y nX | |¡}t|ƒ|krJ|t|ƒd krJt  d|t|ƒ|||  |t|ƒf ¡ t  d|||  t|ƒ  ¡ | j 	t
d¡ | |¡ y|| d@ }W qÜ tk
rŠ   | j 	t
d¡ P Y qÜX qÜW d |¡}t|ƒ|krÒt  dt|ƒ|f ¡ |d|… }|| _nR|	röt  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#   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 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 tj|¡\| _	| _
| _| _| _| _| _}| _| _| _| _| _| _| jttttgkr€| td¡ | jtkrž|dkrž| td¡ |dkr¼| jtkr¼| td¡ | j
dkrØ| 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ržt  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kr`| j$dkr`| j$|j*k rJ| jtkrJd| _)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 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rB|jsB| ¡  | j	}x4|t
kr|| j  |¡ | jrp|j| }qJ|j| }qJW 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  d| jt| jƒ| jf ¡ | jtkr>|  | 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_tree@  s
    
	z$OleDirectoryEntry.build_storage_treec             C   sî   t  d| ¡ |tkrdS |dk s2|t| jjƒkrB| j td¡ n¨| j |¡}t  d|j	t
|jƒ|j|j|jf ¡ |jrŒ| j td¡ dS d|_|  |j¡ |j ¡ }|| jkrÀ| 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   rV   r,   Ú
direntriesr¾   r   Ú_load_direntryrÐ   r²   r'   rÖ   r×   rØ   rÓ   rç   ÚlowerrÒ   rÑ   r¿   ré   )r¢   Z	child_sidZchildZ
name_lowerr)   r)   r*   rç   X  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   |   |¡ S )N)rî   )r¢   rí   r)   r)   r*   Ú__ne__  s    zOleDirectoryEntry.__ne__c             C   s   |   |¡p|  |¡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}y|| j  }W n tk
r6   d}Y nX td| t| jƒ |dd	 | j ttfkrrt| jd
dd	 tƒ  | j ttfkr¢| j	r¢td| d| j	  ƒ x| j
D ]}| |d ¡ qªW 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)z	(UNKNOWN)ú )ÚendrY   z{%s}r.   N)rÕ   rÀ   r°   r²   r'   r
   r   rÂ   r   rn   rÑ   r³   )r¢   ÚtabZTYPESZ	type_nameÚ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               @   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dRdd„ZdSdd„ZdTdd„Zdd„ Zdd„ Zdd„ Zd d!„ Zd"d#„ ZdUd%d&„ZdVd'd(„Zd)d*„ Zd+d,„ Zd-d.„ Zedfd/d0„ZdWd2d3„ZdXd4d5„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)dYdLdM„Z*dNdO„ Z+dS )Zr   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   | S )Nr)   )r¢   r)   r)   r*   Ú	__enter__6  s    zOleFileIO.__enter__c             G   s   |   ¡  d S )N)Úclose)r¢   Úargsr)   r)   r*   Ú__exit__:  s    zOleFileIO.__exit__c             C   s<   || j krt |¡ ||ƒ‚n| 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 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Ü   X  s    
zOleFileIO._decode_utf16_strc       	      C   sž  || _ t|dƒr|| _n@t|tƒr<t|ƒtkr<t |¡| _n| j rHd}nd}t	||ƒ| _d}| j 
dtj¡ z| j ¡ }W d| j 
d¡ X || _t d| j| jf ¡ g | _g | _| j d¡}t|ƒdksÜ|dd… tkrt 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kr|  t-d¡ t d| j ¡ | jdkr,|  t-d¡ d| j | _.t d| j. ¡ | j.dkr`|  t-d¡ | jdkrx| j.dks| jdkrœ| j.dkrœ|  t-d¡ d| j  | _/t d | j/ ¡ | j/d!krÐ|  t-d"¡ | j!dksè| 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rp|  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)rh|  7| j(¡ | j+r||  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)
        rS   zr+brT   r   NzFile size: %d bytes (%Xh)i   r2   zMagic = %r instead of %rz#not an OLE2 structured storage filez<8s16sHHHHHHLLLLLLLLLLzfmt_header size = %d, +FAT = %di´  zincorrect OLE signaturer9   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 headerr.   z0Sector Size   = %d bytes (expected: 512 or 4096))i   i   z#incorrect sector_size in OLE headerr"   r   i   z3sector_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   );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   k  s¨    
'
T

zOleFileIO.openc             C   s   | j  ¡  dS )z@
        close the OLE file, to release the file object
        N)r]   r  )r¢   r)   r)   r*   r  K  s    zOleFileIO.closec             C   sf   |rt  d| ¡ | j}n(t  d| ¡ |ttttfkr<dS | j}||krX|  t	d¡ n
| 
|¡ 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	 x t|ƒD ]}td
| dd	 qFW tƒ  xœt|ƒD ]}|| }	td||	  dd	 xht|	|	| ƒD ]V}||kr¬P || }
|
d@ }||krÎ|| }n|
|d kràd}nd
|
 }t|dd	 qžW 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*   Údumpfatl  s4    
zOleFileIO.dumpfatc             C   sä   d}t   t|¡}tjdkr"| ¡  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r¶P || }
d|
 }t|dd q¨W 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   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)
        r4  )r5  r6  r7  r8  r9  )r¢   rÅ   Úar)   r)   r*   Ú
sect2arrayª  s    
zOleFileIO.sect2arrayc             C   sš   t |tjƒr|}n |  |¡}t tj¡r2|  |¡ d}x^|D ]V}|d@ }t d| ¡ |t	ksf|t
krrt d¡ P |  |¡}|  |¡}| 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  d¡ |dd… }t  dt|ƒt|ƒd f ¡ t t¡| _|  |¡ | jdkrrt  d¡ | jdkrv|  	t
d	¡ | j| jkrŽ|  	td
¡ t  d¡ | jd d }| jd | d | }t  d| ¡ | j|krÜtdƒ‚| j}xvt|ƒD ]j}t  d||f ¡ |  |¡}|  |¡}t  tj¡r.|  |¡ |  |d|… ¡ || }t  d| ¡ qìW |ttgkr|tdƒ‚n
t  d¡ t| jƒ| jkrºt  dt| jƒ| jf ¡ | jd| j… | _t  dt| jƒ| jf ¡ t  tj¡røt  d¡ |  | j¡ dS )z%
        Load the FAT table.
        zDLoading the FAT table, starting with the 1st sector after the headeréL   i   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º   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 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¡rÜt d
¡ |  | 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|d  ¡ W n8   t d|| j|d  | jf ¡ |  td¡ Y nX | j  | j¡}t	|ƒ| jkr–t 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=%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@  R  s    zOleFileIO.getsectrh   c          
   C   sÐ   t |tƒstdƒ‚t |tƒr(t|ƒdkr0tdƒ‚y| j | j|d  ¡ W n8   t d|| j|d  | j	f ¡ |  
td¡ Y nX t|ƒ| jk rª||| 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=%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_sectr  s    
zOleFileIO.write_sectc             C   s´   t |tƒstdƒ‚t |tƒr(t|ƒdkr0tdƒ‚y| j |¡ W n,   t d|| jf ¡ |  	t
d¡ Y nX t|ƒ}|| jk r’||| j|  7 }| j|k r¤t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=%dzOLE sector index out of rangezData is larger than sector sizeN)rX   rY   rI  rV   r]   rW   r-   rº   rý   r¾   r   r  rJ  rK  )r¢   Úfp_posrÌ   rL  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:T)rG  rÎ   z&loaddirectory: size=%d, max_entries=%dNr   )	r-   rº   rH  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"|  td¡ | j| dk	rF|  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Î   )	rV   rê   r¾   r   r   r  rW   rS   rÍ   )r¢   rÐ   râ   r)   r)   r*   rë   Ï  s    
zOleFileIO._load_direntryc             C   s   | j  ¡  dS )z5
        Dump directory (for debugging only)
        N)r  r³   )r¢   r)   r)   r*   Údumpdirectoryé  s    zOleFileIO.dumpdirectoryc          
   C   s°   t  d||t|ƒf ¡ || jk rŠ|sŠ| jsh|  ¡  | 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 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)rG  r   )r]   rÅ   rÂ   rÆ   rÇ   rÈ   rÉ   rÊ   N)r-   rº   Ústrrß   rþ   rå   r  rÂ   rÛ   rH  r¸   r  rä   r]   rÇ   rÈ   rý   )r¢   ÚstartrÂ   rG  Zsize_ministreamr)   r)   r*   rH  ð  s&    




zOleFileIO._openTc             C   s’   ||j g }x€|jD ]v}|jtkrT|r@| |dd… |j g ¡ |  |||||¡ q|jtkr~|rŠ| |dd… |j g ¡ q|  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*   rS    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
        )rS  r  )r¢   rW  rX  rT  r)   r)   r*   Úlistdir3  s    	zOleFileIO.listdirc             C   s^   t |tƒr| d¡}| j}x<|D ]4}x*|jD ]}|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ì   rE  rÐ   )r¢   r[   rV  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
   rE  rH  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 }xŽt|j ƒD ]€\}}|| }|| }| jj | d | j || j  }	||d k r¨||| j |d | j … }
n||| j d … }
|  |	|
¡ qFW d S )Nr#   )rá   ræ   rV   r  r  r  Ú	enumeraterO  )r¢   râ   Údata_to_writerË   Z
block_sizeÚidxrÅ   Z	sect_baseZsect_offsetrN  Zdata_per_sectorr)   r)   r*   Ú_write_mini_streamv  s    

 zOleFileIO._write_mini_streamc       
   	   C   sŒ  t |tƒstdƒ‚|  |¡}| 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 d| ¡ xØt|ƒD ]Ì}||d k ræ||| j |d | j … }	t	|	ƒ| jksät‚nR||| j d… }	t d|| jt	|	ƒ|| j f ¡ t	|	ƒ| j || j ks8t‚|  ||	¡ y| j| }W q¦ tk
rp   td	ƒ‚Y q¦X q¦W |tkrˆt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   rI  r]  rê   rÕ   r
   rE  rÂ   rV   rJ  rß   r   rb  rÛ   rÇ   r-   rº   r«   rj   rM  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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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| }| ¡ 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| }| ¡ 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|   |¡}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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
   rI  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   sF  |dkrg }|}t |tƒs$d |¡}|  |¡}i }yn| d¡}t|dd… ƒ}| d¡}t|dd… ƒ}	| t|dƒ¡ d| t| d	¡ƒd	 ¡ }t|d	ƒ}
W nD tk
rä } z&d
t	|ƒ|f }|  
t|t|ƒ¡ |S d}~X Y nX t|
tt|ƒd ƒƒ}
xBt|
ƒD ]4}d}yÞt|d|d  ƒ}t|d|d  ƒ}t||ƒ}t d|||f ¡ |tkr†t||d	 ƒ}|dkrè|d }nb|tkr¢t||d	 ƒ}nF|tttfkrÄt||d	 ƒ}n$|ttfkrät||d	 ƒ}n|ttfkr,t||d	 ƒ}||d |d | d … }| dd¡}n¼|tkr`t||d	 ƒ}||d |d | … }nˆ|tkržt||d	 ƒ}|   ||d |d |d  … ¡}nJ|t!krBt"t||d	 ƒƒt"t||d ƒƒd>  }|r8||kr8t d||t#|ƒd f ¡ t$ $dddddd¡}t d|d  ¡ |t$j%|d d }n|d }n¦|t&kr^t'||d	  ƒ}nŠ|t(kr‚t||d	 |d … ƒ}nf|t)kr´t||d	 ƒ}||d |d | … }n4|t*krÒt+t||d	 ƒƒ}nd}t d||f ¡ |||< W nH tk
r: } z(d|t	|ƒ|f }|  
t|t|ƒ¡ W dd}~X Y 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)
        NrZ  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=%dl    @ÓT$r4   )rp   z5property id=%d: type=%d not implemented in parser yetz3Error while parsing property id %d in stream %s: %s),rX   rQ  rÁ   r^  rS   ro   rW   rg   ÚBaseExceptionr²   r¾   r   ÚtypeÚminrb   rV   rF  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ª   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"  )F)F)r   )r   )rh   )rh   )TF)TF)FN),r´   rµ   r¶   r·   r   r   r£   r  r  rE  r¾   rÜ   rZ   r  rà   r3  r;  r=  rB  r*  rå   r@  rM  rO  r+  rë   rP  r   rH  rS  rY  r]  r^  rb  rc  rd  re  rö   r÷   r©   rf  rg  rª   r€  r)   r)   r)   r*   r   Ì  sP   L

 a

%
$T$ 

)&

 >
 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rÄd|_tj||j dd tƒ  xÖ|D ]Ì}yªt|ƒ}	tdƒ t|ƒ tdƒ |	 ¡  xä|	 ¡ D ]Ø}
|
d d dkr"td|
 ƒ y˜|	j|
dd}t| ¡ ƒ}xx|D ]p\}}t|ttfƒr˜t|ƒdkr˜|dd… }t|tƒrÈx"d D ]}|t|ƒkrªd!}P qªW td"||ƒ qfW W n   t  !d#|
 ¡ Y nX q"W |j"r€td$ƒ xj|	 ¡ D ]^}
td%t#d& $|
¡ƒd%d'd( |	 %|
¡}|t&krhtd)|	 '|
¡ ƒ |	 (|
¡ ntd*| ƒ qW tƒ  td+ƒ x6|	j)D ],}|dk	rtd,|j*| +¡ | ,¡ f ƒ qW tƒ  y|	 -¡ }| .¡  W n   t  !d-¡ Y nX tƒ  |	 /¡ }td.| ƒ |	 0d/¡rTtd0ƒ td1|	 %d/¡ƒ td2|	 'd/¡ƒ |	 0d3¡rTtd4ƒ td5ƒ |	j1rŽx0|	j1D ]\}}td6|j2|f ƒ qlW ntd7ƒ W qæ   t  !d8| ¡ Y qæX qæW d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Ú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(   ÚformatzD--------------------------------------------------------------------éÿÿÿÿúz%r: propertiesT)r¤   é2   )r#   r.   r"   r   r/   r0   r1   r5   r6   r8   é   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   rE   rF   rG   rH   z(binary data)z   z&Error while parsing property stream %rz
Checking streams...ú-rZ  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)3r7  Úoptparser$   r?  ÚINFOZWARNINGZERRORÚCRITICALZOptionParserZ
add_optionÚ
parse_argsr°   Ú__version__Ú__date__rV   r·   Z
print_helpÚexitrˆ  r‰  ZbasicConfigr   r   rP  rY  rª   ÚsortedÚitemsrX   r[  rY   r)  r-   Z	exceptionr„  r²   rÁ   rd  r
   rf  r^  rê   r'   rö   r÷   r€  r³   rg  r©   rû   r´   )r7  r’  ZDEFAULT_LOG_LEVELZ
LOG_LEVELSr‚  ÚparserZoptionsr  r[   r»   Z
streamnamer­   ÚkÚvr_   Zst_typerâ   Úmetar  Úexctyper~  r)   r)   r*   ÚmainÛ  s®    






r   Ú__main__)r   )r   )mr·   Z
__future__r   r—  r–  Ú
__author__Ú__all__rÃ   r7  rc   r5  Úos.pathr&  rq   r$   rQ  rY   rb   rÝ   ZxrangerF  r«   Úitemsizer6  rJ  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_NULLrk  rm  ZVT_R4ZVT_R8ZVT_CYZVT_DATErr  ZVT_DISPATCHro  r{  Z
VT_VARIANTZ
VT_UNKNOWNZ
VT_DECIMALZVT_I1rx  rl  rp  ZVT_I8ZVT_UI8rn  rq  ZVT_VOIDZ
VT_HRESULTZVT_PTRZVT_SAFEARRAYZ	VT_CARRAYZVT_USERDEFINEDrs  ru  rv  rt  Z	VT_STREAMZ
VT_STORAGEZVT_STREAMED_OBJECTZVT_STORED_OBJECTZVT_BLOB_OBJECTrz  ry  Z	VT_VECTORr   r   r   r   r   r   r   r`   rf   rg   ro   rt   r   rÄ   r¸   rÍ   r   r   r´   r)   r)   r)   r*   Ú<module>   s  <
(

                                *





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