
    6[_                       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reZ	 eZ e
j                  d      j,                  d	k(  rdZnL e
j                  d
      j,                  d	k(  rd
Zn* e
j                  d      j,                  d	k(  rdZn ed      	 e dZej8                  d   dk  rdZndZej<                  dz   fdZ e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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-ZGd.ZHd/ZId0ZJd1ZKd2ZLd3ZMd4ZNd5ZOd6ZPd7ZQd8ZRd9ZSd:ZTd;ZUd<ZVd=ZWd>ZXd?ZYd@ZZd!Z[d*Z\d4Z]dAZ^dBZ_dC Z`eeu rdD ZandE ZadTdFZbdTdGZcdH ZddI Ze G dJ dK      Zf G dL dMej                        Zh G dN dO      Zi G dP dQ      ZjdR ZkeldSk(  r ek        yy#  eZY xY w# e$ r eZY &w xY w)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                 4   | t         j                  j                  j                  v r(t        j                  |       }|j                  |       |S t        j                  |       }|j                  t        j                                |j                  |       |S )an  
    Create a suitable logger object for this module.
    The goal is not to change settings of the root logger, to avoid getting
    other modules' logs on the screen.
    If a logger exists with same name, reuse it. (Else it would have duplicate
    handlers and messages would be doubled.)
    The level is set to CRITICAL+1 by default, to avoid any logging.
    )loggingLoggermanager
loggerDict	getLoggersetLevel
addHandlerNullHandler)namelevelloggers      1/usr/lib/python3/dist-packages/olefile/olefile.py
get_loggerr2      sy     w~~%%000 ""4(t$F g))+,
OOEM    olefilec                  J    t         j                  t        j                         y)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&   NOTSET r3   r1   r   r      s     LL r3   s   ࡱl    l    l    l              i         	   
                                                               @   A   B   C   D   E   F   G   H      z$00020900-0000-0000-C000-000000000046(   i   c                 x   t        | d      r0| j                  t        t                    }| j	                  d       nht        | t              r%t        |       t        k\  r| dt        t               }n3t        | d      5 }|j                  t        t                    }ddd       t        k(  ryy# 1 sw Y   xY w)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)	hasattrra   lenr   seek
isinstancebytesr   open)filenameheaderfps      r1   r   r     s    0 x s5z*a	He	$X:N)N+3u:& (D! 	)RWWSZ(F	)	) 	)s   >B00B9c                     t        |       S N)ordcs    r1   i8rq   ?  s    1vr3   c                 4    | j                   t        u r| S | d   S Nr   )	__class__intro   s    r1   rq   rq   C  s    KK3&q0AaD0r3   c                 @    t        j                  d| ||dz          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rp   os     r1   i16r|   G  $     ==q1Q3x(++r3   c                 @    t        j                  d| ||dz          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   rw   rz   s     r1   i32r   Q  r}   r3   c           
          t        |       dk(  sJ | j                  d      sydt        | d      t        | d      t        | d      ft	        t        t        | dd             z   z  S )	z^
    Converts a CLSID to a human-readable string.

    :param clsid: string of length 16.
    rE        z0%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02Xr   r    r<   r>   )rd   stripr   r|   tuplemaprq   )clsids    r1   _clsidr   [  sj     u: ;;u4%mS]CqM:#b%"+&'() *r3   c                 n    t        j                   dddddd      }|t        j                  | dz        z   S )zL
        convert FILETIME (64 bits int) to Python datetime.datetime
        A  r$   r   r@   microseconds)datetime	timedelta)filetime_FILETIME_null_dates     r1   filetime2datetimer   l  s9     '//aAq!D"X%7%7Xr\%RRRr3   c                   2    e Zd ZdZg dZg dZd Zd Zd Zy)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_targetrg   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                    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| _.        y)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   rg   r   r   r   r   r   r   r   r   r   r(   r   r   r   r   r   r   r   r   r   r   r   r   r   r   selfs    r1   __init__zOleMetadata.__init__  s_    
!## #$(! #' 


!!#!%" "r3   c                 8   | j                   | j                  z   D ]  }t        | |d        |j                  d      rg|j	                  dddg      }t        t        | j                               D ]1  }|j                  |dz   d      }t        | | j                   |   |       3 |j                  d      rf|j	                  dd      }t        t        | j                              D ]1  }|j                  |dz   d      }t        | | j                  |   |       3 yy)	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rangerd   get)r   r4   attribpropsr"   values         r1   parse_propertieszOleMetadata.parse_properties  s%    ++d.A.AA 	(FD&$'	(>>23 ))*B!" * 7E 3t3345 >		!A#t,d2215u=> >>:;))*J! * #E 3t2234 =		!A#t,d11!4e<= <r3   c           	         t        d       | j                  D ](  }t        | |      }t        d|dt        |             * t        d       | j                  D ](  }t        | |      }t        d|dt        |             * y)z<
        Dump all metadata, for debugging purposes.
        z*Properties from SummaryInformation stream:- : z2Properties from DocumentSummaryInformation stream:N)printr   getattrreprr   )r   propr   s      r1   dumpzOleMetadata.dump  s|     	:;(( 	4DD$'Ed5k23	4 	BC'' 	4DD$'Ed5k23	4r3   N)	__name__
__module____qualname____doc__r   r   r   r   r   r8   r3   r1   r   r   z  s(     HOEN5 p=@4r3   r   c                       e Zd ZdZd Zy)	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	                 	   t         j                  d       t         j                  d|||||t        |      t        |      fz         || _        | j                  j
                  j                  rt        d      d}	|t        k(  r%t        |      |z  }d}	t         j                  d       ||dz
  z   |z  }
t         j                  d|
z         |
t        |      kD  r | j                  j                  t        d	       g }|d
k(  r>|t        k7  r5t         j                  d       | j                  j                  t        d       t        |
      D ]  }t         j                  d||fz         |t        k(  rO|	rt         j                  d        nt         j                  d       | j                  j                  t        d       |d
k  s|t        |      k\  r`t         j                  d||t        |      fz         t         j                  d||
fz         | j                  j                  t        d        n	 |j                  |||z  z          |j                  |      }t        |      |k7  r|t        |      dz
  k7  rt         j                  d|t        |      |||z  z   |t        |      fz         t         j                  d|||z  z   t        |      z   z         | j                  j                  t        d       |j                  |       	 ||   dz  } dj#                  |      }t        |      |k\  r0t         j                  dt        |      |fz         |d| }|| _        n|	r2t         j                  dt        |      z         t        |      | _        nSt         j                  dt        |      |fz         t        |      | _        | j                  j                  t        d       t&        j(                  j+                  | |       y#  t         j                  d||||z  z   |fz         | j                  j                  t        d       Y  >xY w# t         $ r% | j                  j                  t        d       Y  nw xY w) 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 sectorr9   r3   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)r6   debugrd   r   olerk   closedOSErrorr   _raise_defectr   r   r   re   ra   append
IndexErrorjoinsizeioBytesIOr   )r   rk   sectr   offset
sectorsizefatfilesize	olefileiounknown_size
nb_sectorsdatar"   sector_datas                 r1   r   zOleStream.__init__*  s    			'(		Y4VJs3xbBC 	D 88;;NOO < s8J&DLII23jl+
:
		#j01 C HH""#35_` 19+II9:HH""#35bc z" 3	AII71d)CDz!IIVW IIDEHH**+;=TUAvs3x		6$c#h9OOP		01j/AB &&'79ghd!223 ''*-K
 ;+s3xz0B		U3s8VJtO%;Xs;GWXY Z		-
41GKHX1XYZ&&'79PQKK$4y:-]3	n xx~t9IIKsSWyZ^N__`;DDI IIKcRViWXD	DI IIQUXY]U^`dTeefD	DIHH""#35\]


D$'_		96*T/18<= >&&'79XY  &&'79gh	s   4PQAQ)RRN)r   r   r   r   r   r8   r3   r1   r   r     s    &|(r3   r   c                       e Zd ZdZdZdZ ej                  e      ek(  sJ d Zd Z	d Z
d Zd Zd	 Zd
 Zd ZddZd Zd Zy)OleDirectoryEntryz
    OLE2 Directory Entry
    z<64sHBBIII16sIQQIII   c                 P   || _         || _        g | _        i | _        d| _        t        j                  t        j                  |      \  | _	        | _
        | _        | _        | _        | _        | _        }| _        | _        | _        | _        | _        | _        | j                  t,        t.        t0        t2        fvr|j5                  t6        d       | j                  t,        k(  r|dk7  r|j5                  t6        d       |dk(  r)| j                  t,        k7  r|j5                  t6        d       | j                  dkD  r|j5                  t6        d       d| _
        | j                  d| j                  d	z
   | _        |j;                  | j8                        | _        t>        jA                  d
| j                   tC        | j<                        fz         t>        jA                  d| j                  z         t>        jA                  d| j&                  z         t>        jA                  d| j                  | j                  | j                  fz         |jD                  dk(  r| j*                  dk7  ri| j*                  dk7  rZt>        jA                  d|jD                  | j(                  | j*                  | j*                  fz         |j5                  tF        d       | j(                  | _$        n*| j(                  tK        | j*                        dz  z   | _$        t>        jA                  d| jH                  | j(                  | j*                  fz         tM        |      | _'        | j                  t.        k(  r%| jH                  dk7  r|j5                  tP        d       d| _)        | j                  t,        t0        fv rp| jH                  dkD  ra| jH                  |jT                  k  r| j                  t0        k(  rd| _)        nd| _)        |jW                  | j&                  | jR                         d| _,        y)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 entryrU   z(incorrect DirEntry name length >64 bytesNr:   zDirEntry SID=%d: %sz - type: %dz - sect: %Xhz% - SID left: %d, right: %d, child: %d   r9   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)-sidr4   kids	kids_dictusedrx   ry   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.   r6   r   r   r   r   r   longr   r   r   
is_minifatminisectorcutoff_check_duplicate_stream
sect_chain)r   entryr   r4   r   s        r1   r   zOleDirectoryEntry.__init__  s0     	  	" MM+;;UC	
MOOJMNNOOOLM??:}lK"XX!!"24PQ??j(SAX!!"24NO!8:5!!"24NO ??2!!"24^_ DO--(<$//!*;=
 --doo>			'488T$))_*EEF		-$//12		.4??23		9T]]NNDNN=, , 	- $}}!dmmz&A		G''t}}dmmTU V%%m5PQDIT]](;R(?@DI		9TYYVZVcVc<ddeE]
 ??m+		Q!!"24MN??z<88TYYq[yy7333-"&"'++DOOT__Mr3   c                    | j                   ry | j                  t        t        fvs| j                  dk(  ry t               | _         | j                  r|j                  s|j                          | j                  }|t        k7  rQ| j                   j                  |       | j                  r|j                  |   }n|j                  |   }|t        k7  rPy y rs   )r  r  r   r   r   listr  minifatloadminifatr  r   r   r   )r   r4   	next_sects      r1   build_sect_chainz"OleDirectoryEntry.build_sect_chain-  s    ????:|"<<		Q&??7??!OO	:%OO""9-#OOI6	#KK	2	 :%r3   c                    t         j                  d| j                  t        | j                        | j
                  fz         | j
                  t        k7  r6| j                  | j
                         | j                  j                          yy)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)
r6   r   r   r   r.   r  r   append_kidsr  sortr   s    r1   build_storage_treez$OleDirectoryEntry.build_storage_tree@  sg     			Bxxdii$..9: 	;>>X% T^^, IINN &r3   c                    t         j                  d|z         |t        k(  ry|dk  s"|t        | j                  j
                        k\  r!| j                  j                  t        d       y| j                  j                  |      }t         j                  d|j                  t        |j                        |j                  |j                  |j                  fz         |j                  r!| j                  j                  t        d       yd|_        | j!                  |j                         |j                  j#                         }|| j$                  v r | j                  j                  t        d       | j&                  j)                  |       || j$                  |<   | j!                  |j                         |j+                          y)	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)r6   r   r   rd   r4   
direntriesr   r   _load_direntryr   r   r.   r	  r
  r  r  r!  lowerr  r  r   r#  )r   	child_sidchild
name_lowers       r1   r!  zOleDirectoryEntry.append_kidsX  sa    			-	9:  Q;)S)@)@%AALL&&'79Z[ LL//	:EII`99d5::.QVQ`Q`ab c zz**+;9;EJ U^^,))+JT^^+**+;79 IIU#).DNN:&U__-$$&r3   c                 4    | j                   |j                   k(  S zCompare entries by namer.   r   others     r1   __eq__zOleDirectoryEntry.__eq__  s    yyEJJ&&r3   c                 4    | j                   |j                   k  S r,  r-  r.  s     r1   __lt__zOleDirectoryEntry.__lt__  s    yy5::%%r3   c                 &    | j                  |       S rm   )r0  r.  s     r1   __ne__zOleDirectoryEntry.__ne__  s    ;;u%%%r3   c                 J    | j                  |      xs | j                  |      S rm   )r0  r2  r.  s     r1   __le__zOleDirectoryEntry.__le__  s    {{5!7T[[%77r3   c                    g d}	 || j                      }t        d|z  t        | j                        z   |d       | j                   t
        t        fv rt        | j                  dd       t                | j                   t        t        fv r*| j                  rt        d|z  d| j                  z  z          | j                  D ]  }|j                  |dz           y# t        $ r d}Y w xY w)	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) endrg   z{%s}r:   N)r  r   r   r   r.   r   r   r   r   r   r  r   )r   tabTYPES	type_namekids        r1   r   zOleDirectoryEntry.dump  s    )	$doo.I 	c#gTYY'<??|Z88$))W#.??}j99djj#c'FTZZ//099 	CHHS1W	  	$#I	$s   C C,+C,c                 L    | j                   dk(  ry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   s    r1   getmtimezOleDirectoryEntry.getmtime  "     ??a 11r3   c                 L    | j                   dk(  ry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  r   r   s    r1   getctimezOleDirectoryEntry.getctime  rA  r3   Nr   )r   r   r   r   r  DIRENTRY_SIZErx   calcsizer   r  r#  r!  r0  r2  r4  r6  r   r@  rC  r8   r3   r1   r   r     sf    . ,OM6???+}<<<_D3&0,'^'&&8&22r3   r   c                      e Zd ZdZdeddefdZd Zd Ze	fdZ
