
    ZiZ                        S r SrSSKrSSKrSSKrSSKrSSKrSSKr\R                  R                  \R                  R                  \R                  R                  \5      5      5      r\R                  R                  \R                  R                  \S5      5      r\\R                  ;  a  \R                  R!                  S\5        SSKr\R$                  S-   4S jr\" S5      rS rS	rS
rS\-  r " S S\5      rS rS rS rS r " S S\5      r  " S S\5      r! " S S\!5      r" " S S\!5      r# " S S\!5      r$ " S S\!5      r% " S S\5      r& " S  S!\!5      r' " S" S#\!5      r( " S$ S%\!5      r) " S& S'\!5      r* " S( S)\!5      r+ " S* S+\!5      r, " S, S-\,5      r- " S. S/\,5      r.S0 r/S1 r0 " S2 S3\5      r1S7S4 jr2\3S5:X  a	  \4" S65        gg)8a'  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!

z0.54    Nz..   c                 >   U [         R                  R                  R                  ;   a)  [         R                  " U 5      nUR                  U5        U$ [         R                  " U 5      nUR                  [         R                  " 5       5        UR                  U5        U$ )aR  
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      m/var/www/eduai.edurigo.com/question_generate/ques_gen_env/lib/python3.13/site-packages/oletools/ppt_parser.py
get_loggerr   J   sy     w~~%%000 ""4(t$F g))+,
OOEM    pptc                  J    [         R                  [        R                  5        g)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 r   r   enable_loggingr   k   s     LL r   PowerPoint Documentz.https://bitbucket.org/decalage/oletools/issueszPlease report this issue on %sc                   ,   ^  \ rS rSrSrU 4S jrSrU =r$ )PptUnexpectedData   z<raise by PptParser if some field's value is not as expected c                 n   > SR                  XX45      U l        [        [        U ]  U R                  5        g )NzCIn stream "{0}" for field "{1}" found value "{2}" but expected {3}!)formatmsgsuperr   __init__)selfstream
field_namefound_valueexpected_value	__class__s        r   r!   PptUnexpectedData.__init__   s/    QVFD 	 	/9r   )r   )__name__
__module____qualname____firstlineno____doc__r!   __static_attributes____classcell__r'   s   @r   r   r      s    G: :r   r   c                 T    [         R                  " SU R                  S5      5      S   $ )zread 1 byte from stream <Br   r   structunpackreadr#   s    r   read_1r8           ==v{{1~.q11r   c                 T    [         R                  " SU R                  S5      5      S   $ )z read 2 byte (short) from stream <H   r   r3   r7   s    r   read_2r=      r9   r   c                 T    [         R                  " SU R                  S5      5      S   $ )zread 4 byte (long) from stream <L   r   r3   r7   s    r   read_4rA      r9   r   c                    [        U[        [        45      (       aA  X;  a;  SSR                  S U 5       5      -   S-   n[	        SU SR                  U5      U5      egX!:w  a,  [	        SU SR                  U5      SR                  U5      5      eg)z0simplify verification of values in extract_from [ OR c              3   D   #    U  H  nS R                  U5      v   M     g7f{0:04X}Nr   .0vals     r   	<genexpr>check_value.<locals>.<genexpr>   s%      (=3;C )2(8(8(=(=3;    ]Current UserrG   N)
isinstancelisttuplejoinr   r   )r   valueexpectedexp_strs       r   check_valuerX      s    (T5M** FKK (=3;(= = =?BCG#  '2 2 ! 
	DU#Y%5%5h%?A 	A 
r   c                   B    \ rS rSrSrS r\S 5       r\SS j5       rSr	g)	RecordHeader   za 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                 <    S U l         S U l        S U l        S U l        g N)rec_verrec_instancerec_typerec_lenr"   s    r   r!   RecordHeader.__init__   s     r   c                 J   U " 5       n[         R                  " SUR                  S5      5      u  n[        US5      u  Ul        Ul        [         R                  " SUR                  S5      5      u  Ul        [         R                  " SUR                  S5      5      u  Ul        U$ )zreads 8 byte from stream r;   r<      r?   r@   )r4   r5   r6   divmodr_   r^   r`   ra   )clzr#   objversion_instances       r   extract_fromRecordHeader.extract_from   s}     e"MM$A?(./?(F%#+dFKKN;}}T6;;q>: 
r   Nc                     Uc  [        S5      eUSU-  -   nUc  [        R                  " SXQ5      $ [        R                  " SXQU5      $ )zegenerate a record header string given values

length of result depends on rec_len being given or not
zRECORD_TYPE not set!re   z<HHz<HHL)
ValueErrorr4   pack)rg   r`   ra   r_   r^   ri   s         r   generateRecordHeader.generate   sQ     344"TL%88?;;u&6AA;;v'77KKr   )r_   ra   r`   r^   )Nr   r   )
r)   r*   r+   r,   r-   r!   classmethodrj   ro   r.   r   r   r   rZ   rZ      s6       L Lr   rZ   c                   v    \ rS rSrSrSrSrSr\S 5       r	\
4S jrS rS rS	 rS
 rSS jr\SS j5       rSrg)PptType   z|base class of data types found in ppt ole files

starts with a RecordHeader, has a extract_from and a check_validity method
Nr   c                     [        S5      e)Nabstract base function!NotImplementedError)rg   r#   s     r   rj   PptType.extract_from   s    !";<<r   c                     Xl         S U l        g r]   )stream_namerec_head)r"   r{   s     r   r!   PptType.__init__   s    &r   c                 8    [         R                  U5      U l        g r]   )rZ   rj   r|   r"   r#   s     r   read_rec_headPptType.read_rec_head   s    $11&9r   c                     [        S5      e)zcheck validity of data

replaces 'raise PptUnexpectedData' so caller can get all the errors
(not just the first) whenever she wishes.

to be overwritten in subclasses

