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

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

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

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

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

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

See source code and LICENSE.txt for information on usage and redistribution.
é    )Úprint_functionz
2018-09-09z0.46zPhilippe Lagadec)Ú	isOleFileÚ	OleFileIOÚOleMetadataÚenable_loggingÚMAGICÚSTGTY_EMPTYÚKEEP_UNICODE_NAMESÚSTGTY_STREAMÚSTGTY_STORAGEÚ
STGTY_ROOTÚSTGTY_PROPERTYÚSTGTY_LOCKBYTESÚMINIMAL_OLEFILE_SIZEÚDEFECT_UNSUREÚDEFECT_POTENTIALÚDEFECT_INCORRECTÚDEFECT_FATALÚDEFAULT_PATH_ENCODINGÚ
MAXREGSECTÚDIFSECTÚFATSECTÚ
ENDOFCHAINÚFREESECTÚ	MAXREGSIDÚNOSTREAMÚUNKNOWN_SIZEÚ
WORD_CLSIDNÚLé   ÚIÚiz>Need to fix a bug with 32 bit arrays, please contact author...Té   zutf-8é   c                 C   sL   | t jjjv rt  | ¡}| |¡ |S t  | ¡}| t  ¡ ¡ | |¡ |S )an  
    Create a suitable logger object for this module.
    The goal is not to change settings of the root logger, to avoid getting
    other modules' logs on the screen.
    If a logger exists with same name, reuse it. (Else it would have duplicate
    handlers and messages would be doubled.)
    The level is set to CRITICAL+1 by default, to avoid any logging.
    )ÚloggingÚLoggerÚmanagerÚ
loggerDictÚ	getLoggerÚsetLevelÚ
addHandlerÚNullHandler)ÚnameÚlevelÚlogger© r/   ú1/usr/lib/python3/dist-packages/olefile/olefile.pyÚ
get_logger¦   s   



r1   Ú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$   ÚNOTSETr/   r/   r/   r0   r   Å   s   r   s   ÐÏà¡±ál   úÿ l   üÿ l   ýÿ l   þÿ ì   ÿÿ é   é   iÿÿÿé   é   é   é	   é
   é   é   é   é   é   é   é   é   é   é   é   é   é   é   é   é   é   é   é   é   é@   éA   éB   éC   éD   éE   éF   éG   éH   é   z$00020900-0000-0000-C000-000000000046é(   i   c                 C   s”   t | dƒr|  ttƒ¡}|  d¡ n0t| tƒr&t| ƒtkr&| dttƒ… }nt| dƒ�}| ttƒ¡}W d  ƒ n1 s=w   Y  |tkrHdS dS )aJ  
    Test if a file is an OLE container (according to the magic bytes in its header).

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

    .. versionadded:: 0.16

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

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

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

    :param c: string containing bytes to convert
    :param o: offset of bytes to convert in string
    z<Hr6   r   ©ÚstructÚunpack©rj   Úor/   r/   r0   Úi16G  ó   ru   c                 C   ro   )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   rp   rs   r/   r/   r0   Úi32Q  rv   rw   c                 C   sT   t | ƒdksJ ‚|  d¡sdS dt| dƒt| dƒt| dƒfttt| dd… ƒƒ  S )	z^
    Converts a CLSID to a human-readable string.

    :param clsid: string of length 16.
    rA   ó    Ú z0%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02Xr   r   r8   r:   )r_   Ústriprw   ru   ÚtupleÚmaprk   )Úclsidr/   r/   r0   Ú_clsid[  s   
ÿÿr~   c                 C   s(   t   dddddd¡}|t j| d d� S )zL
        convert FILETIME (64 bits int) to Python datetime.datetime
        éA  r#   r   r<   ©Úmicroseconds)ÚdatetimeÚ	timedelta)ÚfiletimeÚ_FILETIME_null_dater/   r/   r0   Úfiletime2datetimel  s   r†   c                   @   s8   e Zd ZdZg d¢Zg d¢Zdd„ Zdd„ Zdd	„ Zd
S )r   aT  
    class to parse and store metadata from standard properties of OLE files.

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

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

    References for SummaryInformation stream:

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

    References for DocumentSummaryInformation stream:

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

    new in version 0.25
    )ÚcodepageÚtitleÚsubjectÚauthorÚkeywordsÚcommentsÚtemplateÚlast_saved_byÚrevision_numberÚtotal_edit_timeÚlast_printedÚcreate_timeÚlast_saved_timeÚ	num_pagesÚ	num_wordsÚ	num_charsÚ	thumbnailÚcreating_applicationÚsecurity)Úcodepage_docÚcategoryÚpresentation_targetrb   ÚlinesÚ
paragraphsÚslidesÚnotesÚhidden_slidesÚmm_clipsÚ
scale_cropÚheading_pairsÚtitles_of_partsr&   ÚcompanyÚlinks_dirtyÚchars_with_spacesÚunusedÚ
shared_docÚ	link_baseÚhlinksÚhlinks_changedÚversionÚdig_sigÚcontent_typeÚcontent_statusÚlanguageÚdoc_versionc                 C   s  d| _ d| _d| _d| _d| _d| _d| _d| _d| _d| _	d| _
d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _d| _ d| _!d| _"d| _#d| _$d| _%d| _&d| _'d| _(d| _)d| _*d| _+d| _,d| _-d| _.dS )z_
        Constructor for OleMetadata
        All attributes are set to None by default
        N)/r‡   rˆ   r‰   rŠ   r‹   rŒ   r�   rŽ   r�   r�   r‘   r’   r“   r”   r•   r–   r—   r˜   r™   rš   r›   rœ   rb   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/   r0   Ú__init__®  s^   