d(dZd)d	Zd
 Zd)dZd*dZd*dZd Zd Zd Zd Zd Zd+dZd+dZd Zd Zd ZedfdZd,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-d&Z*d' Z+y).r   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                 `   || _         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| jO                  ||       yy)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_issuesrI  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_sectorrk   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_numberrh   )r   ri   raise_defectsrI  r   rL  s         r1   r   zOleFileIO.__init__  sP   : %2! !$*!#%'" "& $%)"  $!% $'+$ $"!!%##$(!	 ,0)IIh:I6 r3   c                     | S rm   r8   r   s    r1   	__enter__zOleFileIO.__enter__6  s    r3   c                 $    | j                          y rm   )close)r   argss     r1   __exit__zOleFileIO.__exit__:  s    

r3   c                     || j                   k\  rt        j                  |        ||      | j                  j	                  ||f       t        j                  |       y)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)rJ  r6   errorrK  r   warning)r   defect_levelmessageexception_types       r1   r   zOleFileIO._raise_defect>  sP    " 4444IIg )) &&'@AKK r3   c                 z    |j                  d|      }| j                  r|j                  | 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)decoderL  encode)r   	utf16_strerrorsunicode_strs       r1   r  zOleFileIO._decode_utf16_strX  s@      &&z6:%%d&8&8&AA r3   c                    || _         t        |d      r|| _        n_t        |t              r-t        |      t        k\  rt        j                  |      | _        n"| j                   rd}nd}t        ||      | _        d}| j                  j                  dt        j                         	 | j                  j                         }| j                  j                  d       || _        t        j!                  d| j                  | j                  fz         g | _        g | _        | j                  j'                  d      }t        |      dk7  s|dd t(        k7  r8t        j!                  d	|dd d
t(               | j+                  t,        d       d}t/        j0                  |      }t        j!                  d||dz   fz         |d| }t/        j2                  ||      \  | _        | _        | _        | _        | _        | _        | _         | _!        | _"        | _#        | _$        | _%        | _&        | _'        | _(        | _)        | _*        | _+        t        j!                  t/        j2                  ||             | j4                  t(        k7  r| j+                  t,        d       | j6                  tY        d      k7  r| j+                  tZ        d       t        j!                  d| j8                  z         t        j!                  d| j:                  z         | j:                  dvr| j+                  tZ        d       t        j!                  d| j<                  z         | j<                  dk7  r| j+                  tZ        d       d| j>                  z  | _.        t        j!                  d| j\                  z         | j\                  dvr| j+                  tZ        d       | j:                  dk(  r| j\                  dk7  s| j:                  dk(  r%| j\                  dk7  r| j+                  tZ        d        d| j@                  z  | _/        t        j!                  d!| j^                  z         | j^                  d"vr| j+                  tZ        d#       | jB                  dk7  s| jD                  dk7  r| j+                  tZ        d$       t        j!                  d%| jF                  z         | j\                  dk(  r%| jF                  dk7  r| j+                  tZ        d&       t        j!                  d'| jH                  z         t        j!                  d(| jJ                  z         t        j!                  d)| jL                  z         | jL                  dk7  r| j+                  t`        d*       t        j!                  d+| jN                  z         | jN                  dk7  r?| j+                  tZ        d,       t        jc                  d-| jN                  z         d| _'        t        j!                  d.| jP                  z         t        j!                  d/| jR                  z         t        j!                  d0| jT                  z         t        j!                  d1| jV                  z         || j\                  z   d2z
  | j\                  z  d2z
  | _2        t        j!                  d3| jd                  | jd                  fz         tg        |dd4       | _        | j\                  | _4        | j^                  | _5        | jN                  | _6        | jo                  | jJ                         | jR                  r| jo                  | jP                         | jV                  r| jo                  | jT                         | jq                  |       | js                  | jJ                         | jP                  | _:        y# | j                  j                  d       w xY w)5a  
        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)
        ra   zr+brb   r   zFile size: %d bytes (%Xh)r   Nr>   zMagic = z instead of z#not an OLE2 structured storage filez<8s16sHHHHHHLLLLLLLLLLzfmt_header size = %d, +FAT = %di  zincorrect OLE signaturerE   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))r   r^   z#incorrect sector_size in OLE headerr#   r    r^   z3sector_size does not match DllVersion in OLE headerz/MiniFAT Sector Size   = %d bytes (expected: 64))rU   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)rM   );rI  rc   rk   rf   rg   rd   r   r   r   rh   re   osSEEK_ENDtellrM  r6   r   rO  rP  ra   r   r   r   rx   rF  ry   rX  rW  r_  rS  rQ  rh  rZ  re  rf  rb  rc  rU  rj  r\  rV  rd  rT  ra  	bytearrayr   ri  r[  r   rt  r`  r   r   r^  r  r  loadfatloaddirectoryr]  )	r   ri   rI  moder   rj   