:returns: list of PptUnexpectedData
rv   rw   rb   s    r   check_validityPptType.check_validity   s     "";<<r   c                    [        U[        [        45      (       aj  X#;  ab  U R                  R                  nSSR                  S U 5       5      -   S-   n[        U R                  US-   U-   SR                  U5      U5      /$  / $ X2:w  aS  U R                  R                  n[        U R                  US-   U-   SR                  U5      SR                  U5      5      /$ / $ )zssimplify verification of values: check value equals/is in expected

:returns: list of PptUnexpectedData exceptions
rC   rD   c              3   D   #    U  H  nS R                  U5      v   M     g7frF   rH   rI   s     r   rL   &PptType.check_value.<locals>.<genexpr>   s&      ,A7? -6,<,<S,A,A7?rN   rO   .rG   )	rQ   rR   rS   r'   r)   rT   r   r{   r   )r"   r   rU   rV   clz_namerW   s         r   rX   PptType.check_value   s    
 hu..$>>22 ,A7?,A !A ACFG)$$hnt&;$$U+W6 9 9	 % 	 ~~..H%  (S.4"7  ')9)9()CE H H 	r   c                 b   SnUc  Uc  [        S5      eUb  X#::  a  SnUb  X$:  a  SnU(       a  U R                  R                  nUc  SR                  U5      nO'Uc  SR                  U5      nOSR                  UU5      n[	        U R
                  US-   U-   SR                  U5      U5      /$ / $ )	a   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
Fz$need at least one non-None boundary!Tz	< {0:04X}z	> {0:04X}zwithin ({0:04X}, {1:04X})r   rG   )rm   r'   r)   r   r   r{   )r"   r   rU   expect_lowerexpect_upperis_errr   
expect_strs           r   check_rangePptType.check_range  s     L$8CDD#$#$~~..H#(//=
%(//=
8??@LN
%d&6&638M&/&6&6u&=zK N N Ir   c                 ,   / nUR                  U R                  SU R                  R                  U R                  5      5        UR                  U R                  SU R                  R
                  U R                  5      5        U R                  c  [        S5      eUR                  U R                  SU R                  R                  U R                  5      5        Ub6  UR                  U R                  SU R                  R                  U5      5        U$ )zto be called by check_validity to check the self.rec_head

uses self.RECORD_... constants, (not quite that constant for DummyType)
zrec_head.recVerzrec_head.recInstancezRECORD_TYPE not specified!zrec_head.recTypezrec_head.recLen)extendrX   r|   r^   RECORD_VERSIONr_   RECORD_INSTANCERECORD_TYPErx   r`   ra   )r"   lengtherrss      r   check_rec_headPptType.check_rec_head.  s     D$$%68M8M%)%8%8: 	;D$$%;%)]]%?%?%)%9%9; 	< #%&BCCD$$%7%)]]%;%;%)%5%57 	8 KK(():)-)>)>H Ir   c                 n    [         R                  U R                  UU R                  U R                  5      $ )z5call RecordHeader.generate with values for this type )rZ   ro   r   r   r   )rg   ra   s     r   generate_patternPptType.generate_patternD  s2     $$S__g%(%8%8#:L:LN 	Nr   )r|   r{   r]   )r)   r*   r+   r,   r-   r   r   r   rq   rj   MAIN_STREAM_NAMEr!   r   r   rX   r   r   r   r.   r   r   r   rs   rs      sd    
 KON= = $4 :
=( D, N Nr   rs   c                   l   ^  \ rS rSrSrSrSrSrSrSr	Sr
S	rS
rSrU 4S jrS r\S 5       rS rSrU =r$ )CurrentUserAtomiK  a  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
l   Dg l   _@#G    	   i     i     r   c                    > [         [        U ]  SS9  S U l        S U l        S U l        S U l        S U l        S U l        S U l	        S U l
        S U l        S U l        S U l        g )NrP   )r{   )r    r   r!   r|   sizeheader_tokenoffset_to_current_editlen_user_namedoc_file_versionmajor_versionminor_versionansi_user_nameunicode_user_namerel_versionr"   r'   s    r   r!   CurrentUserAtom.__init__b  sk    ot-.-I	 &*#! $!!"!%r   c                 4    U R                   U R                  :H  $ r]   )r   HEADER_TOKEN_ENCRYPTrb   s    r   is_encryptedCurrentUserAtom.is_encryptedp  s      D$=$===r   c                    U " 5       n[         R                  U5      Ul        [        R                  " SUR                  S5      5      u  Ul        [        R                  " SUR                  S5      5      u  Ul        [        R                  " SUR                  S5      5      u  Ul        [        R                  " SUR                  S5      5      u  Ul	        [        R                  " SUR                  S5      5      u  Ul
        [        R                  " SUR                  S5      5      u  Ul        [        R                  " SUR                  S5      5      u  Ul        UR                  S5        UR                  UR                  5      Ul        [        R                  " SUR                  S5      5      u  Ul        UR                  SUR                  -  5      Ul        U$ )z&create instance with info from stream r?   r@   r;   r<   r2   r   )rZ   rj   r|   r4   r5   r6   r   r   r   r   r   r   r   r   r   r   rg   r#   rh   s      r   rj   CurrentUserAtom.extract_froms  sO    e $008MM$A7	"MM$A?&,mmD&++a.&I#"#]]4Q@ &dFKKN C#]]4Q@#]]4Q@A#[[):):;!==v{{1~> &A0A0A,A B
r   c                 8   U R                  5       nUR                  U R                  SU R                  U R                  5      5        UR                  U R                  SU R
                  U R                  U R                  /5      5        UR                  U R                  SU R                  S S5      5        UR                  U R                  SU R                  U R                  5      5        UR                  U R                  SU R                  U R                  5      5        UR                  U R                  SU R                  U R                  5      5        UR                  U R                  SU R                   U R"                  U R$                  /5      5        U$ )	Nr   headerTokenlenUserName   docFileVersionmajorVersionminorVersion
relVersion)r   r   rX   r   SIZEr   r   HEADER_TOKEN_NOCRYPTr   r   r   DOC_FILE_VERSIONr   MAJOR_VERSIONr   MINOR_VERSIONr   REL_VERSION_CAN_USEREL_VERSION_NO_USEr"   r   s     r   r   CurrentUserAtom.check_validity  sb   ""$D$$VTYY		BCD$$]D4E4E&*&?&?&*&?&?&AB 	C 	D$$]D4F4F%(* 	+D$$%5t7L7L%)%:%:< 	=D$$^T5G5G%)%7%79 	:D$$^T5G5G%)%7%79 	:D$$\43C3C&*&>&>&*&=&=&?@ 	A r   )r   r   r   r   r   r   r   r|   r   r   r   )r)   r*   r+   r,   r-   r   r   r   r   r   r   r   r   r   r!   r   rq   rj   r   r.   r/   r0   s   @r   r   r   K  sh     &% %# KDMM >  , r   r   c                   R   ^  \ rS rSrSrSrSrSrU 4S jr\	S 5       r
S
S jrS	rU =r$ )UserEditAtomi  zAn atom record that specifies information about a user edit

https://msdn.microsoft.com/en-us/library/dd945746%28v=office.12%29.aspx
i  r   r   c                    > [         [        U ]  5         S U l        S U l        S U l        S U l        S U l        S U l        S U l	        S U l
        S U l        S U l        S U l        g r]   )r    r   r!   r|   last_slide_id_refversionr   r   offset_last_editoffset_persist_directorydoc_persist_id_refpersist_id_seed	last_viewencrypt_session_persist_id_refr   s    r   r!   UserEditAtom.__init__  se    lD*,!%!! $(,%"&#.2+r   c                 8   [         R                  S5        U " 5       n[        R                  U5      Ul        [
        R                  " SUR                  S5      5      u  Ul        [
        R                  " SUR                  S5      5      u  Ul	        [
        R                  " SUR                  S5      5      u  Ul
        [
        R                  " SUR                  S5      5      u  Ul        [
        R                  " SUR                  S5      5      u  Ul        [
        R                  " SUR                  S5      5      u  Ul        [
        R                  " SUR                  S5      5      u  Ul        [
        R                  " SUR                  S5      5      u  Ul        [
        R                  " SUR                  S5      5      u  Ul        UR                  S5        U(       a/  [
        R                  " SUR                  S5      5      u  Ul        U$ SUl        U$ )	z?extract info from given stream (already positioned correctly!) z extract UserEditAtom from streamr?   r@   r;   r<   r2   r   N)r   debugrZ   rj   r|   r4   r5   r6   r   r   r   r   r   r   r   r   r   r   )rg   r#   r   rh   s       r   rj   UserEditAtom.extract_from  sz    			45e $008!'tV[[^!D}}T6;;q>:#]]4Q@#]]4Q@ &dFKKN C(.dFKKN(K%$"(--fkk!n"E%}}T6;;q>BtV[[^<AdFKKN3 0C.
 
 26C.
r   c                    U R                  5       nUR                  U R                  SU R                  U R                  5      5        UR                  U R                  SU R
                  U R                  5      5        Ub  U R                  U:  a6  UR                  [        SSU R                  SR                  U5      5      5        U R                  U:  d  U R                  U R                  ::  aA  UR                  [        SSU R                  SR                  U R                  U5      5      5        UR                  U R                  SU R                  S	5      5        U$ )
Nr   r   r   zUserEditAtom.offsetLastEditz< {0}z#UserEditAtom.offsetPersistDirectoryzin ({0}, {1})docPersistIdRefr   )r   r   rX   r   r   r   r   r   appendr   r   r   r   )r"   offsetr   s      r   r   UserEditAtom.check_validity  s;   ""$D$$^T5G5G%)%7%79 	:D$$^T5G5G%)%7%79 	:$$.-)+H))7>>&+AC D ,,611T5J5JJ-)9))#**4+@+@&I	K L
 	D$$%6%)%<%<aA 	Br   )r   r   r   r   r   r   r   r   r   r|   r   r]   )r)   r*   r+   r,   r-   r   r   r   r!   rq   rj   r   r.   r/   r0   s   @r   r   r     s<    
 KMM3  : r   r   c                   @   ^  \ rS rSrSr  SU 4S jjrS rS rSrU =r	$ )	DummyTypei  a  a type that is found in ppt documents we are not interested in

instead of parsing many uninteresting types, we just read their
RecordHeader and set the RECORD_... values on an instance- (instead of
class-) level

used to skip over uninteresting types in e.g. DocumentContainer
c                 f   > [         [        U ]  5         Xl        X l        X0l        X@l        XPl        g r]   )r    r   r!   	type_namer   r   r   record_length)r"   r   record_typer^   r_   ra   r'   s         r   r!   DummyType.__init__  s-    i')"&%+$r   c                    U R                  U5        [        R                  SR                  U R                  R
                  U R                  5      5        [        R                  SR                  UR                  5       5      5        UR                  U R                  R
                  [        R                  5        [        R                  SR                  UR                  5       5      5        U $ )a  extract record header and just skip as many bytes as header says

Since this requires RECORD_... values set in constructor, this is NOT
a classmethod like all the other extract_from!

Otherwise this tries to be compatible with other extract_from methods
(e.g. returns self)
z#skipping over {0} Byte for type {1}start at pos {0}now at pos {0})r   r   r   r   r|   ra   r   tellseekosSEEK_CURr   s     r   rj   DummyType.extract_from   s     	6"		76$--//@	B		$++FKKM:;DMM))2;;7		"))&++-89r   c                 8    U R                  U R                  5      $ r]   )r   r   rb   s    r   r   DummyType.check_validity  s    ""4#5#566r   )r   r   r   r   r   )r   r   N)
r)   r*   r+   r,   r-   r!   rj   r   r.   r/   r0   s   @r   r   r     s&     HI%"7 7r   r   c                   J   ^  \ rS rSrSrSrU 4S jr\S 5       rSS jr	Sr
U =r$ )	PersistDirectoryAtomi  zone part of a persist object directory with unique persist object id

contains PersistDirectoryEntry objects

https://msdn.microsoft.com/en-us/library/dd952680%28v=office.12%29.aspx
ir  c                 F   > [         [        U ]  5         S U l        S U l        g r]   )r    r   r!   rg_persist_dir_entrystream_offsetr   s    r   r!   PersistDirectoryAtom.__init__  s!    "D24$(!!r   c                    [         R                  S5        U " 5       nUR                  5       Ul        UR	                  U5        UR                  5       nX2R
                  R                  -   n[         R                  SR                  X45      5        / Ul        X4:  ak  [        R                  U5      nUR                  R                  U5        UR                  5       n[         R                  SR                  U5      5        X4:  a  Mk  U$ )z5create and return object with data from given stream z-Extracting a PersistDirectoryAtom from streamz(start reading at pos {0}, read until {1}z
at pos {0})r   r   r   r   r   r|   ra   r   r   PersistDirectoryEntryrj   r   )rg   r#   rh   curr_posstop_pos	new_entrys         r   rj   !PersistDirectoryAtom.extract_from$  s     			ABe #KKM 	&! ;;=ll222		<6(-	/#% !-::6BI$$++I6{{}HIIl))(34	 !
 
r   c                     U R                  5       nU R                   H.  nUR                  UR                  UU R                  5      5        M0     U$ r]   )r   r   r   r   r   )r"   user_edit_last_offsetr   entrys       r   r   #PersistDirectoryAtom.check_validity?  sN    ""$..EKK,,-B-1-?-?A B / r   )r   r   r]   r)   r*   r+   r,   r-   r   r!   rq   rj   r   r.   r/   r0   s   @r   r   r     s2     K"
  4 r   r   c                   <    \ rS rSrSrS r\S 5       r  SS jrSr	g)	r   iG  aL  an entry contained in a PersistDirectoryAtom.rg_persist_dir_entry

A structure that specifies a compressed table of sequential persist object
identifiers and stream offsets to associated persist objects.

NOT a subclass of PptType because has no RecordHeader

https://msdn.microsoft.com/en-us/library/dd947347%28v=office.12%29.aspx
c                 .    S U l         S U l        S U l        g r]   )
persist_id	c_persistrg_persist_offsetrb   s    r   r!   PersistDirectoryEntry.__init__R  s    !%r   c           	      <   [         R                  S5        U " 5       n[        R                  " SUR	                  S5      5      u  n[        US5      u  Ul        Ul        [         R                  SR                  X2R                  UR                  5      5        [        UR                  5       Vs/ s H,  n[        R                  " SUR	                  S5      5      S   PM.     snUl
        [         R                  SR                  UR                  5      5        U$ s  snf )Nz.Extracting a PersistDirectoryEntry from streamr?   r@   i   z4temp is 0x{0:04X} --> id is {1}, reading {2} offsetsr   zoffsets are: {0})r   r   r4   r5   r6   rf   r  r  r   ranger  )rg   r#   rh   temp_s        r   rj   "PersistDirectoryEntry.extract_fromW  s     			BCe dFKKN3(.tU(;%s~		H6$>	@ +0*>!@*>Q "(tV[[^!DQ!G*>!@		$++C,A,ABC
!@s   .3DNc           
         / nU R                   S:  a:  UR                  [        [        SU R                   SR	                  S5      5      5        U R
                  S:X  a+  UR                  [        [        SU R
                  S5      5        Ub\  [        U R                  5      U:  aC  UR                  [        [        S[        U R                  5      SR	                  U5      5      5        Ub\  [        U R                  5      U:  aC  UR                  [        [        S[        U R                  5      S	R	                  U5      5      5        U$ )
Ni z PersistDirectoryEntry.persist_idz< 0xFFFFE (dec: {0})r   zPersistDirectoryEntry.c_persistz> 0z'PersistDirectoryEntry.rg_persist_offsetz> UserEdit.offsetLastEdit ({0})z%> PersistObjectDirectory offset ({0}))	r  r   r   r   r   r  minr  max)r"   r   persist_obj_dir_offsetr   s       r   r   $PersistDirectoryEntry.check_validityz  s    ??W$KK) "D!7!>!>w!GI J >>QKK) "C' ( !,../2GGKK) "KD**+1-.	0 1
 "-../2HHKK) "KD**+7./	1 2
 r   )r  r  r  )NN)
r)   r*   r+   r,   r-   r!   rq   rj   r   r.   r   r   r   r   r   G  s.    &
    D 48.2r   r   c                   J   ^  \ rS rSrSr/ SQrU 4S jr\S 5       rS r	Sr
U =r$ )DocInfoListSubContainerOrAtomi  a"  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
)i  i  i  i  i  i  c                 *   > [         [        U ]  5         g r]   )r    r  r!   r   s    r   r!   &DocInfoListSubContainerOrAtom.__init__  s    +T;=r   c                    [         R                  S5        U " 5       nUR                  U5        UR                  R                  [
        R                  :X  a!  [
        R                  XR                  5      nU$ [         R                  SR                  UR                  R                  5      5        [         R                  SR                  UR                  5       5      5        UR                  UR                  R                  [        R                  5        [         R                  SR                  UR                  5       5      5        U$ )*build instance with info read from stream z1Parsing DocInfoListSubContainerOrAtom from streamz7skipping over {0} Byte in DocInfoListSubContainerOrAtomr   r   )r   r   r   r|   r`   VBAInfoContainerr   rj   r   ra   r   r   r   r   r   s      r   rj   *DocInfoListSubContainerOrAtom.extract_from  s     			EFe&!<<  $4$@$@@"//EC 
 IIOvcll2235II(//>?KK,,bkk:II&--fkkm<=
r   c                 f    U R                  SU R                  R                  U R                  5        g)zcan be any of multiple types z
rh.recTypeN)rX   r|   r`   VALID_RECORD_TYPESrb   s    r   r   ,DocInfoListSubContainerOrAtom.check_validity  s'    t}}'='=00	2r   r   )r)   r*   r+   r,   r-   r  r!   rq   rj   r   r.   r/   r0   s   @r   r  r    s3    	">  "2 2r   r  c                   J   ^  \ rS rSrSrSrSrU 4S jr\S 5       r	S r
SrU =r$ )	DocInfoListContaineri  zinformation about the document and document display settings

https://msdn.microsoft.com/en-us/library/dd926767%28v=office.12%29.aspx
   i  c                 8   > [         [        U ]  5         S U l        g r]   )r    r  r!   rg_child_recr   s    r   r!   DocInfoListContainer.__init__  s    "D24 r   c                 4   [         R                  S5        U " 5       nUR                  U5        UR                  5       nX2R                  R
                  -   n[         R                  SR                  X45      5        / Ul        X4:  ao  [        5       R                  U5      nUR                  R                  U5        UR                  5       n[         R                  SR                  U5      5        X4:  a  Mo  [         R                  SR                  XC5      5        g)r  z(Parsing DocInfoListContainer from streamz-start reading at pos {0}, will read until {1}r   z<reached end pos {0} ({1}). stop reading DocInfoListContainerN)r   r   r   r   r|   ra   r   r  r  rj   r   )rg   r#   rh   r   end_posnew_objs         r   rj   !DocInfoListContainer.extract_from  s     			<=e&! ;;=\\111		A6(,	. 35BB6JG##G,{{}HII&--h78	   			P6',	.r   c                     U R                  5       nU R                   H"  nUR                  UR                  5       5        M$     U$ r]   )r   r  r   r   )r"   r   rh   s      r   r   #DocInfoListContainer.check_validity  s:    ""$$$CKK**,- %r   )r  )r)   r*   r+   r,   r-   r   r   r!   rq   rj   r   r.   r/   r0   s   @r   r  r    s7    
 NK! . .4 r   r  c                   F   ^  \ rS rSrSrSrU 4S jr\S 5       rS r	Sr
U =r$ )DocumentContaineri  zda DocumentContainer record

https://msdn.microsoft.com/en-us/library/dd947357%28v=office.12%29.aspx
i  c                 4  > [         [        U ]  5         S U l        S U l        S U l        S U l        S U l        S U l        S U l	        S U l
        S U l        S U l        S U l        S U l        S U l        S U l        S U l        S U l        S U l        S U l        S U l        g r]   )r    r(  r!   document_atomex_obj_listdocument_text_infosound_collectiondrawing_groupmaster_listdoc_info_listslide_hfnotes_hf
slide_list
notes_listslide_show_doc_infonamed_showssummarydoc_routing_slipprint_optionsrt_custom_table_styles_1end_documentrt_custom_table_styles_2r   s    r   r!   DocumentContainer.__init__  s    /1!"& $!!#'  $!(,% (,%r   c                    [         R                  S5        U " 5       nUR                  U5        [         R                  SR	                  [        UR                  5       5      5      5        [        SSSSS9R                  U5      Ul	        [         R                  SR	                  [        UR                  R                  5       5      5      5        [        SS	S
S9R                  U5      Ul        [         R                  SR	                  [        UR                  R                  5       5      5      5        [        SSS
S9R                  U5      Ul        [         R                  SR	                  [        UR                  R                  5       5      5      5        [        SSS
SS9R                  U5      Ul        [         R                  SR	                  [        UR                  R                  5       5      5      5        [        SSS
S9R                  U5      Ul        [         R                  SR	                  [        UR                  R                  5       5      5      5        [        SSS
S9R                  U5      Ul        [         R                  SR	                  [        UR                  R                  5       5      5      5        [         R                  U5      Ul        U$ )zcreated object with values from given stream

stream is assumed to be positioned correctly

this container contains lots of data we are not interested in.
z%Parsing DocumentContainer from streamzvalidity: {0} errsDocumentAtomi  r   (   )r^   ra   ExObjListContaineri	  r  )r^   DocumentTextInfoContaineri  SoundCollectionContaineri     )r^   r_   DrawingGroupContaineri  MasterListWithContaineri  )r   r   r   infor   lenr   r   rj   r*  r   r+  r,  r-  r.  r/  r  r0  r   s      r   rj   DocumentContainer.extract_from  sT    			9:e 	&!%,,S1C1C1E-FGH &nfc.244@L4H 	%&S..==?@A	C
 $$8&#N'</ 	%&S__;;=>?	A "++F36"88DV8L 	%&S33BBDEF	H  ))CV145 J ,V 4 	 	%&S11@@BCD	F
 &&=v.133?<3G 	%&S..==?@A	C $$=v,/11=f1E 	%&S__;;=>?	A 1==fEp 
r   c                 d   U R                  5       nUR                  U R                  R                  5       5        UR                  U R                  R                  5       5        UR                  U R
                  R                  5       5        UR                  U R                  R                  5       5        UR                  U R                  R                  5       5        UR                  U R                  R                  5       5        UR                  U R                  R                  5       5        U$ )z,check all values in object for valid values )
r   r   r*  r   r+  r,  r-  r.  r/  r0  r   s     r   r    DocumentContainer.check_validity  s    ""$D&&5578D$$3356D++::<=D))88:;D&&5578D$$3356D&&5578r   )r0  r8  r*  r,  r.  r;  r+  r/  r6  r2  r4  r9  r:  r<  r1  r3  r5  r-  r7  r   r0   s   @r   r(  r(    s5    
 K-, x xv
 
r   r(  c                   V   ^  \ rS rSrSrSrSrSrSrU 4S jr	\
SS j5       rS	 rS
rU =r$ )r  i  zA container record that specifies VBA information for the document.

https://msdn.microsoft.com/en-us/library/dd952168%28v=office.12%29.aspx
i  r  r   r   c                 8   > [         [        U ]  5         S U l        g r]   )r    r  r!   vba_info_atomr   s    r   r!   VBAInfoContainer.__init__  s    .0!r   c                     [         R                  S5        U " 5       nUc  UR                  U5        O[         R                  S5        X#l        [        R                  U5      Ul        U$ )zKsince can determine this type only after reading header, it is arg
        zparsing VBAInfoContainerzskip parsing of RecordHeader)r   r   r   r|   VBAInfoAtomrj   rN  )rg   r#   r|   rh   s       r   rj   VBAInfoContainer.extract_from  sV     			,-ef%II45#L'44V<
r   c                     U R                  U R                  S9nUR                  U R                  R	                  5       5        U$ )Nr   )r   RECORD_LENGTHr   rN  r   r   s     r   r   VBAInfoContainer.check_validity  s;    ""$*<*<"=D&&5578r   )rN  r]   )r)   r*   r+   r,   r-   r   r   r   rU  r!   rq   rj   r   r.   r/   r0   s   @r   r  r    sA    
 KNOM"   r   r  c                   N   ^  \ rS rSrSrSrSrSrU 4S jr\	S 5       r
S rS	rU =r$ )
rQ  i  zAn atom record that specifies a reference to the VBA project storage.

https://msdn.microsoft.com/en-us/library/dd948874%28v=office.12%29.aspx
   r<      c                 T   > [         [        U ]  5         S U l        S U l        S U l        g r]   )r    rQ  r!   persist_id_reff_has_macrosr   r   s    r   r!   VBAInfoAtom.__init__  s'    k4)+" r   c                     [         R                  S5        U " 5       nUR                  U5        [        U5      Ul        [        U5      Ul        [        U5      Ul        U$ )Nzparsing VBAInfoAtom)r   r   r   rA   r[  r\  r   r   s      r   rj   VBAInfoAtom.extract_from  sR    		'(e&!
 $F^
 "&>
 Vn
r   c                     U R                  U R                  S9nUR                  U R                  SU R                  S S5      5        UR                  U R                  SU R                  S5      5        U$ )NrT  
fHasMacrosr<   r   )r   rU  r   r   r\  rX   r   r   s     r   r   VBAInfoAtom.check_validity  sd    ""$*<*<"= 	D$$\43D3DdANOD$$Ya@Ar   )r\  r[  r   )r)   r*   r+   r,   r-   r   r   rU  r!   rq   rj   r   r.   r/   r0   s   @r   rQ  rQ    s<    
 KNM  , r   rQ  c                   H   ^  \ rS rSrSrSrSrSrS
U 4S jjrS r	S r
S	rU =r$ )ExternalObjectStoragei  a$  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
i  r   r   c                    > [         [        U ]  5         Uc  S U l        O8U(       a  U R                  U l        SU l        OU R                  U l        SU l        S U l        S U l        S U l	        g )NTF)
r    rd  r!   r   RECORD_INSTANCE_COMPRESSEDis_compressedRECORD_INSTANCE_UNCOMPRESSEDuncompressed_sizedata_offset	data_size)r"   rg  r'   s     r   r!   ExternalObjectStorage.__init__  se    #T35 #'D #'#B#BD !%D#'#D#DD !&D!%r   c                 N   [         R                  SR                  U R                  5      5        U R	                  U5        U R
                  R                  U l        U R                  (       a%  [        U5      U l	        U =R                  S-  sl        UR                  5       U l        g)zGnot a classmethod because of is_compressed attrib

see also: DummyType
z:Parsing ExternalObjectStorage (compressed={0}) from streamr@   N)r   r   r   rg  r   r|   ra   rk  rA   ri  r   rj  r   s     r   rj   "ExternalObjectStorage.extract_from  ss    
 			N6$,,-	/6"..%+F^D"NNaN!;;=r   c                 "    U R                  5       $ r]   )r   rb   s    r   r   $ExternalObjectStorage.check_validity  s    ""$$r   )r   rj  rk  rg  ri  r]   )r)   r*   r+   r,   r-   r   rf  rh  r!   rj   r   r.   r/   r0   s   @r   rd  rd    s/     K!"#$ )% %r   rd  c                   Z   ^  \ rS rSrSr\R                  rU 4S jr\	U 4S j5       r
SrU =r$ )!ExternalObjectStorageUncompressedi#  z;subclass of ExternalObjectStorage for uncompressed objects c                 ,   > [         [        U ]  S5        g )NF)r    rr  r!   r   s    r   r!   *ExternalObjectStorageUncompressed.__init__'  s    /?Fr   c                 <   > U " 5       n[         [        U]  U5        U$ zKnote the usage of super here: call instance method of super class!
        )r    rr  rj   rg   r#   rh   r'   s      r   rj   .ExternalObjectStorageUncompressed.extract_from*  s!     e/B6J
r   r   )r)   r*   r+   r,   r-   rd  rh  r   r!   rq   rj   r.   r/   r0   s   @r   rr  rr  #  s+    F+HHOG  r   rr  c                   Z   ^  \ rS rSrSr\R                  rU 4S jr\	U 4S j5       r
SrU =r$ )ExternalObjectStorageCompressedi3  z9subclass of ExternalObjectStorage for compressed objects c                 ,   > [         [        U ]  S5        g )NT)r    rz  r!   r   s    r   r!   (ExternalObjectStorageCompressed.__init__7  s    -t=dCr   c                 <   > U " 5       n[         [        U]  U5        U$ rv  )r    rz  rj   rw  s      r   rj   ,ExternalObjectStorageCompressed.extract_from:  s!     e-s@H
r   r   )r)   r*   r+   r,   r-   rd  rf  r   r!   rq   rj   r.   r/   r0   s   @r   rz  rz  3  s+    D+FFOD  r   rz  c                    ^  U 4S jnU$ )za 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, ...)
c                   > Sn U R                   cY  [        R                  SR                  [        TR
                  5      5        U R                  R                  [        5      U l         SnT" X R                   /UQ70 UD6U(       aU  [        R                  SR                  [        TR
                  5      5        U R                   R                  5         S U l         $ $ ! [         a%    U R                  (       a  e U R                  5          Of = f U(       aU  [        R                  SR                  [        TR
                  5      5        U R                   R                  5         S U l         g g ! U(       aU  [        R                  SR                  [        TR
                  5      5        U R                   R                  5         S U l         f f = fNFzopening stream {0!r} for {1}Tzclosing stream {0!r} after {1})_open_main_streamr   r   r   r   r)   ole
openstreamclose	Exception	fast_fail_log_exception)r"   argskwargsstream_opened_by_mefuncs       r   wrapped(with_opened_main_stream.<locals>.wrappedN  sn   #	.%%-		8!6"2DMMBD)-)<)<=M)N&&*# 44FtFvF #		:!6"2DMMBD&&,,.)-&	 #  	&~~##%		& & #		:!6"2DMMBD&&,,.)-&	 #"		:!6"2DMMBD&&,,.)-&	 #s%   A;C ,D	E- DE- -AGr   r  r  s   ` r   with_opened_main_streamr  E  s    .6 Nr   c                    ^  U 4S jnU$ )zAsame as with_opened_main_stream but with yield instead of return c              ?      >#    Sn U R                   cY  [        R                  SR                  [        TR
                  5      5        U R                  R                  [        5      U l         SnT" X R                   /UQ70 UD6 H  nUv   M	     U(       aU  [        R                  SR                  [        TR
                  5      5        U R                   R                  5         S U l         g g ! [         a%    U R                  (       a  e U R                  5          Nf = f! U(       aU  [        R                  SR                  [        TR
                  5      5        U R                   R                  5         S U l         f f = f7fr  )r  r   r   r   r   r)   r  r  r  r  r  r  )r"   r  r  r  resultr  s        r   r  2generator_with_opened_main_stream.<locals>.wrappedo  s4    #	.%%-		8!6"2DMMBD)-)<)<=M)N&&*# t%;%;MdMfM N #		:!6"2DMMBD&&,,.)-&	 #  	&~~##%		& #		:!6"2DMMBD&&,,.)-&	 #s7   E>BC+ AE>+,DD DD AE;;E>r   r  s   ` r   !generator_with_opened_main_streamr  l  s    .8 Nr   c                       \ rS rSrSrSS jrSS jrS rS r\	S 5       r