zOleMetadata.__init__c                 C   sÆ   | j | j D ]}t| |dƒ q| d¡r8|jdddgd�}tt| j ƒƒD ]}| |d d¡}t| | j | |ƒ q$| d¡r_|jddd�}tt| jƒƒD ]}| |d d¡}t| | j| |ƒ qKdS dS )	a=  
        Parse standard properties of an OLE file, from the streams
        ``\x05SummaryInformation`` and ``\x05DocumentSummaryInformation``,
        if present.
        Properties are converted to strings, integers or python datetime objects.
        If a property is not present, its value is set to None.
        NzSummaryInformationTr<   )Úconvert_timeÚno_conversionr#   zDocumentSummaryInformation©r·   )ÚSUMMARY_ATTRIBSÚDOCSUM_ATTRIBSÚsetattrÚexistsÚgetpropertiesÚranger_   Úget)rµ   r2   ÚattribÚpropsr!   Úvaluer/   r/   r0   Úparse_propertiesæ  s$   	
ÿ
ÿøzOleMetadata.parse_propertiesc                 C   sh   t dƒ | jD ]}t| |ƒ}t d|t|ƒf ƒ qt dƒ | jD ]}t| |ƒ}t d|t|ƒf ƒ q dS )z<
        Dump all metadata, for debugging purposes.
        z*Properties from SummaryInformation stream:ú- %s: %sz2Properties from DocumentSummaryInformation stream:N)Úprintrº   ÚgetattrÚreprr»   )rµ   ÚproprÃ   r/   r/   r0   Údump  s   



þzOleMetadata.dumpN)	Ú__name__Ú
__module__Ú__qualname__Ú__doc__rº   r»   r¶   rÄ   rÊ   r/   r/   r/   r0   r   z  s    $8 r   c                   @   s   e Zd ZdZdd„ ZdS )Ú	OleStreamaÂ  
    OLE2 Stream

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

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

    Attributes:

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

        :param fp: file object, the OLE container or the MiniFAT stream
        :param sect: sector index of first sector in the stream
        :param size: total size of the stream
        :param offset: offset in bytes for the first FAT or MiniFAT sector
        :param sectorsize: size of one sector
        :param fat: array/list of sector indexes (FAT or MiniFAT)
        :param filesize: size of OLE file (for debugging)
        :param olefileio: OleFileIO object containing this stream
        :returns: a BytesIO instance containing the OLE stream
        zOleStream.__init__:zE  sect=%d (%X), size=%d, offset=%d, sectorsize=%d, len(fat)=%d, fp=%sz2Attempting to open a stream from a closed OLE FileFTz  stream with UNKNOWN SIZEr#   únb_sectors = %dz(malformed OLE document, stream too larger   z!size == 0 and sect != ENDOFCHAIN:z+incorrect OLE sector index for empty streamzReading stream sector[%d] = %Xhz6Reached ENDOFCHAIN sector for stream with unknown sizez$sect=ENDOFCHAIN before expected sizezincomplete OLE streamzsect=%d (%X) / len(fat)=%dzi=%d / nb_sectors=%dú,incorrect OLE FAT, sector index out of rangezsect=%d, seek=%d, filesize=%dúOLE sector index out of rangez9sect=%d / len(fat)=%d, seek=%d / filesize=%d, len read=%dzseek+len(read)=%dúincomplete OLE sectorr5   ó    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)r3   Údebugr_   rÈ   Úolerf   ÚclosedÚOSErrorr   Ú_raise_defectr   r   r¿   r`   r\   ÚappendÚ
IndexErrorÚjoinÚsizeÚioÚBytesIOr¶   )rµ   rf   ÚsectrÝ   ÚoffsetÚ
sectorsizeÚfatÚfilesizeÚ	olefileioÚunknown_sizeÚ
nb_sectorsÚdatar!   Úsector_datar/   r/   r0   r¶   *  s†   
ÿ




ÿ
 ÿ
ü