fmt_headerheader_sizeheader1s	            r1   rh   zOleFileIO.openk  sn   " % 8V$ DG%(S]>R-R jj*DG   8T*DG
 Q$	ww||~HGGLLO!		-0PPQ "$%'"c"v;#u!4IIF2AJFG|-RSN .
ooj1		4[SXEX7YY[+&( MM*g.'	
!O"NN  !-(&%#"		6==89  E)|-FG	"-/1PQ		'$*<*<<>		:T=M=MMO6) /1UV		84??JL??f$/1TU d///		EHXHXXZ;./1VWaD$4$4c$9aD$4$4d$:/1fg !4#9#9 9		DtG\G\\^  ,/1[\>>Q$..A"5/1ab		58L8LLNS T%9%91%</1fg		/$2F2FFH		2T5J5JJL		9D<]<]]_
 ,,1/1hi		DtGcGcce ''61/1bcKKd445 6+1D(		4t7Q7QQS		3d6O6OOQ		4t7N7NNP		3d6L6LLN #T%5%55a7D<L<LLPQQ		DVZVbVbGccd
 #6!B<0 **"33 $ < < 	$$T%:%:;$$(()C)CD!!(()@)@A 	V 	400155[ GGLLOs   (_ _*c                 8    | j                   j                          y)z@
        close the OLE file, to release the file object
        N)rk   ro  r   s    r1   ro  zOleFileIO.closeK  s     	r3   c                 $   |r%t         j                  d|z         | j                  }n=t         j                  d|z         |t        t        t
        t        fv ry| j                  }||v r| j                  t        d       y|j                  |       y)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)r6   r   rP  r   r   r   r   rO  r   r   r   )r   
