File size: 4,098 Bytes
d94b56e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# -*- coding: utf-8 -*-
#
#   pyhwp : hwp file format parser in python
#   Copyright (C) 2010-2023 mete0r <https://github.com/mete0r>
#
#   This program is free software: you can redistribute it and/or modify
#   it under the terms of the GNU Affero General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU Affero General Public License for more details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
import os.path
import sys

from ..errors import InvalidOleStorageError


PY3 = sys.version_info.major == 3
if PY3:
    basestring = str


def is_enabled():
    try:
        from org.apache.poi.poifs.filesystem import POIFSFileSystem
        POIFSFileSystem  # silencing
        return True
    except ImportError:
        return False


class OleStorage(object):
    ''' Create an OleStorage instance.

    :param olefile: an OLE2 Compound Binary File.
    :raises: `InvalidOleStorageError` when `olefile` is not valid OLE2 format.
    '''

    def __init__(self, olefile):
        from java.io import FileInputStream
        from java.io import IOException
        from org.apache.poi.poifs.filesystem import POIFSFileSystem
        from org.apache.poi.poifs.filesystem import DirectoryEntry

        if isinstance(olefile, basestring):
            path = os.path.abspath(olefile)
            fis = FileInputStream(path)
            try:
                fs = POIFSFileSystem(fis)
            except IOException as e:
                raise InvalidOleStorageError(e.getMessage())
            entry = fs.getRoot()
        elif isinstance(olefile, DirectoryEntry):
            entry = olefile
        else:
            raise ValueError('invalid olefile')

        self.entry = entry

    def __iter__(self):
        return (entry.getName() for entry in self.entry.getEntries())

    def __getitem__(self, name):
        from java.io import FileNotFoundException
        try:
            entry = self.entry.getEntry(name)
        except FileNotFoundException:
            raise KeyError('%s not found' % name)

        if entry.directoryEntry:
            return OleStorage(entry)
        elif entry.documentEntry:
            return OleStream(entry)
        else:
            raise KeyError('%s is invalid' % name)

    def close(self):
        return


class OleStream(object):

    def __init__(self, entry):
        self.entry = entry

    def open(self):
        from org.apache.poi.poifs.filesystem import DocumentInputStream
        dis = DocumentInputStream(self.entry)
        return FileFromDocumentInputStream(dis)


class FileFromDocumentInputStream(object):

    def __init__(self, dis):
        self.dis = dis
        self.size = dis.available()
        dis.mark(0)

    def read(self, size=None):
        import jarray
        dis = self.dis
        available = dis.available()
        if size is None:
            size = available
        elif size > available:
            size = available
        bytes = jarray.zeros(size, 'b')
        n_read = dis.read(bytes)
        data = bytes.tostring()
        if n_read < size:
            return data[:n_read]
        return data

    def seek(self, offset, whence=0):
        dis = self.dis
        if whence == 0:
            dis.reset()
            dis.skip(offset)
        elif whence == 1:
            dis.skip(offset)
        elif whence == 2:
            dis.reset()
            dis.skip(self.size - offset)
        else:
            raise ValueError('invalid whence: %s', whence)

    def tell(self):
        return self.size - self.dis.available()

    def close(self):
        return self.dis.close()