zOleStream.__init__N)rË   rÌ   rÍ   rÎ   r¶   r/   r/   r/   r0   rÏ     s    rÏ   c                   @   s„   e Zd ZdZdZdZe e¡eksJ ‚dd„ Zdd„ Z	dd	„ Z
d
d„ Zdd„ Zdd„ Zdd„ Zdd„ Zddd„Zdd„ Zdd„ ZdS )ÚOleDirectoryEntryz
    OLE2 Directory Entry
    z<64sHBBIII16sIQQIIIé€   c                 C   s`  || _ || _g | _i | _d| _t tj|¡\| _	| _
| _| _| _| _| _}| _| _| _| _| _| _| jttttfvr@| td¡ | jtkrO|dkrO| td¡ |dkr^| jtkr^| td¡ | j
dkrl| td¡ d| _
| j	d| j
d	 … | _| | j¡| _t  d
| j t!| jƒf ¡ t  d| j ¡ t  d| j ¡ t  d| j| j| jf ¡ |j"dkrÑ| jdkrÌ| jdk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v �r+| j$dk�r+| j$|j*k �r | jtk�r d| _)nd| _)| +| j| j)¡ d| _,dS )aI  
        Constructor for an OleDirectoryEntry object.
        Parses a 128-bytes entry from the OLE Directory stream.

        :param entry  : string (must be 128 bytes long)
        :param sid    : index of this directory entry in the OLE file directory
        :param olefile: OleFileIO containing this directory entry
        Fzunhandled OLE storage typer   zduplicate OLE root entryzincorrect OLE root entryrQ   z(incorrect DirEntry name length >64 bytesNr6   zDirEntry SID=%d: %sz - type: %dz - sect: %Xhz% - SID left: %d, right: %d, child: %dé   r5   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)-Úsidr2   ÚkidsÚ	kids_dictÚusedrq   rr   rê   ÚSTRUCT_DIRENTRYÚname_rawÚ
namelengthÚ
entry_typeÚcolorÚsid_leftÚ	sid_rightÚ	sid_childÚdwUserFlagsÚ
createTimeÚ
modifyTimeÚ
isectStartÚsizeLowÚsizeHighr   r   r
   r   rÙ   r   Ú
name_utf16Ú_decode_utf16_strr,   r3   rÕ   rÈ   râ   r   rÝ   Úlongr~   r}   r   Ú
is_minifatÚminisectorcutoffÚ_check_duplicate_streamÚ
sect_chain)rµ   Úentryrî   r2   r}   r/   r/   r0   r¶   Ë  st   	ñ

ÿ
ÿ


zOleDirectoryEntry.__init__c                 C   sˆ   | j rd S | jttfvs| jdkrd S tƒ | _ | jr!|js!| ¡  | j	}|t
krB| j  |¡ | jr7|j| }n|j| }|t
ks(d S d S rl   )r  rõ   r   r
   rÝ   Úlistr  ÚminifatÚloadminifatrý   r   rÚ   rã   )rµ   r2   Ú	next_sectr/   r/   r0   Úbuild_sect_chain-  s   
ûz"OleDirectoryEntry.build_sect_chainc                 C   sF   t  d| jt| jƒ| jf ¡ | jtkr!|  | j¡ | j 	¡  dS dS )z÷
        Read and build the red-black tree attached to this OleDirectoryEntry
        object, if it is a storage.
        Note that this method builds a tree of all subentries, so it should
        only be called for the root object once.
        z.build_storage_tree: SID=%d - %s - sid_child=%dN)
r3   rÕ   rî   rÈ   r,   rù   r   Úappend_kidsrï   Úsortr´   r/   r/   r0   Úbuild_storage_tree@  s   ÿ
	ôz$OleDirectoryEntry.build_storage_treec                 C   sð   t  d| ¡ |tkrdS |dk s|t| jjƒkr"| j td¡ dS | j |¡}t  d|j	t
|jƒ|j|j|jf ¡ |jrG| j td¡ dS d|_|  |j¡ |j ¡ }|| jv ra| j td¡ | j |¡ || j|< |  |j¡ | ¡  dS )	a)  
        Walk through red-black tree of children of this directory entry to add
        all of them to the kids list. (recursive method)

        :param child_sid: index of child directory entry to use, or None when called
            first time for the root. (only used during recursion)
        zappend_kids: child_sid=%dNr   zOLE DirEntry index out of rangezHappend_kids: child_sid=%d - %s - sid_left=%d, sid_right=%d, sid_child=%dz#OLE Entry referenced more than onceTz!Duplicate filename in OLE storage)r3   rÕ   r   r_   r2   Ú
direntriesrÙ   r   Ú_load_direntryrî   rÈ   r,   r÷   rø   rù   rñ   r  Úlowerrð   rï   rÚ   r  )rµ   Ú	child_sidÚchildÚ
name_lowerr/   r/   r0   r  X  s2   ÿÿ

ÿ
zOleDirectoryEntry.append_kidsc                 C   s   | j |j kS ©zCompare entries by name©r,   ©rµ   Úotherr/   r/   r0   Ú__eq__‡  ó   zOleDirectoryEntry.__eq__c                 C   s   | j |j k S r  r  r  r/   r/   r0   Ú__lt__‹  r  zOleDirectoryEntry.__lt__c                 C   s   |   |¡ S rg   )r  r  r/   r/   r0   Ú__ne__�  ó   zOleDirectoryEntry.__ne__c                 C   s   |   |¡p	|  |¡S rg   )r  r  r  r/   r/   r0   Ú__le__’  s   zOleDirectoryEntry.__le__r   c                 C   s¶   g d¢}z|| j  }W n ty   d}Y nw td| t| jƒ |dd� | j ttfv r4t| jddd� tƒ  | j ttfv rL| j	rLtd| d| j	  ƒ | j
D ]	}| |d ¡ qOdS )	zADump this entry, and all its subentries (for debug purposes only))z	(invalid)z	(storage)z(stream)z(lockbytes)z
(property)z(root)z	(UNKNOWN)ú ©Úendrb   z{%s}r6   N)rõ   rÛ   rÆ   rÈ   r,   r
   r   rÝ   r   r}   rï   rÊ   )rµ   ÚtabÚTYPESÚ	type_nameÚkidr/   r/   r0   rÊ   ›  s   ÿ
ÿzOleDirectoryEntry.dumpc                 C   ó   | j dkrdS t| j ƒS )zÑ
        Return modification time of a directory entry.

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

        new in version 0.26
        r   N)rü   r†   r´   r/   r/   r0   Úgetmtime®  ó   
	
zOleDirectoryEntry.getmtimec                 C   r'  )zÍ
        Return creation time of a directory entry.

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

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

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

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

        ole = OleFileIO("fan.mic")

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

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

        :param filename: file to open.

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

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

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

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

        :param path_encoding: None or str, name of the codec to use for path
            names (streams and storages), or None for Unicode.
            Unicode by default on Python 3+, UTF-8 on Python 2.x.
            (new in olefile 0.42, was hardcoded to Latin-1 until olefile v0.41)
        N)Ú
write_mode)(Ú_raise_defects_levelÚparsing_issuesr.  Úpath_encodingÚ	_filesizeÚ
ministreamÚ_used_streams_fatÚ_used_streams_minifatÚ
byte_orderÚdirectory_fpr  Údll_versionrã   Úfirst_difat_sectorÚfirst_dir_sectorÚfirst_mini_fat_sectorrf   Ú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_numberrc   )rµ   rd   Úraise_defectsr.  rÕ   r1  r/   r/   r0   r¶   é  sV   ÿzOleFileIO.__init__c                 C   s   | S rg   r/   r´   r/   r/   r0   Ú	__enter__6  s   zOleFileIO.__enter__c                 G   s   |   ¡  d S rg   )Úclose)rµ   Úargsr/   r/   r0   Ú__exit__:  r  zOleFileIO.__exit__c                 C   s:   || j krt |¡ ||ƒ‚| j ||f¡ t |¡ dS )aï  
        This method should be called for any defect found during file parsing.
        It may raise an IOError exception according to the minimal level chosen
        for the OleFileIO object.

        :param defect_level: defect level, possible values are:

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

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

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

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

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

        :param write_mode: bool, if True the file is opened in read/write mode instead
            of read-only by default. (ignored if filename is not a path)
        r\   zr+br]   r   zFile size: %d bytes (%Xh)rì   Nr:   zMagic = %r instead of %rz#not an OLE2 structured storage filez<8s16sHHHHHHLLLLLLLLLLzfmt_header size = %d, +FAT = %di´  zincorrect OLE signaturerA   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 headerr6   z0Sector Size   = %d bytes (expected: 512 or 4096))rì   rZ   z#incorrect sector_size in OLE headerr"   r   rZ   z3sector_size does not match DllVersion in OLE headerz/MiniFAT Sector Size   = %d bytes (expected: 64))rQ   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)rI   );r.  r^   rf   ra   rb   r_   r   rÞ   rß   rc   r`   ÚosÚSEEK_ENDÚtellr2  r3   rÕ   r4  r5  r\   r   rÙ   r   rq   r-  rr   r=  r<  rD  r8  r6  rM  r?  rJ  rK  rG  rH  r:  rO  rA  r;  rI  r9  rF  Ú	bytearrayr   rN  r@  r   rV  rE  r~   râ   rC  r  r  ÚloadfatÚloaddirectoryrB  )	rµ   rd   r.  Úmoderä   re   Ú