first_sectr  used_streamss       r1   r  z!OleFileIO._check_duplicate_streamR  s     IIDzQR55LII@:MNggjBB11L %/1JK
+r3   c                    d}t         dt        dt        dt        di}t	        |      }||z   dz
  |z  }t        dd	       t        |      D ]  }t        d
|z  d	        t                t        |      D ]p  }||z  }	t        d||	z   z  d	       t        |	|	|z         D ]:  }||k\  r n3||   }
|
dz  }||v r||   }n|
|dz   k(  rd}nd
|
z  }t        |d	       < t                r y)zU
        Display a part of FAT in human-readable form for debugging purposes
        r>   z..free..z[ END. ]zFATSECT zDIFSECT r$   indexr8  r9  %8X%6X:r9   z    --->N)r   r   r   r   rd   r   r   )r   r   
firstindexVPLfatnamesnbsectnlinesr"   lr  r   auxr.   s                r1   dumpfatzOleFileIO.dumpfatl  s   
 



	 S*Q,$g3s 	&A%!)%	&v 	AcEE&Ju,-375%), %f91vZ'(?#C=Dqs{)$t|d$% G!	r3   c                    d}t        j                   t        |      }t        j                  dk(  r|j	                          t        |      }||z   dz
  |z  }t        dd       t        |      D ]  }t        d|z  d        t                t        |      D ]V  }||z  }	t        d||	z   z  d       t        |	|	|z         D ]   }||k\  r n||   }
d|
z  }t        |d       " t                X y	)
zS
        Display a sector in a human-readable form, for debugging purposes
        r>   bigr$   r  r8  r9  r  r  N)arrayUINT32sys	byteorderbyteswaprd   r   r   )r   sectorr  r  r;  r  r  r"   r  r  r   r.   s               r1   dumpsectzOleFileIO.dumpsect  s     kk&&)==E!LLNS*Q,$g3s 	&A%!)%	&v 		AcEE&Ju,-375%), %f91vt|d$% G		r3   c                     t        j                   t        |      }t        j                  dk(  r|j	                          |S )z
        convert a sector to an array of 32 bits unsigned integers,
        swapping bytes on big endian CPUs such as PowerPC (old Macs)
        r  )r  r  r  r  r  )r   r   as      r1   
