|iZdZdZddlZddlZddlZddlZddlZddlZej ej ej e Z ej eje dZeejvrejdeddlZejdzfdZedZdZd Zd Zd ezZGd d eZdZdZdZdZGddeZ GddeZ!Gdde!Z"Gdde!Z#Gdde!Z$Gdde!Z%GddeZ&Gd d!e!Z'Gd"d#e!Z(Gd$d%e!Z)Gd&d'e!Z*Gd(d)e!Z+Gd*d+e!Z,Gd,d-e,Z-Gd.d/e,Z.d0Z/d1Z0Gd2d3eZ1d8d5Z2e3d6kr e4d7dSdS)9a( Parse a ppt (MS PowerPoint 97-2003) file Based on olefile, parse the ppt-specific info Code much influenced by olevba._extract_vba but much more object-oriented (possibly slightly excessively so) Currently quite narrowly focused on extracting VBA from ppt files, no slides or stuff, but built to be extended to parsing more/all of the file. For better "understanding" of ppt files, see module ppt_record_parser, which will probably replace this module some time soon. References: * https://msdn.microsoft.com/en-us/library/dd921564%28v=office.12%29.aspx and links there-in WARNING! Before thinking about understanding or even extending this module, please keep in mind that module ppt_record_parser has a better "understanding" of the ppt file structure and will replace this module some time soon! z0.54Nz..c*|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 AC:\PYTHON\_runtimes\venv\Lib\site-packages\oletools/ppt_parser.py get_loggerrJs w~%000"4((  t $ $F g)++,,, OOE MpptcNttjdS)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 rNOTSETrrenable_loggingrks LL     rPowerPoint Documentz.https://bitbucket.org/decalage/oletools/issueszPlease report this issue on %sc"eZdZdZfdZxZS)PptUnexpectedDataz= raise by PptParser if some field's value is not as expected cd|||||_tt||jdS)NzCIn stream "{0}" for field "{1}" found value "{2}" but expected {3}!)formatmsgsuperr__init__)selfstream field_name found_valueexpected_value __class__s rr zPptUnexpectedData.__init__sI Q VFJ ^ D D  &&//99999r)__name__ __module__ __qualname____doc__r __classcell__r&s@rrrs>GG:::::::::rrc^tjd|ddS)z read 1 byte from stream zcheck_value..sD(=(=,/)2(8(8(=(=(=(=(=(=(=(=r] Current UserrCN) isinstancelisttuplejoinrr)r valueexpectedexp_strs r check_valuerRs(T5M** A  FKK(=(=3;(=(=(====?BCG#  ''22 2 ! U   D   U # #Y%5%5h%?%?AA A  rcFeZdZdZdZedZeddZdS) RecordHeaderz a record header, at start of many types found in ppt files https://msdn.microsoft.com/en-us/library/dd926377%28v=office.12%29.aspx https://msdn.microsoft.com/en-us/library/dd948895%28v=office.12%29.aspx c>d|_d|_d|_d|_dSN)rec_ver rec_instancerec_typerec_lenr!s rr zRecordHeader.__init__s#    rcd|}tjd|d\}t|d\|_|_tjd|d\|_tjd|d\|_|S)z reads 8 byte from stream r7r8r;r<)r0r1r2divmodrXrWrYrZ)clzr"objversion_instances r extract_fromzRecordHeader.extract_fromscee"M$ A??(./?(F(F%#+ dFKKNN;;  }T6;;q>>::   rNrc|td|d|zz}|tjd||Stjd|||S)zv generate a record header string given values length of result depends on rec_len being given or not NzRECORD_TYPE not set!r]z.sL,A,A03-6,<,2 ,A,A7?,A,A,A!A!AACFG)$hnt&;$$U++W6699 %  ~.H% (S.4"7  '')9)9()C)CEEH H rcbd}||td|||krd}|||krd}|r|jj}|d|}n.|d|}nd||}t |j|dz|zd ||gSgS) aI simplify verification of values: check value is in given range expect_lower or expected_upper can be given as None to check only one boundary. If value equals one of the boundaries, that is also an error (boundaries form an open interval) :returns: list of PptUnexpectedData exceptions FNz$need at least one non-None boundary!Tz < {0:04X}z > {0:04X}zwithin ({0:04X}, {1:04X})rxrC)rdr&r'rrro)r!r rO expect_lower expect_upperis_errry expect_strs r check_rangezPptType.check_range s  L$8CDD D  # $$  # $$  ~.H#(// == %(// == 8?? @LNN %d&638M&/&6&6u&=&=zKKN NIrcg}||d|jj|j||d|jj|j|jtd||d|jj |j|4||d|jj ||S)z to be called by check_validity to check the self.rec_head uses self.RECORD_... constants, (not quite that constant for DummyType) zrec_head.recVerzrec_head.recInstanceNzRECORD_TYPE not specified!zrec_head.recTypezrec_head.recLen) extendrRrprWRECORD_VERSIONrXRECORD_INSTANCE RECORD_TYPErmrYrZ)r!lengtherrss rcheck_rec_headzPptType.check_rec_head.s  D$$%6 8M%)%8:: ; ; ; D$$%;%)]%?%)%9;; < < <   #%&BCC C D$$%7%)]%;%)%577 8 8 8   KK(():)-)>HH I I I rcZt|j||j|jS)z6 call RecordHeader.generate with values for this type )rTrfrrr)r_rZs rgenerate_patternzPptType.generate_patternDs0$$S_g%(%8#:LNN NrrV)r'r(r)r*rrrrgrbMAIN_STREAM_NAMEr rsrurRrrrrrrriris KON==[=$4::: = = =(   D,NNN[NNNrricheZdZdZdZdZdZdZdZdZ dZ d Z d Z fd Z d Zed ZdZxZS)CurrentUserAtoma An atom record that specifies information about the last user to modify the file and where the most recent user edit is located. This is the only record in the Current User Stream (section 2.1.1). https://msdn.microsoft.com/en-us/library/dd948895%28v=office.12%29.aspx lDgl_@#G iirctt|dd|_d|_d|_d|_d|_d|_d|_ d|_ d|_ d|_ d|_ dS)NrJ)ro)rrr rpsize header_tokenoffset_to_current_edit len_user_namedoc_file_version major_version minor_versionansi_user_nameunicode_user_name rel_versionr!r&s rr zCurrentUserAtom.__init__bs ot$$--.-III   &*#! $!!"!%rc"|j|jkSrV)rHEADER_TOKEN_ENCRYPTr[s r is_encryptedzCurrentUserAtom.is_encryptedps D$===rc|}t||_tjd|d\|_tjd|d\|_tjd|d\|_tjd|d\|_ tjd|d\|_ tjd|d\|_ tjd|d\|_ |d||j |_ tjd|d\|_|d|j z|_|S)z' create instance with info from stream r;r<r7r8r.r)rTrbrpr0r1r2rrrrrrrrrrr_r"r`s rrbzCurrentUserAtom.extract_fromssrcee$0088 M$ A77 "M$ A??&,mD&++a..&I&I#"#]4Q@@ & dFKKNN C C#]4Q@@#]4Q@@ A#[[):;;!=v{{1~~>> & A0A,A B B rc|}||d|j|j||d|j|j|jg||d|j dd||d|j |j ||d|j |j ||d|j|j||d|j|j|jg|S) Nr headerToken lenUserNamedocFileVersion majorVersion minorVersion relVersion)rrrRrSIZErrHEADER_TOKEN_NOCRYPTrrrDOC_FILE_VERSIONr MAJOR_VERSIONr MINOR_VERSIONrREL_VERSION_CAN_USEREL_VERSION_NO_USEr!rs rruzCurrentUserAtom.check_validitys""$$ D$$VTY BBCCC D$$]D4E&*&?&*&?&ABB C C C D$$]D4F%(** + + + D$$%5t7L%)%:<< = = = D$$^T5G%)%799 : : : D$$^T5G%)%799 : : : D$$\43C&*&>&*&=&?@@ A A A r)r'r(r)r*rrrrrrrrrr rrgrbrur+r,s@rrrKs&%%#K DMM      >>>[,rrcLeZdZdZdZdZdZfdZedZ d dZ xZ S) UserEditAtomz An atom record that specifies information about a user edit https://msdn.microsoft.com/en-us/library/dd945746%28v=office.12%29.aspx irrctt|d|_d|_d|_d|_d|_d|_d|_ d|_ d|_ d|_ d|_ dSrV)rrr rplast_slide_id_refversionrroffset_last_editoffset_persist_directorydoc_persist_id_refpersist_id_seed last_viewencrypt_session_persist_id_refrs rr zUserEditAtom.__init__sz lD!!**,,, !% !! $(,%"&#.2+++rcvtd|}t||_t jd|d\|_t jd|d\|_ t jd|d\|_ t jd|d\|_ t jd|d\|_ t jd|d\|_ t jd|d\|_t jd|d\|_t jd|d\|_|d|r0t jd|d\|_nd|_|S) z@ extract info from given stream (already positioned correctly!) z extract UserEditAtom from streamr;r<r7r8r.rN)rdebugrTrbrpr0r1r2rrrrrrrrrr)r_r"rr`s rrbzUserEditAtom.extract_froms 4555cee$0088 !'tV[[^^!D!D}T6;;q>>::  #]4Q@@#]4Q@@ & dFKKNN C C(. dFKKNN(K(K%$"(-fkk!nn"E"E%}T6;;q>>BBtV[[^^<<  A  6 dFKKNN33 0C . .26C . rNc |}||d|j|j||d|j|j||j|kr=|tdd|jd ||j |ks|j |jkrC|tdd|jd |j|||d|j d |S) NrrrzUserEditAtom.offsetLastEditz< {0}z#UserEditAtom.offsetPersistDirectoryz in ({0}, {1})docPersistIdRefr) rrrRrrrrrappendrrrr)r!offsetrs rruzUserEditAtom.check_validitys}""$$ D$$^T5G%)%799 : : : D$$^T5G%)%799 : : :  $.. -)+H)7>>&+A+ACCDDD,661T5JJJ -)9)#**4+@&II KKLLL D$$%6%)% id is {1}, reading {2} offsetsclg|]0}tjddd1S)r;r<rr/)rF_r"s r z6PersistDirectoryEntry.extract_from..usJ!@!@!@%&"(tV[[^^!D!DQ!G!@!@!@rzoffsets are: {0}) rrr0r1r2r^rrrranger)r_r"r`temps ` rrbz"PersistDirectoryEntry.extract_fromWs BCCCcee dFKKNN33(.tU(;(;% s~ H6$ >> @ @ @!@!@!@!@*/ *>*>!@!@!@ $++C,ABBCCC rNc g}|jdkrB|ttd|jdd|jdkr/|ttd|jd|gt |j|krO|ttdt |jd||gt|j|krO|ttdt|jd ||S) Niz PersistDirectoryEntry.persist_idz< 0xFFFFE (dec: {0})rzPersistDirectoryEntry.c_persistz> 0z'PersistDirectoryEntry.rg_persist_offsetz> UserEdit.offsetLastEdit ({0})z%> PersistObjectDirectory offset ({0})) rrrrrrminrmax)r!rpersist_obj_dir_offsetrs rruz$PersistDirectoryEntry.check_validityzsl ?W $ $ KK) "D!7!>!>w!G!GII J J J >Q   KK) "C'' ( ( ( ! ,.//2GGG KK) "KD*++1-.. 00 1 1 1 " -.//2HHH KK) "KD*++7.// 11 2 2 2  r)NN)r'r(r)r*r rgrbrurrrrrGse&&&   [ D48.2rrcFeZdZdZgdZfdZedZdZxZ S)DocInfoListSubContainerOrAtoma; one of various types found in a DocInfoListContainer https://msdn.microsoft.com/en-us/library/dd921705%28v=office.12%29.aspx actual type of this object is defined by the recVersion field in its Record Head Similar to DummyType, RECORD_TYPE varies from instance to instance for this type )iiiiiicVtt|dSrV)rrr rs rr z&DocInfoListSubContainerOrAtom.__init__s& +T22;;=====rctd|}|||jjt jkr!t ||j}ntd|jj td| | |jj tj td| |S)+ build instance with info read from stream z1Parsing DocInfoListSubContainerOrAtom from streamz7skipping over {0} Byte in DocInfoListSubContainerOrAtomrr)rrrsrprYVBAInfoContainerrrbrrZrrrrrs rrbz*DocInfoListSubContainerOrAtom.extract_froms EFFFcee &!!! < $4$@ @ @"// EECC IIOvcl233 5 5 5 II(// >> ? ? ? KK ,bk : : : II&--fkkmm<< = = = rcR|d|jj|jdS)z can be any of multiple types z rh.recTypeN)rRrprYVALID_RECORD_TYPESr[s rruz,DocInfoListSubContainerOrAtom.check_validitys3 t}'=0 2 2 2 2 2r) r'r(r)r*rr rgrbrur+r,s@rrrs~  """>>>>>["2222222rrcFeZdZdZdZdZfdZedZdZ xZ S)DocInfoListContainerz information about the document and document display settings https://msdn.microsoft.com/en-us/library/dd926767%28v=office.12%29.aspx icdtt|d|_dSrV)rrr rg_child_recrs rr zDocInfoListContainer.__init__s. "D))22444 rctd|}|||}||jjz}td||g|_||krt |}|j ||}td|||ktd||dS)rz(Parsing DocInfoListContainer from streamz-start reading at pos {0}, will read until {1}rz>?? A A A "++F36"8"8"88D V8L8L  %&S3BBDDEEFF H H H ))CV145 J J J , V 4 4  %&S1@@BBCCDD F F F &&=v.13333?<3G3G  %&S.==??@@AA C C C $$=v,/1111=f1E1E  %&S_;;==>>?? A A A 1==fEEp rc|}||j||j||j||j||j||j||j |S)z- check all values in object for valid values ) rrrrurrrrrrrs rruz DocumentContainer.check_validitys""$$ D&5577888 D$3355666 D+::<<=== D)88::;;; D&5577888 D$3355666 D&5577888 rrr,s@rrrsw K-----,xx[xv       rrcPeZdZdZdZdZdZdZfdZe d dZ d Z xZ S) rz A container record that specifies VBA information for the document. https://msdn.microsoft.com/en-us/library/dd952168%28v=office.12%29.aspx irrrcdtt|d|_dSrV)rrr vba_info_atomrs rr zVBAInfoContainer.__init__s. %%..000!rNctd|}|||n!td||_t||_|S)zL since can determine this type only after reading header, it is arg zparsing VBAInfoContainerNzskip parsing of RecordHeader)rrrsrp VBAInfoAtomrbr#)r_r"rpr`s rrbzVBAInfoContainer.extract_fromst ,---cee     f % % % % II4 5 5 5#CL'44V<< rc||j}||j|S)Nr)r RECORD_LENGTHrr#rurs rruzVBAInfoContainer.check_validitysA""$*<"== D&5577888 rrV) r'r(r)r*rrrr(r rgrbrur+r,s@rrrs KNOM"""""   [ rrcJeZdZdZdZdZdZfdZedZ dZ xZ S)r%z An atom record that specifies a reference to the VBA project storage. https://msdn.microsoft.com/en-us/library/dd948874%28v=office.12%29.aspx r8 ctt|d|_d|_d|_dSrV)rr%r persist_id_ref f_has_macrosrrs rr zVBAInfoAtom.__init__s: k4  ))+++"  rctd|}||t||_t||_t||_|S)Nzparsing VBAInfoAtom)rrrsr=r-r.rrs rrbzVBAInfoAtom.extract_fromsh '(((cee &!!! $F^^ "&>> Vnn  rc||j}||d|jdd||d|jd|S)Nr' fHasMacrosr8r)rr(rrr.rRrrs rruzVBAInfoAtom.check_validitysq""$*<"== D$$\43DdANNOOO D$$Y a@@AAA r) r'r(r)r*rrr(r rgrbrur+r,s@rr%r%s} KNM [,rr%c<eZdZdZdZdZdZd fd ZdZdZ xZ S) ExternalObjectStorageaI storage for compressed/uncompressed OLE/VBA/ActiveX control data Matches types ExOleObjStgCompressedAtom, ExOleObjStgUncompressedAtom, VbaProjectStgCompressedAtom, VbaProjectStgUncompressedAtom, ExControlStgUncompressedAtom, ExControlStgCompressedAtom Difference between compressed and uncompressed: RecordHeader.rec_instance is 0 or 1, first variable after RecordHeader is decompressed_size Data is not read at first, only its offset in the stream and size is saved e.g. https://msdn.microsoft.com/en-us/library/dd952169%28v=office.12%29.aspx irrNctt||d|_n)|r|j|_d|_n|j|_d|_d|_d|_d|_ dS)NTF) rr3r rRECORD_INSTANCE_COMPRESSED is_compressedRECORD_INSTANCE_UNCOMPRESSEDuncompressed_size data_offset data_size)r!r6r&s rr zExternalObjectStorage.__init__s} #T**33555  #'D  '#'#BD !%D  #'#DD !&D !%rc>td|j|||jj|_|jr$t||_ |xjdzc_| |_ dS)zX not a classmethod because of is_compressed attrib see also: DummyType z:Parsing ExternalObjectStorage (compressed={0}) from streamr<N) rrrr6rsrprZr:r=r8rr9rrs rrbz"ExternalObjectStorage.extract_froms N6$,-- / / / 6""".   %+F^^D " NNa NN!;;==rc*|SrV)rr[s rruz$ExternalObjectStorage.check_validitys""$$$rrV) r'r(r)r*rr5r7r rbrur+r,s@rr3r3sx  K!"#$        ) ) )%%%%%%%rr3cJeZdZdZejZfdZefdZ xZ S)!ExternalObjectStorageUncompressedz< subclass of ExternalObjectStorage for uncompressed objects cXtt|ddS)NF)rr>r rs rr z*ExternalObjectStorageUncompressed.__init__'s( /66??FFFFFrcl|}tt|||SzL note the usage of super here: call instance method of super class! )rr>rbr_r"r`r&s rrbz.ExternalObjectStorageUncompressed.extract_from*s4cee /55BB6JJJ r) r'r(r)r*r3r7rr rgrbr+r,s@rr>r>#spFF+HOGGGGG[rr>cJeZdZdZejZfdZefdZ xZ S)ExternalObjectStorageCompressedz: subclass of ExternalObjectStorage for compressed objects cXtt|ddS)NT)rrDr rs rr z(ExternalObjectStorageCompressed.__init__7s( -t44==dCCCCCrcl|}tt|||SrA)rrDrbrBs rrbz,ExternalObjectStorageCompressed.extract_from:s4cee -s33@@HHH r) r'r(r)r*r3r5rr rgrbr+r,s@rrDrD3spDD+FODDDDD[rrDcfd}|S)z a decorator that can open and close the default stream for func to be applied only to functions in PptParser that read from default stream (:py:data:`MAIN_STREAM_NAME`) Decorated functions need to accept args (self, stream, ...) cd} |j^tdtj|jt|_d}||jg|Ri||rYtdtj|jd|_SS#t$r|j r| YnwxYw |rZtdtj|jd|_dSdS#|rXtdtj|jd|_wxYwNFzopening stream {0!r} for {1}Tzclosing stream {0!r} after {1}) _open_main_streamrrrrr'ole openstreamclose Exception fast_fail_log_exception)r!argskwargsstream_opened_by_mefuncs rwrappedz(with_opened_main_stream..wrappedNs# .%- 8!6"2DMBBDDD)-)<)<=M)N)N&&*#4d4FtFFFvFF# . :!6"2DMBBDDD&,,...)-&&  . & & &~ &##%%%%%  &&# . :!6"2DMBBDDD&,,...)-&&&  . ." . :!6"2DMBBDDD&,,...)-&----s%A6C&D=E"?DE""AF>rrTrUs` rwith_opened_main_streamrWEs#.....6 Nrcfd}|S)zB same as with_opened_main_stream but with yield instead of return c?Kd} |j^tdtj|jt|_d}||jg|Ri|D]}|Vn,#t$r|j r| YnwxYw|rZtdtj|j d|_dSdS#|rXtdtj|j d|_wxYwrI) rJrrrrr'rKrLrNrOrPrM)r!rQrRrSresultrTs rrUz2generator_with_opened_main_stream..wrappedos# .%- 8!6"2DMBBDDD)-)<)<=M)N)N&&*#$tT%;MdMMMfMM     & & &~ &##%%%%%  &# . :!6"2DMBBDDD&,,...)-&&&  . ." . :!6"2DMBBDDD&,,...)-&----s+A>BD&B/,D.B//DAE,rrVs` r!generator_with_opened_main_streamr[ls#.....8 NrceZdZdZddZddZdZdZedZ ed Z e d Z e d Z e d Zed ZedZe dZdS) PptParserzW Parser for PowerPoint 97-2003 specific data structures requires an OleFileIO Fct|tjr"td||_nFtd|tj||_||_d|_d|_ d|_ d|_ |j }td|Dr|dd|dd|D}d |vr|dd|d t|vr|dd|td|_dS) z constructor :param ole: OleFileIO or anything that OleFileIO constructor accepts :param bool fast_fail: if True, all unexpected data will raise a PptUnexpectedData; if False will only log error zusing open OleFileIOzOpening file {0}Nc3<K|]}t|dkVdS)rN)rrFr"s rrHz%PptParser.__init__..s-;;Fs6{{a;;;;;;rrootlistdirzlen = 1cBg|]}|dS)r)lowerr`s rrz&PptParser.__init__..s&EEEfq ))EEErz current userrJ)rKolefile OleFileIOrrrKrrOcurrent_user_atomnewest_user_editdocument_persist_objpersist_object_directoryrbany_failrrdrJ)r!rKrO root_streamss rr zPptParser.__init__sR c7, - - . II, - - -DHH II(//44 5 5 5(--DH"!% $$(!(,%x''))  ;;l;;; ; ; C JJvy, B B BEE EEE -- JJvy, G G G%%''<77 JJvy,8H I I I!%rNc|tjdd}n:tj\}}}tj|}t |}t |ttj |D]J\}}| D]0}t d ||1KdS)a log an exception instead of raising it call in one of 2 ways: try: if fail(): self._log_exception('this is the message') except: self._log_exception() # only possible in except clause Nztrace {0}: {1}) traceback extract_stacksysexc_info extract_tbstrrerror enumerate format_list splitlinesrr) r!rstackrexctracei_entryrlines rrPzPptParser._log_exceptions ?+--crc2EELNNMAsE(//Ec((C #' (=e(D(DEE B BNGU((** B B *11'4@@AAAA B B Brch|jr t||t|jdS)zt depending on self.fast_fail raise PptUnexpectedData or just log err args as for PptUnexpectedData N)rOrrPr)r!rQs rrlzPptParser._fails< > >#T* *    14 8 < = = = = =rcR|jtdtdd} td|jd}t ||_n,#t$r|j r| YnwxYw|0td| dSdS#|/td| wwxYw)z parse the CurrentUserAtom record from stream 'Current User' Structure described in https://msdn.microsoft.com/en-us/library/dd948895%28v=office.12%29.aspx Nz-::<< (*% $kk KK , , ,%11&,GGI$,(1% II) * * *++--D 0 =#VCII..000 L L >EEcJJKKKK  1g II*vi@AA C C C KK :BK H H H 4@@HH  II) * * *#226::D 0 =#VCII..000 * * F#VC[[****  1g **> ! !*3u/F+G+GGI E!6%"2G"'"9;;<<<&/u/F%G%G!!ME6 1%2B52HII!/FYkkkkkkrcL|jtd|j||jj}|j|}td||td|| |tj t ||_td|j}|r:tdt||D]/}td|0|r|jr |ddSdS) z. Part 2: Identify the document persist object NzBre-reading and overwriting previously read document_persist_objectz)newest user edit ID is {0}, offset is {1}z seek to {0}rrz)check_validity(document_persist_obj): {0}r)rirrrjrrhrrrrrrrrbrurrO)r!r" newest_refrrrs rparse_document_persist_objectz'PptParser.parse_document_persist_objectYs  $ 0 KKB C C C  ( 0  / / 1 1 1 *= .z: =6*f-- / / / -&&v../// FBK(((%6$B$B6$J$J! %&&&(7799  M KK9@@TKK L L L & &C KKC & & & &  DN q'M    rc#Kd}t|}td|||krt dd} |}|dz }||}||}|dkrVtd||z||zV|||dz}|dkVt||kr'|||z|z tj n>td t|||d S) z. search for pattern in stream, return indices r*zpattern length is {0}zneed buf > pattern to search!rTrrozfound pattern at index {0}z1reached end of buf (read {0}<{1}) after {2} readsN) rrrrrdrr2findrrr) r!r"patternBUF_SIZE pattern_lenn_reads start_posbufidxs rsearch_patternzPptParser.search_patternsj'll  )00==>>>  ! !<== =  I qLG++h''C((7##C)) 6==imLLMMM#o%%%hhwA..)) 3xx8## I0;> LLLL M!6#c((Hg>>@@@% rc#Ktdttjt t jz}||D]|}||td| t |}n$#t$r| YwxYw| }|r;t dt|nctd|j}td|j|j|j|V|D]/}t d|0|r|jr|d~d S) aY search through stream for VBAInfoContainer, alternative to parse... quick-and-dirty: do not parse everything, just look for right bytes "quick" here means quick to program. Runtime now is linear is document size (--> for big documents the other method might be faster) .. seealso:: search_vba_storage zlooking for VBA info containers)rZextracting at idx {0}rzcontainer is okz2persist id ref is {0}, has_macros {1}, version {2}z%check_validity(VBAInfoContainer): {0}rN)rrrrr(r%rrrrbrNrPrurrr#r-r.rrO)r!r"rr containerratomrs rsearch_vba_infozPptParser.search_vba_infos  3444"33(8(F4HH..(3(A/CCC &&w//  C KK    II-44S99 : : : ,99&AA    ##%%% ++--D  =#VCII..0000 +,,, . N!6$"5t7H"&,00111  * * C#VC[[****  1g 3  sCC?>C?c #KtdttfD]}|dt j|}||D]a}||td | | |}n$#t$r| Y|wxYw| }|r;td t|nGtd |j|jj|j|V|D]5}td |j|6|r|jr|dcdS)a search through stream for VBAProjectStg, alternative to parse... quick-and-dirty: do not parse everything, just look for right bytes "quick" here means quick to program. Runtime now is linear is document size (--> for big documents the other method might be faster) The storages found could also contain (instead of VBA data): ActiveX data or general OLE data yields results as it finds them .. seealso:: :py:meth:`search_vba_info` zlooking for VBA storage objectsrrrz8storage is ok; compressed={0}, size={1}, size_decomp={2}zcheck_validity({0}): {1}N)rrr>rDrrrrrrrbrNrPrurrr6rprZr8r'rO)r!r"obj_typerrstoragerrs rsearch_vba_storagezPptParser.search_vba_storages" 3444:8:! "! "H KK2; ' ' '//11G**733 " " C    188==>>>&33F;;GG '')))H--// "KK A!'D !2!24444II0%vg&;&-&6&>&-&? A ABBB "MMMAACKK :!'(93!?!?AAAA"DN"q'M3 "! "! "s=CC43C4cDtd||jtjt ||j\}}}td|t|||r |j r||S)z2 return decompressed data from search_vba_storage z.decompressing storage for VBA OLE data stream z-decompressed {0} to {1} bytes; found err: {2}) rrrr9rriterative_decompressr:rrrO)r!r"rdecompn_readrs rdecompress_vba_storagez PptParser.decompress_vba_storage s BCCC  G'555 ): ; ;  A6&#f++s33 5 5 5  4> I rctd|j|j||jt j||j}|S)z0 return data pointed to by uncompressed storage zCreading uncompressed VBA OLE data stream: {0} bytes starting at {1}) rrrr:r9rrrr2)r!r"rdatas rread_vba_storage_datazPptParser.read_vba_storage_data'sk .6'+W-@AA C C C  G'555{{7,-- rc#Kd}d}|D]}|dz }|jjdkr|dz }d}d}|D]B}|dz }|jr|dz }||V+||VCtd ||||dS)z@ search vba infos and storages, yield uncompressed storage data rrzCfound {0} infos ({1} with macros) and {2} storages ({3} compressed)N) rr#r.rr6rrrrr)r!r"n_infosn_macrosr n_storages n_compressedrs r iter_vba_datazPptParser.iter_vba_data2s ((**  D qLG!.22A   ..00 : :G !OJ$ :! 11'::::::00999999 $&(J EE G G G G Gr)FrV)r'r(r)r*r rPrlrrWrrr[rrrrrrrrrr]r]sU %&%&%&%&NBBBB,>>>8_0_0_0B$$$V''&>',,'&,\'2"2"'&2"h:'GG'&GGGrr]ctj}d}d}d} ||krIt||z |}||||z }||z }||kIn#tj$r }|}Yd}~nd}~wwxYw|||fS)z( decompress data from stream chunk-wise rrN)zlib decompressobjr decompressr2rv) r"r chunk_size decompressorrr return_errn_newrs rrrMs%''L F FJtmmV Z00E l--fkk%.@.@AA AF eOFtmm :  6: %%sAA++B:BB__main__znothing here to run!)r)5r* __version__rrrr0rprrpathnormpathabspathdirname__file___thismodule_dirrN _parent_dirinsertreCRITICALrrrrURL_OLEVBA_ISSUESMSG_OLEVBA_ISSUESrNrr4r9r=rRobjectrTrirrrrrrrrrr%r3r>rDrWr[r]rr'printrrrrsZ    '""27??27??83L3L#M#MNNgrw||OTBBCC chHOOA{####+A-<j!!!)E47HH ::::: :::222 222 222 A A A"(L(L(L(L(L6(L(L(LVqNqNqNqNqNfqNqNqNhPPPPPgPPPfJJJJJ7JJJ^%7%7%7%7%7%7%7%7P/////7///dLLLLLFLLL^,2,2,2,2,2G,2,2,2^,,,,,7,,,^ddddddddN     w   F.....'...b1%1%1%1%1%G1%1%1%h     (=        &;   $$$$ND|G|G|G|G|G|G|G|G~ &&&&& z E !!!!!r