fmt_headerÚheader_sizeÚheader1r/   r/   r0   rc   k  sÐ   
'

í
ÿ
zOleFileIO.openc                 C   ó   | j  ¡  dS )z@
        close the OLE file, to release the file object
        N)rf   rR  r´   r/   r/   r0   rR  K  ó   zOleFileIO.closec                 C   sh   |rt  d| ¡ | j}nt  d| ¡ |ttttfv rdS | j}||v r-|  t	d¡ dS | 
|¡ dS )ag  
        Checks if a stream has not been already referenced elsewhere.
        This method should only be called once for each known stream, and only
        if stream size is not null.

        :param first_sect: int, index of first sector of the stream in FAT
        :param minifat: bool, if True, stream is located in the MiniFAT, else in the FAT
        z,_check_duplicate_stream: sect=%Xh in MiniFATz(_check_duplicate_stream: sect=%Xh in FATNzStream referenced twice)r3   rÕ   r5  r   r   r   r   r4  rÙ   r   rÚ   )rµ   Ú
first_sectr	  Úused_streamsr/   r/   r0   r  R  s   	z!OleFileIO._check_duplicate_streamr   c                 C   sü   d}t dtdtdtdi}t|ƒ}|| d | }tddd	� t|ƒD ]
}td
| dd	� q"tƒ  t|ƒD ]G}|| }	td||	  dd	� t|	|	| ƒD ],}||krS n%|| }
|
d@ }||v rd|| }n|
|d krmd}nd
|
 }t|dd	� qKtƒ  q4dS )zU
        Display a part of FAT in human-readable form for debugging purposes
        r:   z..free..z[ END. ]zFATSECT zDIFSECT r#   Úindexr   r!  ú%8Xú%6X:r5   z    --->N)r   r   r   r   r_   rÆ   r¿   )rµ   rã   Ú
firstindexÚVPLÚfatnamesÚnbsectÚnlinesr!   Úlrn  rà   Úauxr,   r/   r/   r0   Údumpfatl  s8   ü
ðzOleFileIO.dumpfatc                 C   sÚ   d}t   t|¡}tjdkr| ¡  t|ƒ}|| d | }tddd� t|ƒD ]
}td| dd� q'tƒ  t|ƒD ]1}|| }	td||	  dd� t|	|	| ƒD ]}||krX n|| }
d|
 }t|dd� qPtƒ  q9d	S )
zS
        Display a sector in a human-readable form, for debugging purposes
        r:   Úbigr#   rn  r   r!  ro  rp  N)ÚarrayÚUINT32ÚsysÚ	byteorderÚbyteswapr_   rÆ   r¿   )rµ   Úsectorrq  rr  r#  rt  ru  r!   rv  rn  rà   r,   r/   r/   r0   Ú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)
        ry  )rz  r{  r|  r}  r~  )rµ   rà   Úar/   r/   r0   Ú