sect2arrayzOleFileIO.sect2array  s.    
 KK%==E!JJLr3   c                    t        |t        j                        r|}nE| j                  |      }t        j	                  t
        j                        r| j                  |       d}|D ]  }|dz  }t        j                  d|z         |t        k(  s	|t        k(  rt        j                  d        |S | j                  |      }| j                  |      }| j                  |z   | _         |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.
        Nr9   z
isect = %Xzfound end of sector chain)rf   r  r  r6   isEnabledForr&   DEBUGr  r   r   r   getsectr   )r   r   fat1isectsnextfats         r1   loadfat_sectzOleFileIO.loadfat_sect  s     dEKK(D ??4(D.d#  	*EJ&EIIlU*+
"ex&7		56  U#A ooa(Gxx')DH	* r3   c                    t         j                  d       |dd }t         j                  dt        |      t        |      dz  fz         t        j                  t              | _        | j                  |       | j                  dk7  rt         j                  d       | j                  dk  r| j                  t        d	       | j                  | j                  k\  r| j                  t        d
       t         j                  d       | j                  dz  dz
  }| j                  dz
  |z   dz
  |z  }t         j                  d|z         | j                  |k7  rt        d      | j                  }t!        |      D ]  }t         j                  d||fz         | j#                  |      }| j%                  |      }t         j'                  t(        j*                        r| j-                  |       | j                  |d|        ||   }t         j                  d|z          |t.        t0        fvr t        d      t         j                  d       t        | j
                        | j                  kD  rUt         j                  dt        | j
                        | j                  fz         | j
                  d| j                   | _        t         j                  dt        | j
                        | j                  fz         t         j'                  t(        j*                        r1t         j                  d       | j3                  | j
                         yy)z%
        Load the FAT table.
        zDLoading the FAT table, starting with the 1st sector after the headerL   r   zlen(sect)=%d, so %d integersr    r   z)DIFAT is used, because file size > 6.8MB.m   z#incorrect DIFAT, not enough sectorsz)incorrect DIFAT, first index out of rangezDIFAT analysis...r$   znb_difat = %dzincorrect DIFATzDIFAT block %d, sector %XNznext DIFAT sector: %Xzincorrect end of DIFATz$No DIFAT, because file size < 6.8MB.z!len(fat)=%d, shrunk to nb_sect=%dz6FAT references %d sectors / Maximum %d sectors in filez
FAT:)r6   r   rd   r  r  r   r  ra  rc  r   r   rT  r`  r   r   IOError	iterranger  r  r  r&   r  r  r   r   r  )	r   rj   r   nb_difat_sectorsnb_difatisect_difatr"   sector_difatdifats	            r1   r  zOleFileIO.loadfat  s    			XYb~		1SYD	14MMO
 ;;v&$ !!Q&IIAB ##s* ""#35Z[&&$,,6""<1\]II*, !% 2A5,,S03CCAEHXXHII13%%1/0011Kx( C		6![9IIK#||K85##GMM2MM,/!!%(9)9":;#$45		2[@BC :x"88677 II<= txx=4<<'II9S]DLL<YYZxx.DH		JcRVRZRZm]a]i]iMjjkGMM*IIhLL" +r3   c                 B   | j                   | j                  z  }| j                  j                  | j                  z   dz
  | j                  z  }|dz  }t
        j                  d| j                  | j                   |||fz         ||kD  r| j                  t        d       | j                  | j                  |d      j                         }| j                  |      | _        t
        j                  dt        | j                        |fz         | j                  d| | _        t
        j                  d	t        | j                        z         t
        j                  t         j"                        r1t
        j                  d
       | j%                  | j                         yy)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:)rd  ri  rg  r   r[  r6   r   r]  r   r   _openra   r  r  rd   r  r&   r  r  )r   stream_sizenb_minisectors	used_sizer  s        r1   r  zOleFileIO.loadminifat.  sN    //$2B2BB ))..4+@+@@BtG\G\\"Q&			ut88)[R`ab 	c{"/1XYJJt''JEJJL q)		8C<M~;^^_||O^4		)C,==>GMM*IIl#LL& +r3   c                    	 | j                   j                  | j                  |dz   z         | j                   j                  | j                        }t        |      | j                  k7  rDt        j	                  d|t        |      | j                  fz         | j                  t        d       |S #  t        j	                  d|| j                  |dz   z  | j
                  fz         | j                  t        d       Y xY w)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   )
rk   re   r   r6   r   rM  r   r   ra   rd   )r   r   r  s      r1   r  zOleFileIO.getsectR  s    $	NGGLLDF34
 doo.v;$//)IIBs6{DOO45 6|-DE	NII@tQ/@A B|-LMs   +B0 0AC?c                 r   t        |t              st        d      t        |t              rt        |      dk7  rt        d      	 | j                  j                  | j                  |dz   z         t        |      | j                  k  r||| j                  t        |      z
  z  z  }n#t        |      | j                  k  rt        d      | j                  j                  |       y#  t        j                  d|| j                  |dz   z  | j                  fz         | j                  t        d       Y xY w)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)rf   rg   	TypeErrorrd   rk   re   r   r6   r   rM  r   r   