\	S	 5       r\S
 5       r\S 5       r\S 5       r\	S 5       r\	S 5       r\S 5       rSrg)	PptParseri  zNParser for PowerPoint 97-2003 specific data structures

requires an OleFileIO
c                    [        U[        R                  5      (       a  [        R	                  S5        Xl        O?[        R	                  SR                  U5      5        [        R                  " U5      U l        X l        SU l        SU l	        SU l
        SU l        U R
                  R                  5       n[        S U 5       5      (       a  U R                  SSUS5        U Vs/ s H  oDS   R                  5       PM     nnS	U;  a  U R                  SSUS
5        [         R                  5       U;  a  U R                  SSU[         5        SU l        gs  snf )zconstructor

: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
zusing open OleFileIOzOpening file {0}Nc              3   >   #    U  H  n[        U5      S :g  v   M     g7f)r   N)rH  )rJ   r#   s     r   rL   %PptParser.__init__.<locals>.<genexpr>  s     ;lFs6{als   rootlistdirzlen = 1r   zcurrent userrP   )rQ   olefile	OleFileIOr   r   r  r   r  current_user_atomnewest_user_editdocument_persist_objpersist_object_directoryr  any_faillowerr   r  )r"   r  r  root_streamsr#   s        r   r!   PptParser.__init__  s    c7,,--II,-HII(//45((-DH"!% $$(!(,% xx'') ;l;;;JJvy,	B8DEfq	)E-JJvy,G%%'<7JJvy,8HI!% Fs   &ENc                    Ub  [         R                  " 5       SS nO9[        R                  " 5       u  p4n[         R                  " U5      n[        U5      n[        R                  U5        [        [         R                  " U5      5       H@  u  pgUR                  5        H'  n[        R                  SR                  Xh5      5        M)     MB     g)zlog 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
Nztrace {0}: {1})	tracebackextract_stacksysexc_info
extract_tbstrr   error	enumerateformat_list
splitlinesr   r   )	r"   r   stackr	  exctracei_entryr   lines	            r   r  PptParser._log_exception  s     ?++-cr2ELLNMAE((/Ec(C		#'	(=(=e(DENG((*		*11'@A + Fr   c                 x    U R                   (       a  [        U6 eU R                  [        U6 R                  5        g)zcdepending on self.fast_fail raise PptUnexpectedData or just log err

args as for PptUnexpectedData
N)r  r   r  r   )r"   r  s     r   r  PptParser._fail  s0    
 >>#T** 14 8 < <=r   c                    U R                   b  [        R                  S5        [        R                  S5        Sn [        R                  S5        U R                  R                  S5      n[        R                  U5      U l         Ub&  [        R                  S5        UR                  5         gg! [         a%    U R                  (       a  e U R                  5          NXf = f! Ub&  [        R                  S5        UR                  5         f f = f)zparse the CurrentUserAtom record from stream 'Current User'

Structure described in
https://msdn.microsoft.com/en-us/library/dd948895%28v=office.12%29.aspx
Nz<re-reading and overwriting previously read current_user_atomzparsing "Current User"zopening stream "Current User"rP   zclosing stream "Current User")r  r   warningr   r  r  r   rj   r  r  r  r  r   s     r   parse_current_userPptParser.parse_current_user  s     !!-KK < = 			*+	II56XX((8F%4%A%A&%ID" !		9: "  	&~~##%		& !		9: "s$   A
B/ /,CC! CC! !+Dc                    U R                   b  [        R                  S5        U R                  c  U R	                  5         U R                  R
                  nU R                  R                  5       n0 U l         SU l        US:w  Ga  UR                  U[        R                  5        [        R                  X5      nU R                  c  X@l        [        R                  S5        UR                  5       nU(       a-  [        R                  SR                  [!        U5      5      5        U H'  n[        R                  SR                  U5      5        M)     U(       a  U R"                  (       a  US   e[        R                  SR                  UR$                  5      5        UR                  UR$                  [        R                  5        [&        R                  U5      n[        R                  S5        UR                  U5      nU(       a-  [        R                  SR                  [!        U5      5      5        U H'  n[        R                  SR                  U5      5        M)     U(       a  U R"                  (       a  US   eUR(                   H  nUR*                  [!        UR,                  5      -   S	-
  n	[        R                  S
R                  UR*                  U	UR,                  5      5        [/        UR,                  5       H!  u  pUU R                   UR*                  U
-   '   M#     M     UR0                  nUS:w  a  GM  gg)z/Part 1: Construct the persist object directory NzCre-reading and overwriting previously read persist_object_directoryr   checking validitycheck_validity found {0} issuesz UserEditAtom.check_validity: {0}zseeking to pos {0}z(PersistDirectoryAtom.check_validity: {0}r   z)for persist IDs {0}-{1}, save offsets {2})r  r   r  r  r  r   r   r  r   r   SEEK_SETr   rj   r   r   r   rH  r  r   r   r   r  r  r  r   )r"   r#   r   r   	user_editr   errpersist_dir_atomr   last_idcounts              r   parse_persist_object_directory(PptParser.parse_persist_object_directory  s    ((4KK C D !!)##%''>>--::<(*% $ k
 KK, %11&GI$$,(1%II)*++-D=#VCI.0>EEcJK 1g
 II*vi@@ACKK	::BKKH  4@@HII)*#226:D=#VCI.0F#VC[*  1g* *>>**3u/F/F+GGI		E!6%"2"2G"'"9"9;< &/u/F/F%GME  11%2B2B52HI &H ? //FY kkr   c                 ,   U R                   b  [        R                  S5        U R                  c  U R	                  5         U R
                  R                  nU R                  U   n[        R                  SR                  X#5      5        [        R                  SR                  U5      5        UR                  U[        R                  5        [        R                  U5      U l         [        R                  S5        U R                   R                  5       nU(       a-  [        R                  SR                  [        U5      5      5        U H'  n[        R                  SR                  U5      5        M)     U(       a  U R                   (       a  US   egg)	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}r  r  z)check_validity(document_persist_obj): {0}r   )r  r   r  r  r  r  r   r   r   r   r   r  r(  rj   r   rH  r  )r"   r#   
newest_refr   r   r  s         r   parse_document_persist_object'PptParser.parse_document_persist_objectY  s6    $$0KK B C ((0//1
 **==
..z:		=6*-	/ 			-&&v./FBKK( %6$B$B6$J!		%&((779KK9@@TKLCKKC&  DNNq'M #4r   c              #   h  #    Sn[        U5      n[        R                  SR                  U5      5        XC:  a  [	        S5      eSn UR                  5       nUS-  nUR                  U5      nUR                  U5      nUS:w  aH  [        R                  SR                  Xh-   5      5        Xh-   v   UR                  X(S-   5      nUS:w  a  MH  [        U5      U:X  a&  UR                  Xc-   U-
  [        R                  5        O/[        R                  SR                  [        U5      X55      5        g	M  7f)
z-search for pattern in stream, return indices rX  zpattern length is {0}zneed buf > pattern to search!r   r   r  zfound pattern at index {0}z1reached end of buf (read {0}<{1}) after {2} readsN)rH  r   r   r   rm   r   r6   findr   r   r  )	r"   r#   patternBUF_SIZEpattern_lenn_reads	start_posbufidxs	            r   search_patternPptParser.search_pattern  s     'l		)00=>!<==IqLG ++h'C((7#C)		6==imLMo%hhwA. )
 3x8#I0;>L		M!6#c(H>@% s   CD2A&D2c              #     #    [         R                  S5        [        R                  [        R                  S9[
        R                  [
        R                  S9-   nU R                  U5       GHJ  nUR                  U5        [         R                  SR                  U5      5         [        R                  U5      nUR                  5       nU(       a.  [         R                  SR                  [        U5      5      5        Oi[         R                  S5        UR                  n[         R                  SR                  UR                   UR"                  UR$                  5      5        Uv   U H'  n[         R                  SR                  U5      5        M)     U(       d  GM4  U R&                  (       d  GMH  US   e   g	! [         a    U R                  5          GMn  f = f7f)
a0  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
zlooking for VBA info containers)ra   extracting at idx {0}r  zcontainer is okz2persist id ref is {0}, has_macros {1}, version {2}z%check_validity(VBAInfoContainer): {0}r   N)r   r   r  r   rU  rQ  r  r   r   rj   r  r  r   r  rH  rN  r[  r\  r   r  )r"   r#   r  r  	containerr   atomr  s           r   search_vba_infoPptParser.search_vba_info  s     			34"33(8(F(F 4 H..(3(A(A / CC &&w/CKKII-44S9:,99&A	
 ++-D=#VCI.0 		+, ..		N!6$"5"5t7H7H"&,,01  C#VC[*  t1g3 0  ##%s7   B#G&F<;C G G4G<GGGGc           	   #     #    [         R                  S5        [        [        4 GH  nUR	                  S[
        R                  5        UR                  5       nU R                  U5       GH:  nUR	                  U5        [         R                  SR                  U5      5         UR                  U5      nUR                  5       nU(       a.  [         R                  SR                  [        U5      5      5        OR[         R                  SR                  UR                   UR"                  R$                  UR&                  5      5        Uv   U H2  n[         R                  SR                  UR(                  U5      5        M4     U(       d  GM$  U R*                  (       d  GM8  US   e   GM     g! [         a    U R                  5          GMc  f = f7f)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`
zlooking for VBA storage objectsr   r  r  z8storage is ok; compressed={0}, size={1}, size_decomp={2}zcheck_validity({0}): {1}N)r   r   rr  rz  r   r   r  r   r  r   rj   r  r  r   r  rH  rg  r|   ra   ri  r)   r  )r"   r#   obj_typer  r  storager   r  s           r   search_vba_storagePptParser.search_vba_storage  sq    " 			34:8:H KK2;;'//1G **73C 		188=>&33F;G
 --/KK A!'D	!24 II 0%vg&;&;&-&6&6&>&>&-&?&? AB
 "MCKK :!'(9(93!?A   4DNNNq'M3 4: ! '')s7   B G#F.4CGG!G.GGGGc                 F   [         R                  S5        UR                  UR                  [        R
                  5        [        XR                  5      u  p4n[         R                  SR                  U[        U5      U5      5        U(       a  U R                  (       a  UeU$ )z1return decompressed data from search_vba_storage z.decompressing storage for VBA OLE data stream z-decompressed {0} to {1} bytes; found err: {2})r   r   r   rj  r   r  iterative_decompressrk  r   rH  r  )r"   r#   r  decompn_readr  s         r   decompress_vba_storage PptParser.decompress_vba_storage	  sx     			BC 	G''5 ):):; 			A6&#f+s3	54>>I r   c                    [         R                  SR                  UR                  UR                  5      5        UR                  UR                  [        R                  5        UR                  UR                  5      nU$ )z/return data pointed to by uncompressed storage zCreading uncompressed VBA OLE data stream: {0} bytes starting at {1})	r   r   r   rk  rj  r   r   r  r6   )r"   r#   r  datas       r   read_vba_storage_dataPptParser.read_vba_storage_data'  sa     			 .6'++W-@-@A	C 	G''5{{7,,-r   c              #     #    SnSnU R                  5        H)  nUS-  nUR                  R                  S:  d  M$  US-  nM+     SnSnU R                  5        HF  nUS-  nUR                  (       a  US-  nU R                  U5      v   M3  U R                  U5      v   MH     [        R                  SR                  X#XV5      5        g7f)z?search vba infos and storages, yield uncompressed storage data r   r   zCfound {0} infos ({1} with macros) and {2} storages ({3} compressed)N)
r  rN  r\  r  rg  r  r  r   rG  r   )r"   r#   n_infosn_macrosrG  
n_storagesn_compressedr  s           r   iter_vba_dataPptParser.iter_vba_data2  s      ((*DqLG!!..2A + 
..0G!OJ$$!11'::0099 1 	 $&JE	Gs   5CBC)r  r  r  r  r  r  r  )Fr]   )r)   r*   r+   r,   r-   r!   r  r  r  r  r  r  r  r  r  r  r  r  r  r.   r   r   r   r  r    s    
%&NB,>8 _0 _0B $ $V ' '> ', ',\ '2" '2"h  :   'G 'Gr   r  c                    [         R                  " 5       nSnSnSn XA:  a;  [        X-
  U5      nXSR                  U R	                  U5      5      -  nXG-  nXA:  a  M;  XTU4$ ! [         R
                   a  nUn SnANSnAff = f)z'decompress data from stream chunk-wise r   r   N)zlibdecompressobjr  
decompressr6   r  )	r#   r   
chunk_sizedecompressorr  r  
return_errn_newr  s	            r   r  r  M  s     %%'LFFJmZ0E--fkk%.@AAFOF m :%% :: 
s   >A! !B5A<<B__main__znothing here to run!)i   )5r-   __version__r  r   r4   r  r   r  pathnormpathabspathdirname__file___thismodule_dirrT   _parent_dirinsertr  CRITICALr   r   r   r   URL_OLEVBA_ISSUESMSG_OLEVBA_ISSUESr  r   r8   r=   rA   rX   objectrZ   rs   r   r   r   r   r   r  r  r(  r  rQ  rd  rr  rz  r  r  r  r  r)   printr   r   r   <module>r     s	  Z 
     	  ''""277??277??83L#MNggrww||OTBCchhHHOOA{#  #++A- < ! )  E 47HH :	 :2
2
2
A"(L6 (LVqNf qNhPg PfJ7 J^%7 %7P/7 /dLF L^,2G ,2^,7 ,^d dN w  F.' .b1%G 1%h(=  &; $$ND|G |G~&& z	
 ! r   