sect2arrayª  s   
zOleFileIO.sect2arrayc                 C   sš   t |tjƒr	|}n|  |¡}t tj¡r|  |¡ d}|D ]-}|d@ }t d| ¡ |t	ks2|t
kr:t d¡  |S |  |¡}|  |¡}| j| | _q|S )zÅ
        Adds the indexes of the given sector to the FAT

        :param sect: string containing the first FAT sector, or array of long integers
        :returns: index of last FAT sector.
        Nr5   z
isect = %Xzfound end of sector chain)ra   rz  r‚  r3   ÚisEnabledForr$   ÚDEBUGr€  rÕ   r   r   Úgetsectrã   )rµ   rà   Úfat1ÚisectÚsÚnextfatr/   r/   r0   Úloadfat_sect¶  s"   



û
zOleFileIO.loadfat_sectc           	      C   sò  t  d¡ |dd… }t  dt|ƒt|ƒd f ¡ t t¡| _|  |¡ | jdkr´t  d¡ | jdkr:|  	t
d	¡ | j| jkrF|  	td
¡ t  d¡ | jd d }| jd | d | }t  d| ¡ | j|krmtdƒ‚| j}t|ƒD ]4}t  d||f ¡ |  |¡}|  |¡}t  tj¡r”|  |¡ |  |d|… ¡ || }t  d| ¡ qt|ttfv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 dS )z%
        Load the FAT table.
        zDLoading the FAT table, starting with the 1st sector after the headeréL   rì   zlen(sect)=%d, so %d integersr   r   z)DIFAT is used, because file size > 6.8MB.ém   z#incorrect DIFAT, not enough sectorsz)incorrect DIFAT, first index out of rangezDIFAT analysis...r#   znb_difat = %dzincorrect DIFATzDIFAT block %d, sector %XNznext DIFAT sector: %Xzincorrect end of DIFATz$No DIFAT, because file size < 6.8MB.z!len(fat)=%d, shrunk to nb_sect=%dz6FAT references %d sectors / Maximum %d sectors in filez
FAT:)r3   rÕ   r_   rz  r{  rã   rŠ  rF  rH  rÙ   r   r9  rE  r   râ   ÚIOErrorÚ	iterranger…  r‚  rƒ  r$   r„  r€  r   r   rx  )	rµ   re   rà   Únb_difat_sectorsÚnb_difatÚisect_difatr!   Úsector_difatÚdifatr/   r/   r0   rd  Ú  sN   
	









þ

þzOleFileIO.loadfatc                 C   sä   | j | j }| jj| j d | j }|d }t d| j| j |||f ¡ ||kr.|  t	d¡ | j
| j|dd� ¡ }|  |¡| _t dt| jƒ|f ¡ | jd|… | _t d	t| jƒ ¡ t tj¡rpt d
¡ |  | j¡ dS dS )z)
        Load the MiniFAT table.
        r#   r   zaloadminifat(): minifatsect=%d, nb FAT sectors=%d, used_size=%d, stream_size=%d, nb MiniSectors=%dz%OLE MiniStream is larger than MiniFATT©Ú	force_FATz$MiniFAT shrunk from %d to %d sectorsNzloadminifat(): len=%dz	
MiniFAT:)rI  rN  rL  rÝ   r@  r3   rÕ   rB  rÙ   r   Ú_openr\   r‚  r	  r_   rƒ  r$   r„  rx  )rµ   Ústream_sizeÚnb_minisectorsÚ	used_sizerˆ  r/   r/   r0   r
  .  s"   ÿ
þzOleFileIO.loadminifatc              
   C   s–   z| j  | j|d  ¡ W n   t d|| j|d  | jf ¡ |  td¡ Y | j  | j¡}t	|ƒ| jkrIt d|t	|ƒ| jf ¡ |  td¡ |S )z•
        Read given sector from file on disk.

        :param sect: int, sector index
        :returns: a string containing the sector data.
        r#   z(getsect(): sect=%X, seek=%d, filesize=%drÒ   z*getsect(): sect=%X, read=%d, sectorsize=%drÓ   )
rf   r`   râ   r3   rÕ   r2  rÙ   r   r\   r_   )rµ   rà   r  r/   r/   r0   r…  R  s   ÿÿzOleFileIO.getsectrx   c              
   C   sÌ   t |tƒs	tdƒ‚t |tƒrt|ƒdkrtdƒ‚z| j | j|d  ¡ W n   t d|| j|d  | j	f ¡ |  
td¡ Y t|ƒ| jk rS||| jt|ƒ  7 }nt|ƒ| jk r^tdƒ‚| j |¡ dS )zÒ
        Write given sector to file on disk.

        :param sect: int, sector index
        :param data: bytes, sector data
        :param padding: single byte, padding character if data < sector size
        z'write_sect: data must be a bytes stringr#   z4write_sect: padding must be a bytes string of 1 charz+write_sect(): sect=%X, seek=%d, filesize=%drÒ   úData is larger than sector sizeN)ra   rb   Ú	TypeErrorr_   rf   r`   râ   r3   rÕ   r2  rÙ   r   Ú