ValueErrorwrite)r   r   r   paddings       r1   
write_sectzOleFileIO.write_sectr  s    $&EFF'5)S\1_RSS	NGGLLDF34
 t9t&GtT:;;DY(>??d	NIICtQ/@A B|-LMs   +C' 'AD6c                    t        |t              st        d      t        |t              rt        |      dk7  rt        d      	 | j                  j                  |       t        |      }|| j                  k  r||| j                  |z
  z  z  }| j                  |k  rt        d      | j                  j                  |       y#  t        j                  d|| j                  fz         | j                  t        d       Y xY w)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)rf   rg   r  rd   rk   re   r6   r   rM  r   r   r[  r  r  )r   fp_posr   r  len_datas        r1   _write_mini_sectzOleFileIO._write_mini_sect  s     $&JKK'5)S\Q->WXX	NGGLL 
 t9d+++Gt44x?@@D  8+>??d	NIIAt~~./ 0|-LMs   C <Dc                    t         j                  d       | j                  |d      | _        | j                  j                  dz  }t         j                  d| j                  j                  |fz         dg|z  | _        | j                  d      }| j
                  d   | _        | j                  j                          y)z]
        Load the directory.

        :param sect: sector index of directory stream.
        zLoading the Directory:Tr  r   z&loaddirectory: size=%d, max_entries=%dNr   )	r6   r   r  rR  r   r%  r&  rg  r#  )r   r   max_entries
root_entrys       r1   r  zOleFileIO.loaddirectory  s     			*+ !JJttJ< '',,3		:##[12 	3  &;. ((+
OOA&	 			$$&r3   c                    |dk  s|t        | j                        k\  r| j                  t        d       | j                  |   %| j                  t        d       | j                  |   S | j
                  j                  |dz         | j
                  j                  d      }t        |||       | j                  |<   | j                  |   S )aY  
        Load a directory entry from the directory.
        This method should only be called once for each storage/stream when
        loading the directory.

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

        :exception IOError: if the entry has always been referenced.
        r   z OLE directory index out of rangez'double reference for OLE stream/storager   )	rd   r%  r   r   r   rR  re   ra   r   )r   r   r  s      r1   r&  zOleFileIO._load_direntry  s     q5CT__--|-OP??3+/9; ??3''sSy)!!&&s+0TBs##r3   c                 8    | j                   j                          y)z5
        Dump directory (for debugging only)
        N)rg  r   r   s    r1   dumpdirectoryzOleFileIO.dumpdirectory  s     			r3   c           
         t         j                  d||t        |      fz         || j                  k  r|s| j                  s| j                          | j                  j                  }t         j                  d| j                  j                  |fz         | j                  | j                  j                  |d      | _        t        | j                  ||d| j                  | j                  | j                  j                  |       S t        | j                  ||| j                  | j                  | j                  | j                   |       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   )rk   r   r   r   r   r   r   r   )r6   r   strr  rN  r  rg  r   r  r  r   r^  r  rk   r   r   rM  )r   startr   r  size_ministreams        r1   r  zOleFileIO._open  s    			ED#i.)* 	+ $'''	??  " #'))..		AYY))?;< ="&**TYY-A-A#t #- #5e$$%$2E2E!%8L8L'+- - e$$(OO(,TXX&*nn'+	- -r3   c                 ~   ||j                   gz   }|j                  D ]  }|j                  t        k(  r:|r"|j	                  |dd |j                   gz          | j                  |||||       P|j                  t        k(  r&|sf|j	                  |dd |j                   gz          | j                  t        d        y)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  s          r1   r  zOleFileIO._list  s     499+%YY 	BE=0LLuzzl!:;

5&%(C!!\1LLuzzl!:;""#3  6A  B	Br3   c                 H    g }| j                  |g | j                  ||       |S )am  
        Return a list of streams and/or storages stored in this file

        :param streams: bool, include streams if True (True by default) - new in v0.26
        :param storages: bool, include storages if True (False by default) - new in v0.26
            (note: the root storage is never included)
        :returns: list of stream and/or storage paths
        )r  rg  )r   r  r  r  s       r1   listdirzOleFileIO.listdir3  s&     

5"dii(;r3   c                    t        |t              r|j                  d      }| j                  }|D ]M  }|j                  D ]/  }|j
                  j                         |j                         k(  s/ n t        d      |}O |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)	rf   
basestringsplitrg  r  r.   r'  r  r   )r   ri   r  r.   r>  s        r1   _findzOleFileIO._findA  s    $ h
+~~c*Hyy 	Dyy 088>>#tzz|30 .//D	 xxr3   c                     | j                  |      }| j                  |   }|j                  t        k7  rt	        d      | j                  |j                  |j                        S )a;  
        Open a stream as a read-only file object (BytesIO).
        Note: filename is case-insensitive.

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

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

        :returns: file object (read-only)
        :exception IOError: if filename not found, or if this is not a stream.
        zthis file is not a stream)r  r%  r  r   r  r  r  r   r   ri   r   r  s       r1   
openstreamzOleFileIO.openstreama  sU     jj"$|+566zz%**EJJ77r3   c                 Z   |j                   s|j                  |        t        |j                         }| j                  j                   s| j                  j                  |        | j                  | j
                  z  }t        |j                         D ]  \  }}||z  }||z  }| j                  j                   |   dz   | j                  z  || j
                  z  z   }	||dz
  k  r#||| j
                  z  |dz   | j
                  z   }
n||| j
                  z  d  }
| j                  |	|
        y )Nr$   )r  r  rd   rg  ri  r[  	enumerater  )r   r  data_to_writer   
block_sizeidxr   	sect_basesect_offsetr  data_per_sectors              r1   _write_mini_streamzOleFileIO._write_mini_streamv  s!   ""4())*
yy##II&&t,%%)>)>>
"5#3#34 	;IC
*I+Kii**9594;K;KKkZ^ZoZoNooFj1n%"/d6K6K0KcTUgY]YnYnMn"o"/d6K6K0K0L"M!!&/:	;r3   c           	      $   t        |t              st        d      | j                  |      }| j                  |   }|j
                  t        k7  rt        d      |j                  }|t        |      k7  rt        d      || j                  k  r&|j
                  t        k7  r| j                  ||      S |j                  }|| j                  dz
  z   | j                  z  }t         j#                  d|z         t%        |      D ]  }||dz
  k  r<||| j                  z  |dz   | j                  z   }	t        |	      | j                  k(  szJ ||| j                  z  d }	t         j#                  d|| j                  t        |	      || j                  z  fz         t        |	      | j                  z  || j                  z  k(  sJ | j'                  ||	       	 | j(                  |   } |t,        k7  rt        d
      y# t*        $ r t        d	      w xY w)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)rf   rg   r  r  r%  r  r   r  r   rd   r  r  r   r  r  r   r6   r   r   r  r   r   r   )
