|idZddlmZdZdZdZgdZddlZddlZddl Z ddl Z ddl Z ddl Z ddlZddlZddlZeeureZ eZn #e$reZYnwxYwe j djd krdZnCe j d jd krd Zn'e j d jd krd Zn ed  en #e$reZYnwxYwejdd krdZndZej dzfdZ!e!dZ"dZ#dZ$dZ%dZ&dZ'dZ(dZ)dZ*dZ+dZ,dZ-dZ.d Z/d Z0dZ1dZ2dZ3dZ4dZ5d Z6d Z7dZ8dZ9dZ:dZ;dZd"Z?d#Z@d$ZAd%ZBd&ZCd'ZDd(ZEd)ZFd*ZGd+ZHd,ZId-ZJd.ZKd/ZLd0ZMd1ZNd2ZOd3ZPd4ZQd5ZRd6ZSd7ZTd8ZUd9ZVd:ZWd;ZXdZ[iZ\e]e^_D]\Z`Zae`dd d?kre`e\ea<d@Zbd Zcd)Zdd3ZedAZfdBZgdZdCZheeurdDZindEZid[dFZjd[dGZkdHZldIZmGdJdKenZoGdLdMeoZpGdNdOZqGdPdQerZsGdRdSejtZuGdTdUZvGdVdWZwdXZxeydYkr exdSdS)\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.5+ Project website: https://www.decalage.info/olefile olefile is copyright (c) 2005-2023 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 2023-12-01z0.47zPhilippe Lagadec) isOleFile OleFileIO OleMetadataenable_loggingMAGIC STGTY_EMPTY STGTY_STREAM STGTY_STORAGE STGTY_ROOTSTGTY_PROPERTYSTGTY_LOCKBYTESMINIMAL_OLEFILE_SIZE DEFECT_UNSUREDEFECT_POTENTIALDEFECT_INCORRECT DEFECT_FATALDEFAULT_PATH_ENCODING MAXREGSECTDIFSECTFATSECT ENDOFCHAINFREESECT MAXREGSIDNOSTREAM UNKNOWN_SIZE WORD_CLSIDOleFileIONotClosedNLIiz>Need to fix a bug with 32 bit arrays, please contact author...zutf-8c*|tjjjvr+tj|}|||Stj|}|tj|||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. )loggingLoggermanager loggerDict getLoggersetLevel addHandler NullHandler)namelevelloggers =C:\PYTHON\_runtimes\venv\Lib\site-packages\olefile/olefile.py get_loggerr2s w~%000"4((  t $ $F g)++,,, OOE MolefilecNttjdS)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&NOTSETr3r1rrs LL     r3sࡱlllli @ABCDEFGHVT_z$00020900-0000-0000-C000-000000000046(icd}|7t|tkr|dtt}ndSt|drMt|dr=|tt}|dnt |tr5t|tkr|dtt}nOt|d5}|tt}dddn #1swxYwY|tkrdSdS)a 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. If data is provided, it also checks if the file size is above the minimal size of an OLE file (1536 bytes). If filename is provided with the path of the file on disk, the file is open only to read the first 8 bytes, then closed. .. versionadded:: 0.16 :param filename: filename, contents or file-like object of the OLE file (string-like or file-like object) - if data is provided, filename is ignored. - if filename is a unicode string, it is used as path of the file to open on disk. - if filename is a bytes string smaller than 1536 bytes, it is used as path of the file to open on disk. - [deprecated] if filename is a bytes string longer than 1535 bytes, it is parsed as the content of an OLE file in memory. (bytes type only) Note that this use case is deprecated and should be replaced by the new data parameter - if filename is a file-like object (with read and seek methods), it is parsed as-is. :type filename: bytes, str, unicode or file-like object :param data: bytes string with the contents of the file to be checked, when the file is in memory (added in olefile 0.47) :type data: bytes :returns: True if OLE, False otherwise. :rtype: bool NFreadseekrrbT) lenrrhasattrrbrc isinstancebytesopen)filenamedataheaderfps r1rrsUDF  t99, , ,+3u::+&FF5 6 " " )wx'@'@ )s5zz** a He $ $)X:N)N)N+3u::+&(D ! ! )RWWSZZ((F ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) tus3(D''D+.D+c t|SN)ordcs r1i8rsOs 1vv r3c2|jtur|n|dS)Nr) __class__intrqs r1rsrsSsK3&&qqAaD0r3cNtjd|||dzdS)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)restriprr}tuplemaprs)clsids r1_clsidrks u::     ;;u  r 4%mmS]]CqMM : #b%"+&& ' '( )*r3cjtjdddddd}|tj|dzzS)zD convert FILETIME (64 bits int) to Python datetime.datetime Ar$rr@ microseconds)datetime timedelta)filetime_FILETIME_null_dates r1filetime2datetimer|s< #+D!Q1a@@ !32!N!N!N NNr3ceZdZdZdS) OleFileErrorz- Generic base error for this module. N__name__ __module__ __qualname____doc__r8r3r1rr Dr3rceZdZdZdS)NotOleFileErrorz? Error raised when the opened file is not an OLE file. Nrr8r3r1rrrr3rc4eZdZdZgdZgdZdZdZdZdS)raT 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 )codepagetitlesubjectauthorkeywordscommentstemplate last_saved_byrevision_numbertotal_edit_time last_printed create_timelast_saved_time num_pages num_words num_chars thumbnailcreating_applicationsecurity) codepage_doccategorypresentation_targetrhlines paragraphsslidesnotes hidden_slidesmm_clips scale_crop heading_pairstitles_of_partsr(company links_dirtychars_with_spacesunused shared_doc link_basehlinkshlinks_changedversiondig_sig content_typecontent_statuslanguage doc_versioncd|_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|_.dS)z_ Constructor for OleMetadata All attributes are set to None by default N)/rrrrrrrrrrrrrrrrrrrrrrrhrrrrrrrrrr(rrrrrrrrrrrrrrselfs r1__init__zOleMetadata.__init__se        !## #$(!   #'     ! !#  !%  "   " r3ch|j|jzD]}t||d|drr|dddg}t t |jD]7}||dzd}t||j||8|drp|dd}t t |jD]9}||dzd}t||j||8dSdS) 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. :param ole_file: OleFileIO object from which to parse properties NzSummaryInformationTr@) convert_time no_conversionr$zDocumentSummaryInformationr)SUMMARY_ATTRIBSDOCSUM_ATTRIBSsetattrexists getpropertiesrangereget)role_fileattribpropsr"values r1parse_propertieszOleMetadata.parse_propertiessi+d.AA ( (F D&$ ' ' ' ' ??3 4 4 >**+C8 > !A#t,,d215u==== ??; < < =**+K8<+>>E3t23344 = = !A#t,,d1!4e<<<< = =  = =r3c jtd|jD]B}t||}td|t |Ctd|jD]B}t||}td|t |CdS)z< Dump all metadata, for debugging purposes. z*Properties from SummaryInformation stream:- {}: {}z2Properties from DocumentSummaryInformation stream:N)printrgetattrformatreprr)rproprs r1dumpzOleMetadata.dump#s :;;;( 8 8DD$''E *##D$u++66 7 7 7 7 BCCC' 8 8DD$''E *##D$u++66 7 7 7 7 8 8r3N) rrrrrrrrrr8r3r1rrss  HOEEEN5 5 5 n = = =D 8 8 8 8 8r3rc*eZdZdZdfd ZdZxZS)rzR Warning type used when OleFileIO is destructed but has open file handle. Ncdtt|||_dSro)superrr stack_of_open)rrrus r1rzOleFileIONotClosed.__init__4s.  $''00222*r3c|d}|jr2d|ddg|jzS|S)NzDeleting OleFileIO instance with open file handle. You should ensure that OleFileIO is never deleted without calling close() first. Consider using "with OleFileIO(...) as ole: ...".r zStacktrace of open() call: )rjoinr)rmsgs r1__str__zOleFileIONotClosed.__str__8sT3   77C'EF-4466788 8Jr3ro)rrrrrr __classcell__)rus@r1rr0sV++++++       r3rceZdZdZdZdS) 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 OleFileIO 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  tdtd|||||t|t|fz||_|jjjrtdd} |tkr.t||z}d} td||dz z|z} td| z| t|kr |j td g} |d krE|tkr:td |j td t| D]} td | |fz|tkrY| rtdn^td|j td|d ks|t|krotd||t|fztd| | fz|j tdn | |||zznX#t$rKtd||||zz|fz|j tdYn+wxYw||} t| |kr|t|dz krtd|t||||zz|t| fztd|||zzt| zz|j td| |  ||dz}y#t"$r$|j tdYnwxYwd| } t| |kr>tdt| |fz| d|} ||_n| r?tdt| zt| |_n`tdt| |fzt| |_|j tdt(j|| dS) 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 zOleStream.__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 largerz!size == 0 and sect != ENDOFCHAIN:z+incorrect OLE sector index for empty streamzReading stream sector[%d] = %Xhz6Reached ENDOFCHAIN sector for stream with unknown sizez$sect=ENDOFCHAIN before expected sizezincomplete OLE streamzsect=%d (%X) / len(fat)=%dzi=%d / nb_sectors=%d,incorrect OLE FAT, sector index out of rangezsect=%d, seek=%d, filesize=%dOLE sector index out of rangez9sect=%d / len(fat)=%d, seek=%d / filesize=%d, len read=%dzseek+len(read)=%dincomplete OLE sectorr9r3z3Read 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)r6debugrerolermclosedOSErrorr _raise_defectrrrrc Exceptionrbappend IndexErrorrsizeioBytesIOr)rrmsectroffset sectorsizefatfilesize olefileio unknown_size nb_sectorsrkr" sector_datas r1rzOleStream.__init__Zs' '((( Y4VJs3xxb BC D D D 8;  PNOO O <  s88J&DL II2 3 3 3jl+ :  #j0111 C H " "#35_ ` ` ` 199++ II9 : : : H " "#35b c c cz""3 3 A II71d)C D D Dz!!VIIVWWWEIIDEEEH**+;=TUUUAvvs3xx 6$c#hh9OOPPP 01j/ABBB &&'79ghhh d!223333    96*T/18<=>>>&&'79XYYY   ''*--K ;++s3xxz0B0B U3s88VJtO%;Xs;GWGWXYZZZ - 41GKHXHX1XYZZZ&&'79PQQQ KK $ $ $ 4y:-   &&'79ghhh  xx~~ t99   IIKsSWyyZ^N__ ` ` `;DDII  ^ IIKcRViiW X X XD DII IIQUXY]U^U^`dTee f f fD DI H " "#35\ ] ] ] D$'''''s%JAK21K2 O++*PPN)rrrrrr8r3r1rrFs2&|(|(|(|(|(r3rceZdZdZdZdZejeeksJdZdZ dZ dZ dZ d Z d Zd Zdd ZdZdZdS)OleDirectoryEntryz@ OLE2 Directory Entry pointing to a stream or a storage z<64sHBBIII16sIQQIIIc||_||_g|_i|_d|_t jtj|\|_ |_ |_ |_ |_ |_|_}|_|_|_|_|_|_|j t,t.t0t2fvr|t6d|j t,kr!|dkr|t6d|dkr+|j t,kr|t6d|j dkr"|t6dd|_ |j d|j d z |_||j|_t> d |jtC|jfzt> d |j zt> d |jzt> d |j |j|jfz|j"dkrs|jdkr[|jdkrPt> d|j"|j|j|jfz|tFd|j|_$n$|jtK|jdzz|_$t> d|j$|j|jfztM||_'|j t.kr&|j$dkr|tPdd|_)|j t,t0fvrZ|j$dkrO|j$|j*kr|j t0krd|_)nd|_)|+|j|j)d|_,dS)ae Constructor for an OleDirectoryEntry object. Parses a 128-bytes entry from the OLE Directory stream. :param bytes entry: bytes string (must be 128 bytes long) :param int sid: index of this directory entry in the OLE file directory :param OleFileIO ole_file: OleFileIO object containing this directory entry Fzunhandled OLE storage typerzduplicate OLE root entryzincorrect OLE root entryrUz(incorrect DirEntry name length >64 bytesNr:zDirEntry SID=%d: %sz - type: %dz - sect: %Xhz% - SID left: %d, right: %d, child: %dr9z+sectorsize=%d, sizeLow=%d, sizeHigh=%d (%X)zincorrect OLE stream size z% - size: %d (sizeLow=%d, sizeHigh=%d)zOLE storage with size>0T)-sidr4kids kids_dictusedryrzr STRUCT_DIRENTRYname_raw namelength entry_typecolorsid_left sid_right sid_child dwUserFlags createTime modifyTime isectStartsizeLowsizeHighr r r r rr name_utf16_decode_utf16_strr.r6rrrrrlongrrr is_minifatminisectorcutoff_check_duplicate_stream sect_chain)rentryrrrs r1rzOleDirectoryEntry.__init__sx   " M+;U C C M O O J M N N    O O O L M ?:}lK"X X X  " "#35Q R R R ?j ( (SAXX  " "#35O P P P !88:55  " "#35O P P P ?R    " "#35_ ` ` ` DO-(<$/!*;(<= ..t??  '48T$)__*EEFFF -$/1222 .4?2333 9T] NDN=,, - - -  # % %}!!dmz&A&A G#. dmT][\]]]&&}6QRRR DII T](;(;R(?@DI 9TY VZVcX % %   T^ , , , INN      & %r3cdtd|z|tkrdS|dks|t|jjkr"|jtddS|j|}td|j t|j |j |j |jfz|jr"|jtddSd|_||j |j }||jvr |jtd|j|||j|<||j |dS) 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) zappend_kids: child_sid=%dNrzOLE 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)r6rrrer4 direntriesrr_load_direntryrrr.rrrrr2lowerrrrr4)r child_sidchild name_lowers r1r2zOleDirectoryEntry.append_kidss - 9:::  F Q;;)S)@%A%AAA L & &'79Z [ [ [ [ [L// ::E II`9d5:..QVQ`ab c c cz  **+;9;;;EJ   U^ , , ,))++JT^++ **+;7999 I  U # # #).DN: &   U_ - - -  $ $ & & & & &r3c"|j|jkSzCompare entries by namer.rothers r1__eq__zOleDirectoryEntry.__eq__syEJ&&r3c"|j|jkSr=r>r?s r1__lt__zOleDirectoryEntry.__lt__sy5:%%r3c.|| Sro)rAr?s r1__ne__zOleDirectoryEntry.__ne__s;;u%%%%r3cV||p||Sro)rArCr?s r1__le__zOleDirectoryEntry.__le__s%{{5!!7T[[%7%77r3rcgd} ||j}n#t$rd}YnwxYwtd|zt|jz|d|jt t fvrt|jddt|jtt fvr$|j rtd|zd|j zz|j D]}| |dzdS) 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) endrhz{%s}r:N) rrrrr.r r rr rrr)rtabTYPES type_namekids r1rzOleDirectoryEntry.dumps ))) $do.II $ $ $#III $ c#gTY'<<<< ?|Z8 8 8 $)W# . . . .  ?}j9 9 9dj 9 #c'FTZ// 0 0 09  C HHS1W      s  ##cD|jdkrdSt|jS)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 rN)rrrs r1getmtimezOleDirectoryEntry.getmtime& ?a  4 111r3cD|jdkrdSt|jS)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 rN)rrrs r1getctimezOleDirectoryEntry.getctimerRr3Nr)rrrrr DIRENTRY_SIZErycalcsizerr0r4r2rArCrErGrrQrTr8r3r1r r s*,OM 6?? + +} < < < <___B4446.,',','\'''&&&&&&888$ 2 2 2 2 2 2 2 2r3r c6eZdZdZdeddefdZdZdZdZ e fdZ d1d Z d2d Z d Zd2d Zd2dZd3dZd3dZdZdZdZdZdZd4dZd4dZdZdZdZedfdZd5dZd5d Z d!Z!d"Z"d#Z#d$Z$d%Z%d&Z&d'Z'd(Z(d)Z)d*Z*d+Z+d6d,Z,d-Z-d.Z.d/Z/d6d0Z0dS)7ra 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:: with OleFileIO("fan.mic") as ole: 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|_&d|_'d|_(d|_)|r? |*||dS#tV$r|,dwxYwdS)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. The caller is responsible for closing it when done. :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) NF) write_modewarn)-_raise_defects_levelparsing_issuesrZ path_encoding _filesize ministream_used_streams_fat_used_streams_minifat byte_order directory_fpr6 dll_versionrfirst_difat_sectorfirst_dir_sectorfirst_mini_fat_sectorrm header_clsidheader_signaturemetadatamini_sector_shiftmini_sector_sizemini_stream_cutoff_sizer- minifatsectr'minisectorsize minor_versionnb_sectnum_difat_sectorsnum_dir_sectorsnum_fat_sectorsnum_mini_fat_sectors reserved1 reserved2root sector_shift sector_sizetransaction_signature_numberwarn_if_not_closed _we_opened_fp _open_stackrir_close)rrj raise_defectsrZrr_s r1rzOleFileIO.__init__s:%2!!$*!#%'" "& $%)"  $ !% $'+$  $"! !%##$(!  ,0)"'"    (z :::::     '''    s 1E "E,c2|ddS)z?Destructor, ensures all file handles are closed that we opened.Tr[Nrrs r1__del__zOleFileIO.__del__ms  r3c|Sror8rs r1 __enter__zOleFileIO.__enter__ss r3c2|ddS)NFr[r)rargss r1__exit__zOleFileIO.__exit__ws  r3c||jkr%t||||j||ft|dS)a This method should be called for any defect found during file parsing. It may raise an OleFileError 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, OleFileError by default N)r]r6errorr^rwarning)r defect_levelmessageexception_types r1rzOleFileIO._raise_defect{sj" 44 4 4 IIg    .)) )   & &'@ A A A KK r3replacecv|d|}|jr||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 bytes utf16_str: bytes string encoded in UTF-16 LE format :param str errors: str, see python documentation for str.decode() :return: str, encoded according to path_encoding :rtype: str zUTF-16LE)decoder_encode)r utf16_strerrors unicode_strs r1r$zOleFileIO._decode_utf16_strsE &&z6::   %%d&8&AA A r3c(||_t|dr||_nt|tr2t |t krtj||_n@|jrd}nd}t|||_d|_ tj |_ d}|jdtj |j}|jdn#|jdwxYw||_t&d|j|jfzg|_g|_|jd}t |dks|dd t0kr\t&d |dd t0|t6d t8d }t;j|}t&d ||dzfz|d|}t;j||\|_ |_!|_"|_#|_$|_%|_&|_'|_(|_)|_*|_+|_,|_-|_.|_/|_0|_1t&t;j|||j t0kr|t6d|j!tedkr|tfdt&d|j"zt&d|j#z|j#dvr|tfdt&d|j$z|j$dkr|tfdd|j%z|_4t&d|j4z|j4dvr|tfd|j#dkr |j4dks|j#dkr&|j4dkr|tfd d|j&z|_5t&d!|j5z|j5d"vr|tfd#|j'dks |j(dkr|tfd$t&d%|j)z|j4dkr&|j)dkr|tfd&t&d'|j*zt&d(|j+zt&d)|j,z|j,dkr|tld*t&d+|j-z|j-dkrD|tfd,t&7d-|j-zd|_-t&d.|j.zt&d/|j/zt&d0|j0zt&d1|j1z||j4zd2z |j4zd2z |_8t&d3|j8|j8fzts|d d4|_!|j4|_:|j5|_;|j-|_<|=|j+|j/r|=|j.|j1r|=|j0|>||?|j+|j.|_@dS)5a1 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. The caller is responsible for closing it when done :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) rbzr+brdTrzFile size: %d bytes (%Xh)rNr>zMagic = {!r} instead of {!r}z#not an OLE2 structured storage filez<8s16sHHHHHHLLLLLLLLLLzfmt_header size = %d, +FAT = %dizincorrect OLE signaturerEzincorrect CLSID in OLE headerzMinor Version = %dz%DLL Version = %d (expected: 3 or 4))r#r z"incorrect DllVersion in OLE headerz#Byte Order = %X (expected: FFFE)iz!incorrect ByteOrder in OLE headerr:z0Sector Size = %d bytes (expected: 512 or 4096))rr^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))rUz(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 headerzNumber of FAT sectors = %dzFirst 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 %dzFirst MiniFAT sector = %XhzNumber of MiniFAT sectors = %dzFirst DIFAT sector = %XhzNumber of DIFAT sectors = %dr$z/Maximum number of sectors in the file: %d (%Xh)rM)ArZrfrmrgrhrerrrrir traceback extract_stackrrcosSEEK_ENDtellr`r6rrbrcrbrrrrrryrWrzrkrjrrrfrdr{rmrxryrurvrhr}rorirwrgrt bytearrayrr|rnrrrsrrrqr'r(loadfat loaddirectoryrp) rrjrZmoderrl fmt_header header_sizeheader1s r1rizOleFileIO.opensq"% 8V $ $ 9DGG % ( ( 9S]]>R-R-Rj**DGG 8T**DG!%D (688D    Q $$$ w||~~H GLLOOOODGLLOOOO! -0PPQQQ"$%'"c"" v;;#  u!4!4 II4;;F2A2JNN O O O   |-RTc d d dN. oj11  4 [SXEX7YY[[[+&( M*g . .'  !       O    " N N    !  -  (  &  %  #  " 6=88999  E ) )   |-F G G G   " - -   /1P Q Q Q '$*<<>>> :T=MMOOO  6 ) )   /1U V V V 84?JLLL ?f $ $   /1T U U Ud// EHXXZZZ  ; . .   /1V W W W  a  D$4c$9$9  a  D$4d$:$:   /1f g g g !4#9 9 DtG\\^^^   , ,   /1[ \ \ \ >Q  $.A"5"5   /1a b b b 58LLNNN  S T%91%<%<   /1f g g g /$2FFHHH 2T5JJLLL 9D<]]___  , 1 1   /1h i i i DtGcceee  '6 1 1   /1b c c c KKd45 6 6 6+1D ( 4t7QQSSS 3d6OOQQQ 4t7NNPPP 3d6LLNNN#T%55a7Dz..free..z[ END. ]zFATSECT zDIFSECT r$indexrIrJ%8X%6X:r9z --->N)rrrrrerr) rr firstindexVPLfatnamesnbsectnlinesr"lrrauxr.s r1dumpfatzOleFileIO.dumpfatsc       S*Q,$ g3s & &A %!) % % % % % v  AcEE &Ju,-3 7 7 7 75%),, % %f99E1vZ'(??#C=DDqs{{)$t|d$$$$$ GGGG!  r3c4d}tjt|}tjdkr|t |}||zdz |z}t ddt|D]}t d|zdt t|D]h}||z} t d|| zzdt| | |zD](}||krn||} d| z} t | d)t id S) zS Display a sector in a human-readable form, for debugging purposes r>bigr$rrIrJrrN)arrayUINT32sys byteorderbyteswaprerr) rsectorrrrLrrr"rrrr.s r1dumpsectzOleFileIO.dumpsects? k&&)) =E ! ! LLNNNS*Q,$ g3s & &A %!) % % % % % v  AcEE &Ju,-3 7 7 7 75%),, % %f99E1vt|d$$$$$ GGGG  r3ctjt|}tjdkr||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)rrrrr)rras r1 sect2arrayzOleFileIO.sect2arrays4 K % % =E ! ! JJLLLr3ct|tjr|}nN||}tt jr||d}|D]}|dz}td|z|tks |tkrtdn:| |}||}|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. Nr9z isect = %Xzfound end of sector chain) rgrrr6 isEnabledForr&DEBUGrrrrgetsectr)rrfat1isectsnextfats r1 loadfat_sectzOleFileIO.loadfat_sects dEK ( ( $DD??4((D .. $ d### * *EJ&E IIlU* + + + ""ex&7&7 5666 U##Aooa((Gx')DHH r3c"td|dd}tdt|t|dzfztjt|_|||jdkrtd|jdkr| td |j |j kr| td td |jdzd z }|jdz |zd z |z}td |z|j|krtd|j }t!|D]}td||fz||}||}tt(jr||||d|||}td|z|t.t0fvrtdntdt|j|j krOtdt|j|j fz|jd|j |_tdt|j|j fztt(jr6td||jdSdS)z% Load the FAT table. zDLoading the FAT table, starting with the 1st sector after the headerLrzlen(sect)=%d, so %d integersr rz)DIFAT is used, because file size > 6.8MB.mz#incorrect DIFAT, not enough sectorsz)incorrect DIFAT, first index out of rangezDIFAT analysis...r$z nb_difat = %dzincorrect DIFATzDIFAT block %d, sector %XNznext DIFAT sector: %Xzincorrect 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:)r6rrerrrrrtrvrrrgrsrrIOError iterrangerrrr&rrrrr) rrlrnb_difat_sectorsnb_difat isect_difatr" sector_difatdifats r1rzOleFileIO.loadfat!s9 XYYYbf~ 1SYYD 1 4MMOOO ;v&& $  !Q & & IIA B B B#s**""#35Z[[[&$,66""<1\]]] II* , , ,!% 2A5 ,S03CCAEHXXH II1 3 3 3%11/0001Kx(( C C 6![9IIKKK#||K88  55##GM220MM,///!!%(9)9(9":;;;#$45  2[@BBBB:x"88867779 II< = = = tx==4< ' ' II9S]]DL>>   GM * * ' IIl # # # LL & & & & & ' 'r3c |j|j|dzzn[#t$rNtd||j|dzz|jfz|tdYnwxYw|j |j}t||jkrMtd|t||jfz|td|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=%drz*getsect(): sect=%X, read=%d, sectorsize=%dr) rmrcrrr6rr`rrrbre)rrrs r1rzOleFileIO.getsects$ N GLLDF3 4 4 4 4 N N N II@tQ/@A B B B   |-L M M M M M Ndo.. v;;$/ ) ) IIBs6{{DO45 6 6 6   |-D E E E s%(AB?Brct|tstdt|trt|dkrtd |j|j|dzzn[#t$rNt d||j|dzz|j fz| tdYnwxYwt||jkr|||jt|z zz }n't||jkrtd|j|dS)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=%drData is larger than sector sizeN)rgrh TypeErrorrermrcrrr6rr`rr ValueErrorwrite)rrrkpaddings r1 write_sectzOleFileIO.write_sectsb$&& GEFF F'5)) TS\\1__RSS S N GLLDF3 4 4 4 4 N N N IICtQ/@A B B B   |-L M M M M M N t99t & & GtT:; ;DD YY ( (>?? ?  ds%BACCcNt|tstdt|trt|dkrtd |j|nO#t $rBtd||j fz| tdYnwxYwt|}||j kr|||j |z zz }|j |krtd|j|dS)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=%drrN)rgrhrrermrcrr6rr`rrrnrr)rfp_posrkrlen_datas r1_write_mini_sectzOleFileIO._write_mini_sectsB$&& LJKK K'5)) YS\\Q->->WXX X N GLL  N N N IIAt~./ 0 0 0   |-L M M M M M Nt99 d+ + + Gt4x?@ @D  8 + +>?? ?  dsA88A CCcxtd||d|_|jjdz}td|jj|fzdg|z|_|d}|jd|_|jdS)z] Load the directory. :param sect: sector index of directory stream. zLoading the Directory:Trr z&loaddirectory: size=%d, max_entries=%dNr) r6rrrerr6r7rzr4)rr max_entries root_entrys r1rzOleFileIO.loaddirectorys *+++ !JJttJ<<',3  :   #[ 12 3 3 3  &;.((++ OA& $$&&&&&r3c|dks|t|jkr|td|j|(|td|j|S|j|dz|jd}t||||j|<|j|S)a^ 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 OleFileError: if the entry has always been referenced. rz OLE directory index out of rangeNz'double reference for OLE stream/storager ) rer6rrrrercrbr )rrr*s r1r7zOleFileIO._load_direntrys q55CT_----   |-O P P P ?3  +   /9 ; ; ;?3' ' sSy)))!&&s++0TBBs##r3c8|jdS)z5 Dump directory (for debugging only) N)rzrrs r1 dumpdirectoryzOleFileIO.dumpdirectory,s r3c $td||t|fz||jkr|s|jsp||jj}td|jj|fz| |jj|d|_t|j||d|j |j |jj|St|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=%dTrr)rmrrrrrrr)r6rstrr'rar.rzrr rrrqr-rmrrr`)rstartrrsize_ministreams r1rzOleFileIO._open2s, E D#i.. )* + + + $' ' ' '? 5  """#'). AY)?;<==="&**TY-A#t#-#5#5e$$%$2E!%8L'+--- - e$$(O(,TX&*n'+ --- -r3Tc|||jgz}|jD]}|jtkrB|r&||dd|jgz||||||T|jt kr)|r&||dd|jgz|tddS)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.rrr r_listr rr)rfilesprefixnodestreamsstoragesr*s r1rzOleFileIO._listWs49+%Y B BE=00<LLuzl!:;;; 5&%(CCCC!\11<LLuzl!:;;;""#36ABBBB B Br3cFg}||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 )rrz)rrrrs r1listdirzOleFileIO.listdirss* 5"di(;;; r3ct|tr|d}|j}|D]N}|jD]3}|j|krn4td|}O|jS)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 /zfile not found) rg basestringsplitrzrr.r8rr)rrjrr.rOs r1_findzOleFileIO._finds$ h + + +~~c**Hy  Dy 0 08>>##tzz||33E4.///DDxr3c||}|j|}|jtkrt d||j|jS)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. zthis file is not a stream)rr6rr rrr rrrjrr*s r1 openstreamzOleFileIO.openstreamsWjj""$  | + +566 6zz%*EJ777r3c|js||t|j}|jjs|j||j|jz}t |jD]\}}||z}||z}|jj|dz|jz||jzz} ||dz kr|||jz|dz|jz} n|||jzd} || | dS)Nr$)r)r0rerzr|rn enumerater) rr* data_to_writer  block_sizeidxr sect_base sect_offsetrdata_per_sectors r1_write_mini_streamzOleFileIO._write_mini_streams1 )  " "4 ( ( ()** y# - I & &t , , ,%)>> "5#344 ; ;IC *I+Ki*9594;KKkZ^ZoNooFj1n%%"/d6K0KcTUgY]YnMn0n"o"/d6K0K0L0L"M  ! !&/ : : : : ; ;r3c 8t|tstd||}|j|}|jt krtd|j}|t|krtd||j kr'|jtkr| ||S|j}||jdz z|jz}t d|zt%|D]}||dz kr8|||jz|dz|jz} t| |jksJnr|||jzd} t d||jt| ||jzfzt| |jz||jzksJ|||  |j|}#t*$rtd wxYw|t,krtd dS) 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 stringzthis is not a streamz?write_stream: data must be the same size as the existing stream)r*rr$rNzGwrite_stream: size=%d sectorsize=%d data_sector=%Xh size%%sectorsize=%drz)incorrect last sector index in OLE stream)rgrhrrr6rr rrrerr'r r r rr6rrrrrr) r stream_namerkrr*rrr r" data_sectors r1 write_streamzOleFileIO.write_streamsR$&& IGHH Hjj%%$  | + +011 1z 3t99  ^__ _ $' ' 'E,< ,J,J**5$*OO Odoa/0T_D  #j0111z"" N NA*Q,"Ado$51do8M$MN ;''88888"Ado$5$6$67  cT_c+.>.>t@VWXYYY;''$/94$/;QQQQQ OOD+ . . . Nx~ N N NLMMM N :  EFF F  s  G##G=cx ||}|j|}|jS#t$rYdSwxYw)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)rr6rrrs r1get_typezOleFileIO.get_typesO **X&&COC(E# #   55 s (+ 99cT||}|j|}|jS)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 )rr6rrs r1getclsidzOleFileIO.getclsids)jj""${r3cn||}|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 )rr6rQrs r1rQzOleFileIO.getmtime$1jj""$~~r3cn||}|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 )rr6rTrs r1rTzOleFileIO.getctime3rr3cT ||}dS#t$rYdSwxYw)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)rr)rrjrs r1rzOleFileIO.existsBs? **X&&C4   55 s  ''c||}|j|}|jtkrt d|jS)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. zobject is not an OLE stream)rr6rr rrrs r1get_sizezOleFileIO.get_sizeQsFjj""$  | + +9:: :zr3c|jjS)zp Return root entry name. Should usually be 'Root Entry' or 'R' in most implementations. )rzr.rs r1get_rootentry_namezOleFileIO.get_rootentry_nameas y~r3c X|dkrg}|}t|tsd|}||}i} |d}t |dd}|d}t |dd} |t|dd|t|d d z z}t|d } ne#t$rX} d t|| } | t| t| |cYd} ~ Sd} ~ wwxYwt| tt!|dz } t#| D]} d } t|d| dzz}t|d | dzz}t||}t$|d }t(d||||fz|||d z||||}|||<#t$rH} d|t|| fz} | t| t| Yd} ~ d} ~ wwxYw|S) 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) NrrQr>rMrIrE****r z6Error while parsing properties header in stream {}: {}rrBUNKNOWN$property id=%d: type=%d/%s offset=%X3Error while parsing property id %d in stream %s: %s)rgrrrrbrrcr BaseExceptionrrrrtypeminrvrerVTrr6r_parse_property)rrjrr streampathrmrkrrfmtid num_propsexcrr" property_idr property_typevt_namers r1rzOleFileIO.getpropertieshs D M *c** .*--J __X & &  A1QrT7OOE A1SbS6NNE GGC2JJ   "''#bggajj//!"3444AAq II   KQQZ  #''C   /d3ii @ @ @KKKKKK  3s1vvz??33 9%% E EAK E!!QqsUmm Q1Q3 #Av && :: @KQ^`gioCppqqq,,Qq+}Vbdqrr$)[!!  E E ELj!1!13O88""#3S$s))DDDDDDDD  E s9 CD E6A E1+E61E6:BI J'>J""J'c |d}|tks|ttfvr|||||||\}}n|tt zkrt dd} t||} g} t| D]U}t||| z}|||| zdz||||\}} | || | dzz } V| }n|tzr|tz} t dt | dzd} t||} g} t| D]E}|||| z||tz||\}} | || | z } F| }nt d||fz|S)Nz'property_type == VT_VECTOR | VT_VARIANTr zproperty_type == VT_VECTOR | %sr!5property id=%d: type=%d not implemented in parser yet) VT_BLOBVT_CLSIDVT_CF_parse_property_basic VT_VECTOR VT_VARIANTr6rrrrr'r)rrrr-r.rrv_offcountvaluesszproperty_type_bases r1r(zOleFileIO._parse_propertys  G # #}58I'I'I--amUacpqqDAqq i*4 4 4 II? @ @ @C6NNEF5\\   #Av| 4 4 33Av|a7GVceqtABB2 a   rAv AA Y & n!.)!;  II7"&&ASU^:_:__ ` ` `C6NNEF5\\  221fslKQ^bkakQkmy|IJJ2 a   r AA IIMQ\^kPll m m mr3cFd}d}|tkrt||}|dkr|dz }d}n|tkrt||}d}n|ttt fvrt ||}d}n|ttfvrt ||}d}n|ttfvrCt ||} ||dz|dz| zdz }| dd}d| z}n0|tkr*t ||} ||dz|dz| z}d| z}n|tkrFt ||dz} |||dz|dz| dzz}d| dzz}n|tkrt!t ||t!t ||dzd zz}|r||vrt"d ||t'|d z fzt)jd ddddd} t"d |dzz| t)j|dzz}n|d z}d}n|t,krt/||}d}n|t0krt3|||dz}d}n|t4kr)t ||} ||dz|dz| z}d| z}nL|t6kr t9t||}d}n!d}t"d||fz||fS)Nrr:r r$rr3r8Converting property #%d to python datetime, value=%d=%fs逖rtimedelta days=%d@T$r@rr>rEr1)VT_I2r}VT_UI2VT_I4VT_INTVT_ERRORrVT_UI4VT_UINTVT_BSTRVT_LPSTRrr2 VT_LPWSTRr$ VT_FILETIMEr%r6rfloatrrVT_UI1rsr3rr4VT_BOOLbool) rrrr-r.rrrrr;rs r1r5zOleFileIO._parse_property_basicsED%%AvE>>!EME&((Av5&(";;;Av67"333Av7H"555 Av&(6!8E>!#334 gs335y'))Av&(6!8E>125y)++ Avax((..q&(57:J1J/KLL519}+--SF^^,,SF1H5E5E0F0F0JK .K}$D$DIIX)5%,,x2GHIJJJ+3*;D!Q1a*P*P'II1U=O5PQRRR/(2DRWY[R[2\2\2\\EE"X-E&((1V9 (**qr !1233%''Av&(6!8E>125y'))SF^^,, QU`boTppqqq$; r3cjt|_|j||jS)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 )rrlrrs r1 get_metadatazOleFileIO.get_metadata% s-$   &&t,,,}r3c  td}|dkrg}|}t|tsd|}||}g}|d}t|dd} t |d} g} t| D]} |d}t|dd} | |krt |d}||d |t |d d z z}t |d }|ddd|zz}dd|zz}t |||d z}|d z }t|D]} |||d z}t ||d z|dz}||dz|dz|z d  d }| |dd |dz|z}t|tt|dz }td|D]'} d} t |d| dzz}t |d| dzz}t ||}t |d}t$d||||fz|t(kr t+||d z}|dkr|dz }n|dkr+t ||dz}||dz|dz|zdz }n|t,krt+||d z}n|t.t0t2fvrt ||d z}n|t4t6fvrt ||d z}ny|t8t:fvrAt ||d z}||dz|dz|zdz }|dd}n(|t>kr(t ||d z}||dz|dz|z}n|t@kr>t ||d z}|!||dz|dz|dzz}n|tDkrtGt ||d ztGt ||dzdzz}|r||vrt$d||tI|dz fztKj%dddddd}t$d|dzz|tKj&|dzz}n|dz}n|tNkrtQ||d z}n|tRkrt||d z|dz}n|tTkr't ||d z}||dz|dz|z}nM|tVkr!tYt+||d z}n!d}t$d ||fz||| dz d!<#tZ$rI}d"|t]||fz}|/t`|tc|Yd}~!d}~wwxYwnW#tZ$rJ}d#t]|d$|}|/t`|tc||cYd}~Sd}~wwxYw|S)%rs՜.+,NrrQr>rMrIrEr r utf_8) property_namerr:rrBr!r"r@rAr$rr3rrBrCrrDrEr@rr1rr#z0Error while parsing properties header in stream z: )2rrgrrrrbrrrcrrrr&rvrerr'rr6rrFr}rGrHrIrJrKrLrMrNrr2rOr$rPr%rQrrrRrsr3r4rSrTr$rrrr%)rrjrrFMTID_USERDEFINED_PROPERTIESr)rmrkrrsections_countsection_file_pointersr"r* file_pointerr+PropertyIdentifierAndOffsetr entry_count identifierstr_sizestringr-rr.r/rr;rr,rs r1get_userdefined_propertiesz$OleFileIO.get_userdefined_properties1 s (..q'r'r$ D M *c** .*--J __X & & GGBKKq2wQ "R >**H QH QGGBKKq"v888#&q"::LGGL)))"''#bggajj//A*=">">>A #Aq I23Aq9}4D2E/a kME"%auQw&7"8"8KQJE";//11%&ueQh%7 #&qq%!));'<#=#=!"57E!GH,<#>,1EME!.!!3!3+.q&1*+=+=()&2+frkH6Lq6P*P(Q!.&!8!8(+Avz(:(:!.5&(2K!K!K),Avz(:(:!.672C!C!C(+Avz(:(:!.7H2E!E!E ),Avz(:(:()&1*VaZ%5G!5K*K(L(- gs(C(C!.'!9!9),Avz(:(:()&1*VaZ%5G*G(H!.)!;!; ),Avz(:(:(,(>(>q!FUVJY^abYbLbAb?c(d(d!.+!=!=(,SFQJ-?-?(@(@DQPVYZPZI[I[D\D\`bDb(c$0 !>K}4T4T$'II.h15>Y93Z9Y>>Z [?[ [[)r)FrU)r)TF)FN)1rrrrrrrrrrrrr$rirrr(rrrrrr.rrrrr7rrrrrrrr rrrrQrTrrrrr(r5rVrdr8r3r1rrs8!%L!>SSSSSj    CO!!!!4(_6_6_6_6B   '''',,,,2""""H2   !!!FQ#Q#Q#f"'"'"'H>44&'&'&'P$$$2 #/%#-#-#-#-JBBBB8    >888*;;;$;G;G;Gz&               >>>>@>[[[|   {{{{{{r3rc | ddl}ddl}d}tjtjtjtjtjd}d}||}| ddd d | d dd d | dddd | dddd|d| \}}td ttt|dkr7tt ||j|jrd|_tj||jdt-|D]*} t/|} tdt|td| | D]} | dddkrtd| z | | d !} t7| } | D]~\} } t;| t<t>frt| d"kr | dd"} t;| t>rd#D]}|tA| vrd$} ntd%| | n-#tB$r tD#d&| zYnwxYw |j$r}| %| d !}t|rWtd'| ztM|D]5\}}td( ||d)|d*6#tD#d+| zYxYw|j'rtd,| D]} td-tQd.)| d-d/0| *| }|tVkr;td1| ,| z| -| td2|zttd3| j.D]Q}|Mtd4 |j/|0|1Rt | 2}|3n*#tB$rtD#d5YnwxYwt| 4}td6|z| 5d7rytd8td9| *d7td:| ,d7| 5d;rtd<td=| j6r6| j6D]-\}}td> |j7|.ntd?| 8#tB$r!tD#d@|zY(wxYwdS)Az 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 rNr)rinforrcriticalz1usage: %prog [options] [filename2 ...])usagez-c store_true check_streamsz*check all streams (for debugging purposes))actiondesthelpz-pextract_custompropz$extract all user-defined propertiresz-d debug_modez\debug mode, shortcut for -l debug (displays a lot of debug information, for developers only)z-lz --loglevelloglevelstorezBlogging level debug/info/warning/error/critical (default=%default))rlrkdefaultrmz=olefile version {} {} - https://www.decalage.info/en/olefile rz%(levelname)-8s %(message)s)r/rzD--------------------------------------------------------------------z%r: propertiesTr2)r$r:r#r r;r<r=rArBrDrErFrGrHrIrJrKrLrMrNrOrPrQrRrSrTz (binary data)z z&Error while parsing property stream %rz%r: user-defined propertiesz {} {}: {}rZrz3Error while parsing user-defined property stream %rz Checking streams...-rrIrJzsize %dzNOT a stream : type=%dz5Modification/Creation times of all directory entries:z- {}: mtime={} ctime={}zError while parsing metadatazRoot entry name: "%s" worddocumentzThis is a Word document.ztype of stream 'WordDocument':zsize :z macros/vbaz%This document may contain VBA macros.z( Non-fatal issues raised during parsing:rNonezError while parsing file %r)9roptparser&rINFOWARNINGERRORCRITICAL OptionParser add_option parse_argsrr __version____date__rer print_helpexitrorp basicConfigrrrrrsorteditemsrgrrhrrr6 exceptionrnrdrrjrrrr rrr6r.rQrTrVrrrr^rr)rrzDEFAULT_LOG_LEVEL LOG_LEVELSrhparseroptionsrrjr streamnamerkr8rr variablesrvariablest_typer*metarzexctypers r1mainr sR !MLOM$   J @E  " " " / /F d!$..*Z7888] # 1 1*4 1 P P &u{{}} 5 5$) / /DAq)!j%-@AA/#&q66B;;()#2#A)!U33.*L!.!.A'(IaLL'8'8,;(-(9"%A.... /%]]] &NQ[&[\\\\\] j"5t(+(F(Fz`d(F(e(eI"9~~t %&Cj&P Q Q Q7@7K7K!t!tOE8$)-*>*>uhF_`hip`q*r*r$s$s$s$sj &[^h&hiiiii=/B$ -..."%++-- B BJ#tCHHZ$8$899#3GGGG!ll:66G,..i#,,z*B*BBCCCz22226@AAAA I J J J = =$3::5:((%..*:*:<<=== GGG >''))  > > > <===== > GGG))++D )D0 1 1 1zz.)) C01116 ^8T8TUUUh ^ < <===::l++CABBB = > > >! $'$6DDLGS*++G,rs8&%%%%%x      EEEEEEEEEEEEEEEEEEEEEEEEEEEE e DIIIII 5;s!! FFU[!## FFU[!##FF *U V VV JJJJJA#! #+A-8j!!! ,          AGQuaq%5 17!kbX"' "zj2Ubv "6Ber"6bg rJ"62lyB8" "k bIR*B);B^b2(  D((LGSrr{e3 4   ::::z C<<111,,,,,,,, * * *"OOO     7        l   X8X8X8X8X8X8X8X8t,P(P(P(P(P( P(P(P(lZ2Z2Z2Z2Z2Z2Z2Z2~qqqqqqqqp/ODODODd zDFFFFFs#AA  A .B11B;:B;