ValueErrorÚwrite)rµ   rà   rè   Úpaddingr/   r/   r0   Ú
write_sectr  s    
ÿzOleFileIO.write_sectc                 C   s°   t |tƒs	tdƒ‚t |tƒrt|ƒdkrtdƒ‚z| j |¡ W n   t d|| jf ¡ |  	t
d¡ Y t|ƒ}|| jk rG||| j|  7 }| j|k rPtdƒ‚| j |¡ dS )zÕ
        Write given sector to file on disk.

        :param fp_pos: int, file position
        :param data: bytes, sector data
        :param padding: single byte, padding character if data < sector size
        z,write_mini_sect: data must be a bytes stringr#   z9write_mini_sect: padding must be a bytes string of 1 charz)write_mini_sect(): fp_pos=%d, filesize=%drÒ   rš  N)ra   rb   r›  r_   rf   r`   r3   rÕ   r2  rÙ   r   r@  rœ  r�  )rµ   Úfp_posrè   rž  Úlen_datar/   r/   r0   Ú_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:Tr”  rë   z&loaddirectory: size=%d, max_entries=%dNr   )	r3   rÕ   r–  r7  rÝ   r  r  rL  r  )rµ   rà   Úmax_entriesÚ
root_entryr/   r/   r0   re  ¦  s   

ÿ
zOleFileIO.loaddirectoryc                 C   s~   |dk s|t | jƒkr|  td¡ | j| dur#|  td¡ | j| S | j |d ¡ | j d¡}t||| ƒ| j|< | j| S )aY  
        Load a directory entry from the directory.
        This method should only be called once for each storage/stream when
        loading the directory.

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

        :exception IOError: if the entry has always been referenced.
        r   z OLE directory index out of rangeNz'double reference for OLE stream/storagerë   )	r_   r  rÙ   r   r   r7  r`   r\   rê   )rµ   rî   r  r/   r/   r0   r  Ï  s   ÿ

zOleFileIO._load_direntryc                 C   rj  )z5
        Dump directory (for debugging only)
        N)rL  rÊ   r´   r/   r/   r0   Údumpdirectoryé  rk  zOleFileIO.dumpdirectoryc              
   C   s¬   t  d||t|ƒf ¡ || jk rE|sE| js4|  ¡  | jj}t  d| jj|f ¡ | j	| jj|dd�| _t
| j||d| j| j| jj| d�S t
| j||| j| j| j| j| d�S )a|  
        Open a stream, either in FAT or MiniFAT according to its size.
        (openstream helper)

        :param start: index of first sector
        :param size: size of stream (or nothing if size is unknown)
        :param force_FAT: if False (default), stream will be opened in FAT or MiniFAT
            according to size. If True, it will always be opened in FAT.
        z1OleFileIO.open(): sect=%Xh, size=%d, force_FAT=%sz%Opening MiniStream: sect=%Xh, size=%dTr”  r   )rf   rà   rÝ   rá   râ   rã   rä   rå   )r3   rÕ   Ústrr  r3  r
  rL  rÝ   rý   r–  rÏ   rC  r	  rf   râ   rã   r2  )rµ   ÚstartrÝ   r•  Úsize_ministreamr/   r/   r0   r–  ð  s0   
ÿ
ÿ
ÿ

ý
üzOleFileIO._openTc                 C   sŽ   ||j g }|jD ];}|jtkr)|r| |dd… |j g ¡ |  |||||¡ q	|jtkr>|r=| |dd… |j g ¡ q	|  td¡ q	dS )a½  
        listdir helper

        :param files: list of files to fill in
        :param prefix: current location in storage tree (list of names)
        :param node: current node (OleDirectoryEntry object)
        :param streams: bool, include streams if True (True by default) - new in v0.26
        :param storages: bool, include storages if True (False by default) - new in v0.26
            (note: the root storage is never included)
        r#   NzIThe directory tree contains an entry which is not a stream nor a storage.)	r,   rï   rõ   r   rÚ   Ú_listr
   rÙ   r   )rµ   ÚfilesÚprefixÚnodeÚstreamsÚstoragesr  r/   r/   r0   r©    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
        )r©  rL  )rµ   r­  r®  rª  r/   r/   r0   Úlistdir3  s   	zOleFileIO.listdirc                 C   sX   t |tƒr
| d¡}| j}|D ]}|jD ]}|j ¡ | ¡ kr! nqtdƒ‚|}q|jS )a*  
        Returns directory entry of given filename. (openstream helper)
        Note: this method is case-insensitive.

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

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

        :returns: sid of requested filename
        :exception IOError: if file not found
        ú/zfile not found)	ra   Ú
basestringÚsplitrL  rï   r,   r  r�  rî   )rµ   rd   r¬  r,   r&  r/   r/   r0   Ú_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
   r�  r–  rý   rÝ   ©rµ   rd   rî   r  r/   r/   r0   Ú
openstreama  s
   


zOleFileIO.openstreamc                 C   sÊ   |j s| | ¡ t|j ƒ}| jj s| j | ¡ | j| j }t|j ƒD ]@\}}|| }|| }| jj | d | j || j  }	||d k rS||| j |d | j … }
n	||| j d … }
|  |	|
¡ q"d S )Nr#   )r  r  r_   rL  rN  r@  Ú	enumerater¢  )rµ   r  Údata_to_writerç   Ú
block_sizeÚidxrà   Ú	sect_baseÚsect_offsetr   Údata_per_sectorr/   r/   r0   Ú_write_mini_streamv  s   

 øzOleFileIO._write_mini_streamc           
   	   C   sz  t |tƒs	tdƒ‚|  |¡}| j| }|jtkrtdƒ‚|j}|t	|ƒkr)t