r   stream_namer   r   r  r   r   r   r"   data_sectors
             r1   write_streamzOleFileIO.write_stream  s    $&GHHjj%$|+011zz3t9^__$'''E,<,<
,J**5$*OOdooa/0T__D
		#j01z" 	NA *Q,"Adoo$51doo8MN;'898"Adoo$5$67		cT__c+.>t@VWX Y;'$//94$//;QQRQOOD+.Nxx~-	N6 :EFF 	  NLMMNs   G::Hc                 j    	 | j                  |      }| j                  |   }|j                  S #  Y yxY w)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  s       r1   get_typezOleFileIO.get_type  s9    	**X&COOC(E###	s   +. 2c                 Z    | j                  |      }| j                  |   }|j                  S )a  
        Return clsid of a stream/storage.

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

        new in version 0.44
        )r  r%  r   r  s       r1   getclsidzOleFileIO.getclsid  s*     jj"${{r3   c                 b    | j                  |      }| j                  |   }|j                         S )a9  
        Return modification time of a stream/storage.

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

        new in version 0.26
        )r  r%  r@  r  s       r1   r@  zOleFileIO.getmtime  -     jj"$~~r3   c                 b    | j                  |      }| j                  |   }|j                         S )a1  
        Return creation time of a stream/storage.

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

        new in version 0.26
        )r  r%  rC  r  s       r1   rC  zOleFileIO.getctime  r  r3   c                 6    	 | j                  |      }y#  Y yxY w)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   ri   r   s      r1   r   zOleFileIO.exists	  s"    	**X&C	s    c                     | j                  |      }| j                  |   }|j                  t        k7  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  s       r1   get_sizezOleFileIO.get_size  sD     jj"$|+9::zzr3   c                 .    | j                   j                  S )zp
        Return root entry name. Should usually be 'Root Entry' or 'R' in most
        implementations.
        )rg  r.   r   s    r1   get_rootentry_namezOleFileIO.get_rootentry_name*  s    
 yy~~r3   c           	         |dk(  rg }|}t        |t              sdj                  |      }| j                  |      }i }	 |j	                  d      }t        |dd       }|j	                  d      }t        |dd       }	|j                  t        |d             d|j	                  t        |j	                  d	            d	z
        z   }t        |d	      }
t        |
t        t        |      dz              }
t!        |
      D ]  }d}	 t        |d|dz  z         }t        |d|dz  z         }t        ||      }t"        j%                  d|||fz         |t&        k(  rt)        ||d	z         }|dk\  rh|dz
  }na|t*        k(  rt)        ||d	z         }nG|t,        t.        t0        fv rt        ||d	z         }n#|t2        t4        fv rt        ||d	z         }n|t6        t8        fv r4t        ||d	z         }||dz   |dz   |z   dz
   }|j;                  dd      }n|t<        k(  rt        ||d	z         }||dz   |dz   |z    }n|t>        k(  r1t        ||d	z         }| jA                  ||dz   |dz   |dz  z          }n`|tB        k(  rtE        t        ||d	z               tE        t        ||dz               dz  z   }|r}||vryt"        j%                  d||tG        |      dz  fz         tI        jH                  dddddd      }t"        j%                  d|dz  z         |tI        jJ                  |dz        z   }n|dz  }n|tL        k(  rtO        ||d	z            }n|tP        k(  rt        ||d	z   |dz          }ne|tR        k(  rt        ||d	z         }||dz   |dz   |z    }n>|tT        k(  rtW        t)        ||d	z               }nd}t"        j%                  d||fz         |||<    |S # t        $ r=}d
t        |      d|}| j                  t        |t        |             |cY d}~S d}~ww xY w# t        $ r<}d|t        |      |fz  }| j                  t        |t        |             Y d}~kd}~ww xY w)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  rQ   r>   rM   rI   rE   s   ****r    z0Error while parsing properties header in stream r   r   rB   z!property id=%d: type=%d offset=%Xi   i   r$   r   r3   r:   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),rf   r  r   r  ra   r   re   r   BaseExceptionr   r   r   typeminru   rd   r  r6   r   VT_I2r|   VT_UI2VT_I4VT_INTVT_ERRORVT_UI4VT_UINTVT_BSTRVT_LPSTRreplaceVT_BLOB	VT_LPWSTRr  VT_FILETIMEr  floatr   r   VT_UI1rq   VT_CLSIDVT_CFVT_BOOLbool)r   ri   r   r   
streampathrk   r   r  r   fmtid	num_propsexcmsgr"   property_idr   property_typer   countr   s                       r1   r   zOleFileIO.getproperties2  s    D M
*c**-J__X&	A1Qr7OE A1Sb6NEGGC2J "''#bggaj/!"344AAq	I 	3s1vz?3	9% b	EAK`E!!QqsUmQ1Q3 #Av		=m]c@dde
 !E)6!8,E~ %"f,6!8,E"ufh&??  6!8,E"vw&776!8,E"w&99
  6!8,EfQhvax~a'78E!MM'37E"g-  6!8,EfQhvax~6E"i/
  6!8,E 221VAXfQhuQw>N3OPE"k1 Qq!12d3q&(;K6Lb6PQE $=(H		"\"-ueEl86K!L#M N /7.?.?aAqRS.T+		"5AS9T"UV 3h6H6HV[]_V_6` ` !& 1"f,q{OE"h."1VAXfRi#89E"e+  6!8,EfQhvax~6E"g- !Qq!12E EIIUYdfsXttu %*[!yb	EH a  	
 Z #'C/d3i@K	R ! E Lj!13O8 8""#3S$s)DDEs7   BO! KP*!	P'*2P"P'"P'*	Q/31Q**Q/c                 n    t               | _        | j                  j                  |        | j                  S )z
        Parse standard properties streams, return an OleMetadata object
        containing all the available metadata.
        (also stored in the metadata attribute of the OleFileIO object)

        new in version 0.25
        )r   rY  r   r   s    r1   get_metadatazOleFileIO.get_metadata  s)     $&&t,}}r3   )r  )FrD  )r   )TF)FN),r   r   r   r   r   r   r   rm  rq  r  r   r  rh   ro  r  r  r  r  r  r  r  r  r  r  r  r&  r  r   r  r  r  r  r  r  r  r  r  r@  rC  r   r  r  r   r  r8   r3   r1   r   r     s    8 !%L!>SJ7Z CJ !4&]6@,4"J2	!HQ#h"'H@44&'R$4 #/% #-LB:@8*;$;G|(     "Vp
r3   r   c                  	   ddl } ddl}d}t        j                  t        j                  t        j
                  t        j                  t        j                  d}d}|j                  |      }|j                  ddd	d
       |j                  dddd       |j                  dddd|d       |j                         \  }}t        dt        dt        d       t        |      dk(  r0t        t               |j!                           | j"                          |j$                  rd|_        t        j(                  ||j&                     d       t+                |D ]$  }	 t-        |      }	t        d       t        |       t        d       |	j/                          |	j1                         D ]  }
|
d   d   dk(  st        d|
z         	 |	j3                  |
d       }t5        |j7                               }|D ]c  \  }}t9        |t:        t<        f      rt        |      d!kD  r|dd! }t9        |t<              rd"D ]  }|t?        |      v sd#} n t        d$||       e  |jD                  rt        d&       |	j1                         D ]  }
t        d'tG        d(jI                  |
            d'd)       |	jK                  |
      }|tL        k(  r/t        d*|	jO                  |
      z         |	jQ                  |
       st        d+|z          t                t        d,       |	jR                  D ]?  }|t        d-|jT                  d.|jW                         d/|jY                                A t                	 |	j[                         }|j]                          t                |	j_                         }t        d1|z         |	ja                  d2      r]t        d3       t        d4|	jK                  d2             t        d5|	jO                  d2             |	ja                  d6      rt        d7       t        d8       |	jb                  r0|	jb                  D ]   \  }}t        d-|jd                  d9|       " nt        d:       ' y#  t@        jC                  d%|
z         Y xY w#  t@        jC                  d0       Y &xY w#  t@        jC                  d;|z         Y xY w)<z
    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   Nrt  )r   infort  rs  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 r8  z( - https://www.decalage.info/en/olefile
r   z%(levelname)-8s %(message)s)r/   formatzD--------------------------------------------------------------------z%r: propertiesTr   2   )r$   r:   r#   r    r;   r<   r=   rA   rB   rD      rE   rF   rG   rH   rI   rJ   rK   rL   rM   rN   rO   rP   rQ   rR   rS   rT   z(binary data)z   z&Error while parsing property stream %rz
Checking streams...-r  r9  zsize %dzNOT a stream : type=%dz5Modification/Creation times of all directory entries:r   z: mtime=z ctime=z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__rd   r   
print_helpexitr)  r*  basicConfigr   r   r  r  r   sorteditemsrf   r  rg   r  r6   	exceptionr%  r   r   r  r   r  r  r%  r.   r@  rC  r  r   r  r   rK  r   )r  r5  DEFAULT_LOG_LEVEL
LOG_LEVELSr#  parseroptionsrp  ri   r   
streamnamer   kvrp   st_typer  metarg  exctyper  s                        r1   mainrO    sY    !MMLLOOMM$$
J @E"""/F
d<o9  ;
d<lk  m
dLz'Sd!e  g '')OWd	k[c
de 4yA~g
" j)9)9:C`a  RDQ	DH%C(O(O(O!kkm ]
b>!$.*Z78] # 1 1*4 1 P &u{{} 5$) /DAq)!j%-@A#&q6B;()#2A)!U3*F !.A'(IaL'8,;(-	!.
 "%A./], $$-."%++- 	BJ#tCHHZ$89#3G!ll:6G,.i#,,z*BBCz26@A	B  IJ =$uzz(%..*:< == G>'')		 G))+D)D01zz.)016^8TUh^ <=::l+AB =>!!$'$6$6 @LGS(8(8#>?@ faRD4]&NQ[&[\D><=&	DMM7(BCsS   !AS<SA?RRCS2AS9 R%C(SR"S%R?<SS__main__rD  )mr   
__future__r   r>  r=  
__author____all__r   r  rx   r  os.pathr  r   r&   r  rg   ru   r  xranger  r   itemsizer  r  r  	NameErrorr
   version_infor   r9  r2   r6   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   rq   r|   r   r   r   r   r   r   r   r   rO  r   r8   r3   r1   <module>rr     s  8 &x  
 
 
 0 0 0
 eDI 5;;s!FU[[!#FU[[!# F
U
VV
  A# !
 #++A- 8 ! 	, 

 	 
  
AGQuaq%5	17!kbX"'
"zj2Ubv	"6Ber"6bg
rJ"62lyB8"	"k
bIR*B); B^b2(
	 4
   
  
'T 	C<1,,*"SW4 W4xP(

 P(l[2 [2@	H H^(DD zF QGI<  Js   F; 'G ;GGG