<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>PIL.OleFileIO — Pillow v2.6.2 (PIL fork)</title> <link rel="stylesheet" href="../../_static/default.css" type="text/css" /> <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" /> <script type="text/javascript"> var DOCUMENTATION_OPTIONS = { URL_ROOT: '../../', VERSION: '2.6.2', COLLAPSE_INDEX: false, FILE_SUFFIX: '.html', HAS_SOURCE: true }; </script> <script type="text/javascript" src="../../_static/jquery.js"></script> <script type="text/javascript" src="../../_static/underscore.js"></script> <script type="text/javascript" src="../../_static/doctools.js"></script> <link rel="author" title="About these documents" href="../../about.html" /> <link rel="top" title="Pillow v2.6.2 (PIL fork)" href="../../index.html" /> <link rel="up" title="Module code" href="../index.html" /> </head> <body> <div class="related"> <h3>Navigation</h3> <ul> <li class="right" style="margin-right: 10px"> <a href="../../genindex.html" title="General Index" accesskey="I">index</a></li> <li class="right" > <a href="../../py-modindex.html" title="Python Module Index" >modules</a> |</li> <li><a href="../../index.html">Home</a> »</li> <li><a href="../index.html" accesskey="U">Module code</a> »</li> </ul> </div> <div class="document"> <div class="documentwrapper"> <div class="bodywrapper"> <div class="body"> <h1>Source code for PIL.OleFileIO</h1><div class="highlight"><pre> <span class="c">#!/usr/bin/python</span> <span class="c"># -*- coding: latin-1 -*-</span> <span class="c">## OleFileIO_PL:</span> <span class="c">## Module to read Microsoft OLE2 files (also called Structured Storage or</span> <span class="c">## Microsoft Compound Document File Format), such as Microsoft Office</span> <span class="c">## documents, Image Composer and FlashPix files, Outlook messages, ...</span> <span class="c">## This version is compatible with Python 2.6+ and 3.x</span> <span class="c">## version 0.30 2014-02-04 Philippe Lagadec - http://www.decalage.info</span> <span class="c">## Project website: http://www.decalage.info/python/olefileio</span> <span class="c">## Improved version of the OleFileIO module from PIL library v1.1.6</span> <span class="c">## See: http://www.pythonware.com/products/pil/index.htm</span> <span class="c">## The Python Imaging Library (PIL) is</span> <span class="c">## Copyright (c) 1997-2005 by Secret Labs AB</span> <span class="c">## Copyright (c) 1995-2005 by Fredrik Lundh</span> <span class="c">## OleFileIO_PL changes are Copyright (c) 2005-2014 by Philippe Lagadec</span> <span class="c">## See source code and LICENSE.txt for information on usage and redistribution.</span> <span class="c">## WARNING: THIS IS (STILL) WORK IN PROGRESS.</span> <span class="c"># Starting with OleFileIO_PL v0.30, only Python 2.6+ and 3.x is supported</span> <span class="c"># This import enables print() as a function rather than a keyword</span> <span class="c"># (main requirement to be compatible with Python 3.x)</span> <span class="c"># The comment on the line below should be printed on Python 2.5 or older:</span> <span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">print_function</span> <span class="c"># This version of OleFileIO_PL requires Python 2.6+ or 3.x.</span> <span class="n">__author__</span> <span class="o">=</span> <span class="s">"Philippe Lagadec, Fredrik Lundh (Secret Labs AB)"</span> <span class="n">__date__</span> <span class="o">=</span> <span class="s">"2014-02-04"</span> <span class="n">__version__</span> <span class="o">=</span> <span class="s">'0.30'</span> <span class="c">#--- LICENSE ------------------------------------------------------------------</span> <span class="c"># OleFileIO_PL is an improved version of the OleFileIO module from the</span> <span class="c"># Python Imaging Library (PIL).</span> <span class="c"># OleFileIO_PL changes are Copyright (c) 2005-2014 by Philippe Lagadec</span> <span class="c">#</span> <span class="c"># The Python Imaging Library (PIL) is</span> <span class="c"># Copyright (c) 1997-2005 by Secret Labs AB</span> <span class="c"># Copyright (c) 1995-2005 by Fredrik Lundh</span> <span class="c">#</span> <span class="c"># By obtaining, using, and/or copying this software and/or its associated</span> <span class="c"># documentation, you agree that you have read, understood, and will comply with</span> <span class="c"># the following terms and conditions:</span> <span class="c">#</span> <span class="c"># Permission to use, copy, modify, and distribute this software and its</span> <span class="c"># associated documentation for any purpose and without fee is hereby granted,</span> <span class="c"># provided that the above copyright notice appears in all copies, and that both</span> <span class="c"># that copyright notice and this permission notice appear in supporting</span> <span class="c"># documentation, and that the name of Secret Labs AB or the author(s) not be used</span> <span class="c"># in advertising or publicity pertaining to distribution of the software</span> <span class="c"># without specific, written prior permission.</span> <span class="c">#</span> <span class="c"># SECRET LABS AB AND THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS</span> <span class="c"># SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.</span> <span class="c"># IN NO EVENT SHALL SECRET LABS AB OR THE AUTHORS BE LIABLE FOR ANY SPECIAL,</span> <span class="c"># INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM</span> <span class="c"># LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR</span> <span class="c"># OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR</span> <span class="c"># PERFORMANCE OF THIS SOFTWARE.</span> <span class="c">#-----------------------------------------------------------------------------</span> <span class="c"># CHANGELOG: (only OleFileIO_PL changes compared to PIL 1.1.6)</span> <span class="c"># 2005-05-11 v0.10 PL: - a few fixes for Python 2.4 compatibility</span> <span class="c"># (all changes flagged with [PL])</span> <span class="c"># 2006-02-22 v0.11 PL: - a few fixes for some Office 2003 documents which raise</span> <span class="c"># exceptions in _OleStream.__init__()</span> <span class="c"># 2006-06-09 v0.12 PL: - fixes for files above 6.8MB (DIFAT in loadfat)</span> <span class="c"># - added some constants</span> <span class="c"># - added header values checks</span> <span class="c"># - added some docstrings</span> <span class="c"># - getsect: bugfix in case sectors >512 bytes</span> <span class="c"># - getsect: added conformity checks</span> <span class="c"># - DEBUG_MODE constant to activate debug display</span> <span class="c"># 2007-09-04 v0.13 PL: - improved/translated (lots of) comments</span> <span class="c"># - updated license</span> <span class="c"># - converted tabs to 4 spaces</span> <span class="c"># 2007-11-19 v0.14 PL: - added OleFileIO._raise_defect() to adapt sensitivity</span> <span class="c"># - improved _unicode() to use Python 2.x unicode support</span> <span class="c"># - fixed bug in _OleDirectoryEntry</span> <span class="c"># 2007-11-25 v0.15 PL: - added safety checks to detect FAT loops</span> <span class="c"># - fixed _OleStream which didn't check stream size</span> <span class="c"># - added/improved many docstrings and comments</span> <span class="c"># - moved helper functions _unicode and _clsid out of</span> <span class="c"># OleFileIO class</span> <span class="c"># - improved OleFileIO._find() to add Unix path syntax</span> <span class="c"># - OleFileIO._find() is now case-insensitive</span> <span class="c"># - added get_type() and get_rootentry_name()</span> <span class="c"># - rewritten loaddirectory and _OleDirectoryEntry</span> <span class="c"># 2007-11-27 v0.16 PL: - added _OleDirectoryEntry.kids_dict</span> <span class="c"># - added detection of duplicate filenames in storages</span> <span class="c"># - added detection of duplicate references to streams</span> <span class="c"># - added get_size() and exists() to _OleDirectoryEntry</span> <span class="c"># - added isOleFile to check header before parsing</span> <span class="c"># - added __all__ list to control public keywords in pydoc</span> <span class="c"># 2007-12-04 v0.17 PL: - added _load_direntry to fix a bug in loaddirectory</span> <span class="c"># - improved _unicode(), added workarounds for Python <2.3</span> <span class="c"># - added set_debug_mode and -d option to set debug mode</span> <span class="c"># - fixed bugs in OleFileIO.open and _OleDirectoryEntry</span> <span class="c"># - added safety check in main for large or binary</span> <span class="c"># properties</span> <span class="c"># - allow size>0 for storages for some implementations</span> <span class="c"># 2007-12-05 v0.18 PL: - fixed several bugs in handling of FAT, MiniFAT and</span> <span class="c"># streams</span> <span class="c"># - added option '-c' in main to check all streams</span> <span class="c"># 2009-12-10 v0.19 PL: - bugfix for 32 bit arrays on 64 bits platforms</span> <span class="c"># (thanks to Ben G. and Martijn for reporting the bug)</span> <span class="c"># 2009-12-11 v0.20 PL: - bugfix in OleFileIO.open when filename is not plain str</span> <span class="c"># 2010-01-22 v0.21 PL: - added support for big-endian CPUs such as PowerPC Macs</span> <span class="c"># 2012-02-16 v0.22 PL: - fixed bug in getproperties, patch by chuckleberryfinn</span> <span class="c"># (https://bitbucket.org/decalage/olefileio_pl/issue/7)</span> <span class="c"># - added close method to OleFileIO (fixed issue #2)</span> <span class="c"># 2012-07-25 v0.23 PL: - added support for file-like objects (patch by mete0r_kr)</span> <span class="c"># 2013-05-05 v0.24 PL: - getproperties: added conversion from filetime to python</span> <span class="c"># datetime</span> <span class="c"># - main: displays properties with date format</span> <span class="c"># - new class OleMetadata to parse standard properties</span> <span class="c"># - added get_metadata method</span> <span class="c"># 2013-05-07 v0.24 PL: - a few improvements in OleMetadata</span> <span class="c"># 2013-05-24 v0.25 PL: - getproperties: option to not convert some timestamps</span> <span class="c"># - OleMetaData: total_edit_time is now a number of seconds,</span> <span class="c"># not a timestamp</span> <span class="c"># - getproperties: added support for VT_BOOL, VT_INT, V_UINT</span> <span class="c"># - getproperties: filter out null chars from strings</span> <span class="c"># - getproperties: raise non-fatal defects instead of</span> <span class="c"># exceptions when properties cannot be parsed properly</span> <span class="c"># 2013-05-27 PL: - getproperties: improved exception handling</span> <span class="c"># - _raise_defect: added option to set exception type</span> <span class="c"># - all non-fatal issues are now recorded, and displayed</span> <span class="c"># when run as a script</span> <span class="c"># 2013-07-11 v0.26 PL: - added methods to get modification and creation times</span> <span class="c"># of a directory entry or a storage/stream</span> <span class="c"># - fixed parsing of direntry timestamps</span> <span class="c"># 2013-07-24 PL: - new options in listdir to list storages and/or streams</span> <span class="c"># 2014-02-04 v0.30 PL: - upgraded code to support Python 3.x by Martin Panter</span> <span class="c"># - several fixes for Python 2.6 (xrange, MAGIC)</span> <span class="c"># - reused i32 from Pillow's _binary</span> <span class="c">#-----------------------------------------------------------------------------</span> <span class="c"># TODO (for version 1.0):</span> <span class="c"># + isOleFile should accept file-like objects like open</span> <span class="c"># + fix how all the methods handle unicode str and/or bytes as arguments</span> <span class="c"># + add path attrib to _OleDirEntry, set it once and for all in init or</span> <span class="c"># append_kids (then listdir/_list can be simplified)</span> <span class="c"># - TESTS with Linux, MacOSX, Python 1.5.2, various files, PIL, ...</span> <span class="c"># - add underscore to each private method, to avoid their display in</span> <span class="c"># pydoc/epydoc documentation - Remove it for classes to be documented</span> <span class="c"># - replace all raised exceptions with _raise_defect (at least in OleFileIO)</span> <span class="c"># - merge code from _OleStream and OleFileIO.getsect to read sectors</span> <span class="c"># (maybe add a class for FAT and MiniFAT ?)</span> <span class="c"># - add method to check all streams (follow sectors chains without storing all</span> <span class="c"># stream in memory, and report anomalies)</span> <span class="c"># - use _OleDirectoryEntry.kids_dict to improve _find and _list ?</span> <span class="c"># - fix Unicode names handling (find some way to stay compatible with Py1.5.2)</span> <span class="c"># => if possible avoid converting names to Latin-1</span> <span class="c"># - review DIFAT code: fix handling of DIFSECT blocks in FAT (not stop)</span> <span class="c"># - rewrite OleFileIO.getproperties</span> <span class="c"># - improve docstrings to show more sample uses</span> <span class="c"># - see also original notes and FIXME below</span> <span class="c"># - remove all obsolete FIXMEs</span> <span class="c"># - OleMetadata: fix version attrib according to</span> <span class="c"># http://msdn.microsoft.com/en-us/library/dd945671%28v=office.12%29.aspx</span> <span class="c"># IDEAS:</span> <span class="c"># - in OleFileIO._open and _OleStream, use size=None instead of 0x7FFFFFFF for</span> <span class="c"># streams with unknown size</span> <span class="c"># - use arrays of int instead of long integers for FAT/MiniFAT, to improve</span> <span class="c"># performance and reduce memory usage ? (possible issue with values >2^31)</span> <span class="c"># - provide tests with unittest (may need write support to create samples)</span> <span class="c"># - move all debug code (and maybe dump methods) to a separate module, with</span> <span class="c"># a class which inherits OleFileIO ?</span> <span class="c"># - fix docstrings to follow epydoc format</span> <span class="c"># - add support for 4K sectors ?</span> <span class="c"># - add support for big endian byte order ?</span> <span class="c"># - create a simple OLE explorer with wxPython</span> <span class="c"># FUTURE EVOLUTIONS to add write support:</span> <span class="c"># 1) add ability to write a stream back on disk from BytesIO (same size, no</span> <span class="c"># change in FAT/MiniFAT).</span> <span class="c"># 2) rename a stream/storage if it doesn't change the RB tree</span> <span class="c"># 3) use rbtree module to update the red-black tree + any rename</span> <span class="c"># 4) remove a stream/storage: free sectors in FAT/MiniFAT</span> <span class="c"># 5) allocate new sectors in FAT/MiniFAT</span> <span class="c"># 6) create new storage/stream</span> <span class="c">#-----------------------------------------------------------------------------</span> <span class="c">#</span> <span class="c"># THIS IS WORK IN PROGRESS</span> <span class="c">#</span> <span class="c"># The Python Imaging Library</span> <span class="c"># $Id$</span> <span class="c">#</span> <span class="c"># stuff to deal with OLE2 Structured Storage files. this module is</span> <span class="c"># used by PIL to read Image Composer and FlashPix files, but can also</span> <span class="c"># be used to read other files of this type.</span> <span class="c">#</span> <span class="c"># History:</span> <span class="c"># 1997-01-20 fl Created</span> <span class="c"># 1997-01-22 fl Fixed 64-bit portability quirk</span> <span class="c"># 2003-09-09 fl Fixed typo in OleFileIO.loadfat (noted by Daniel Haertle)</span> <span class="c"># 2004-02-29 fl Changed long hex constants to signed integers</span> <span class="c">#</span> <span class="c"># Notes:</span> <span class="c"># FIXME: sort out sign problem (eliminate long hex constants)</span> <span class="c"># FIXME: change filename to use "a/b/c" instead of ["a", "b", "c"]</span> <span class="c"># FIXME: provide a glob mechanism function (using fnmatchcase)</span> <span class="c">#</span> <span class="c"># Literature:</span> <span class="c">#</span> <span class="c"># "FlashPix Format Specification, Appendix A", Kodak and Microsoft,</span> <span class="c"># September 1996.</span> <span class="c">#</span> <span class="c"># Quotes:</span> <span class="c">#</span> <span class="c"># "If this document and functionality of the Software conflict,</span> <span class="c"># the actual functionality of the Software represents the correct</span> <span class="c"># functionality" -- Microsoft, in the OLE format specification</span> <span class="c">#</span> <span class="c"># Copyright (c) Secret Labs AB 1997.</span> <span class="c"># Copyright (c) Fredrik Lundh 1997.</span> <span class="c">#</span> <span class="c"># See the README file for information on usage and redistribution.</span> <span class="c">#</span> <span class="c">#------------------------------------------------------------------------------</span> <span class="kn">import</span> <span class="nn">io</span> <span class="kn">import</span> <span class="nn">sys</span> <span class="kn">import</span> <span class="nn">struct</span><span class="o">,</span> <span class="nn">array</span><span class="o">,</span> <span class="nn">os.path</span><span class="o">,</span> <span class="nn">datetime</span> <span class="c">#[PL] Define explicitly the public API to avoid private objects in pydoc:</span> <span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span><span class="s">'OleFileIO'</span><span class="p">,</span> <span class="s">'isOleFile'</span><span class="p">,</span> <span class="s">'MAGIC'</span><span class="p">]</span> <span class="c"># For Python 3.x, need to redefine long as int:</span> <span class="k">if</span> <span class="nb">str</span> <span class="ow">is</span> <span class="ow">not</span> <span class="nb">bytes</span><span class="p">:</span> <span class="nb">long</span> <span class="o">=</span> <span class="nb">int</span> <span class="c"># Need to make sure we use xrange both on Python 2 and 3.x:</span> <span class="k">try</span><span class="p">:</span> <span class="c"># on Python 2 we need xrange:</span> <span class="n">iterrange</span> <span class="o">=</span> <span class="nb">xrange</span> <span class="k">except</span><span class="p">:</span> <span class="c"># no xrange, for Python 3 it was renamed as range:</span> <span class="n">iterrange</span> <span class="o">=</span> <span class="nb">range</span> <span class="c">#[PL] workaround to fix an issue with array item size on 64 bits systems:</span> <span class="k">if</span> <span class="n">array</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="s">'L'</span><span class="p">)</span><span class="o">.</span><span class="n">itemsize</span> <span class="o">==</span> <span class="mi">4</span><span class="p">:</span> <span class="c"># on 32 bits platforms, long integers in an array are 32 bits:</span> <span class="n">UINT32</span> <span class="o">=</span> <span class="s">'L'</span> <span class="k">elif</span> <span class="n">array</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="s">'I'</span><span class="p">)</span><span class="o">.</span><span class="n">itemsize</span> <span class="o">==</span> <span class="mi">4</span><span class="p">:</span> <span class="c"># on 64 bits platforms, integers in an array are 32 bits:</span> <span class="n">UINT32</span> <span class="o">=</span> <span class="s">'I'</span> <span class="k">else</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s">'Need to fix a bug with 32 bit arrays, please contact author...'</span><span class="p">)</span> <span class="c">#[PL] These workarounds were inspired from the Path module</span> <span class="c"># (see http://www.jorendorff.com/articles/python/path/)</span> <span class="c">#TODO: test with old Python versions</span> <span class="c"># Pre-2.3 workaround for basestring.</span> <span class="k">try</span><span class="p">:</span> <span class="nb">basestring</span> <span class="k">except</span> <span class="ne">NameError</span><span class="p">:</span> <span class="k">try</span><span class="p">:</span> <span class="c"># is Unicode supported (Python >2.0 or >1.6 ?)</span> <span class="nb">basestring</span> <span class="o">=</span> <span class="p">(</span><span class="nb">str</span><span class="p">,</span> <span class="nb">unicode</span><span class="p">)</span> <span class="k">except</span> <span class="ne">NameError</span><span class="p">:</span> <span class="nb">basestring</span> <span class="o">=</span> <span class="nb">str</span> <span class="c">#[PL] Experimental setting: if True, OLE filenames will be kept in Unicode</span> <span class="c"># if False (default PIL behaviour), all filenames are converted to Latin-1.</span> <span class="n">KEEP_UNICODE_NAMES</span> <span class="o">=</span> <span class="bp">False</span> <span class="c">#[PL] DEBUG display mode: False by default, use set_debug_mode() or "-d" on</span> <span class="c"># command line to change it.</span> <span class="n">DEBUG_MODE</span> <span class="o">=</span> <span class="bp">False</span> <span class="k">def</span> <span class="nf">debug_print</span><span class="p">(</span><span class="n">msg</span><span class="p">):</span> <span class="k">print</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span> <span class="k">def</span> <span class="nf">debug_pass</span><span class="p">(</span><span class="n">msg</span><span class="p">):</span> <span class="k">pass</span> <span class="n">debug</span> <span class="o">=</span> <span class="n">debug_pass</span> <span class="k">def</span> <span class="nf">set_debug_mode</span><span class="p">(</span><span class="n">debug_mode</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Set debug mode on or off, to control display of debugging messages.</span> <span class="sd"> mode: True or False</span> <span class="sd"> """</span> <span class="k">global</span> <span class="n">DEBUG_MODE</span><span class="p">,</span> <span class="n">debug</span> <span class="n">DEBUG_MODE</span> <span class="o">=</span> <span class="n">debug_mode</span> <span class="k">if</span> <span class="n">debug_mode</span><span class="p">:</span> <span class="n">debug</span> <span class="o">=</span> <span class="n">debug_print</span> <span class="k">else</span><span class="p">:</span> <span class="n">debug</span> <span class="o">=</span> <span class="n">debug_pass</span> <span class="n">MAGIC</span> <span class="o">=</span> <span class="n">b</span><span class="s">'</span><span class="se">\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1</span><span class="s">'</span> <span class="c">#[PL]: added constants for Sector IDs (from AAF specifications)</span> <span class="n">MAXREGSECT</span> <span class="o">=</span> <span class="mh">0xFFFFFFFA</span><span class="p">;</span> <span class="c"># maximum SECT</span> <span class="n">DIFSECT</span> <span class="o">=</span> <span class="mh">0xFFFFFFFC</span><span class="p">;</span> <span class="c"># (-4) denotes a DIFAT sector in a FAT</span> <span class="n">FATSECT</span> <span class="o">=</span> <span class="mh">0xFFFFFFFD</span><span class="p">;</span> <span class="c"># (-3) denotes a FAT sector in a FAT</span> <span class="n">ENDOFCHAIN</span> <span class="o">=</span> <span class="mh">0xFFFFFFFE</span><span class="p">;</span> <span class="c"># (-2) end of a virtual stream chain</span> <span class="n">FREESECT</span> <span class="o">=</span> <span class="mh">0xFFFFFFFF</span><span class="p">;</span> <span class="c"># (-1) unallocated sector</span> <span class="c">#[PL]: added constants for Directory Entry IDs (from AAF specifications)</span> <span class="n">MAXREGSID</span> <span class="o">=</span> <span class="mh">0xFFFFFFFA</span><span class="p">;</span> <span class="c"># maximum directory entry ID</span> <span class="n">NOSTREAM</span> <span class="o">=</span> <span class="mh">0xFFFFFFFF</span><span class="p">;</span> <span class="c"># (-1) unallocated directory entry</span> <span class="c">#[PL] object types in storage (from AAF specifications)</span> <span class="n">STGTY_EMPTY</span> <span class="o">=</span> <span class="mi">0</span> <span class="c"># empty directory entry (according to OpenOffice.org doc)</span> <span class="n">STGTY_STORAGE</span> <span class="o">=</span> <span class="mi">1</span> <span class="c"># element is a storage object</span> <span class="n">STGTY_STREAM</span> <span class="o">=</span> <span class="mi">2</span> <span class="c"># element is a stream object</span> <span class="n">STGTY_LOCKBYTES</span> <span class="o">=</span> <span class="mi">3</span> <span class="c"># element is an ILockBytes object</span> <span class="n">STGTY_PROPERTY</span> <span class="o">=</span> <span class="mi">4</span> <span class="c"># element is an IPropertyStorage object</span> <span class="n">STGTY_ROOT</span> <span class="o">=</span> <span class="mi">5</span> <span class="c"># element is a root storage</span> <span class="c">#</span> <span class="c"># --------------------------------------------------------------------</span> <span class="c"># property types</span> <span class="n">VT_EMPTY</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">VT_NULL</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span> <span class="n">VT_I2</span><span class="o">=</span><span class="mi">2</span><span class="p">;</span> <span class="n">VT_I4</span><span class="o">=</span><span class="mi">3</span><span class="p">;</span> <span class="n">VT_R4</span><span class="o">=</span><span class="mi">4</span><span class="p">;</span> <span class="n">VT_R8</span><span class="o">=</span><span class="mi">5</span><span class="p">;</span> <span class="n">VT_CY</span><span class="o">=</span><span class="mi">6</span><span class="p">;</span> <span class="n">VT_DATE</span><span class="o">=</span><span class="mi">7</span><span class="p">;</span> <span class="n">VT_BSTR</span><span class="o">=</span><span class="mi">8</span><span class="p">;</span> <span class="n">VT_DISPATCH</span><span class="o">=</span><span class="mi">9</span><span class="p">;</span> <span class="n">VT_ERROR</span><span class="o">=</span><span class="mi">10</span><span class="p">;</span> <span class="n">VT_BOOL</span><span class="o">=</span><span class="mi">11</span><span class="p">;</span> <span class="n">VT_VARIANT</span><span class="o">=</span><span class="mi">12</span><span class="p">;</span> <span class="n">VT_UNKNOWN</span><span class="o">=</span><span class="mi">13</span><span class="p">;</span> <span class="n">VT_DECIMAL</span><span class="o">=</span><span class="mi">14</span><span class="p">;</span> <span class="n">VT_I1</span><span class="o">=</span><span class="mi">16</span><span class="p">;</span> <span class="n">VT_UI1</span><span class="o">=</span><span class="mi">17</span><span class="p">;</span> <span class="n">VT_UI2</span><span class="o">=</span><span class="mi">18</span><span class="p">;</span> <span class="n">VT_UI4</span><span class="o">=</span><span class="mi">19</span><span class="p">;</span> <span class="n">VT_I8</span><span class="o">=</span><span class="mi">20</span><span class="p">;</span> <span class="n">VT_UI8</span><span class="o">=</span><span class="mi">21</span><span class="p">;</span> <span class="n">VT_INT</span><span class="o">=</span><span class="mi">22</span><span class="p">;</span> <span class="n">VT_UINT</span><span class="o">=</span><span class="mi">23</span><span class="p">;</span> <span class="n">VT_VOID</span><span class="o">=</span><span class="mi">24</span><span class="p">;</span> <span class="n">VT_HRESULT</span><span class="o">=</span><span class="mi">25</span><span class="p">;</span> <span class="n">VT_PTR</span><span class="o">=</span><span class="mi">26</span><span class="p">;</span> <span class="n">VT_SAFEARRAY</span><span class="o">=</span><span class="mi">27</span><span class="p">;</span> <span class="n">VT_CARRAY</span><span class="o">=</span><span class="mi">28</span><span class="p">;</span> <span class="n">VT_USERDEFINED</span><span class="o">=</span><span class="mi">29</span><span class="p">;</span> <span class="n">VT_LPSTR</span><span class="o">=</span><span class="mi">30</span><span class="p">;</span> <span class="n">VT_LPWSTR</span><span class="o">=</span><span class="mi">31</span><span class="p">;</span> <span class="n">VT_FILETIME</span><span class="o">=</span><span class="mi">64</span><span class="p">;</span> <span class="n">VT_BLOB</span><span class="o">=</span><span class="mi">65</span><span class="p">;</span> <span class="n">VT_STREAM</span><span class="o">=</span><span class="mi">66</span><span class="p">;</span> <span class="n">VT_STORAGE</span><span class="o">=</span><span class="mi">67</span><span class="p">;</span> <span class="n">VT_STREAMED_OBJECT</span><span class="o">=</span><span class="mi">68</span><span class="p">;</span> <span class="n">VT_STORED_OBJECT</span><span class="o">=</span><span class="mi">69</span><span class="p">;</span> <span class="n">VT_BLOB_OBJECT</span><span class="o">=</span><span class="mi">70</span><span class="p">;</span> <span class="n">VT_CF</span><span class="o">=</span><span class="mi">71</span><span class="p">;</span> <span class="n">VT_CLSID</span><span class="o">=</span><span class="mi">72</span><span class="p">;</span> <span class="n">VT_VECTOR</span><span class="o">=</span><span class="mh">0x1000</span><span class="p">;</span> <span class="c"># map property id to name (for debugging purposes)</span> <span class="n">VT</span> <span class="o">=</span> <span class="p">{}</span> <span class="k">for</span> <span class="n">keyword</span><span class="p">,</span> <span class="n">var</span> <span class="ow">in</span> <span class="nb">list</span><span class="p">(</span><span class="nb">vars</span><span class="p">()</span><span class="o">.</span><span class="n">items</span><span class="p">()):</span> <span class="k">if</span> <span class="n">keyword</span><span class="p">[:</span><span class="mi">3</span><span class="p">]</span> <span class="o">==</span> <span class="s">"VT_"</span><span class="p">:</span> <span class="n">VT</span><span class="p">[</span><span class="n">var</span><span class="p">]</span> <span class="o">=</span> <span class="n">keyword</span> <span class="c">#</span> <span class="c"># --------------------------------------------------------------------</span> <span class="c"># Some common document types (root.clsid fields)</span> <span class="n">WORD_CLSID</span> <span class="o">=</span> <span class="s">"00020900-0000-0000-C000-000000000046"</span> <span class="c">#TODO: check Excel, PPT, ...</span> <span class="c">#[PL]: Defect levels to classify parsing errors - see OleFileIO._raise_defect()</span> <span class="n">DEFECT_UNSURE</span> <span class="o">=</span> <span class="mi">10</span> <span class="c"># a case which looks weird, but not sure it's a defect</span> <span class="n">DEFECT_POTENTIAL</span> <span class="o">=</span> <span class="mi">20</span> <span class="c"># a potential defect</span> <span class="n">DEFECT_INCORRECT</span> <span class="o">=</span> <span class="mi">30</span> <span class="c"># an error according to specifications, but parsing</span> <span class="c"># can go on</span> <span class="n">DEFECT_FATAL</span> <span class="o">=</span> <span class="mi">40</span> <span class="c"># an error which cannot be ignored, parsing is</span> <span class="c"># impossible</span> <span class="c">#[PL] add useful constants to __all__:</span> <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="nb">list</span><span class="p">(</span><span class="nb">vars</span><span class="p">()</span><span class="o">.</span><span class="n">keys</span><span class="p">()):</span> <span class="k">if</span> <span class="n">key</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">'STGTY_'</span><span class="p">)</span> <span class="ow">or</span> <span class="n">key</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">'DEFECT_'</span><span class="p">):</span> <span class="n">__all__</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">key</span><span class="p">)</span> <span class="c">#--- FUNCTIONS ----------------------------------------------------------------</span> <div class="viewcode-block" id="isOleFile"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.isOleFile">[docs]</a><span class="k">def</span> <span class="nf">isOleFile</span> <span class="p">(</span><span class="n">filename</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Test if file is an OLE container (according to its header).</span> <span class="sd"> </span> <span class="sd"> :param filename: file name or path (str, unicode)</span> <span class="sd"> :returns: True if OLE, False otherwise.</span> <span class="sd"> """</span> <span class="n">f</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s">'rb'</span><span class="p">)</span> <span class="n">header</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">MAGIC</span><span class="p">))</span> <span class="k">if</span> <span class="n">header</span> <span class="o">==</span> <span class="n">MAGIC</span><span class="p">:</span> <span class="k">return</span> <span class="bp">True</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="bp">False</span> </div> <span class="k">if</span> <span class="nb">bytes</span> <span class="ow">is</span> <span class="nb">str</span><span class="p">:</span> <span class="c"># version for Python 2.x</span> <span class="k">def</span> <span class="nf">i8</span><span class="p">(</span><span class="n">c</span><span class="p">):</span> <span class="k">return</span> <span class="nb">ord</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="c"># version for Python 3.x</span> <span class="k">def</span> <span class="nf">i8</span><span class="p">(</span><span class="n">c</span><span class="p">):</span> <span class="k">return</span> <span class="n">c</span> <span class="k">if</span> <span class="n">c</span><span class="o">.</span><span class="n">__class__</span> <span class="ow">is</span> <span class="nb">int</span> <span class="k">else</span> <span class="n">c</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="c">#TODO: replace i16 and i32 with more readable struct.unpack equivalent?</span> <span class="k">def</span> <span class="nf">i16</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="n">o</span> <span class="o">=</span> <span class="mi">0</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Converts a 2-bytes (16 bits) string to an integer.</span> <span class="sd"> :param c: string containing bytes to convert</span> <span class="sd"> :param o: offset of bytes to convert in string</span> <span class="sd"> """</span> <span class="k">return</span> <span class="n">i8</span><span class="p">(</span><span class="n">c</span><span class="p">[</span><span class="n">o</span><span class="p">])</span> <span class="o">|</span> <span class="p">(</span><span class="n">i8</span><span class="p">(</span><span class="n">c</span><span class="p">[</span><span class="n">o</span><span class="o">+</span><span class="mi">1</span><span class="p">])</span><span class="o"><<</span><span class="mi">8</span><span class="p">)</span> <span class="k">def</span> <span class="nf">i32</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="n">o</span> <span class="o">=</span> <span class="mi">0</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Converts a 4-bytes (32 bits) string to an integer.</span> <span class="sd"> :param c: string containing bytes to convert</span> <span class="sd"> :param o: offset of bytes to convert in string</span> <span class="sd"> """</span> <span class="c">## return int(ord(c[o])+(ord(c[o+1])<<8)+(ord(c[o+2])<<16)+(ord(c[o+3])<<24))</span> <span class="c">## # [PL]: added int() because "<<" gives long int since Python 2.4</span> <span class="c"># copied from Pillow's _binary:</span> <span class="k">return</span> <span class="n">i8</span><span class="p">(</span><span class="n">c</span><span class="p">[</span><span class="n">o</span><span class="p">])</span> <span class="o">|</span> <span class="p">(</span><span class="n">i8</span><span class="p">(</span><span class="n">c</span><span class="p">[</span><span class="n">o</span><span class="o">+</span><span class="mi">1</span><span class="p">])</span><span class="o"><<</span><span class="mi">8</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">i8</span><span class="p">(</span><span class="n">c</span><span class="p">[</span><span class="n">o</span><span class="o">+</span><span class="mi">2</span><span class="p">])</span><span class="o"><<</span><span class="mi">16</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">i8</span><span class="p">(</span><span class="n">c</span><span class="p">[</span><span class="n">o</span><span class="o">+</span><span class="mi">3</span><span class="p">])</span><span class="o"><<</span><span class="mi">24</span><span class="p">)</span> <span class="k">def</span> <span class="nf">_clsid</span><span class="p">(</span><span class="n">clsid</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Converts a CLSID to a human-readable string.</span> <span class="sd"> :param clsid: string of length 16.</span> <span class="sd"> """</span> <span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">clsid</span><span class="p">)</span> <span class="o">==</span> <span class="mi">16</span> <span class="c"># if clsid is only made of null bytes, return an empty string:</span> <span class="c"># (PL: why not simply return the string with zeroes?)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">clsid</span><span class="o">.</span><span class="n">strip</span><span class="p">(</span><span class="n">b</span><span class="s">"</span><span class="se">\0</span><span class="s">"</span><span class="p">):</span> <span class="k">return</span> <span class="s">""</span> <span class="k">return</span> <span class="p">((</span><span class="s">"</span><span class="si">%08X</span><span class="s">-</span><span class="si">%04X</span><span class="s">-</span><span class="si">%04X</span><span class="s">-</span><span class="si">%02X%02X</span><span class="s">-"</span> <span class="o">+</span> <span class="s">"</span><span class="si">%02X</span><span class="s">"</span> <span class="o">*</span> <span class="mi">6</span><span class="p">)</span> <span class="o">%</span> <span class="p">((</span><span class="n">i32</span><span class="p">(</span><span class="n">clsid</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">i16</span><span class="p">(</span><span class="n">clsid</span><span class="p">,</span> <span class="mi">4</span><span class="p">),</span> <span class="n">i16</span><span class="p">(</span><span class="n">clsid</span><span class="p">,</span> <span class="mi">6</span><span class="p">))</span> <span class="o">+</span> <span class="nb">tuple</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="n">i8</span><span class="p">,</span> <span class="n">clsid</span><span class="p">[</span><span class="mi">8</span><span class="p">:</span><span class="mi">16</span><span class="p">]))))</span> <span class="c"># UNICODE support:</span> <span class="c"># (necessary to handle storages/streams names which use Unicode)</span> <span class="k">def</span> <span class="nf">_unicode</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">errors</span><span class="o">=</span><span class="s">'replace'</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Map unicode string to Latin 1. (Python with Unicode support)</span> <span class="sd"> :param s: UTF-16LE unicode string to convert to Latin-1</span> <span class="sd"> :param errors: 'replace', 'ignore' or 'strict'.</span> <span class="sd"> """</span> <span class="c">#TODO: test if it OleFileIO works with Unicode strings, instead of</span> <span class="c"># converting to Latin-1.</span> <span class="k">try</span><span class="p">:</span> <span class="c"># First the string is converted to plain Unicode:</span> <span class="c"># (assuming it is encoded as UTF-16 little-endian)</span> <span class="n">u</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s">'UTF-16LE'</span><span class="p">,</span> <span class="n">errors</span><span class="p">)</span> <span class="k">if</span> <span class="nb">bytes</span> <span class="ow">is</span> <span class="ow">not</span> <span class="nb">str</span> <span class="ow">or</span> <span class="n">KEEP_UNICODE_NAMES</span><span class="p">:</span> <span class="k">return</span> <span class="n">u</span> <span class="k">else</span><span class="p">:</span> <span class="c"># Second the unicode string is converted to Latin-1</span> <span class="k">return</span> <span class="n">u</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'latin_1'</span><span class="p">,</span> <span class="n">errors</span><span class="p">)</span> <span class="k">except</span><span class="p">:</span> <span class="c"># there was an error during Unicode to Latin-1 conversion:</span> <span class="k">raise</span> <span class="ne">IOError</span><span class="p">(</span><span class="s">'incorrect Unicode name'</span><span class="p">)</span> <span class="k">def</span> <span class="nf">filetime2datetime</span><span class="p">(</span><span class="n">filetime</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> convert FILETIME (64 bits int) to Python datetime.datetime</span> <span class="sd"> """</span> <span class="c"># TODO: manage exception when microseconds is too large</span> <span class="c"># inspired from http://code.activestate.com/recipes/511425-filetime-to-datetime/</span> <span class="n">_FILETIME_null_date</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="p">(</span><span class="mi">1601</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="c">#debug('timedelta days=%d' % (filetime//(10*1000000*3600*24)))</span> <span class="k">return</span> <span class="n">_FILETIME_null_date</span> <span class="o">+</span> <span class="n">datetime</span><span class="o">.</span><span class="n">timedelta</span><span class="p">(</span><span class="n">microseconds</span><span class="o">=</span><span class="n">filetime</span><span class="o">//</span><span class="mi">10</span><span class="p">)</span> <span class="c">#=== CLASSES ==================================================================</span> <span class="k">class</span> <span class="nc">OleMetadata</span><span class="p">:</span> <span class="sd">"""</span> <span class="sd"> class to parse and store metadata from standard properties of OLE files.</span> <span class="sd"> Available attributes:</span> <span class="sd"> codepage, title, subject, author, keywords, comments, template,</span> <span class="sd"> last_saved_by, revision_number, total_edit_time, last_printed, create_time,</span> <span class="sd"> last_saved_time, num_pages, num_words, num_chars, thumbnail,</span> <span class="sd"> creating_application, security, codepage_doc, category, presentation_target,</span> <span class="sd"> bytes, lines, paragraphs, slides, notes, hidden_slides, mm_clips,</span> <span class="sd"> scale_crop, heading_pairs, titles_of_parts, manager, company, links_dirty,</span> <span class="sd"> chars_with_spaces, unused, shared_doc, link_base, hlinks, hlinks_changed,</span> <span class="sd"> version, dig_sig, content_type, content_status, language, doc_version</span> <span class="sd"> Note: an attribute is set to None when not present in the properties of the</span> <span class="sd"> OLE file.</span> <span class="sd"> References for SummaryInformation stream:</span> <span class="sd"> - http://msdn.microsoft.com/en-us/library/dd942545.aspx</span> <span class="sd"> - http://msdn.microsoft.com/en-us/library/dd925819%28v=office.12%29.aspx</span> <span class="sd"> - http://msdn.microsoft.com/en-us/library/windows/desktop/aa380376%28v=vs.85%29.aspx</span> <span class="sd"> - http://msdn.microsoft.com/en-us/library/aa372045.aspx</span> <span class="sd"> - http://sedna-soft.de/summary-information-stream/</span> <span class="sd"> - http://poi.apache.org/apidocs/org/apache/poi/hpsf/SummaryInformation.html</span> <span class="sd"> References for DocumentSummaryInformation stream:</span> <span class="sd"> - http://msdn.microsoft.com/en-us/library/dd945671%28v=office.12%29.aspx</span> <span class="sd"> - http://msdn.microsoft.com/en-us/library/windows/desktop/aa380374%28v=vs.85%29.aspx</span> <span class="sd"> - http://poi.apache.org/apidocs/org/apache/poi/hpsf/DocumentSummaryInformation.html</span> <span class="sd"> new in version 0.25</span> <span class="sd"> """</span> <span class="c"># attribute names for SummaryInformation stream properties:</span> <span class="c"># (ordered by property id, starting at 1)</span> <span class="n">SUMMARY_ATTRIBS</span> <span class="o">=</span> <span class="p">[</span><span class="s">'codepage'</span><span class="p">,</span> <span class="s">'title'</span><span class="p">,</span> <span class="s">'subject'</span><span class="p">,</span> <span class="s">'author'</span><span class="p">,</span> <span class="s">'keywords'</span><span class="p">,</span> <span class="s">'comments'</span><span class="p">,</span> <span class="s">'template'</span><span class="p">,</span> <span class="s">'last_saved_by'</span><span class="p">,</span> <span class="s">'revision_number'</span><span class="p">,</span> <span class="s">'total_edit_time'</span><span class="p">,</span> <span class="s">'last_printed'</span><span class="p">,</span> <span class="s">'create_time'</span><span class="p">,</span> <span class="s">'last_saved_time'</span><span class="p">,</span> <span class="s">'num_pages'</span><span class="p">,</span> <span class="s">'num_words'</span><span class="p">,</span> <span class="s">'num_chars'</span><span class="p">,</span> <span class="s">'thumbnail'</span><span class="p">,</span> <span class="s">'creating_application'</span><span class="p">,</span> <span class="s">'security'</span><span class="p">]</span> <span class="c"># attribute names for DocumentSummaryInformation stream properties:</span> <span class="c"># (ordered by property id, starting at 1)</span> <span class="n">DOCSUM_ATTRIBS</span> <span class="o">=</span> <span class="p">[</span><span class="s">'codepage_doc'</span><span class="p">,</span> <span class="s">'category'</span><span class="p">,</span> <span class="s">'presentation_target'</span><span class="p">,</span> <span class="s">'bytes'</span><span class="p">,</span> <span class="s">'lines'</span><span class="p">,</span> <span class="s">'paragraphs'</span><span class="p">,</span> <span class="s">'slides'</span><span class="p">,</span> <span class="s">'notes'</span><span class="p">,</span> <span class="s">'hidden_slides'</span><span class="p">,</span> <span class="s">'mm_clips'</span><span class="p">,</span> <span class="s">'scale_crop'</span><span class="p">,</span> <span class="s">'heading_pairs'</span><span class="p">,</span> <span class="s">'titles_of_parts'</span><span class="p">,</span> <span class="s">'manager'</span><span class="p">,</span> <span class="s">'company'</span><span class="p">,</span> <span class="s">'links_dirty'</span><span class="p">,</span> <span class="s">'chars_with_spaces'</span><span class="p">,</span> <span class="s">'unused'</span><span class="p">,</span> <span class="s">'shared_doc'</span><span class="p">,</span> <span class="s">'link_base'</span><span class="p">,</span> <span class="s">'hlinks'</span><span class="p">,</span> <span class="s">'hlinks_changed'</span><span class="p">,</span> <span class="s">'version'</span><span class="p">,</span> <span class="s">'dig_sig'</span><span class="p">,</span> <span class="s">'content_type'</span><span class="p">,</span> <span class="s">'content_status'</span><span class="p">,</span> <span class="s">'language'</span><span class="p">,</span> <span class="s">'doc_version'</span><span class="p">]</span> <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Constructor for OleMetadata</span> <span class="sd"> All attributes are set to None by default</span> <span class="sd"> """</span> <span class="c"># properties from SummaryInformation stream</span> <span class="bp">self</span><span class="o">.</span><span class="n">codepage</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">title</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">subject</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">author</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">keywords</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">comments</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">template</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">last_saved_by</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">revision_number</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">total_edit_time</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">last_printed</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">create_time</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">last_saved_time</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">num_pages</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">num_words</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">num_chars</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">thumbnail</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">creating_application</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">security</span> <span class="o">=</span> <span class="bp">None</span> <span class="c"># properties from DocumentSummaryInformation stream</span> <span class="bp">self</span><span class="o">.</span><span class="n">codepage_doc</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">category</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">presentation_target</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">bytes</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">lines</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">paragraphs</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">slides</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">notes</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">hidden_slides</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">mm_clips</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">scale_crop</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">heading_pairs</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">titles_of_parts</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">manager</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">company</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">links_dirty</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">chars_with_spaces</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">unused</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">shared_doc</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">link_base</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">hlinks</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">hlinks_changed</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">version</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">dig_sig</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">content_type</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">content_status</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">language</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">doc_version</span> <span class="o">=</span> <span class="bp">None</span> <span class="k">def</span> <span class="nf">parse_properties</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">olefile</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Parse standard properties of an OLE file, from the streams</span> <span class="sd"> "\x05SummaryInformation" and "\x05DocumentSummaryInformation",</span> <span class="sd"> if present.</span> <span class="sd"> Properties are converted to strings, integers or python datetime objects.</span> <span class="sd"> If a property is not present, its value is set to None.</span> <span class="sd"> """</span> <span class="c"># first set all attributes to None:</span> <span class="k">for</span> <span class="n">attrib</span> <span class="ow">in</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">SUMMARY_ATTRIBS</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">DOCSUM_ATTRIBS</span><span class="p">):</span> <span class="nb">setattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">attrib</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> <span class="k">if</span> <span class="n">olefile</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="s">"</span><span class="se">\x05</span><span class="s">SummaryInformation"</span><span class="p">):</span> <span class="c"># get properties from the stream:</span> <span class="c"># (converting timestamps to python datetime, except total_edit_time,</span> <span class="c"># which is property #10)</span> <span class="n">props</span> <span class="o">=</span> <span class="n">olefile</span><span class="o">.</span><span class="n">getproperties</span><span class="p">(</span><span class="s">"</span><span class="se">\x05</span><span class="s">SummaryInformation"</span><span class="p">,</span> <span class="n">convert_time</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">no_conversion</span><span class="o">=</span><span class="p">[</span><span class="mi">10</span><span class="p">])</span> <span class="c"># store them into this object's attributes:</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">SUMMARY_ATTRIBS</span><span class="p">)):</span> <span class="c"># ids for standards properties start at 0x01, until 0x13</span> <span class="n">value</span> <span class="o">=</span> <span class="n">props</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> <span class="nb">setattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">SUMMARY_ATTRIBS</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">value</span><span class="p">)</span> <span class="k">if</span> <span class="n">olefile</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="s">"</span><span class="se">\x05</span><span class="s">DocumentSummaryInformation"</span><span class="p">):</span> <span class="c"># get properties from the stream:</span> <span class="n">props</span> <span class="o">=</span> <span class="n">olefile</span><span class="o">.</span><span class="n">getproperties</span><span class="p">(</span><span class="s">"</span><span class="se">\x05</span><span class="s">DocumentSummaryInformation"</span><span class="p">,</span> <span class="n">convert_time</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> <span class="c"># store them into this object's attributes:</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">DOCSUM_ATTRIBS</span><span class="p">)):</span> <span class="c"># ids for standards properties start at 0x01, until 0x13</span> <span class="n">value</span> <span class="o">=</span> <span class="n">props</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> <span class="nb">setattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">DOCSUM_ATTRIBS</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">value</span><span class="p">)</span> <span class="k">def</span> <span class="nf">dump</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Dump all metadata, for debugging purposes.</span> <span class="sd"> """</span> <span class="k">print</span><span class="p">(</span><span class="s">'Properties from SummaryInformation stream:'</span><span class="p">)</span> <span class="k">for</span> <span class="n">prop</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">SUMMARY_ATTRIBS</span><span class="p">:</span> <span class="n">value</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">prop</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="s">'- </span><span class="si">%s</span><span class="s">: </span><span class="si">%s</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="n">prop</span><span class="p">,</span> <span class="nb">repr</span><span class="p">(</span><span class="n">value</span><span class="p">)))</span> <span class="k">print</span><span class="p">(</span><span class="s">'Properties from DocumentSummaryInformation stream:'</span><span class="p">)</span> <span class="k">for</span> <span class="n">prop</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">DOCSUM_ATTRIBS</span><span class="p">:</span> <span class="n">value</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">prop</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="s">'- </span><span class="si">%s</span><span class="s">: </span><span class="si">%s</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="n">prop</span><span class="p">,</span> <span class="nb">repr</span><span class="p">(</span><span class="n">value</span><span class="p">)))</span> <span class="c">#--- _OleStream ---------------------------------------------------------------</span> <span class="k">class</span> <span class="nc">_OleStream</span><span class="p">(</span><span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> OLE2 Stream</span> <span class="sd"> Returns a read-only file object which can be used to read</span> <span class="sd"> the contents of a OLE stream (instance of the BytesIO class).</span> <span class="sd"> To open a stream, use the openstream method in the OleFile class.</span> <span class="sd"> This function can be used with either ordinary streams,</span> <span class="sd"> or ministreams, depending on the offset, sectorsize, and</span> <span class="sd"> fat table arguments.</span> <span class="sd"> Attributes:</span> <span class="sd"> - size: actual size of data stream, after it was opened.</span> <span class="sd"> """</span> <span class="c"># FIXME: should store the list of sects obtained by following</span> <span class="c"># the fat chain, and load new sectors on demand instead of</span> <span class="c"># loading it all in one go.</span> <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fp</span><span class="p">,</span> <span class="n">sect</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="n">offset</span><span class="p">,</span> <span class="n">sectorsize</span><span class="p">,</span> <span class="n">fat</span><span class="p">,</span> <span class="n">filesize</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Constructor for _OleStream class.</span> <span class="sd"> :param fp : file object, the OLE container or the MiniFAT stream</span> <span class="sd"> :param sect : sector index of first sector in the stream</span> <span class="sd"> :param size : total size of the stream</span> <span class="sd"> :param offset : offset in bytes for the first FAT or MiniFAT sector</span> <span class="sd"> :param sectorsize: size of one sector</span> <span class="sd"> :param fat : array/list of sector indexes (FAT or MiniFAT)</span> <span class="sd"> :param filesize : size of OLE file (for debugging)</span> <span class="sd"> :returns : a BytesIO instance containing the OLE stream</span> <span class="sd"> """</span> <span class="n">debug</span><span class="p">(</span><span class="s">'_OleStream.__init__:'</span><span class="p">)</span> <span class="n">debug</span><span class="p">(</span><span class="s">' sect=</span><span class="si">%d</span><span class="s"> (</span><span class="si">%X</span><span class="s">), size=</span><span class="si">%d</span><span class="s">, offset=</span><span class="si">%d</span><span class="s">, sectorsize=</span><span class="si">%d</span><span class="s">, len(fat)=</span><span class="si">%d</span><span class="s">, fp=</span><span class="si">%s</span><span class="s">'</span> <span class="o">%</span><span class="p">(</span><span class="n">sect</span><span class="p">,</span><span class="n">sect</span><span class="p">,</span><span class="n">size</span><span class="p">,</span><span class="n">offset</span><span class="p">,</span><span class="n">sectorsize</span><span class="p">,</span><span class="nb">len</span><span class="p">(</span><span class="n">fat</span><span class="p">),</span> <span class="nb">repr</span><span class="p">(</span><span class="n">fp</span><span class="p">)))</span> <span class="c">#[PL] To detect malformed documents with FAT loops, we compute the</span> <span class="c"># expected number of sectors in the stream:</span> <span class="n">unknown_size</span> <span class="o">=</span> <span class="bp">False</span> <span class="k">if</span> <span class="n">size</span><span class="o">==</span><span class="mh">0x7FFFFFFF</span><span class="p">:</span> <span class="c"># this is the case when called from OleFileIO._open(), and stream</span> <span class="c"># size is not known in advance (for example when reading the</span> <span class="c"># Directory stream). Then we can only guess maximum size:</span> <span class="n">size</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">fat</span><span class="p">)</span><span class="o">*</span><span class="n">sectorsize</span> <span class="c"># and we keep a record that size was unknown:</span> <span class="n">unknown_size</span> <span class="o">=</span> <span class="bp">True</span> <span class="n">debug</span><span class="p">(</span><span class="s">' stream with UNKNOWN SIZE'</span><span class="p">)</span> <span class="n">nb_sectors</span> <span class="o">=</span> <span class="p">(</span><span class="n">size</span> <span class="o">+</span> <span class="p">(</span><span class="n">sectorsize</span><span class="o">-</span><span class="mi">1</span><span class="p">))</span> <span class="o">//</span> <span class="n">sectorsize</span> <span class="n">debug</span><span class="p">(</span><span class="s">'nb_sectors = </span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="n">nb_sectors</span><span class="p">)</span> <span class="c"># This number should (at least) be less than the total number of</span> <span class="c"># sectors in the given FAT:</span> <span class="k">if</span> <span class="n">nb_sectors</span> <span class="o">></span> <span class="nb">len</span><span class="p">(</span><span class="n">fat</span><span class="p">):</span> <span class="k">raise</span> <span class="ne">IOError</span><span class="p">(</span><span class="s">'malformed OLE document, stream too large'</span><span class="p">)</span> <span class="c"># optimization(?): data is first a list of strings, and join() is called</span> <span class="c"># at the end to concatenate all in one string.</span> <span class="c"># (this may not be really useful with recent Python versions)</span> <span class="n">data</span> <span class="o">=</span> <span class="p">[]</span> <span class="c"># if size is zero, then first sector index should be ENDOFCHAIN:</span> <span class="k">if</span> <span class="n">size</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">sect</span> <span class="o">!=</span> <span class="n">ENDOFCHAIN</span><span class="p">:</span> <span class="n">debug</span><span class="p">(</span><span class="s">'size == 0 and sect != ENDOFCHAIN:'</span><span class="p">)</span> <span class="k">raise</span> <span class="ne">IOError</span><span class="p">(</span><span class="s">'incorrect OLE sector index for empty stream'</span><span class="p">)</span> <span class="c">#[PL] A fixed-length for loop is used instead of an undefined while</span> <span class="c"># loop to avoid DoS attacks:</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">nb_sectors</span><span class="p">):</span> <span class="c"># Sector index may be ENDOFCHAIN, but only if size was unknown</span> <span class="k">if</span> <span class="n">sect</span> <span class="o">==</span> <span class="n">ENDOFCHAIN</span><span class="p">:</span> <span class="k">if</span> <span class="n">unknown_size</span><span class="p">:</span> <span class="k">break</span> <span class="k">else</span><span class="p">:</span> <span class="c"># else this means that the stream is smaller than declared:</span> <span class="n">debug</span><span class="p">(</span><span class="s">'sect=ENDOFCHAIN before expected size'</span><span class="p">)</span> <span class="k">raise</span> <span class="ne">IOError</span><span class="p">(</span><span class="s">'incomplete OLE stream'</span><span class="p">)</span> <span class="c"># sector index should be within FAT:</span> <span class="k">if</span> <span class="n">sect</span><span class="o"><</span><span class="mi">0</span> <span class="ow">or</span> <span class="n">sect</span><span class="o">>=</span><span class="nb">len</span><span class="p">(</span><span class="n">fat</span><span class="p">):</span> <span class="n">debug</span><span class="p">(</span><span class="s">'sect=</span><span class="si">%d</span><span class="s"> (</span><span class="si">%X</span><span class="s">) / len(fat)=</span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="n">sect</span><span class="p">,</span> <span class="n">sect</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">fat</span><span class="p">)))</span> <span class="n">debug</span><span class="p">(</span><span class="s">'i=</span><span class="si">%d</span><span class="s"> / nb_sectors=</span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">nb_sectors</span><span class="p">))</span> <span class="c">## tmp_data = b"".join(data)</span> <span class="c">## f = open('test_debug.bin', 'wb')</span> <span class="c">## f.write(tmp_data)</span> <span class="c">## f.close()</span> <span class="c">## debug('data read so far: %d bytes' % len(tmp_data))</span> <span class="k">raise</span> <span class="ne">IOError</span><span class="p">(</span><span class="s">'incorrect OLE FAT, sector index out of range'</span><span class="p">)</span> <span class="c">#TODO: merge this code with OleFileIO.getsect() ?</span> <span class="c">#TODO: check if this works with 4K sectors:</span> <span class="k">try</span><span class="p">:</span> <span class="n">fp</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="n">offset</span> <span class="o">+</span> <span class="n">sectorsize</span> <span class="o">*</span> <span class="n">sect</span><span class="p">)</span> <span class="k">except</span><span class="p">:</span> <span class="n">debug</span><span class="p">(</span><span class="s">'sect=</span><span class="si">%d</span><span class="s">, seek=</span><span class="si">%d</span><span class="s">, filesize=</span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="n">sect</span><span class="p">,</span> <span class="n">offset</span><span class="o">+</span><span class="n">sectorsize</span><span class="o">*</span><span class="n">sect</span><span class="p">,</span> <span class="n">filesize</span><span class="p">))</span> <span class="k">raise</span> <span class="ne">IOError</span><span class="p">(</span><span class="s">'OLE sector index out of range'</span><span class="p">)</span> <span class="n">sector_data</span> <span class="o">=</span> <span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">sectorsize</span><span class="p">)</span> <span class="c"># [PL] check if there was enough data:</span> <span class="c"># Note: if sector is the last of the file, sometimes it is not a</span> <span class="c"># complete sector (of 512 or 4K), so we may read less than</span> <span class="c"># sectorsize.</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sector_data</span><span class="p">)</span><span class="o">!=</span><span class="n">sectorsize</span> <span class="ow">and</span> <span class="n">sect</span><span class="o">!=</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">fat</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">):</span> <span class="n">debug</span><span class="p">(</span><span class="s">'sect=</span><span class="si">%d</span><span class="s"> / len(fat)=</span><span class="si">%d</span><span class="s">, seek=</span><span class="si">%d</span><span class="s"> / filesize=</span><span class="si">%d</span><span class="s">, len read=</span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="n">sect</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">fat</span><span class="p">),</span> <span class="n">offset</span><span class="o">+</span><span class="n">sectorsize</span><span class="o">*</span><span class="n">sect</span><span class="p">,</span> <span class="n">filesize</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">sector_data</span><span class="p">)))</span> <span class="n">debug</span><span class="p">(</span><span class="s">'seek+len(read)=</span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="n">offset</span><span class="o">+</span><span class="n">sectorsize</span><span class="o">*</span><span class="n">sect</span><span class="o">+</span><span class="nb">len</span><span class="p">(</span><span class="n">sector_data</span><span class="p">)))</span> <span class="k">raise</span> <span class="ne">IOError</span><span class="p">(</span><span class="s">'incomplete OLE sector'</span><span class="p">)</span> <span class="n">data</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">sector_data</span><span class="p">)</span> <span class="c"># jump to next sector in the FAT:</span> <span class="k">try</span><span class="p">:</span> <span class="n">sect</span> <span class="o">=</span> <span class="n">fat</span><span class="p">[</span><span class="n">sect</span><span class="p">]</span> <span class="k">except</span> <span class="ne">IndexError</span><span class="p">:</span> <span class="c"># [PL] if pointer is out of the FAT an exception is raised</span> <span class="k">raise</span> <span class="ne">IOError</span><span class="p">(</span><span class="s">'incorrect OLE FAT, sector index out of range'</span><span class="p">)</span> <span class="c">#[PL] Last sector should be a "end of chain" marker:</span> <span class="k">if</span> <span class="n">sect</span> <span class="o">!=</span> <span class="n">ENDOFCHAIN</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">IOError</span><span class="p">(</span><span class="s">'incorrect last sector index in OLE stream'</span><span class="p">)</span> <span class="n">data</span> <span class="o">=</span> <span class="n">b</span><span class="s">""</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="c"># Data is truncated to the actual stream size:</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="o">>=</span> <span class="n">size</span><span class="p">:</span> <span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="p">[:</span><span class="n">size</span><span class="p">]</span> <span class="c"># actual stream size is stored for future use:</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o">=</span> <span class="n">size</span> <span class="k">elif</span> <span class="n">unknown_size</span><span class="p">:</span> <span class="c"># actual stream size was not known, now we know the size of read</span> <span class="c"># data:</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="c"># read data is less than expected:</span> <span class="n">debug</span><span class="p">(</span><span class="s">'len(data)=</span><span class="si">%d</span><span class="s">, size=</span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">),</span> <span class="n">size</span><span class="p">))</span> <span class="k">raise</span> <span class="ne">IOError</span><span class="p">(</span><span class="s">'OLE stream size is less than declared'</span><span class="p">)</span> <span class="c"># when all data is read in memory, BytesIO constructor is called</span> <span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span> <span class="c"># Then the _OleStream object can be used as a read-only file object.</span> <span class="c">#--- _OleDirectoryEntry -------------------------------------------------------</span> <span class="k">class</span> <span class="nc">_OleDirectoryEntry</span><span class="p">:</span> <span class="sd">"""</span> <span class="sd"> OLE2 Directory Entry</span> <span class="sd"> """</span> <span class="c">#[PL] parsing code moved from OleFileIO.loaddirectory</span> <span class="c"># struct to parse directory entries:</span> <span class="c"># <: little-endian byte order, standard sizes</span> <span class="c"># (note: this should guarantee that Q returns a 64 bits int)</span> <span class="c"># 64s: string containing entry name in unicode (max 31 chars) + null char</span> <span class="c"># H: uint16, number of bytes used in name buffer, including null = (len+1)*2</span> <span class="c"># B: uint8, dir entry type (between 0 and 5)</span> <span class="c"># B: uint8, color: 0=black, 1=red</span> <span class="c"># I: uint32, index of left child node in the red-black tree, NOSTREAM if none</span> <span class="c"># I: uint32, index of right child node in the red-black tree, NOSTREAM if none</span> <span class="c"># I: uint32, index of child root node if it is a storage, else NOSTREAM</span> <span class="c"># 16s: CLSID, unique identifier (only used if it is a storage)</span> <span class="c"># I: uint32, user flags</span> <span class="c"># Q (was 8s): uint64, creation timestamp or zero</span> <span class="c"># Q (was 8s): uint64, modification timestamp or zero</span> <span class="c"># I: uint32, SID of first sector if stream or ministream, SID of 1st sector</span> <span class="c"># of stream containing ministreams if root entry, 0 otherwise</span> <span class="c"># I: uint32, total stream size in bytes if stream (low 32 bits), 0 otherwise</span> <span class="c"># I: uint32, total stream size in bytes if stream (high 32 bits), 0 otherwise</span> <span class="n">STRUCT_DIRENTRY</span> <span class="o">=</span> <span class="s">'<64sHBBIII16sIQQIII'</span> <span class="c"># size of a directory entry: 128 bytes</span> <span class="n">DIRENTRY_SIZE</span> <span class="o">=</span> <span class="mi">128</span> <span class="k">assert</span> <span class="n">struct</span><span class="o">.</span><span class="n">calcsize</span><span class="p">(</span><span class="n">STRUCT_DIRENTRY</span><span class="p">)</span> <span class="o">==</span> <span class="n">DIRENTRY_SIZE</span> <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">entry</span><span class="p">,</span> <span class="n">sid</span><span class="p">,</span> <span class="n">olefile</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Constructor for an _OleDirectoryEntry object.</span> <span class="sd"> Parses a 128-bytes entry from the OLE Directory stream.</span> <span class="sd"> :param entry : string (must be 128 bytes long)</span> <span class="sd"> :param sid : index of this directory entry in the OLE file directory</span> <span class="sd"> :param olefile: OleFileIO containing this directory entry</span> <span class="sd"> """</span> <span class="bp">self</span><span class="o">.</span><span class="n">sid</span> <span class="o">=</span> <span class="n">sid</span> <span class="c"># ref to olefile is stored for future use</span> <span class="bp">self</span><span class="o">.</span><span class="n">olefile</span> <span class="o">=</span> <span class="n">olefile</span> <span class="c"># kids is a list of children entries, if this entry is a storage:</span> <span class="c"># (list of _OleDirectoryEntry objects)</span> <span class="bp">self</span><span class="o">.</span><span class="n">kids</span> <span class="o">=</span> <span class="p">[]</span> <span class="c"># kids_dict is a dictionary of children entries, indexed by their</span> <span class="c"># name in lowercase: used to quickly find an entry, and to detect</span> <span class="c"># duplicates</span> <span class="bp">self</span><span class="o">.</span><span class="n">kids_dict</span> <span class="o">=</span> <span class="p">{}</span> <span class="c"># flag used to detect if the entry is referenced more than once in</span> <span class="c"># directory:</span> <span class="bp">self</span><span class="o">.</span><span class="n">used</span> <span class="o">=</span> <span class="bp">False</span> <span class="c"># decode DirEntry</span> <span class="p">(</span> <span class="n">name</span><span class="p">,</span> <span class="n">namelength</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">entry_type</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">color</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">sid_left</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">sid_right</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">sid_child</span><span class="p">,</span> <span class="n">clsid</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">dwUserFlags</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">createTime</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">modifyTime</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">isectStart</span><span class="p">,</span> <span class="n">sizeLow</span><span class="p">,</span> <span class="n">sizeHigh</span> <span class="p">)</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">unpack</span><span class="p">(</span><span class="n">_OleDirectoryEntry</span><span class="o">.</span><span class="n">STRUCT_DIRENTRY</span><span class="p">,</span> <span class="n">entry</span><span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">entry_type</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="n">STGTY_ROOT</span><span class="p">,</span> <span class="n">STGTY_STORAGE</span><span class="p">,</span> <span class="n">STGTY_STREAM</span><span class="p">,</span> <span class="n">STGTY_EMPTY</span><span class="p">]:</span> <span class="n">olefile</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_INCORRECT</span><span class="p">,</span> <span class="s">'unhandled OLE storage type'</span><span class="p">)</span> <span class="c"># only first directory entry can (and should) be root:</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">entry_type</span> <span class="o">==</span> <span class="n">STGTY_ROOT</span> <span class="ow">and</span> <span class="n">sid</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">:</span> <span class="n">olefile</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_INCORRECT</span><span class="p">,</span> <span class="s">'duplicate OLE root entry'</span><span class="p">)</span> <span class="k">if</span> <span class="n">sid</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">entry_type</span> <span class="o">!=</span> <span class="n">STGTY_ROOT</span><span class="p">:</span> <span class="n">olefile</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_INCORRECT</span><span class="p">,</span> <span class="s">'incorrect OLE root entry'</span><span class="p">)</span> <span class="c">#debug (struct.unpack(fmt_entry, entry[:len_entry]))</span> <span class="c"># name should be at most 31 unicode characters + null character,</span> <span class="c"># so 64 bytes in total (31*2 + 2):</span> <span class="k">if</span> <span class="n">namelength</span><span class="o">></span><span class="mi">64</span><span class="p">:</span> <span class="n">olefile</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_INCORRECT</span><span class="p">,</span> <span class="s">'incorrect DirEntry name length'</span><span class="p">)</span> <span class="c"># if exception not raised, namelength is set to the maximum value:</span> <span class="n">namelength</span> <span class="o">=</span> <span class="mi">64</span> <span class="c"># only characters without ending null char are kept:</span> <span class="n">name</span> <span class="o">=</span> <span class="n">name</span><span class="p">[:(</span><span class="n">namelength</span><span class="o">-</span><span class="mi">2</span><span class="p">)]</span> <span class="c"># name is converted from unicode to Latin-1:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">_unicode</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="n">debug</span><span class="p">(</span><span class="s">'DirEntry SID=</span><span class="si">%d</span><span class="s">: </span><span class="si">%s</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">sid</span><span class="p">,</span> <span class="nb">repr</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)))</span> <span class="n">debug</span><span class="p">(</span><span class="s">' - type: </span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">entry_type</span><span class="p">)</span> <span class="n">debug</span><span class="p">(</span><span class="s">' - sect: </span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">isectStart</span><span class="p">)</span> <span class="n">debug</span><span class="p">(</span><span class="s">' - SID left: </span><span class="si">%d</span><span class="s">, right: </span><span class="si">%d</span><span class="s">, child: </span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">sid_left</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">sid_right</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">sid_child</span><span class="p">))</span> <span class="c"># sizeHigh is only used for 4K sectors, it should be zero for 512 bytes</span> <span class="c"># sectors, BUT apparently some implementations set it as 0xFFFFFFFF, 1</span> <span class="c"># or some other value so it cannot be raised as a defect in general:</span> <span class="k">if</span> <span class="n">olefile</span><span class="o">.</span><span class="n">sectorsize</span> <span class="o">==</span> <span class="mi">512</span><span class="p">:</span> <span class="k">if</span> <span class="n">sizeHigh</span> <span class="o">!=</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">sizeHigh</span> <span class="o">!=</span> <span class="mh">0xFFFFFFFF</span><span class="p">:</span> <span class="n">debug</span><span class="p">(</span><span class="s">'sectorsize=</span><span class="si">%d</span><span class="s">, sizeLow=</span><span class="si">%d</span><span class="s">, sizeHigh=</span><span class="si">%d</span><span class="s"> (</span><span class="si">%X</span><span class="s">)'</span> <span class="o">%</span> <span class="p">(</span><span class="n">olefile</span><span class="o">.</span><span class="n">sectorsize</span><span class="p">,</span> <span class="n">sizeLow</span><span class="p">,</span> <span class="n">sizeHigh</span><span class="p">,</span> <span class="n">sizeHigh</span><span class="p">))</span> <span class="n">olefile</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_UNSURE</span><span class="p">,</span> <span class="s">'incorrect OLE stream size'</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o">=</span> <span class="n">sizeLow</span> <span class="k">else</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o">=</span> <span class="n">sizeLow</span> <span class="o">+</span> <span class="p">(</span><span class="nb">long</span><span class="p">(</span><span class="n">sizeHigh</span><span class="p">)</span><span class="o"><<</span><span class="mi">32</span><span class="p">)</span> <span class="n">debug</span><span class="p">(</span><span class="s">' - size: </span><span class="si">%d</span><span class="s"> (sizeLow=</span><span class="si">%d</span><span class="s">, sizeHigh=</span><span class="si">%d</span><span class="s">)'</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">size</span><span class="p">,</span> <span class="n">sizeLow</span><span class="p">,</span> <span class="n">sizeHigh</span><span class="p">))</span> <span class="bp">self</span><span class="o">.</span><span class="n">clsid</span> <span class="o">=</span> <span class="n">_clsid</span><span class="p">(</span><span class="n">clsid</span><span class="p">)</span> <span class="c"># a storage should have a null size, BUT some implementations such as</span> <span class="c"># Word 8 for Mac seem to allow non-null values => Potential defect:</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">entry_type</span> <span class="o">==</span> <span class="n">STGTY_STORAGE</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">:</span> <span class="n">olefile</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_POTENTIAL</span><span class="p">,</span> <span class="s">'OLE storage with size>0'</span><span class="p">)</span> <span class="c"># check if stream is not already referenced elsewhere:</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">entry_type</span> <span class="ow">in</span> <span class="p">(</span><span class="n">STGTY_ROOT</span><span class="p">,</span> <span class="n">STGTY_STREAM</span><span class="p">)</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span><span class="o">></span><span class="mi">0</span><span class="p">:</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o"><</span> <span class="n">olefile</span><span class="o">.</span><span class="n">minisectorcutoff</span> \ <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">entry_type</span><span class="o">==</span><span class="n">STGTY_STREAM</span><span class="p">:</span> <span class="c"># only streams can be in MiniFAT</span> <span class="c"># ministream object</span> <span class="n">minifat</span> <span class="o">=</span> <span class="bp">True</span> <span class="k">else</span><span class="p">:</span> <span class="n">minifat</span> <span class="o">=</span> <span class="bp">False</span> <span class="n">olefile</span><span class="o">.</span><span class="n">_check_duplicate_stream</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">isectStart</span><span class="p">,</span> <span class="n">minifat</span><span class="p">)</span> <span class="k">def</span> <span class="nf">build_storage_tree</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Read and build the red-black tree attached to this _OleDirectoryEntry</span> <span class="sd"> object, if it is a storage.</span> <span class="sd"> Note that this method builds a tree of all subentries, so it should</span> <span class="sd"> only be called for the root object once.</span> <span class="sd"> """</span> <span class="n">debug</span><span class="p">(</span><span class="s">'build_storage_tree: SID=</span><span class="si">%d</span><span class="s"> - </span><span class="si">%s</span><span class="s"> - sid_child=</span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">sid</span><span class="p">,</span> <span class="nb">repr</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">sid_child</span><span class="p">))</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">sid_child</span> <span class="o">!=</span> <span class="n">NOSTREAM</span><span class="p">:</span> <span class="c"># if child SID is not NOSTREAM, then this entry is a storage.</span> <span class="c"># Let's walk through the tree of children to fill the kids list:</span> <span class="bp">self</span><span class="o">.</span><span class="n">append_kids</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">sid_child</span><span class="p">)</span> <span class="c"># Note from OpenOffice documentation: the safest way is to</span> <span class="c"># recreate the tree because some implementations may store broken</span> <span class="c"># red-black trees...</span> <span class="c"># in the OLE file, entries are sorted on (length, name).</span> <span class="c"># for convenience, we sort them on name instead:</span> <span class="c"># (see rich comparison methods in this class)</span> <span class="bp">self</span><span class="o">.</span><span class="n">kids</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span> <span class="k">def</span> <span class="nf">append_kids</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">child_sid</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Walk through red-black tree of children of this directory entry to add</span> <span class="sd"> all of them to the kids list. (recursive method)</span> <span class="sd"> child_sid : index of child directory entry to use, or None when called</span> <span class="sd"> first time for the root. (only used during recursion)</span> <span class="sd"> """</span> <span class="c">#[PL] this method was added to use simple recursion instead of a complex</span> <span class="c"># algorithm.</span> <span class="c"># if this is not a storage or a leaf of the tree, nothing to do:</span> <span class="k">if</span> <span class="n">child_sid</span> <span class="o">==</span> <span class="n">NOSTREAM</span><span class="p">:</span> <span class="k">return</span> <span class="c"># check if child SID is in the proper range:</span> <span class="k">if</span> <span class="n">child_sid</span><span class="o"><</span><span class="mi">0</span> <span class="ow">or</span> <span class="n">child_sid</span><span class="o">>=</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">olefile</span><span class="o">.</span><span class="n">direntries</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">olefile</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_FATAL</span><span class="p">,</span> <span class="s">'OLE DirEntry index out of range'</span><span class="p">)</span> <span class="c"># get child direntry:</span> <span class="n">child</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">olefile</span><span class="o">.</span><span class="n">_load_direntry</span><span class="p">(</span><span class="n">child_sid</span><span class="p">)</span> <span class="c">#direntries[child_sid]</span> <span class="n">debug</span><span class="p">(</span><span class="s">'append_kids: child_sid=</span><span class="si">%d</span><span class="s"> - </span><span class="si">%s</span><span class="s"> - sid_left=</span><span class="si">%d</span><span class="s">, sid_right=</span><span class="si">%d</span><span class="s">, sid_child=</span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="n">child</span><span class="o">.</span><span class="n">sid</span><span class="p">,</span> <span class="nb">repr</span><span class="p">(</span><span class="n">child</span><span class="o">.</span><span class="n">name</span><span class="p">),</span> <span class="n">child</span><span class="o">.</span><span class="n">sid_left</span><span class="p">,</span> <span class="n">child</span><span class="o">.</span><span class="n">sid_right</span><span class="p">,</span> <span class="n">child</span><span class="o">.</span><span class="n">sid_child</span><span class="p">))</span> <span class="c"># the directory entries are organized as a red-black tree.</span> <span class="c"># (cf. Wikipedia for details)</span> <span class="c"># First walk through left side of the tree:</span> <span class="bp">self</span><span class="o">.</span><span class="n">append_kids</span><span class="p">(</span><span class="n">child</span><span class="o">.</span><span class="n">sid_left</span><span class="p">)</span> <span class="c"># Check if its name is not already used (case-insensitive):</span> <span class="n">name_lower</span> <span class="o">=</span> <span class="n">child</span><span class="o">.</span><span class="n">name</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="k">if</span> <span class="n">name_lower</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">kids_dict</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">olefile</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_INCORRECT</span><span class="p">,</span> <span class="s">"Duplicate filename in OLE storage"</span><span class="p">)</span> <span class="c"># Then the child_sid _OleDirectoryEntry object is appended to the</span> <span class="c"># kids list and dictionary:</span> <span class="bp">self</span><span class="o">.</span><span class="n">kids</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">child</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">kids_dict</span><span class="p">[</span><span class="n">name_lower</span><span class="p">]</span> <span class="o">=</span> <span class="n">child</span> <span class="c"># Check if kid was not already referenced in a storage:</span> <span class="k">if</span> <span class="n">child</span><span class="o">.</span><span class="n">used</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">olefile</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_INCORRECT</span><span class="p">,</span> <span class="s">'OLE Entry referenced more than once'</span><span class="p">)</span> <span class="n">child</span><span class="o">.</span><span class="n">used</span> <span class="o">=</span> <span class="bp">True</span> <span class="c"># Finally walk through right side of the tree:</span> <span class="bp">self</span><span class="o">.</span><span class="n">append_kids</span><span class="p">(</span><span class="n">child</span><span class="o">.</span><span class="n">sid_right</span><span class="p">)</span> <span class="c"># Afterwards build kid's own tree if it's also a storage:</span> <span class="n">child</span><span class="o">.</span><span class="n">build_storage_tree</span><span class="p">()</span> <span class="k">def</span> <span class="nf">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span> <span class="s">"Compare entries by name"</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">==</span> <span class="n">other</span><span class="o">.</span><span class="n">name</span> <span class="k">def</span> <span class="nf">__lt__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span> <span class="s">"Compare entries by name"</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o"><</span> <span class="n">other</span><span class="o">.</span><span class="n">name</span> <span class="k">def</span> <span class="nf">__ne__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span> <span class="k">return</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">__eq__</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="k">def</span> <span class="nf">__le__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">__eq__</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">__lt__</span><span class="p">(</span><span class="n">other</span><span class="p">)</span> <span class="c"># Reflected __lt__() and __le__() will be used for __gt__() and __ge__()</span> <span class="c">#TODO: replace by the same function as MS implementation ?</span> <span class="c"># (order by name length first, then case-insensitive order)</span> <span class="k">def</span> <span class="nf">dump</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">tab</span> <span class="o">=</span> <span class="mi">0</span><span class="p">):</span> <span class="s">"Dump this entry, and all its subentries (for debug purposes only)"</span> <span class="n">TYPES</span> <span class="o">=</span> <span class="p">[</span><span class="s">"(invalid)"</span><span class="p">,</span> <span class="s">"(storage)"</span><span class="p">,</span> <span class="s">"(stream)"</span><span class="p">,</span> <span class="s">"(lockbytes)"</span><span class="p">,</span> <span class="s">"(property)"</span><span class="p">,</span> <span class="s">"(root)"</span><span class="p">]</span> <span class="k">print</span><span class="p">(</span><span class="s">" "</span><span class="o">*</span><span class="n">tab</span> <span class="o">+</span> <span class="nb">repr</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">),</span> <span class="n">TYPES</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">entry_type</span><span class="p">],</span> <span class="n">end</span><span class="o">=</span><span class="s">' '</span><span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">entry_type</span> <span class="ow">in</span> <span class="p">(</span><span class="n">STGTY_STREAM</span><span class="p">,</span> <span class="n">STGTY_ROOT</span><span class="p">):</span> <span class="k">print</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">size</span><span class="p">,</span> <span class="s">"bytes"</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s">' '</span><span class="p">)</span> <span class="k">print</span><span class="p">()</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">entry_type</span> <span class="ow">in</span> <span class="p">(</span><span class="n">STGTY_STORAGE</span><span class="p">,</span> <span class="n">STGTY_ROOT</span><span class="p">)</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">clsid</span><span class="p">:</span> <span class="k">print</span><span class="p">(</span><span class="s">" "</span><span class="o">*</span><span class="n">tab</span> <span class="o">+</span> <span class="s">"{</span><span class="si">%s</span><span class="s">}"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">clsid</span><span class="p">)</span> <span class="k">for</span> <span class="n">kid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">kids</span><span class="p">:</span> <span class="n">kid</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">tab</span> <span class="o">+</span> <span class="mi">2</span><span class="p">)</span> <span class="k">def</span> <span class="nf">getmtime</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Return modification time of a directory entry.</span> <span class="sd"> :returns: None if modification time is null, a python datetime object</span> <span class="sd"> otherwise (UTC timezone)</span> <span class="sd"> new in version 0.26</span> <span class="sd"> """</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">modifyTime</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span> <span class="k">return</span> <span class="bp">None</span> <span class="k">return</span> <span class="n">filetime2datetime</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">modifyTime</span><span class="p">)</span> <span class="k">def</span> <span class="nf">getctime</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Return creation time of a directory entry.</span> <span class="sd"> :returns: None if modification time is null, a python datetime object</span> <span class="sd"> otherwise (UTC timezone)</span> <span class="sd"> new in version 0.26</span> <span class="sd"> """</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">createTime</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span> <span class="k">return</span> <span class="bp">None</span> <span class="k">return</span> <span class="n">filetime2datetime</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">createTime</span><span class="p">)</span> <span class="c">#--- OleFileIO ----------------------------------------------------------------</span> <div class="viewcode-block" id="OleFileIO"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO">[docs]</a><span class="k">class</span> <span class="nc">OleFileIO</span><span class="p">:</span> <span class="sd">"""</span> <span class="sd"> OLE container object</span> <span class="sd"> This class encapsulates the interface to an OLE 2 structured</span> <span class="sd"> storage file. Use the :py:meth:`~PIL.OleFileIO.OleFileIO.listdir` and</span> <span class="sd"> :py:meth:`~PIL.OleFileIO.OleFileIO.openstream` methods to</span> <span class="sd"> access the contents of this file.</span> <span class="sd"> Object names are given as a list of strings, one for each subentry</span> <span class="sd"> level. The root entry should be omitted. For example, the following</span> <span class="sd"> code extracts all image streams from a Microsoft Image Composer file::</span> <span class="sd"> ole = OleFileIO("fan.mic")</span> <span class="sd"> for entry in ole.listdir():</span> <span class="sd"> if entry[1:2] == "Image":</span> <span class="sd"> fin = ole.openstream(entry)</span> <span class="sd"> fout = open(entry[0:1], "wb")</span> <span class="sd"> while True:</span> <span class="sd"> s = fin.read(8192)</span> <span class="sd"> if not s:</span> <span class="sd"> break</span> <span class="sd"> fout.write(s)</span> <span class="sd"> You can use the viewer application provided with the Python Imaging</span> <span class="sd"> Library to view the resulting files (which happens to be standard</span> <span class="sd"> TIFF files).</span> <span class="sd"> """</span> <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filename</span> <span class="o">=</span> <span class="bp">None</span><span class="p">,</span> <span class="n">raise_defects</span><span class="o">=</span><span class="n">DEFECT_FATAL</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Constructor for OleFileIO class.</span> <span class="sd"> :param filename: file to open.</span> <span class="sd"> :param raise_defects: minimal level for defects to be raised as exceptions.</span> <span class="sd"> (use DEFECT_FATAL for a typical application, DEFECT_INCORRECT for a</span> <span class="sd"> security-oriented application, see source code for details)</span> <span class="sd"> """</span> <span class="c"># minimal level for defects to be raised as exceptions:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defects_level</span> <span class="o">=</span> <span class="n">raise_defects</span> <span class="c"># list of defects/issues not raised as exceptions:</span> <span class="c"># tuples of (exception type, message)</span> <span class="bp">self</span><span class="o">.</span><span class="n">parsing_issues</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">if</span> <span class="n">filename</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="k">def</span> <span class="nf">_raise_defect</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">defect_level</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">exception_type</span><span class="o">=</span><span class="ne">IOError</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> This method should be called for any defect found during file parsing.</span> <span class="sd"> It may raise an IOError exception according to the minimal level chosen</span> <span class="sd"> for the OleFileIO object.</span> <span class="sd"> :param defect_level: defect level, possible values are:</span> <span class="sd"> DEFECT_UNSURE : a case which looks weird, but not sure it's a defect</span> <span class="sd"> DEFECT_POTENTIAL : a potential defect</span> <span class="sd"> DEFECT_INCORRECT : an error according to specifications, but parsing can go on</span> <span class="sd"> DEFECT_FATAL : an error which cannot be ignored, parsing is impossible</span> <span class="sd"> :param message: string describing the defect, used with raised exception.</span> <span class="sd"> :param exception_type: exception class to be raised, IOError by default</span> <span class="sd"> """</span> <span class="c"># added by [PL]</span> <span class="k">if</span> <span class="n">defect_level</span> <span class="o">>=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defects_level</span><span class="p">:</span> <span class="k">raise</span> <span class="n">exception_type</span><span class="p">(</span><span class="n">message</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="c"># just record the issue, no exception raised:</span> <span class="bp">self</span><span class="o">.</span><span class="n">parsing_issues</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">exception_type</span><span class="p">,</span> <span class="n">message</span><span class="p">))</span> <div class="viewcode-block" id="OleFileIO.open"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.open">[docs]</a> <span class="k">def</span> <span class="nf">open</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Open an OLE2 file.</span> <span class="sd"> Reads the header, FAT and directory.</span> <span class="sd"> :param filename: string-like or file-like object</span> <span class="sd"> """</span> <span class="c">#[PL] check if filename is a string-like or file-like object:</span> <span class="c"># (it is better to check for a read() method)</span> <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s">'read'</span><span class="p">):</span> <span class="c"># file-like object</span> <span class="bp">self</span><span class="o">.</span><span class="n">fp</span> <span class="o">=</span> <span class="n">filename</span> <span class="k">else</span><span class="p">:</span> <span class="c"># string-like object: filename of file on disk</span> <span class="c">#TODO: if larger than 1024 bytes, this could be the actual data => BytesIO</span> <span class="bp">self</span><span class="o">.</span><span class="n">fp</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s">"rb"</span><span class="p">)</span> <span class="c"># old code fails if filename is not a plain string:</span> <span class="c">#if isinstance(filename, (bytes, basestring)):</span> <span class="c"># self.fp = open(filename, "rb")</span> <span class="c">#else:</span> <span class="c"># self.fp = filename</span> <span class="c"># obtain the filesize by using seek and tell, which should work on most</span> <span class="c"># file-like objects:</span> <span class="c">#TODO: do it above, using getsize with filename when possible?</span> <span class="c">#TODO: fix code to fail with clear exception when filesize cannot be obtained</span> <span class="bp">self</span><span class="o">.</span><span class="n">fp</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">os</span><span class="o">.</span><span class="n">SEEK_END</span><span class="p">)</span> <span class="k">try</span><span class="p">:</span> <span class="n">filesize</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">fp</span><span class="o">.</span><span class="n">tell</span><span class="p">()</span> <span class="k">finally</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">fp</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">_filesize</span> <span class="o">=</span> <span class="n">filesize</span> <span class="c"># lists of streams in FAT and MiniFAT, to detect duplicate references</span> <span class="c"># (list of indexes of first sectors of each stream)</span> <span class="bp">self</span><span class="o">.</span><span class="n">_used_streams_fat</span> <span class="o">=</span> <span class="p">[]</span> <span class="bp">self</span><span class="o">.</span><span class="n">_used_streams_minifat</span> <span class="o">=</span> <span class="p">[]</span> <span class="n">header</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">512</span><span class="p">)</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">header</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">512</span> <span class="ow">or</span> <span class="n">header</span><span class="p">[:</span><span class="mi">8</span><span class="p">]</span> <span class="o">!=</span> <span class="n">MAGIC</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_FATAL</span><span class="p">,</span> <span class="s">"not an OLE2 structured storage file"</span><span class="p">)</span> <span class="c"># [PL] header structure according to AAF specifications:</span> <span class="c">##Header</span> <span class="c">##struct StructuredStorageHeader { // [offset from start (bytes), length (bytes)]</span> <span class="c">##BYTE _abSig[8]; // [00H,08] {0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1,</span> <span class="c">## // 0x1a, 0xe1} for current version</span> <span class="c">##CLSID _clsid; // [08H,16] reserved must be zero (WriteClassStg/</span> <span class="c">## // GetClassFile uses root directory class id)</span> <span class="c">##USHORT _uMinorVersion; // [18H,02] minor version of the format: 33 is</span> <span class="c">## // written by reference implementation</span> <span class="c">##USHORT _uDllVersion; // [1AH,02] major version of the dll/format: 3 for</span> <span class="c">## // 512-byte sectors, 4 for 4 KB sectors</span> <span class="c">##USHORT _uByteOrder; // [1CH,02] 0xFFFE: indicates Intel byte-ordering</span> <span class="c">##USHORT _uSectorShift; // [1EH,02] size of sectors in power-of-two;</span> <span class="c">## // typically 9 indicating 512-byte sectors</span> <span class="c">##USHORT _uMiniSectorShift; // [20H,02] size of mini-sectors in power-of-two;</span> <span class="c">## // typically 6 indicating 64-byte mini-sectors</span> <span class="c">##USHORT _usReserved; // [22H,02] reserved, must be zero</span> <span class="c">##ULONG _ulReserved1; // [24H,04] reserved, must be zero</span> <span class="c">##FSINDEX _csectDir; // [28H,04] must be zero for 512-byte sectors,</span> <span class="c">## // number of SECTs in directory chain for 4 KB</span> <span class="c">## // sectors</span> <span class="c">##FSINDEX _csectFat; // [2CH,04] number of SECTs in the FAT chain</span> <span class="c">##SECT _sectDirStart; // [30H,04] first SECT in the directory chain</span> <span class="c">##DFSIGNATURE _signature; // [34H,04] signature used for transactions; must</span> <span class="c">## // be zero. The reference implementation</span> <span class="c">## // does not support transactions</span> <span class="c">##ULONG _ulMiniSectorCutoff; // [38H,04] maximum size for a mini stream;</span> <span class="c">## // typically 4096 bytes</span> <span class="c">##SECT _sectMiniFatStart; // [3CH,04] first SECT in the MiniFAT chain</span> <span class="c">##FSINDEX _csectMiniFat; // [40H,04] number of SECTs in the MiniFAT chain</span> <span class="c">##SECT _sectDifStart; // [44H,04] first SECT in the DIFAT chain</span> <span class="c">##FSINDEX _csectDif; // [48H,04] number of SECTs in the DIFAT chain</span> <span class="c">##SECT _sectFat[109]; // [4CH,436] the SECTs of first 109 FAT sectors</span> <span class="c">##};</span> <span class="c"># [PL] header decoding:</span> <span class="c"># '<' indicates little-endian byte ordering for Intel (cf. struct module help)</span> <span class="n">fmt_header</span> <span class="o">=</span> <span class="s">'<8s16sHHHHHHLLLLLLLLLL'</span> <span class="n">header_size</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">calcsize</span><span class="p">(</span><span class="n">fmt_header</span><span class="p">)</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"fmt_header size = </span><span class="si">%d</span><span class="s">, +FAT = </span><span class="si">%d</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">header_size</span><span class="p">,</span> <span class="n">header_size</span> <span class="o">+</span> <span class="mi">109</span><span class="o">*</span><span class="mi">4</span><span class="p">)</span> <span class="p">)</span> <span class="n">header1</span> <span class="o">=</span> <span class="n">header</span><span class="p">[:</span><span class="n">header_size</span><span class="p">]</span> <span class="p">(</span> <span class="bp">self</span><span class="o">.</span><span class="n">Sig</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">clsid</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">MinorVersion</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">DllVersion</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">ByteOrder</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">SectorShift</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">MiniSectorShift</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">Reserved</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">Reserved1</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">csectDir</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">csectFat</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">sectDirStart</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">signature</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">MiniSectorCutoff</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">MiniFatStart</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">csectMiniFat</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">sectDifStart</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">csectDif</span> <span class="p">)</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">unpack</span><span class="p">(</span><span class="n">fmt_header</span><span class="p">,</span> <span class="n">header1</span><span class="p">)</span> <span class="n">debug</span><span class="p">(</span> <span class="n">struct</span><span class="o">.</span><span class="n">unpack</span><span class="p">(</span><span class="n">fmt_header</span><span class="p">,</span> <span class="n">header1</span><span class="p">))</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">Sig</span> <span class="o">!=</span> <span class="n">MAGIC</span><span class="p">:</span> <span class="c"># OLE signature should always be present</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_FATAL</span><span class="p">,</span> <span class="s">"incorrect OLE signature"</span><span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">clsid</span> <span class="o">!=</span> <span class="nb">bytearray</span><span class="p">(</span><span class="mi">16</span><span class="p">):</span> <span class="c"># according to AAF specs, CLSID should always be zero</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_INCORRECT</span><span class="p">,</span> <span class="s">"incorrect CLSID in OLE header"</span><span class="p">)</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"MinorVersion = </span><span class="si">%d</span><span class="s">"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">MinorVersion</span> <span class="p">)</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"DllVersion = </span><span class="si">%d</span><span class="s">"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">DllVersion</span> <span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">DllVersion</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">]:</span> <span class="c"># version 3: usual format, 512 bytes per sector</span> <span class="c"># version 4: large format, 4K per sector</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_INCORRECT</span><span class="p">,</span> <span class="s">"incorrect DllVersion in OLE header"</span><span class="p">)</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"ByteOrder = </span><span class="si">%X</span><span class="s">"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">ByteOrder</span> <span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">ByteOrder</span> <span class="o">!=</span> <span class="mh">0xFFFE</span><span class="p">:</span> <span class="c"># For now only common little-endian documents are handled correctly</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_FATAL</span><span class="p">,</span> <span class="s">"incorrect ByteOrder in OLE header"</span><span class="p">)</span> <span class="c"># TODO: add big-endian support for documents created on Mac ?</span> <span class="bp">self</span><span class="o">.</span><span class="n">SectorSize</span> <span class="o">=</span> <span class="mi">2</span><span class="o">**</span><span class="bp">self</span><span class="o">.</span><span class="n">SectorShift</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"SectorSize = </span><span class="si">%d</span><span class="s">"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">SectorSize</span> <span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">SectorSize</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="mi">512</span><span class="p">,</span> <span class="mi">4096</span><span class="p">]:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_INCORRECT</span><span class="p">,</span> <span class="s">"incorrect SectorSize in OLE header"</span><span class="p">)</span> <span class="k">if</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">DllVersion</span><span class="o">==</span><span class="mi">3</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">SectorSize</span><span class="o">!=</span><span class="mi">512</span><span class="p">)</span> \ <span class="ow">or</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">DllVersion</span><span class="o">==</span><span class="mi">4</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">SectorSize</span><span class="o">!=</span><span class="mi">4096</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_INCORRECT</span><span class="p">,</span> <span class="s">"SectorSize does not match DllVersion in OLE header"</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">MiniSectorSize</span> <span class="o">=</span> <span class="mi">2</span><span class="o">**</span><span class="bp">self</span><span class="o">.</span><span class="n">MiniSectorShift</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"MiniSectorSize = </span><span class="si">%d</span><span class="s">"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">MiniSectorSize</span> <span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">MiniSectorSize</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="mi">64</span><span class="p">]:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_INCORRECT</span><span class="p">,</span> <span class="s">"incorrect MiniSectorSize in OLE header"</span><span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">Reserved</span> <span class="o">!=</span> <span class="mi">0</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">Reserved1</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_INCORRECT</span><span class="p">,</span> <span class="s">"incorrect OLE header (non-null reserved bytes)"</span><span class="p">)</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"csectDir = </span><span class="si">%d</span><span class="s">"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">csectDir</span> <span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">SectorSize</span><span class="o">==</span><span class="mi">512</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">csectDir</span><span class="o">!=</span><span class="mi">0</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_INCORRECT</span><span class="p">,</span> <span class="s">"incorrect csectDir in OLE header"</span><span class="p">)</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"csectFat = </span><span class="si">%d</span><span class="s">"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">csectFat</span> <span class="p">)</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"sectDirStart = </span><span class="si">%X</span><span class="s">"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">sectDirStart</span> <span class="p">)</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"signature = </span><span class="si">%d</span><span class="s">"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">signature</span> <span class="p">)</span> <span class="c"># Signature should be zero, BUT some implementations do not follow this</span> <span class="c"># rule => only a potential defect:</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">signature</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_POTENTIAL</span><span class="p">,</span> <span class="s">"incorrect OLE header (signature>0)"</span><span class="p">)</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"MiniSectorCutoff = </span><span class="si">%d</span><span class="s">"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">MiniSectorCutoff</span> <span class="p">)</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"MiniFatStart = </span><span class="si">%X</span><span class="s">"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">MiniFatStart</span> <span class="p">)</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"csectMiniFat = </span><span class="si">%d</span><span class="s">"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">csectMiniFat</span> <span class="p">)</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"sectDifStart = </span><span class="si">%X</span><span class="s">"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">sectDifStart</span> <span class="p">)</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"csectDif = </span><span class="si">%d</span><span class="s">"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">csectDif</span> <span class="p">)</span> <span class="c"># calculate the number of sectors in the file</span> <span class="c"># (-1 because header doesn't count)</span> <span class="bp">self</span><span class="o">.</span><span class="n">nb_sect</span> <span class="o">=</span> <span class="p">(</span> <span class="p">(</span><span class="n">filesize</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">SectorSize</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="o">//</span> <span class="bp">self</span><span class="o">.</span><span class="n">SectorSize</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"Number of sectors in the file: </span><span class="si">%d</span><span class="s">"</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">nb_sect</span> <span class="p">)</span> <span class="c"># file clsid (probably never used, so we don't store it)</span> <span class="n">clsid</span> <span class="o">=</span> <span class="n">_clsid</span><span class="p">(</span><span class="n">header</span><span class="p">[</span><span class="mi">8</span><span class="p">:</span><span class="mi">24</span><span class="p">])</span> <span class="bp">self</span><span class="o">.</span><span class="n">sectorsize</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">SectorSize</span> <span class="c">#1 << i16(header, 30)</span> <span class="bp">self</span><span class="o">.</span><span class="n">minisectorsize</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">MiniSectorSize</span> <span class="c">#1 << i16(header, 32)</span> <span class="bp">self</span><span class="o">.</span><span class="n">minisectorcutoff</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">MiniSectorCutoff</span> <span class="c"># i32(header, 56)</span> <span class="c"># check known streams for duplicate references (these are always in FAT,</span> <span class="c"># never in MiniFAT):</span> <span class="bp">self</span><span class="o">.</span><span class="n">_check_duplicate_stream</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">sectDirStart</span><span class="p">)</span> <span class="c"># check MiniFAT only if it is not empty:</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">csectMiniFat</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_check_duplicate_stream</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">MiniFatStart</span><span class="p">)</span> <span class="c"># check DIFAT only if it is not empty:</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">csectDif</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_check_duplicate_stream</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">sectDifStart</span><span class="p">)</span> <span class="c"># Load file allocation tables</span> <span class="bp">self</span><span class="o">.</span><span class="n">loadfat</span><span class="p">(</span><span class="n">header</span><span class="p">)</span> <span class="c"># Load direcory. This sets both the direntries list (ordered by sid)</span> <span class="c"># and the root (ordered by hierarchy) members.</span> <span class="bp">self</span><span class="o">.</span><span class="n">loaddirectory</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">sectDirStart</span><span class="p">)</span><span class="c">#i32(header, 48))</span> <span class="bp">self</span><span class="o">.</span><span class="n">ministream</span> <span class="o">=</span> <span class="bp">None</span> <span class="bp">self</span><span class="o">.</span><span class="n">minifatsect</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">MiniFatStart</span> <span class="c">#i32(header, 60)</span> </div> <div class="viewcode-block" id="OleFileIO.close"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.close">[docs]</a> <span class="k">def</span> <span class="nf">close</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> close the OLE file, to release the file object</span> <span class="sd"> """</span> <span class="bp">self</span><span class="o">.</span><span class="n">fp</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> </div> <span class="k">def</span> <span class="nf">_check_duplicate_stream</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">first_sect</span><span class="p">,</span> <span class="n">minifat</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Checks if a stream has not been already referenced elsewhere.</span> <span class="sd"> This method should only be called once for each known stream, and only</span> <span class="sd"> if stream size is not null.</span> <span class="sd"> :param first_sect: index of first sector of the stream in FAT</span> <span class="sd"> :param minifat: if True, stream is located in the MiniFAT, else in the FAT</span> <span class="sd"> """</span> <span class="k">if</span> <span class="n">minifat</span><span class="p">:</span> <span class="n">debug</span><span class="p">(</span><span class="s">'_check_duplicate_stream: sect=</span><span class="si">%d</span><span class="s"> in MiniFAT'</span> <span class="o">%</span> <span class="n">first_sect</span><span class="p">)</span> <span class="n">used_streams</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_used_streams_minifat</span> <span class="k">else</span><span class="p">:</span> <span class="n">debug</span><span class="p">(</span><span class="s">'_check_duplicate_stream: sect=</span><span class="si">%d</span><span class="s"> in FAT'</span> <span class="o">%</span> <span class="n">first_sect</span><span class="p">)</span> <span class="c"># some values can be safely ignored (not a real stream):</span> <span class="k">if</span> <span class="n">first_sect</span> <span class="ow">in</span> <span class="p">(</span><span class="n">DIFSECT</span><span class="p">,</span><span class="n">FATSECT</span><span class="p">,</span><span class="n">ENDOFCHAIN</span><span class="p">,</span><span class="n">FREESECT</span><span class="p">):</span> <span class="k">return</span> <span class="n">used_streams</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_used_streams_fat</span> <span class="c">#TODO: would it be more efficient using a dict or hash values, instead</span> <span class="c"># of a list of long ?</span> <span class="k">if</span> <span class="n">first_sect</span> <span class="ow">in</span> <span class="n">used_streams</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_INCORRECT</span><span class="p">,</span> <span class="s">'Stream referenced twice'</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="n">used_streams</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">first_sect</span><span class="p">)</span> <div class="viewcode-block" id="OleFileIO.dumpfat"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.dumpfat">[docs]</a> <span class="k">def</span> <span class="nf">dumpfat</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fat</span><span class="p">,</span> <span class="n">firstindex</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span> <span class="s">"Displays a part of FAT in human-readable form for debugging purpose"</span> <span class="c"># [PL] added only for debug</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">DEBUG_MODE</span><span class="p">:</span> <span class="k">return</span> <span class="c"># dictionary to convert special FAT values in human-readable strings</span> <span class="n">VPL</span><span class="o">=</span><span class="mi">8</span> <span class="c"># valeurs par ligne (8+1 * 8+1 = 81)</span> <span class="n">fatnames</span> <span class="o">=</span> <span class="p">{</span> <span class="n">FREESECT</span><span class="p">:</span> <span class="s">"..free.."</span><span class="p">,</span> <span class="n">ENDOFCHAIN</span><span class="p">:</span> <span class="s">"[ END. ]"</span><span class="p">,</span> <span class="n">FATSECT</span><span class="p">:</span> <span class="s">"FATSECT "</span><span class="p">,</span> <span class="n">DIFSECT</span><span class="p">:</span> <span class="s">"DIFSECT "</span> <span class="p">}</span> <span class="n">nbsect</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">fat</span><span class="p">)</span> <span class="n">nlines</span> <span class="o">=</span> <span class="p">(</span><span class="n">nbsect</span><span class="o">+</span><span class="n">VPL</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">//</span><span class="n">VPL</span> <span class="k">print</span><span class="p">(</span><span class="s">"index"</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s">" "</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">VPL</span><span class="p">):</span> <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="si">%8X</span><span class="s">"</span> <span class="o">%</span> <span class="n">i</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s">" "</span><span class="p">)</span> <span class="k">print</span><span class="p">()</span> <span class="k">for</span> <span class="n">l</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">nlines</span><span class="p">):</span> <span class="n">index</span> <span class="o">=</span> <span class="n">l</span><span class="o">*</span><span class="n">VPL</span> <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="si">%8X</span><span class="s">:"</span> <span class="o">%</span> <span class="p">(</span><span class="n">firstindex</span><span class="o">+</span><span class="n">index</span><span class="p">),</span> <span class="n">end</span><span class="o">=</span><span class="s">" "</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">index</span><span class="p">,</span> <span class="n">index</span><span class="o">+</span><span class="n">VPL</span><span class="p">):</span> <span class="k">if</span> <span class="n">i</span><span class="o">>=</span><span class="n">nbsect</span><span class="p">:</span> <span class="k">break</span> <span class="n">sect</span> <span class="o">=</span> <span class="n">fat</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">if</span> <span class="n">sect</span> <span class="ow">in</span> <span class="n">fatnames</span><span class="p">:</span> <span class="n">nom</span> <span class="o">=</span> <span class="n">fatnames</span><span class="p">[</span><span class="n">sect</span><span class="p">]</span> <span class="k">else</span><span class="p">:</span> <span class="k">if</span> <span class="n">sect</span> <span class="o">==</span> <span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">:</span> <span class="n">nom</span> <span class="o">=</span> <span class="s">" --->"</span> <span class="k">else</span><span class="p">:</span> <span class="n">nom</span> <span class="o">=</span> <span class="s">"</span><span class="si">%8X</span><span class="s">"</span> <span class="o">%</span> <span class="n">sect</span> <span class="k">print</span><span class="p">(</span><span class="n">nom</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s">" "</span><span class="p">)</span> <span class="k">print</span><span class="p">()</span> </div> <div class="viewcode-block" id="OleFileIO.dumpsect"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.dumpsect">[docs]</a> <span class="k">def</span> <span class="nf">dumpsect</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sector</span><span class="p">,</span> <span class="n">firstindex</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span> <span class="s">"Displays a sector in a human-readable form, for debugging purpose."</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">DEBUG_MODE</span><span class="p">:</span> <span class="k">return</span> <span class="n">VPL</span><span class="o">=</span><span class="mi">8</span> <span class="c"># number of values per line (8+1 * 8+1 = 81)</span> <span class="n">tab</span> <span class="o">=</span> <span class="n">array</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">UINT32</span><span class="p">,</span> <span class="n">sector</span><span class="p">)</span> <span class="n">nbsect</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">tab</span><span class="p">)</span> <span class="n">nlines</span> <span class="o">=</span> <span class="p">(</span><span class="n">nbsect</span><span class="o">+</span><span class="n">VPL</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">//</span><span class="n">VPL</span> <span class="k">print</span><span class="p">(</span><span class="s">"index"</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s">" "</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">VPL</span><span class="p">):</span> <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="si">%8X</span><span class="s">"</span> <span class="o">%</span> <span class="n">i</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s">" "</span><span class="p">)</span> <span class="k">print</span><span class="p">()</span> <span class="k">for</span> <span class="n">l</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">nlines</span><span class="p">):</span> <span class="n">index</span> <span class="o">=</span> <span class="n">l</span><span class="o">*</span><span class="n">VPL</span> <span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="si">%8X</span><span class="s">:"</span> <span class="o">%</span> <span class="p">(</span><span class="n">firstindex</span><span class="o">+</span><span class="n">index</span><span class="p">),</span> <span class="n">end</span><span class="o">=</span><span class="s">" "</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">index</span><span class="p">,</span> <span class="n">index</span><span class="o">+</span><span class="n">VPL</span><span class="p">):</span> <span class="k">if</span> <span class="n">i</span><span class="o">>=</span><span class="n">nbsect</span><span class="p">:</span> <span class="k">break</span> <span class="n">sect</span> <span class="o">=</span> <span class="n">tab</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="n">nom</span> <span class="o">=</span> <span class="s">"</span><span class="si">%8X</span><span class="s">"</span> <span class="o">%</span> <span class="n">sect</span> <span class="k">print</span><span class="p">(</span><span class="n">nom</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s">" "</span><span class="p">)</span> <span class="k">print</span><span class="p">()</span> </div> <div class="viewcode-block" id="OleFileIO.sect2array"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.sect2array">[docs]</a> <span class="k">def</span> <span class="nf">sect2array</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sect</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> convert a sector to an array of 32 bits unsigned integers,</span> <span class="sd"> swapping bytes on big endian CPUs such as PowerPC (old Macs)</span> <span class="sd"> """</span> <span class="n">a</span> <span class="o">=</span> <span class="n">array</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">UINT32</span><span class="p">,</span> <span class="n">sect</span><span class="p">)</span> <span class="c"># if CPU is big endian, swap bytes:</span> <span class="k">if</span> <span class="n">sys</span><span class="o">.</span><span class="n">byteorder</span> <span class="o">==</span> <span class="s">'big'</span><span class="p">:</span> <span class="n">a</span><span class="o">.</span><span class="n">byteswap</span><span class="p">()</span> <span class="k">return</span> <span class="n">a</span> </div> <div class="viewcode-block" id="OleFileIO.loadfat_sect"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.loadfat_sect">[docs]</a> <span class="k">def</span> <span class="nf">loadfat_sect</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sect</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Adds the indexes of the given sector to the FAT</span> <span class="sd"> </span> <span class="sd"> :param sect: string containing the first FAT sector, or array of long integers</span> <span class="sd"> :returns: index of last FAT sector.</span> <span class="sd"> """</span> <span class="c"># a FAT sector is an array of ulong integers.</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">sect</span><span class="p">,</span> <span class="n">array</span><span class="o">.</span><span class="n">array</span><span class="p">):</span> <span class="c"># if sect is already an array it is directly used</span> <span class="n">fat1</span> <span class="o">=</span> <span class="n">sect</span> <span class="k">else</span><span class="p">:</span> <span class="c"># if it's a raw sector, it is parsed in an array</span> <span class="n">fat1</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sect2array</span><span class="p">(</span><span class="n">sect</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">dumpsect</span><span class="p">(</span><span class="n">sect</span><span class="p">)</span> <span class="c"># The FAT is a sector chain starting at the first index of itself.</span> <span class="k">for</span> <span class="n">isect</span> <span class="ow">in</span> <span class="n">fat1</span><span class="p">:</span> <span class="c">#print("isect = %X" % isect)</span> <span class="k">if</span> <span class="n">isect</span> <span class="o">==</span> <span class="n">ENDOFCHAIN</span> <span class="ow">or</span> <span class="n">isect</span> <span class="o">==</span> <span class="n">FREESECT</span><span class="p">:</span> <span class="c"># the end of the sector chain has been reached</span> <span class="k">break</span> <span class="c"># read the FAT sector</span> <span class="n">s</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">getsect</span><span class="p">(</span><span class="n">isect</span><span class="p">)</span> <span class="c"># parse it as an array of 32 bits integers, and add it to the</span> <span class="c"># global FAT array</span> <span class="n">nextfat</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sect2array</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">fat</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">fat</span> <span class="o">+</span> <span class="n">nextfat</span> <span class="k">return</span> <span class="n">isect</span> </div> <div class="viewcode-block" id="OleFileIO.loadfat"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.loadfat">[docs]</a> <span class="k">def</span> <span class="nf">loadfat</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">header</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Load the FAT table.</span> <span class="sd"> """</span> <span class="c"># The header contains a sector numbers</span> <span class="c"># for the first 109 FAT sectors. Additional sectors are</span> <span class="c"># described by DIF blocks</span> <span class="n">sect</span> <span class="o">=</span> <span class="n">header</span><span class="p">[</span><span class="mi">76</span><span class="p">:</span><span class="mi">512</span><span class="p">]</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"len(sect)=</span><span class="si">%d</span><span class="s">, so </span><span class="si">%d</span><span class="s"> integers"</span> <span class="o">%</span> <span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">sect</span><span class="p">),</span> <span class="nb">len</span><span class="p">(</span><span class="n">sect</span><span class="p">)</span><span class="o">//</span><span class="mi">4</span><span class="p">)</span> <span class="p">)</span> <span class="c">#fat = []</span> <span class="c"># [PL] FAT is an array of 32 bits unsigned ints, it's more effective</span> <span class="c"># to use an array than a list in Python.</span> <span class="c"># It's initialized as empty first:</span> <span class="bp">self</span><span class="o">.</span><span class="n">fat</span> <span class="o">=</span> <span class="n">array</span><span class="o">.</span><span class="n">array</span><span class="p">(</span><span class="n">UINT32</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">loadfat_sect</span><span class="p">(</span><span class="n">sect</span><span class="p">)</span> <span class="c">#self.dumpfat(self.fat)</span> <span class="c">## for i in range(0, len(sect), 4):</span> <span class="c">## ix = i32(sect, i)</span> <span class="c">## #[PL] if ix == -2 or ix == -1: # ix == 0xFFFFFFFE or ix == 0xFFFFFFFF:</span> <span class="c">## if ix == 0xFFFFFFFE or ix == 0xFFFFFFFF:</span> <span class="c">## break</span> <span class="c">## s = self.getsect(ix)</span> <span class="c">## #fat = fat + [i32(s, i) for i in range(0, len(s), 4)]</span> <span class="c">## fat = fat + array.array(UINT32, s)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">csectDif</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">:</span> <span class="c"># [PL] There's a DIFAT because file is larger than 6.8MB</span> <span class="c"># some checks just in case:</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">csectFat</span> <span class="o"><=</span> <span class="mi">109</span><span class="p">:</span> <span class="c"># there must be at least 109 blocks in header and the rest in</span> <span class="c"># DIFAT, so number of sectors must be >109.</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_INCORRECT</span><span class="p">,</span> <span class="s">'incorrect DIFAT, not enough sectors'</span><span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">sectDifStart</span> <span class="o">>=</span> <span class="bp">self</span><span class="o">.</span><span class="n">nb_sect</span><span class="p">:</span> <span class="c"># initial DIFAT block index must be valid</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_FATAL</span><span class="p">,</span> <span class="s">'incorrect DIFAT, first index out of range'</span><span class="p">)</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"DIFAT analysis..."</span> <span class="p">)</span> <span class="c"># We compute the necessary number of DIFAT sectors :</span> <span class="c"># (each DIFAT sector = 127 pointers + 1 towards next DIFAT sector)</span> <span class="n">nb_difat</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">csectFat</span><span class="o">-</span><span class="mi">109</span> <span class="o">+</span> <span class="mi">126</span><span class="p">)</span><span class="o">//</span><span class="mi">127</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"nb_difat = </span><span class="si">%d</span><span class="s">"</span> <span class="o">%</span> <span class="n">nb_difat</span> <span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">csectDif</span> <span class="o">!=</span> <span class="n">nb_difat</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">IOError</span><span class="p">(</span><span class="s">'incorrect DIFAT'</span><span class="p">)</span> <span class="n">isect_difat</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sectDifStart</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">iterrange</span><span class="p">(</span><span class="n">nb_difat</span><span class="p">):</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"DIFAT block </span><span class="si">%d</span><span class="s">, sector </span><span class="si">%X</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">isect_difat</span><span class="p">)</span> <span class="p">)</span> <span class="c">#TODO: check if corresponding FAT SID = DIFSECT</span> <span class="n">sector_difat</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">getsect</span><span class="p">(</span><span class="n">isect_difat</span><span class="p">)</span> <span class="n">difat</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sect2array</span><span class="p">(</span><span class="n">sector_difat</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">dumpsect</span><span class="p">(</span><span class="n">sector_difat</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">loadfat_sect</span><span class="p">(</span><span class="n">difat</span><span class="p">[:</span><span class="mi">127</span><span class="p">])</span> <span class="c"># last DIFAT pointer is next DIFAT sector:</span> <span class="n">isect_difat</span> <span class="o">=</span> <span class="n">difat</span><span class="p">[</span><span class="mi">127</span><span class="p">]</span> <span class="n">debug</span><span class="p">(</span> <span class="s">"next DIFAT sector: </span><span class="si">%X</span><span class="s">"</span> <span class="o">%</span> <span class="n">isect_difat</span> <span class="p">)</span> <span class="c"># checks:</span> <span class="k">if</span> <span class="n">isect_difat</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="n">ENDOFCHAIN</span><span class="p">,</span> <span class="n">FREESECT</span><span class="p">]:</span> <span class="c"># last DIFAT pointer value must be ENDOFCHAIN or FREESECT</span> <span class="k">raise</span> <span class="ne">IOError</span><span class="p">(</span><span class="s">'incorrect end of DIFAT'</span><span class="p">)</span> <span class="c">## if len(self.fat) != self.csectFat:</span> <span class="c">## # FAT should contain csectFat blocks</span> <span class="c">## print("FAT length: %d instead of %d" % (len(self.fat), self.csectFat))</span> <span class="c">## raise IOError('incorrect DIFAT')</span> <span class="c"># since FAT is read from fixed-size sectors, it may contain more values</span> <span class="c"># than the actual number of sectors in the file.</span> <span class="c"># Keep only the relevant sector indexes:</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">fat</span><span class="p">)</span> <span class="o">></span> <span class="bp">self</span><span class="o">.</span><span class="n">nb_sect</span><span class="p">:</span> <span class="n">debug</span><span class="p">(</span><span class="s">'len(fat)=</span><span class="si">%d</span><span class="s">, shrunk to nb_sect=</span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">fat</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">nb_sect</span><span class="p">))</span> <span class="bp">self</span><span class="o">.</span><span class="n">fat</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">fat</span><span class="p">[:</span><span class="bp">self</span><span class="o">.</span><span class="n">nb_sect</span><span class="p">]</span> <span class="n">debug</span><span class="p">(</span><span class="s">'</span><span class="se">\n</span><span class="s">FAT:'</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">dumpfat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">fat</span><span class="p">)</span> </div> <div class="viewcode-block" id="OleFileIO.loadminifat"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.loadminifat">[docs]</a> <span class="k">def</span> <span class="nf">loadminifat</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Load the MiniFAT table.</span> <span class="sd"> """</span> <span class="c"># MiniFAT is stored in a standard sub-stream, pointed to by a header</span> <span class="c"># field.</span> <span class="c"># NOTE: there are two sizes to take into account for this stream:</span> <span class="c"># 1) Stream size is calculated according to the number of sectors</span> <span class="c"># declared in the OLE header. This allocated stream may be more than</span> <span class="c"># needed to store the actual sector indexes.</span> <span class="c"># (self.csectMiniFat is the number of sectors of size self.SectorSize)</span> <span class="n">stream_size</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">csectMiniFat</span> <span class="o">*</span> <span class="bp">self</span><span class="o">.</span><span class="n">SectorSize</span> <span class="c"># 2) Actually used size is calculated by dividing the MiniStream size</span> <span class="c"># (given by root entry size) by the size of mini sectors, *4 for</span> <span class="c"># 32 bits indexes:</span> <span class="n">nb_minisectors</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">root</span><span class="o">.</span><span class="n">size</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">MiniSectorSize</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="o">//</span> <span class="bp">self</span><span class="o">.</span><span class="n">MiniSectorSize</span> <span class="n">used_size</span> <span class="o">=</span> <span class="n">nb_minisectors</span> <span class="o">*</span> <span class="mi">4</span> <span class="n">debug</span><span class="p">(</span><span class="s">'loadminifat(): minifatsect=</span><span class="si">%d</span><span class="s">, nb FAT sectors=</span><span class="si">%d</span><span class="s">, used_size=</span><span class="si">%d</span><span class="s">, stream_size=</span><span class="si">%d</span><span class="s">, nb MiniSectors=</span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">minifatsect</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">csectMiniFat</span><span class="p">,</span> <span class="n">used_size</span><span class="p">,</span> <span class="n">stream_size</span><span class="p">,</span> <span class="n">nb_minisectors</span><span class="p">))</span> <span class="k">if</span> <span class="n">used_size</span> <span class="o">></span> <span class="n">stream_size</span><span class="p">:</span> <span class="c"># This is not really a problem, but may indicate a wrong implementation:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_INCORRECT</span><span class="p">,</span> <span class="s">'OLE MiniStream is larger than MiniFAT'</span><span class="p">)</span> <span class="c"># In any case, first read stream_size:</span> <span class="n">s</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">minifatsect</span><span class="p">,</span> <span class="n">stream_size</span><span class="p">,</span> <span class="n">force_FAT</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">()</span> <span class="c">#[PL] Old code replaced by an array:</span> <span class="c">#self.minifat = [i32(s, i) for i in range(0, len(s), 4)]</span> <span class="bp">self</span><span class="o">.</span><span class="n">minifat</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sect2array</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="c"># Then shrink the array to used size, to avoid indexes out of MiniStream:</span> <span class="n">debug</span><span class="p">(</span><span class="s">'MiniFAT shrunk from </span><span class="si">%d</span><span class="s"> to </span><span class="si">%d</span><span class="s"> sectors'</span> <span class="o">%</span> <span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">minifat</span><span class="p">),</span> <span class="n">nb_minisectors</span><span class="p">))</span> <span class="bp">self</span><span class="o">.</span><span class="n">minifat</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">minifat</span><span class="p">[:</span><span class="n">nb_minisectors</span><span class="p">]</span> <span class="n">debug</span><span class="p">(</span><span class="s">'loadminifat(): len=</span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">minifat</span><span class="p">))</span> <span class="n">debug</span><span class="p">(</span><span class="s">'</span><span class="se">\n</span><span class="s">MiniFAT:'</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">dumpfat</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">minifat</span><span class="p">)</span> </div> <div class="viewcode-block" id="OleFileIO.getsect"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.getsect">[docs]</a> <span class="k">def</span> <span class="nf">getsect</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sect</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Read given sector from file on disk.</span> <span class="sd"> </span> <span class="sd"> :param sect: sector index</span> <span class="sd"> :returns: a string containing the sector data.</span> <span class="sd"> """</span> <span class="c"># [PL] this original code was wrong when sectors are 4KB instead of</span> <span class="c"># 512 bytes:</span> <span class="c">#self.fp.seek(512 + self.sectorsize * sect)</span> <span class="c">#[PL]: added safety checks:</span> <span class="c">#print("getsect(%X)" % sect)</span> <span class="k">try</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">fp</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">sectorsize</span> <span class="o">*</span> <span class="p">(</span><span class="n">sect</span><span class="o">+</span><span class="mi">1</span><span class="p">))</span> <span class="k">except</span><span class="p">:</span> <span class="n">debug</span><span class="p">(</span><span class="s">'getsect(): sect=</span><span class="si">%X</span><span class="s">, seek=</span><span class="si">%d</span><span class="s">, filesize=</span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="n">sect</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">sectorsize</span><span class="o">*</span><span class="p">(</span><span class="n">sect</span><span class="o">+</span><span class="mi">1</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">_filesize</span><span class="p">))</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_FATAL</span><span class="p">,</span> <span class="s">'OLE sector index out of range'</span><span class="p">)</span> <span class="n">sector</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">sectorsize</span><span class="p">)</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sector</span><span class="p">)</span> <span class="o">!=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sectorsize</span><span class="p">:</span> <span class="n">debug</span><span class="p">(</span><span class="s">'getsect(): sect=</span><span class="si">%X</span><span class="s">, read=</span><span class="si">%d</span><span class="s">, sectorsize=</span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="n">sect</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">sector</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">sectorsize</span><span class="p">))</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_FATAL</span><span class="p">,</span> <span class="s">'incomplete OLE sector'</span><span class="p">)</span> <span class="k">return</span> <span class="n">sector</span> </div> <div class="viewcode-block" id="OleFileIO.loaddirectory"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.loaddirectory">[docs]</a> <span class="k">def</span> <span class="nf">loaddirectory</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sect</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Load the directory.</span> <span class="sd"> </span> <span class="sd"> :param sect: sector index of directory stream.</span> <span class="sd"> """</span> <span class="c"># The directory is stored in a standard</span> <span class="c"># substream, independent of its size.</span> <span class="c"># open directory stream as a read-only file:</span> <span class="c"># (stream size is not known in advance)</span> <span class="bp">self</span><span class="o">.</span><span class="n">directory_fp</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_open</span><span class="p">(</span><span class="n">sect</span><span class="p">)</span> <span class="c">#[PL] to detect malformed documents and avoid DoS attacks, the maximum</span> <span class="c"># number of directory entries can be calculated:</span> <span class="n">max_entries</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">directory_fp</span><span class="o">.</span><span class="n">size</span> <span class="o">//</span> <span class="mi">128</span> <span class="n">debug</span><span class="p">(</span><span class="s">'loaddirectory: size=</span><span class="si">%d</span><span class="s">, max_entries=</span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">directory_fp</span><span class="o">.</span><span class="n">size</span><span class="p">,</span> <span class="n">max_entries</span><span class="p">))</span> <span class="c"># Create list of directory entries</span> <span class="c">#self.direntries = []</span> <span class="c"># We start with a list of "None" object</span> <span class="bp">self</span><span class="o">.</span><span class="n">direntries</span> <span class="o">=</span> <span class="p">[</span><span class="bp">None</span><span class="p">]</span> <span class="o">*</span> <span class="n">max_entries</span> <span class="c">## for sid in iterrange(max_entries):</span> <span class="c">## entry = fp.read(128)</span> <span class="c">## if not entry:</span> <span class="c">## break</span> <span class="c">## self.direntries.append(_OleDirectoryEntry(entry, sid, self))</span> <span class="c"># load root entry:</span> <span class="n">root_entry</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_load_direntry</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="c"># Root entry is the first entry:</span> <span class="bp">self</span><span class="o">.</span><span class="n">root</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">direntries</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="c"># read and build all storage trees, starting from the root:</span> <span class="bp">self</span><span class="o">.</span><span class="n">root</span><span class="o">.</span><span class="n">build_storage_tree</span><span class="p">()</span> </div> <span class="k">def</span> <span class="nf">_load_direntry</span> <span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sid</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Load a directory entry from the directory.</span> <span class="sd"> This method should only be called once for each storage/stream when</span> <span class="sd"> loading the directory.</span> <span class="sd"> :param sid: index of storage/stream in the directory.</span> <span class="sd"> :returns: a _OleDirectoryEntry object</span> <span class="sd"> :exception IOError: if the entry has always been referenced.</span> <span class="sd"> """</span> <span class="c"># check if SID is OK:</span> <span class="k">if</span> <span class="n">sid</span><span class="o"><</span><span class="mi">0</span> <span class="ow">or</span> <span class="n">sid</span><span class="o">>=</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">direntries</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_FATAL</span><span class="p">,</span> <span class="s">"OLE directory index out of range"</span><span class="p">)</span> <span class="c"># check if entry was already referenced:</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">direntries</span><span class="p">[</span><span class="n">sid</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_INCORRECT</span><span class="p">,</span> <span class="s">"double reference for OLE stream/storage"</span><span class="p">)</span> <span class="c"># if exception not raised, return the object</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">direntries</span><span class="p">[</span><span class="n">sid</span><span class="p">]</span> <span class="bp">self</span><span class="o">.</span><span class="n">directory_fp</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="n">sid</span> <span class="o">*</span> <span class="mi">128</span><span class="p">)</span> <span class="n">entry</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">directory_fp</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">128</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">direntries</span><span class="p">[</span><span class="n">sid</span><span class="p">]</span> <span class="o">=</span> <span class="n">_OleDirectoryEntry</span><span class="p">(</span><span class="n">entry</span><span class="p">,</span> <span class="n">sid</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">direntries</span><span class="p">[</span><span class="n">sid</span><span class="p">]</span> <div class="viewcode-block" id="OleFileIO.dumpdirectory"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.dumpdirectory">[docs]</a> <span class="k">def</span> <span class="nf">dumpdirectory</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Dump directory (for debugging only)</span> <span class="sd"> """</span> <span class="bp">self</span><span class="o">.</span><span class="n">root</span><span class="o">.</span><span class="n">dump</span><span class="p">()</span> </div> <span class="k">def</span> <span class="nf">_open</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">start</span><span class="p">,</span> <span class="n">size</span> <span class="o">=</span> <span class="mh">0x7FFFFFFF</span><span class="p">,</span> <span class="n">force_FAT</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Open a stream, either in FAT or MiniFAT according to its size.</span> <span class="sd"> (openstream helper)</span> <span class="sd"> :param start: index of first sector</span> <span class="sd"> :param size: size of stream (or nothing if size is unknown)</span> <span class="sd"> :param force_FAT: if False (default), stream will be opened in FAT or MiniFAT</span> <span class="sd"> according to size. If True, it will always be opened in FAT.</span> <span class="sd"> """</span> <span class="n">debug</span><span class="p">(</span><span class="s">'OleFileIO.open(): sect=</span><span class="si">%d</span><span class="s">, size=</span><span class="si">%d</span><span class="s">, force_FAT=</span><span class="si">%s</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="n">start</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">force_FAT</span><span class="p">)))</span> <span class="c"># stream size is compared to the MiniSectorCutoff threshold:</span> <span class="k">if</span> <span class="n">size</span> <span class="o"><</span> <span class="bp">self</span><span class="o">.</span><span class="n">minisectorcutoff</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">force_FAT</span><span class="p">:</span> <span class="c"># ministream object</span> <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">ministream</span><span class="p">:</span> <span class="c"># load MiniFAT if it wasn't already done:</span> <span class="bp">self</span><span class="o">.</span><span class="n">loadminifat</span><span class="p">()</span> <span class="c"># The first sector index of the miniFAT stream is stored in the</span> <span class="c"># root directory entry:</span> <span class="n">size_ministream</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">root</span><span class="o">.</span><span class="n">size</span> <span class="n">debug</span><span class="p">(</span><span class="s">'Opening MiniStream: sect=</span><span class="si">%d</span><span class="s">, size=</span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">root</span><span class="o">.</span><span class="n">isectStart</span><span class="p">,</span> <span class="n">size_ministream</span><span class="p">))</span> <span class="bp">self</span><span class="o">.</span><span class="n">ministream</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">root</span><span class="o">.</span><span class="n">isectStart</span><span class="p">,</span> <span class="n">size_ministream</span><span class="p">,</span> <span class="n">force_FAT</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> <span class="k">return</span> <span class="n">_OleStream</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">ministream</span><span class="p">,</span> <span class="n">start</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">minisectorsize</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">minifat</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">ministream</span><span class="o">.</span><span class="n">size</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="c"># standard stream</span> <span class="k">return</span> <span class="n">_OleStream</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">fp</span><span class="p">,</span> <span class="n">start</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="mi">512</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">sectorsize</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">fat</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_filesize</span><span class="p">)</span> <span class="k">def</span> <span class="nf">_list</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">files</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">node</span><span class="p">,</span> <span class="n">streams</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">storages</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> (listdir helper)</span> <span class="sd"> :param files: list of files to fill in</span> <span class="sd"> :param prefix: current location in storage tree (list of names)</span> <span class="sd"> :param node: current node (_OleDirectoryEntry object)</span> <span class="sd"> :param streams: bool, include streams if True (True by default) - new in v0.26</span> <span class="sd"> :param storages: bool, include storages if True (False by default) - new in v0.26</span> <span class="sd"> (note: the root storage is never included)</span> <span class="sd"> """</span> <span class="n">prefix</span> <span class="o">=</span> <span class="n">prefix</span> <span class="o">+</span> <span class="p">[</span><span class="n">node</span><span class="o">.</span><span class="n">name</span><span class="p">]</span> <span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">kids</span><span class="p">:</span> <span class="k">if</span> <span class="n">entry</span><span class="o">.</span><span class="n">kids</span><span class="p">:</span> <span class="c"># this is a storage</span> <span class="k">if</span> <span class="n">storages</span><span class="p">:</span> <span class="c"># add it to the list</span> <span class="n">files</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">prefix</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span> <span class="o">+</span> <span class="p">[</span><span class="n">entry</span><span class="o">.</span><span class="n">name</span><span class="p">])</span> <span class="c"># check its kids</span> <span class="bp">self</span><span class="o">.</span><span class="n">_list</span><span class="p">(</span><span class="n">files</span><span class="p">,</span> <span class="n">prefix</span><span class="p">,</span> <span class="n">entry</span><span class="p">,</span> <span class="n">streams</span><span class="p">,</span> <span class="n">storages</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="c"># this is a stream</span> <span class="k">if</span> <span class="n">streams</span><span class="p">:</span> <span class="c"># add it to the list</span> <span class="n">files</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">prefix</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span> <span class="o">+</span> <span class="p">[</span><span class="n">entry</span><span class="o">.</span><span class="n">name</span><span class="p">])</span> <div class="viewcode-block" id="OleFileIO.listdir"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.listdir">[docs]</a> <span class="k">def</span> <span class="nf">listdir</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">streams</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">storages</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Return a list of streams stored in this file</span> <span class="sd"> :param streams: bool, include streams if True (True by default) - new in v0.26</span> <span class="sd"> :param storages: bool, include storages if True (False by default) - new in v0.26</span> <span class="sd"> (note: the root storage is never included)</span> <span class="sd"> """</span> <span class="n">files</span> <span class="o">=</span> <span class="p">[]</span> <span class="bp">self</span><span class="o">.</span><span class="n">_list</span><span class="p">(</span><span class="n">files</span><span class="p">,</span> <span class="p">[],</span> <span class="bp">self</span><span class="o">.</span><span class="n">root</span><span class="p">,</span> <span class="n">streams</span><span class="p">,</span> <span class="n">storages</span><span class="p">)</span> <span class="k">return</span> <span class="n">files</span> </div> <span class="k">def</span> <span class="nf">_find</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Returns directory entry of given filename. (openstream helper)</span> <span class="sd"> Note: this method is case-insensitive.</span> <span class="sd"> :param filename: path of stream in storage tree (except root entry), either:</span> <span class="sd"> </span> <span class="sd"> - a string using Unix path syntax, for example:</span> <span class="sd"> 'storage_1/storage_1.2/stream'</span> <span class="sd"> - a list of storage filenames, path to the desired stream/storage.</span> <span class="sd"> Example: ['storage_1', 'storage_1.2', 'stream']</span> <span class="sd"> :returns: sid of requested filename</span> <span class="sd"> raise IOError if file not found</span> <span class="sd"> """</span> <span class="c"># if filename is a string instead of a list, split it on slashes to</span> <span class="c"># convert to a list:</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="nb">basestring</span><span class="p">):</span> <span class="n">filename</span> <span class="o">=</span> <span class="n">filename</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">'/'</span><span class="p">)</span> <span class="c"># walk across storage tree, following given path:</span> <span class="n">node</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">root</span> <span class="k">for</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">filename</span><span class="p">:</span> <span class="k">for</span> <span class="n">kid</span> <span class="ow">in</span> <span class="n">node</span><span class="o">.</span><span class="n">kids</span><span class="p">:</span> <span class="k">if</span> <span class="n">kid</span><span class="o">.</span><span class="n">name</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="n">name</span><span class="o">.</span><span class="n">lower</span><span class="p">():</span> <span class="k">break</span> <span class="k">else</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">IOError</span><span class="p">(</span><span class="s">"file not found"</span><span class="p">)</span> <span class="n">node</span> <span class="o">=</span> <span class="n">kid</span> <span class="k">return</span> <span class="n">node</span><span class="o">.</span><span class="n">sid</span> <div class="viewcode-block" id="OleFileIO.openstream"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.openstream">[docs]</a> <span class="k">def</span> <span class="nf">openstream</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Open a stream as a read-only file object (BytesIO).</span> <span class="sd"> :param filename: path of stream in storage tree (except root entry), either:</span> <span class="sd"> </span> <span class="sd"> - a string using Unix path syntax, for example:</span> <span class="sd"> 'storage_1/storage_1.2/stream'</span> <span class="sd"> - a list of storage filenames, path to the desired stream/storage.</span> <span class="sd"> Example: ['storage_1', 'storage_1.2', 'stream']</span> <span class="sd"> </span> <span class="sd"> :returns: file object (read-only)</span> <span class="sd"> :exception IOError: if filename not found, or if this is not a stream.</span> <span class="sd"> """</span> <span class="n">sid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="n">entry</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">direntries</span><span class="p">[</span><span class="n">sid</span><span class="p">]</span> <span class="k">if</span> <span class="n">entry</span><span class="o">.</span><span class="n">entry_type</span> <span class="o">!=</span> <span class="n">STGTY_STREAM</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">IOError</span><span class="p">(</span><span class="s">"this file is not a stream"</span><span class="p">)</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_open</span><span class="p">(</span><span class="n">entry</span><span class="o">.</span><span class="n">isectStart</span><span class="p">,</span> <span class="n">entry</span><span class="o">.</span><span class="n">size</span><span class="p">)</span> </div> <div class="viewcode-block" id="OleFileIO.get_type"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.get_type">[docs]</a> <span class="k">def</span> <span class="nf">get_type</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Test if given filename exists as a stream or a storage in the OLE</span> <span class="sd"> container, and return its type.</span> <span class="sd"> :param filename: path of stream in storage tree. (see openstream for syntax)</span> <span class="sd"> :returns: False if object does not exist, its entry type (>0) otherwise:</span> <span class="sd"> </span> <span class="sd"> - STGTY_STREAM: a stream</span> <span class="sd"> - STGTY_STORAGE: a storage</span> <span class="sd"> - STGTY_ROOT: the root entry</span> <span class="sd"> """</span> <span class="k">try</span><span class="p">:</span> <span class="n">sid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="n">entry</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">direntries</span><span class="p">[</span><span class="n">sid</span><span class="p">]</span> <span class="k">return</span> <span class="n">entry</span><span class="o">.</span><span class="n">entry_type</span> <span class="k">except</span><span class="p">:</span> <span class="k">return</span> <span class="bp">False</span> </div> <div class="viewcode-block" id="OleFileIO.getmtime"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.getmtime">[docs]</a> <span class="k">def</span> <span class="nf">getmtime</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Return modification time of a stream/storage.</span> <span class="sd"> :param filename: path of stream/storage in storage tree. (see openstream for</span> <span class="sd"> syntax)</span> <span class="sd"> :returns: None if modification time is null, a python datetime object</span> <span class="sd"> otherwise (UTC timezone)</span> <span class="sd"> new in version 0.26</span> <span class="sd"> """</span> <span class="n">sid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="n">entry</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">direntries</span><span class="p">[</span><span class="n">sid</span><span class="p">]</span> <span class="k">return</span> <span class="n">entry</span><span class="o">.</span><span class="n">getmtime</span><span class="p">()</span> </div> <div class="viewcode-block" id="OleFileIO.getctime"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.getctime">[docs]</a> <span class="k">def</span> <span class="nf">getctime</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Return creation time of a stream/storage.</span> <span class="sd"> :param filename: path of stream/storage in storage tree. (see openstream for</span> <span class="sd"> syntax)</span> <span class="sd"> :returns: None if creation time is null, a python datetime object</span> <span class="sd"> otherwise (UTC timezone)</span> <span class="sd"> new in version 0.26</span> <span class="sd"> """</span> <span class="n">sid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="n">entry</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">direntries</span><span class="p">[</span><span class="n">sid</span><span class="p">]</span> <span class="k">return</span> <span class="n">entry</span><span class="o">.</span><span class="n">getctime</span><span class="p">()</span> </div> <div class="viewcode-block" id="OleFileIO.exists"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.exists">[docs]</a> <span class="k">def</span> <span class="nf">exists</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Test if given filename exists as a stream or a storage in the OLE</span> <span class="sd"> container.</span> <span class="sd"> :param filename: path of stream in storage tree. (see openstream for syntax)</span> <span class="sd"> :returns: True if object exist, else False.</span> <span class="sd"> """</span> <span class="k">try</span><span class="p">:</span> <span class="n">sid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="k">return</span> <span class="bp">True</span> <span class="k">except</span><span class="p">:</span> <span class="k">return</span> <span class="bp">False</span> </div> <div class="viewcode-block" id="OleFileIO.get_size"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.get_size">[docs]</a> <span class="k">def</span> <span class="nf">get_size</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Return size of a stream in the OLE container, in bytes.</span> <span class="sd"> :param filename: path of stream in storage tree (see openstream for syntax)</span> <span class="sd"> :returns: size in bytes (long integer)</span> <span class="sd"> :exception IOError: if file not found</span> <span class="sd"> :exception TypeError: if this is not a stream</span> <span class="sd"> """</span> <span class="n">sid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_find</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="n">entry</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">direntries</span><span class="p">[</span><span class="n">sid</span><span class="p">]</span> <span class="k">if</span> <span class="n">entry</span><span class="o">.</span><span class="n">entry_type</span> <span class="o">!=</span> <span class="n">STGTY_STREAM</span><span class="p">:</span> <span class="c">#TODO: Should it return zero instead of raising an exception ?</span> <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s">'object is not an OLE stream'</span><span class="p">)</span> <span class="k">return</span> <span class="n">entry</span><span class="o">.</span><span class="n">size</span> </div> <div class="viewcode-block" id="OleFileIO.get_rootentry_name"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.get_rootentry_name">[docs]</a> <span class="k">def</span> <span class="nf">get_rootentry_name</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Return root entry name. Should usually be 'Root Entry' or 'R' in most</span> <span class="sd"> implementations.</span> <span class="sd"> """</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">root</span><span class="o">.</span><span class="n">name</span> </div> <div class="viewcode-block" id="OleFileIO.getproperties"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.getproperties">[docs]</a> <span class="k">def</span> <span class="nf">getproperties</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filename</span><span class="p">,</span> <span class="n">convert_time</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">no_conversion</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Return properties described in substream.</span> <span class="sd"> :param filename: path of stream in storage tree (see openstream for syntax)</span> <span class="sd"> :param convert_time: bool, if True timestamps will be converted to Python datetime</span> <span class="sd"> :param no_conversion: None or list of int, timestamps not to be converted</span> <span class="sd"> (for example total editing time is not a real timestamp)</span> <span class="sd"> :returns: a dictionary of values indexed by id (integer)</span> <span class="sd"> """</span> <span class="c"># make sure no_conversion is a list, just to simplify code below:</span> <span class="k">if</span> <span class="n">no_conversion</span> <span class="o">==</span> <span class="bp">None</span><span class="p">:</span> <span class="n">no_conversion</span> <span class="o">=</span> <span class="p">[]</span> <span class="c"># stream path as a string to report exceptions:</span> <span class="n">streampath</span> <span class="o">=</span> <span class="n">filename</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">streampath</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span> <span class="n">streampath</span> <span class="o">=</span> <span class="s">'/'</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">streampath</span><span class="p">)</span> <span class="n">fp</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">openstream</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="n">data</span> <span class="o">=</span> <span class="p">{}</span> <span class="k">try</span><span class="p">:</span> <span class="c"># header</span> <span class="n">s</span> <span class="o">=</span> <span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">28</span><span class="p">)</span> <span class="n">clsid</span> <span class="o">=</span> <span class="n">_clsid</span><span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="mi">8</span><span class="p">:</span><span class="mi">24</span><span class="p">])</span> <span class="c"># format id</span> <span class="n">s</span> <span class="o">=</span> <span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">20</span><span class="p">)</span> <span class="n">fmtid</span> <span class="o">=</span> <span class="n">_clsid</span><span class="p">(</span><span class="n">s</span><span class="p">[:</span><span class="mi">16</span><span class="p">])</span> <span class="n">fp</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="n">i32</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="mi">16</span><span class="p">))</span> <span class="c"># get section</span> <span class="n">s</span> <span class="o">=</span> <span class="n">b</span><span class="s">"****"</span> <span class="o">+</span> <span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">i32</span><span class="p">(</span><span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">4</span><span class="p">))</span><span class="o">-</span><span class="mi">4</span><span class="p">)</span> <span class="c"># number of properties:</span> <span class="n">num_props</span> <span class="o">=</span> <span class="n">i32</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span> <span class="k">except</span> <span class="ne">BaseException</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="c"># catch exception while parsing property header, and only raise</span> <span class="c"># a DEFECT_INCORRECT then return an empty dict, because this is not</span> <span class="c"># a fatal error when parsing the whole file</span> <span class="n">msg</span> <span class="o">=</span> <span class="s">'Error while parsing properties header in stream </span><span class="si">%s</span><span class="s">: </span><span class="si">%s</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span> <span class="nb">repr</span><span class="p">(</span><span class="n">streampath</span><span class="p">),</span> <span class="n">exc</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_INCORRECT</span><span class="p">,</span> <span class="n">msg</span><span class="p">,</span> <span class="nb">type</span><span class="p">(</span><span class="n">exc</span><span class="p">))</span> <span class="k">return</span> <span class="n">data</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">num_props</span><span class="p">):</span> <span class="k">try</span><span class="p">:</span> <span class="nb">id</span> <span class="o">=</span> <span class="mi">0</span> <span class="c"># just in case of an exception</span> <span class="nb">id</span> <span class="o">=</span> <span class="n">i32</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="mi">8</span><span class="o">+</span><span class="n">i</span><span class="o">*</span><span class="mi">8</span><span class="p">)</span> <span class="n">offset</span> <span class="o">=</span> <span class="n">i32</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="mi">12</span><span class="o">+</span><span class="n">i</span><span class="o">*</span><span class="mi">8</span><span class="p">)</span> <span class="nb">type</span> <span class="o">=</span> <span class="n">i32</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span> <span class="n">debug</span> <span class="p">(</span><span class="s">'property id=</span><span class="si">%d</span><span class="s">: type=</span><span class="si">%d</span><span class="s"> offset=</span><span class="si">%X</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="nb">type</span><span class="p">,</span> <span class="n">offset</span><span class="p">))</span> <span class="c"># test for common types first (should perhaps use</span> <span class="c"># a dictionary instead?)</span> <span class="k">if</span> <span class="nb">type</span> <span class="o">==</span> <span class="n">VT_I2</span><span class="p">:</span> <span class="c"># 16-bit signed integer</span> <span class="n">value</span> <span class="o">=</span> <span class="n">i16</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">offset</span><span class="o">+</span><span class="mi">4</span><span class="p">)</span> <span class="k">if</span> <span class="n">value</span> <span class="o">>=</span> <span class="mi">32768</span><span class="p">:</span> <span class="n">value</span> <span class="o">=</span> <span class="n">value</span> <span class="o">-</span> <span class="mi">65536</span> <span class="k">elif</span> <span class="nb">type</span> <span class="o">==</span> <span class="n">VT_UI2</span><span class="p">:</span> <span class="c"># 2-byte unsigned integer</span> <span class="n">value</span> <span class="o">=</span> <span class="n">i16</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">offset</span><span class="o">+</span><span class="mi">4</span><span class="p">)</span> <span class="k">elif</span> <span class="nb">type</span> <span class="ow">in</span> <span class="p">(</span><span class="n">VT_I4</span><span class="p">,</span> <span class="n">VT_INT</span><span class="p">,</span> <span class="n">VT_ERROR</span><span class="p">):</span> <span class="c"># VT_I4: 32-bit signed integer</span> <span class="c"># VT_ERROR: HRESULT, similar to 32-bit signed integer,</span> <span class="c"># see http://msdn.microsoft.com/en-us/library/cc230330.aspx</span> <span class="n">value</span> <span class="o">=</span> <span class="n">i32</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">offset</span><span class="o">+</span><span class="mi">4</span><span class="p">)</span> <span class="k">elif</span> <span class="nb">type</span> <span class="ow">in</span> <span class="p">(</span><span class="n">VT_UI4</span><span class="p">,</span> <span class="n">VT_UINT</span><span class="p">):</span> <span class="c"># 4-byte unsigned integer</span> <span class="n">value</span> <span class="o">=</span> <span class="n">i32</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">offset</span><span class="o">+</span><span class="mi">4</span><span class="p">)</span> <span class="c"># FIXME</span> <span class="k">elif</span> <span class="nb">type</span> <span class="ow">in</span> <span class="p">(</span><span class="n">VT_BSTR</span><span class="p">,</span> <span class="n">VT_LPSTR</span><span class="p">):</span> <span class="c"># CodePageString, see http://msdn.microsoft.com/en-us/library/dd942354.aspx</span> <span class="c"># size is a 32 bits integer, including the null terminator, and</span> <span class="c"># possibly trailing or embedded null chars</span> <span class="c">#TODO: if codepage is unicode, the string should be converted as such</span> <span class="n">count</span> <span class="o">=</span> <span class="n">i32</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">offset</span><span class="o">+</span><span class="mi">4</span><span class="p">)</span> <span class="n">value</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="n">offset</span><span class="o">+</span><span class="mi">8</span><span class="p">:</span><span class="n">offset</span><span class="o">+</span><span class="mi">8</span><span class="o">+</span><span class="n">count</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="c"># remove all null chars:</span> <span class="n">value</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">b</span><span class="s">'</span><span class="se">\x00</span><span class="s">'</span><span class="p">,</span> <span class="n">b</span><span class="s">''</span><span class="p">)</span> <span class="k">elif</span> <span class="nb">type</span> <span class="o">==</span> <span class="n">VT_BLOB</span><span class="p">:</span> <span class="c"># binary large object (BLOB)</span> <span class="c"># see http://msdn.microsoft.com/en-us/library/dd942282.aspx</span> <span class="n">count</span> <span class="o">=</span> <span class="n">i32</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">offset</span><span class="o">+</span><span class="mi">4</span><span class="p">)</span> <span class="n">value</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="n">offset</span><span class="o">+</span><span class="mi">8</span><span class="p">:</span><span class="n">offset</span><span class="o">+</span><span class="mi">8</span><span class="o">+</span><span class="n">count</span><span class="p">]</span> <span class="k">elif</span> <span class="nb">type</span> <span class="o">==</span> <span class="n">VT_LPWSTR</span><span class="p">:</span> <span class="c"># UnicodeString</span> <span class="c"># see http://msdn.microsoft.com/en-us/library/dd942313.aspx</span> <span class="c"># "the string should NOT contain embedded or additional trailing</span> <span class="c"># null characters."</span> <span class="n">count</span> <span class="o">=</span> <span class="n">i32</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">offset</span><span class="o">+</span><span class="mi">4</span><span class="p">)</span> <span class="n">value</span> <span class="o">=</span> <span class="n">_unicode</span><span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="n">offset</span><span class="o">+</span><span class="mi">8</span><span class="p">:</span><span class="n">offset</span><span class="o">+</span><span class="mi">8</span><span class="o">+</span><span class="n">count</span><span class="o">*</span><span class="mi">2</span><span class="p">])</span> <span class="k">elif</span> <span class="nb">type</span> <span class="o">==</span> <span class="n">VT_FILETIME</span><span class="p">:</span> <span class="n">value</span> <span class="o">=</span> <span class="nb">long</span><span class="p">(</span><span class="n">i32</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">offset</span><span class="o">+</span><span class="mi">4</span><span class="p">))</span> <span class="o">+</span> <span class="p">(</span><span class="nb">long</span><span class="p">(</span><span class="n">i32</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">offset</span><span class="o">+</span><span class="mi">8</span><span class="p">))</span><span class="o"><<</span><span class="mi">32</span><span class="p">)</span> <span class="c"># FILETIME is a 64-bit int: "number of 100ns periods</span> <span class="c"># since Jan 1,1601".</span> <span class="k">if</span> <span class="n">convert_time</span> <span class="ow">and</span> <span class="nb">id</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">no_conversion</span><span class="p">:</span> <span class="n">debug</span><span class="p">(</span><span class="s">'Converting property #</span><span class="si">%d</span><span class="s"> to python datetime, value=</span><span class="si">%d</span><span class="s">=</span><span class="si">%f</span><span class="s">s'</span> <span class="o">%</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="nb">float</span><span class="p">(</span><span class="n">value</span><span class="p">)</span><span class="o">/</span><span class="mi">10000000</span><span class="p">))</span> <span class="c"># convert FILETIME to Python datetime.datetime</span> <span class="c"># inspired from http://code.activestate.com/recipes/511425-filetime-to-datetime/</span> <span class="n">_FILETIME_null_date</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="p">(</span><span class="mi">1601</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="n">debug</span><span class="p">(</span><span class="s">'timedelta days=</span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="n">value</span><span class="o">//</span><span class="p">(</span><span class="mi">10</span><span class="o">*</span><span class="mi">1000000</span><span class="o">*</span><span class="mi">3600</span><span class="o">*</span><span class="mi">24</span><span class="p">)))</span> <span class="n">value</span> <span class="o">=</span> <span class="n">_FILETIME_null_date</span> <span class="o">+</span> <span class="n">datetime</span><span class="o">.</span><span class="n">timedelta</span><span class="p">(</span><span class="n">microseconds</span><span class="o">=</span><span class="n">value</span><span class="o">//</span><span class="mi">10</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="c"># legacy code kept for backward compatibility: returns a</span> <span class="c"># number of seconds since Jan 1,1601</span> <span class="n">value</span> <span class="o">=</span> <span class="n">value</span> <span class="o">//</span> <span class="mi">10000000</span> <span class="c"># seconds</span> <span class="k">elif</span> <span class="nb">type</span> <span class="o">==</span> <span class="n">VT_UI1</span><span class="p">:</span> <span class="c"># 1-byte unsigned integer</span> <span class="n">value</span> <span class="o">=</span> <span class="n">i8</span><span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="n">offset</span><span class="o">+</span><span class="mi">4</span><span class="p">])</span> <span class="k">elif</span> <span class="nb">type</span> <span class="o">==</span> <span class="n">VT_CLSID</span><span class="p">:</span> <span class="n">value</span> <span class="o">=</span> <span class="n">_clsid</span><span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="n">offset</span><span class="o">+</span><span class="mi">4</span><span class="p">:</span><span class="n">offset</span><span class="o">+</span><span class="mi">20</span><span class="p">])</span> <span class="k">elif</span> <span class="nb">type</span> <span class="o">==</span> <span class="n">VT_CF</span><span class="p">:</span> <span class="c"># PropertyIdentifier or ClipboardData??</span> <span class="c"># see http://msdn.microsoft.com/en-us/library/dd941945.aspx</span> <span class="n">count</span> <span class="o">=</span> <span class="n">i32</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">offset</span><span class="o">+</span><span class="mi">4</span><span class="p">)</span> <span class="n">value</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="n">offset</span><span class="o">+</span><span class="mi">8</span><span class="p">:</span><span class="n">offset</span><span class="o">+</span><span class="mi">8</span><span class="o">+</span><span class="n">count</span><span class="p">]</span> <span class="k">elif</span> <span class="nb">type</span> <span class="o">==</span> <span class="n">VT_BOOL</span><span class="p">:</span> <span class="c"># VARIANT_BOOL, 16 bits bool, 0x0000=Fals, 0xFFFF=True</span> <span class="c"># see http://msdn.microsoft.com/en-us/library/cc237864.aspx</span> <span class="n">value</span> <span class="o">=</span> <span class="nb">bool</span><span class="p">(</span><span class="n">i16</span><span class="p">(</span><span class="n">s</span><span class="p">,</span> <span class="n">offset</span><span class="o">+</span><span class="mi">4</span><span class="p">))</span> <span class="k">else</span><span class="p">:</span> <span class="n">value</span> <span class="o">=</span> <span class="bp">None</span> <span class="c"># everything else yields "None"</span> <span class="n">debug</span> <span class="p">(</span><span class="s">'property id=</span><span class="si">%d</span><span class="s">: type=</span><span class="si">%d</span><span class="s"> not implemented in parser yet'</span> <span class="o">%</span> <span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="nb">type</span><span class="p">))</span> <span class="c"># missing: VT_EMPTY, VT_NULL, VT_R4, VT_R8, VT_CY, VT_DATE,</span> <span class="c"># VT_DECIMAL, VT_I1, VT_I8, VT_UI8,</span> <span class="c"># see http://msdn.microsoft.com/en-us/library/dd942033.aspx</span> <span class="c"># FIXME: add support for VT_VECTOR</span> <span class="c"># VT_VECTOR is a 32 uint giving the number of items, followed by</span> <span class="c"># the items in sequence. The VT_VECTOR value is combined with the</span> <span class="c"># type of items, e.g. VT_VECTOR|VT_BSTR</span> <span class="c"># see http://msdn.microsoft.com/en-us/library/dd942011.aspx</span> <span class="c">#print("%08x" % id, repr(value), end=" ")</span> <span class="c">#print("(%s)" % VT[i32(s, offset) & 0xFFF])</span> <span class="n">data</span><span class="p">[</span><span class="nb">id</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span> <span class="k">except</span> <span class="ne">BaseException</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span> <span class="c"># catch exception while parsing each property, and only raise</span> <span class="c"># a DEFECT_INCORRECT, because parsing can go on</span> <span class="n">msg</span> <span class="o">=</span> <span class="s">'Error while parsing property id </span><span class="si">%d</span><span class="s"> in stream </span><span class="si">%s</span><span class="s">: </span><span class="si">%s</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span> <span class="nb">id</span><span class="p">,</span> <span class="nb">repr</span><span class="p">(</span><span class="n">streampath</span><span class="p">),</span> <span class="n">exc</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">_raise_defect</span><span class="p">(</span><span class="n">DEFECT_INCORRECT</span><span class="p">,</span> <span class="n">msg</span><span class="p">,</span> <span class="nb">type</span><span class="p">(</span><span class="n">exc</span><span class="p">))</span> <span class="k">return</span> <span class="n">data</span> </div> <div class="viewcode-block" id="OleFileIO.get_metadata"><a class="viewcode-back" href="../../reference/OleFileIO.html#PIL.OleFileIO.OleFileIO.get_metadata">[docs]</a> <span class="k">def</span> <span class="nf">get_metadata</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="sd">"""</span> <span class="sd"> Parse standard properties streams, return an OleMetadata object</span> <span class="sd"> containing all the available metadata.</span> <span class="sd"> (also stored in the metadata attribute of the OleFileIO object)</span> <span class="sd"> new in version 0.25</span> <span class="sd"> """</span> <span class="bp">self</span><span class="o">.</span><span class="n">metadata</span> <span class="o">=</span> <span class="n">OleMetadata</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">metadata</span><span class="o">.</span><span class="n">parse_properties</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">metadata</span> <span class="c">#</span> <span class="c"># --------------------------------------------------------------------</span> <span class="c"># This script can be used to dump the directory of any OLE2 structured</span> <span class="c"># storage file.</span> </div></div> <span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span> <span class="kn">import</span> <span class="nn">sys</span> <span class="c"># [PL] display quick usage info if launched from command-line</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span> <span class="o"><=</span> <span class="mi">1</span><span class="p">:</span> <span class="k">print</span><span class="p">(</span><span class="n">__doc__</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="s">"""</span> <span class="s">Launched from command line, this script parses OLE files and prints info.</span> <span class="s">Usage: OleFileIO_PL.py [-d] [-c] <file> [file2 ...]</span> <span class="s">Options:</span> <span class="s">-d : debug mode (display a lot of debug information, for developers only)</span> <span class="s">-c : check all streams (for debugging purposes)</span> <span class="s">"""</span><span class="p">)</span> <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">()</span> <span class="n">check_streams</span> <span class="o">=</span> <span class="bp">False</span> <span class="k">for</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span> <span class="c">## try:</span> <span class="c"># OPTIONS:</span> <span class="k">if</span> <span class="n">filename</span> <span class="o">==</span> <span class="s">'-d'</span><span class="p">:</span> <span class="c"># option to switch debug mode on:</span> <span class="n">set_debug_mode</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span> <span class="k">continue</span> <span class="k">if</span> <span class="n">filename</span> <span class="o">==</span> <span class="s">'-c'</span><span class="p">:</span> <span class="c"># option to switch check streams mode on:</span> <span class="n">check_streams</span> <span class="o">=</span> <span class="bp">True</span> <span class="k">continue</span> <span class="n">ole</span> <span class="o">=</span> <span class="n">OleFileIO</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span><span class="c">#, raise_defects=DEFECT_INCORRECT)</span> <span class="k">print</span><span class="p">(</span><span class="s">"-"</span> <span class="o">*</span> <span class="mi">68</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="s">"-"</span> <span class="o">*</span> <span class="mi">68</span><span class="p">)</span> <span class="n">ole</span><span class="o">.</span><span class="n">dumpdirectory</span><span class="p">()</span> <span class="k">for</span> <span class="n">streamname</span> <span class="ow">in</span> <span class="n">ole</span><span class="o">.</span><span class="n">listdir</span><span class="p">():</span> <span class="k">if</span> <span class="n">streamname</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s">"</span><span class="se">\005</span><span class="s">"</span><span class="p">:</span> <span class="k">print</span><span class="p">(</span><span class="n">streamname</span><span class="p">,</span> <span class="s">": properties"</span><span class="p">)</span> <span class="n">props</span> <span class="o">=</span> <span class="n">ole</span><span class="o">.</span><span class="n">getproperties</span><span class="p">(</span><span class="n">streamname</span><span class="p">,</span> <span class="n">convert_time</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> <span class="n">props</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">props</span><span class="o">.</span><span class="n">items</span><span class="p">())</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">props</span><span class="p">:</span> <span class="c">#[PL]: avoid to display too large or binary values:</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="p">(</span><span class="nb">basestring</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">)):</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="o">></span> <span class="mi">50</span><span class="p">:</span> <span class="n">v</span> <span class="o">=</span> <span class="n">v</span><span class="p">[:</span><span class="mi">50</span><span class="p">]</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">):</span> <span class="c"># quick and dirty binary check:</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">,</span><span class="mi">7</span><span class="p">,</span><span class="mi">11</span><span class="p">,</span><span class="mi">12</span><span class="p">,</span><span class="mi">14</span><span class="p">,</span><span class="mi">15</span><span class="p">,</span><span class="mi">16</span><span class="p">,</span><span class="mi">17</span><span class="p">,</span><span class="mi">18</span><span class="p">,</span><span class="mi">19</span><span class="p">,</span><span class="mi">20</span><span class="p">,</span> <span class="mi">21</span><span class="p">,</span><span class="mi">22</span><span class="p">,</span><span class="mi">23</span><span class="p">,</span><span class="mi">24</span><span class="p">,</span><span class="mi">25</span><span class="p">,</span><span class="mi">26</span><span class="p">,</span><span class="mi">27</span><span class="p">,</span><span class="mi">28</span><span class="p">,</span><span class="mi">29</span><span class="p">,</span><span class="mi">30</span><span class="p">,</span><span class="mi">31</span><span class="p">):</span> <span class="k">if</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">bytearray</span><span class="p">(</span><span class="n">v</span><span class="p">):</span> <span class="n">v</span> <span class="o">=</span> <span class="s">'(binary data)'</span> <span class="k">break</span> <span class="k">print</span><span class="p">(</span><span class="s">" "</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span> <span class="k">if</span> <span class="n">check_streams</span><span class="p">:</span> <span class="c"># Read all streams to check if there are errors:</span> <span class="k">print</span><span class="p">(</span><span class="s">'</span><span class="se">\n</span><span class="s">Checking streams...'</span><span class="p">)</span> <span class="k">for</span> <span class="n">streamname</span> <span class="ow">in</span> <span class="n">ole</span><span class="o">.</span><span class="n">listdir</span><span class="p">():</span> <span class="c"># print name using repr() to convert binary chars to \xNN:</span> <span class="k">print</span><span class="p">(</span><span class="s">'-'</span><span class="p">,</span> <span class="nb">repr</span><span class="p">(</span><span class="s">'/'</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">streamname</span><span class="p">)),</span><span class="s">'-'</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s">' '</span><span class="p">)</span> <span class="n">st_type</span> <span class="o">=</span> <span class="n">ole</span><span class="o">.</span><span class="n">get_type</span><span class="p">(</span><span class="n">streamname</span><span class="p">)</span> <span class="k">if</span> <span class="n">st_type</span> <span class="o">==</span> <span class="n">STGTY_STREAM</span><span class="p">:</span> <span class="k">print</span><span class="p">(</span><span class="s">'size </span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="n">ole</span><span class="o">.</span><span class="n">get_size</span><span class="p">(</span><span class="n">streamname</span><span class="p">))</span> <span class="c"># just try to read stream in memory:</span> <span class="n">ole</span><span class="o">.</span><span class="n">openstream</span><span class="p">(</span><span class="n">streamname</span><span class="p">)</span> <span class="k">else</span><span class="p">:</span> <span class="k">print</span><span class="p">(</span><span class="s">'NOT a stream : type=</span><span class="si">%d</span><span class="s">'</span> <span class="o">%</span> <span class="n">st_type</span><span class="p">)</span> <span class="k">print</span><span class="p">()</span> <span class="c">## for streamname in ole.listdir():</span> <span class="c">## # print name using repr() to convert binary chars to \xNN:</span> <span class="c">## print('-', repr('/'.join(streamname)),'-', end=' ')</span> <span class="c">## print(ole.getmtime(streamname))</span> <span class="c">## print()</span> <span class="k">print</span><span class="p">(</span><span class="s">'Modification/Creation times of all directory entries:'</span><span class="p">)</span> <span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">ole</span><span class="o">.</span><span class="n">direntries</span><span class="p">:</span> <span class="k">if</span> <span class="n">entry</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> <span class="k">print</span><span class="p">(</span><span class="s">'- </span><span class="si">%s</span><span class="s">: mtime=</span><span class="si">%s</span><span class="s"> ctime=</span><span class="si">%s</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="n">entry</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">entry</span><span class="o">.</span><span class="n">getmtime</span><span class="p">(),</span> <span class="n">entry</span><span class="o">.</span><span class="n">getctime</span><span class="p">()))</span> <span class="k">print</span><span class="p">()</span> <span class="c"># parse and display metadata:</span> <span class="n">meta</span> <span class="o">=</span> <span class="n">ole</span><span class="o">.</span><span class="n">get_metadata</span><span class="p">()</span> <span class="n">meta</span><span class="o">.</span><span class="n">dump</span><span class="p">()</span> <span class="k">print</span><span class="p">()</span> <span class="c">#[PL] Test a few new methods:</span> <span class="n">root</span> <span class="o">=</span> <span class="n">ole</span><span class="o">.</span><span class="n">get_rootentry_name</span><span class="p">()</span> <span class="k">print</span><span class="p">(</span><span class="s">'Root entry name: "</span><span class="si">%s</span><span class="s">"'</span> <span class="o">%</span> <span class="n">root</span><span class="p">)</span> <span class="k">if</span> <span class="n">ole</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="s">'worddocument'</span><span class="p">):</span> <span class="k">print</span><span class="p">(</span><span class="s">"This is a Word document."</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="s">"type of stream 'WordDocument':"</span><span class="p">,</span> <span class="n">ole</span><span class="o">.</span><span class="n">get_type</span><span class="p">(</span><span class="s">'worddocument'</span><span class="p">))</span> <span class="k">print</span><span class="p">(</span><span class="s">"size :"</span><span class="p">,</span> <span class="n">ole</span><span class="o">.</span><span class="n">get_size</span><span class="p">(</span><span class="s">'worddocument'</span><span class="p">))</span> <span class="k">if</span> <span class="n">ole</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="s">'macros/vba'</span><span class="p">):</span> <span class="k">print</span><span class="p">(</span><span class="s">"This document may contain VBA macros."</span><span class="p">)</span> <span class="c"># print parsing issues:</span> <span class="k">print</span><span class="p">(</span><span class="s">'</span><span class="se">\n</span><span class="s">Non-fatal issues raised during parsing:'</span><span class="p">)</span> <span class="k">if</span> <span class="n">ole</span><span class="o">.</span><span class="n">parsing_issues</span><span class="p">:</span> <span class="k">for</span> <span class="n">exctype</span><span class="p">,</span> <span class="n">msg</span> <span class="ow">in</span> <span class="n">ole</span><span class="o">.</span><span class="n">parsing_issues</span><span class="p">:</span> <span class="k">print</span><span class="p">(</span><span class="s">'- </span><span class="si">%s</span><span class="s">: </span><span class="si">%s</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="n">exctype</span><span class="o">.</span><span class="n">__name__</span><span class="p">,</span> <span class="n">msg</span><span class="p">))</span> <span class="k">else</span><span class="p">:</span> <span class="k">print</span><span class="p">(</span><span class="s">'None'</span><span class="p">)</span> <span class="c">## except IOError as v:</span> <span class="c">## print("***", "cannot read", file, "-", v)</span> </pre></div> </div> </div> </div> <div class="sphinxsidebar"> <div class="sphinxsidebarwrapper"><h3>Need help?</h3> <p> You can get help via IRC at <a href="irc://irc.freenode.net#pil">irc://irc.freenode.net#pil</a> or Stack Overflow <a href="http://stackoverflow.com/questions/tagged/pillow">here</a> and <a href="http://stackoverflow.com/questions/tagged/pil">here</a>. Please <a href="https://github.com/python-pillow/Pillow/issues/new">report issues on GitHub</a>. </p> <div id="searchbox" style="display: none"> <h3>Quick search</h3> <form class="search" action="../../search.html" method="get"> <input type="text" name="q" /> <input type="submit" value="Go" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> <p class="searchtip" style="font-size: 90%"> Enter search terms or a module, class or function name. </p> </div> <script type="text/javascript">$('#searchbox').show(0);</script> </div> </div> <div class="clearer"></div> </div> <div class="related"> <h3>Navigation</h3> <ul> <li class="right" style="margin-right: 10px"> <a href="../../genindex.html" title="General Index" >index</a></li> <li class="right" > <a href="../../py-modindex.html" title="Python Module Index" >modules</a> |</li> <li><a href="../../index.html">Home</a> »</li> <li><a href="../index.html" >Module code</a> »</li> </ul> </div> <div class="footer"> © Copyright 1997-2011 by Secret Labs AB, 1995-2011 by Fredrik Lundh, 2010-2013 Alex Clark. Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3. </div> </body> </html>