dƒ‚|| jk r:|jtkr:| j||d�S |j}|| jd  | j }t d| ¡ t|ƒD ]`}||d k rr||| j |d | j … }	t	|	ƒ| jksqJ ‚n(||| j d… }	t d|| jt	|	ƒ|| j f ¡ t	|	ƒ| j || j ksšJ ‚|  ||	¡ z| j| }W qR ty²   td	ƒ‚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#   rÐ   NzGwrite_stream: size=%d sectorsize=%d data_sector=%Xh size%%sectorsize=%drÑ   z)incorrect last sector index in OLE stream)ra   rb   r›  r³  r  rõ   r
   r�  rÝ   r_   rœ  r  r   r½  rý   râ   r3   rÕ   r¿   rŸ  rã   rÛ   r   )
rµ   Ústream_namerè   rî   r  rÝ   rà   rç   r!   Údata_sectorr/   r/   r0   Úwrite_streamˆ  s@   



ÿþÿzOleFileIO.write_streamc                 C   s*   z|   |¡}| j| }|jW S    Y dS )a˜  
        Test if given filename exists as a stream or a storage in the OLE
        container, and return its type.

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

            - STGTY_STREAM: a stream
            - STGTY_STORAGE: a storage
            - STGTY_ROOT: the root entry
        F)r³  r  rõ   r´  r/   r/   r0   Ú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  r}   r´  r/   r/   r0   ÚgetclsidÚ  s   


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

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

        new in version 0.26
        )r³  r  r(  r´  r/   r/   r0   r(  é  ó   

zOleFileIO.getmtimec                 C   rÃ  )a1  
        Return creation time of a stream/storage.

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

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

        :param filename: path of stream in storage tree. (see openstream for syntax)
        :returns: True if object exist, else False.
        TF)r³  )rµ   rd   rî   r/   r/   r0   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
   r›  rÝ   r´  r/   r/   r0   Ú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.
        )rL  r,   r´   r/   r/   r0   Úget_rootentry_name*  s   zOleFileIO.get_rootentry_namec                 C   s2  |dkrg }|}t |tƒsd |¡}|  |¡}i }z7| d¡}t|dd… ƒ}| d¡}t|dd… ƒ}	| t|dƒ¡ d| t| d	¡ƒd	 ¡ }t|d	ƒ}
W n% tyu } zd
t	|ƒ|f }|  
t|t|ƒ¡ |W  Y d}~S d}~ww t|
tt|ƒd ƒƒ}
t|
ƒD �]�}d}�zft|d|d  ƒ}t|d|d  ƒ}t||ƒ}t d|||f ¡ |tkrÂt||d	 ƒ}|dkrÀ|d }�n*|tkrÏt||d	 ƒ}�n|tttfv rßt||d	 ƒ}�n|ttfv rít||d	 ƒ}nÿ|ttfv �rt||d	 ƒ}||d |d | d … }| dd¡}nÜ|tk�r)t||d	 ƒ}||d |d | … }nÃ|tk�rGt||d	 ƒ}|   ||d |d |d  … ¡}n¥|t!k�r™t"t||d	 ƒƒt"t||d ƒƒd>  }|�r”||v�r”t d||t#|ƒd f ¡ t$ $dddddd¡}t d|d  ¡ |t$j%|d d� }nX|d }nS|t&k�r§t'||d	  ƒ}nE|t(k�r¹t||d	 |d … ƒ}n3|t)k�rÒt||d	 ƒ}||d |d | … }n|t*k�rát+t||d	 ƒƒ}nd}t d||f ¡ |||< W q… t�y } zd|t	|ƒ|f }|  
t|t|ƒ¡ W Y d}~q…d}~ww |S )aÄ  
        Return properties described in substream.

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

        :returns: a dictionary of values indexed by id (integer)
        Nr°  rM   r:   rI   rE   rA   s   ****r   z6Error while parsing properties header in stream %s: %sr   r>   z!property id=%d: type=%d offset=%Xi €  i   r#   rx   rÔ   r6   rí   z8Converting property #%d to python datetime, value=%d=%fsi€–˜ r   ztimedelta days=%dl    @ÓT$r<   r€   z5property id=%d: type=%d not implemented in parser yetz3Error while parsing property id %d in stream %s: %s),ra   r¦  rÜ   rµ  r\   r~   r`   rw   ÚBaseExceptionrÈ   rÙ   r   ÚtypeÚminrn   r_   rŽ  r3   rÕ   ÚVT_I2ru   ÚVT_UI2ÚVT_I4ÚVT_INTÚVT_ERRORÚVT_UI4ÚVT_UINTÚVT_BSTRÚVT_LPSTRrZ  ÚVT_BLOBÚ	VT_LPWSTRr  ÚVT_FILETIMEr  Úfloatr‚   rƒ   ÚVT_UI1rk   ÚVT_CLSIDÚVT_CFÚVT_BOOLÚbool)rµ   rd   r·   r¸   Ú
streampathrf   rè   rˆ  r}   ÚfmtidÚ	num_propsÚexcÚmsgr!   Úproperty_idrá   Úproperty_typerÃ   Úcountr…   r/   r/   r0   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/   r0   Úget_metadataÊ  s   zOleFileIO.get_metadata)rZ  )Fr+  )rx   )TF)FN),rË   rÌ   rÍ   rÎ   r   r   r¶   rQ  rT  r�  rÙ   r  rc   rR  r  rx  r€  r‚  rŠ  rd  r
  r…  rŸ  r¢  re  r  r¥  r   r–  r©  r¯  r³  rµ  r½  rÀ  rÁ  rÂ  r(  r*  r½   rÅ  rÆ  r¾   rä  r/   r/   r/   r0   r   Ì  sT    
ÿM

 a


%$T$
 
)
&
 >
 r   c               	   C   s„  ddl } ddl}d}tjtjtjtjtjdœ}d}|j|d�}|j	ddd	d
d� |j	ddddd� |j	dddd|dd� | 
¡ \}}tdttf ƒ t|ƒdkr\ttƒ | ¡  |  ¡  |jrbd|_tj||j dd� tƒ  |D �]M}�z>t|ƒ}	tdƒ t|ƒ tdƒ |	 ¡  |	 ¡ D ]`}
|
d d dkrîtd|
 ƒ zC|	j|
dd�}t| ¡ ƒ}|D ]1\}}t|ttfƒrÅt|ƒdkrÅ|dd… }t|tƒrÙd D ]}|t|ƒv rØd!} nqÌtd"||ƒ q®W qŽ   t  !d#|
 ¡ Y qŽqŽ|j"�r-td$ƒ |	 ¡ D ].}
td%t#d& $|
¡ƒd%d'd(� |	 %|
¡}|t&k�r#td)|	 '|
¡ ƒ |	 (|
¡ qûtd*| ƒ qûtƒ  td+ƒ |	j)D ]}|du�rItd,|j*| +¡ | ,¡ f ƒ �q4tƒ  z
|	 -¡ }| .¡  W n	   t  !d-¡ Y tƒ  |	 /¡ }td.| ƒ |	 0d/¡�r“td0ƒ td1|	 %d/¡ƒ td2|	 'd/¡ƒ |	 0d3¡�r“td4ƒ td5ƒ |	j1�r®|	j1D ]\}}td6|j2|f ƒ �qžntd7ƒ W qq   t  !d8| ¡ Y qqdS )9z­
    Main function when olefile is runs as a script from the command line.
    This will open an OLE2 file and display its structure and properties
    :return: nothing
    r   NrV  )rÕ   ÚinforV  rU  Úcriticalz1usage: %prog [options] <filename> [filename2 ...])Úusagez-cÚ
store_trueÚcheck_streamsz*check all streams (for debugging purposes))ÚactionÚdestÚhelpz-dÚ
debug_modez\debug mode, shortcut for -l debug (displays a lot of debug information, for developers only)z-lz
--loglevelÚloglevelÚstorezBlogging level debug/info/warning/error/critical (default=%default))rë  rê  Údefaultrì  z=olefile version %s %s - https://www.decalage.info/en/olefile
rÕ   z%(levelname)-8s %(message)s)r-   ÚformatzD--------------------------------------------------------------------éÿÿÿÿúz%r: propertiesTr¹   é2   )r#   r6   r"   r   r7   r8   r9   r=   r>   r@   é   rA   rB   rC   rD   rE   rF   rG   rH   rI   rJ   rK   rL   rM   rN   rO   rP   z(binary data)z   z&Error while parsing property stream %rz
Checking streams...ú-r°  r   r!  zsize %dzNOT a stream : type=%dz5Modification/Creation times of all directory entries:z- %s: mtime=%s ctime=%szError while parsing metadatazRoot entry name: "%s"ÚworddocumentzThis is a Word document.ztype of stream 'WordDocument':zsize :z
macros/vbaz%This document may contain VBA macros.z(
Non-fatal issues raised during parsing:rÅ   ÚNonezError while parsing file %r)3r|  Úoptparser$   r„  ÚINFOÚWARNINGÚERRORÚCRITICALÚOptionParserÚ
add_optionÚ
parse_argsrÆ   Ú__version__Ú__date__r_   rÎ   Ú
print_helpÚexitrí  rî  ÚbasicConfigr   r   r¥  r¯  r¾   ÚsortedÚitemsra   r±  rb   rc  r3   Ú	exceptionré  rÈ   rÜ   rÁ  r
   rÅ  rµ  r  r,   r(  r*  rä  rÊ   rÆ  r½   r0  rË   )r|  rù  ÚDEFAULT_LOG_LEVELÚ
LOG_LEVELSrç  ÚparserÚoptionsrS  rd   rÖ   Ú
streamnamerÂ   ÚkÚvrj   Úst_typer  ÚmetarL  Úexctyperà  r/   r/   r0   ÚmainÛ  sÆ   û
ÿ
ÿÿ

þôí



ÿ€ÿ€®r  Ú__main__r+  )mrÎ   Ú
__future__r   r  r  Ú
__author__Ú__all__rÞ   r|  rq   rz  Úos.pathr`  r‚   r$   r¦  rb   rn   r  ÚxrangerŽ  r¿   Úitemsizer{  rœ  r±  Ú	NameErrorr	   Úversion_infor   rý  r1   r3   r   r   r   r   r   r   r   r   r   r   r   r
   r   r   r   r   ÚVT_EMPTYÚVT_NULLrÊ  rÌ  ÚVT_R4ÚVT_R8ÚVT_CYÚVT_DATErÑ  ÚVT_DISPATCHrÎ  rÚ  Ú
VT_VARIANTÚ
VT_UNKNOWNÚ
VT_DECIMALÚVT_I1r×  rË  rÏ  ÚVT_I8ÚVT_UI8rÍ  rÐ  ÚVT_VOIDÚ
VT_HRESULTÚVT_PTRÚVT_SAFEARRAYÚ	VT_CARRAYÚVT_USERDEFINEDrÒ  rÔ  rÕ  rÓ  Ú	VT_STREAMÚ
VT_STORAGEÚVT_STREAMED_OBJECTÚVT_STORED_OBJECTÚVT_BLOB_OBJECTrÙ  rØ  Ú	VT_VECTORr   r   r   r   r   r   r   rk   ru   rw   r~   r†   r   rß   rÏ   rê   r   r  rË   r/   r/   r/   r0   Ú<module>   s¾    <
(ÿ
*



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