Commit 0d8d1a28b46abbb4e5c3a3dfc8b8bd62f071de99
1 parent
0acaf934
mraptor3: import tablestream, removed tablestream3
Showing
2 changed files
with
1 additions
and
349 deletions
oletools/mraptor3.py
| @@ -66,7 +66,7 @@ import sys, logging, optparse, re | @@ -66,7 +66,7 @@ import sys, logging, optparse, re | ||
| 66 | from thirdparty.xglob import xglob | 66 | from thirdparty.xglob import xglob |
| 67 | 67 | ||
| 68 | # import the python 3 version of tablestream: | 68 | # import the python 3 version of tablestream: |
| 69 | -from thirdparty.tablestream import tablestream3 as tablestream | 69 | +from thirdparty.tablestream import tablestream |
| 70 | 70 | ||
| 71 | # import the python 3 version of olevba | 71 | # import the python 3 version of olevba |
| 72 | import olevba3 as olevba | 72 | import olevba3 as olevba |
oletools/thirdparty/tablestream/tablestream3.py deleted
| 1 | -#!/usr/bin/env python | ||
| 2 | -""" | ||
| 3 | -tablestream | ||
| 4 | - | ||
| 5 | -tablestream can format table data for pretty printing as text, | ||
| 6 | -to be displayed on the console or written to any file-like object. | ||
| 7 | -The table data can be provided as rows, each row is an iterable of | ||
| 8 | -cells. The text in each cell is wrapped to fit into a maximum width | ||
| 9 | -set for each column. | ||
| 10 | -Contrary to many table pretty printing libraries, TableStream writes | ||
| 11 | -each row to the output as soon as it is provided, and the whole table | ||
| 12 | -does not need to be built in memory before printing. | ||
| 13 | -It is therefore suitable for large tables, or tables that take time to | ||
| 14 | -be processed row by row. | ||
| 15 | - | ||
| 16 | -Author: Philippe Lagadec - http://www.decalage.info | ||
| 17 | -License: BSD, see source code or documentation | ||
| 18 | -""" | ||
| 19 | - | ||
| 20 | -#=== LICENSE ================================================================== | ||
| 21 | - | ||
| 22 | -# tablestream is copyright (c) 2015-2016 Philippe Lagadec (http://www.decalage.info) | ||
| 23 | -# All rights reserved. | ||
| 24 | -# | ||
| 25 | -# Redistribution and use in source and binary forms, with or without modification, | ||
| 26 | -# are permitted provided that the following conditions are met: | ||
| 27 | -# | ||
| 28 | -# * Redistributions of source code must retain the above copyright notice, this | ||
| 29 | -# list of conditions and the following disclaimer. | ||
| 30 | -# * Redistributions in binary form must reproduce the above copyright notice, | ||
| 31 | -# this list of conditions and the following disclaimer in the documentation | ||
| 32 | -# and/or other materials provided with the distribution. | ||
| 33 | -# | ||
| 34 | -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
| 35 | -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
| 36 | -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
| 37 | -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||
| 38 | -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| 39 | -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
| 40 | -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
| 41 | -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
| 42 | -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| 43 | -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 44 | - | ||
| 45 | -from __future__ import print_function | ||
| 46 | - | ||
| 47 | -#------------------------------------------------------------------------------ | ||
| 48 | -# CHANGELOG: | ||
| 49 | -# 2015-11-01 v0.01 PL: - first version | ||
| 50 | -# 2016-01-01 v0.02 PL: - added styles, color support | ||
| 51 | -# 2016-04-19 v0.03 PL: - enable colorclass on Windows, fixed issue #39 | ||
| 52 | -# 2016-05-25 v0.04 PL: - updated for colorclass 2.2.0 (now a package) | ||
| 53 | -# 2016-07-29 v0.05 PL: - fixed oletools issue #57, bug when importing colorclass | ||
| 54 | -# 2016-07-31 v0.06 PL: - handle newline characters properly in each cell | ||
| 55 | - | ||
| 56 | -__version__ = '0.06' | ||
| 57 | - | ||
| 58 | -#------------------------------------------------------------------------------ | ||
| 59 | -# TODO: | ||
| 60 | -# - several styles | ||
| 61 | -# - colorized rows or cells | ||
| 62 | -# - automatic width for the last column, based on max total width | ||
| 63 | -# - automatic width for selected columns, based on N first lines | ||
| 64 | -# - determine the console width | ||
| 65 | - | ||
| 66 | -# === IMPORTS ================================================================= | ||
| 67 | - | ||
| 68 | -import textwrap | ||
| 69 | -import sys, os | ||
| 70 | - | ||
| 71 | -# add the thirdparty subfolder to sys.path (absolute+normalized path): | ||
| 72 | -_thismodule_dir = os.path.normpath(os.path.abspath(os.path.dirname(__file__))) | ||
| 73 | -# print('_thismodule_dir = %r' % _thismodule_dir) | ||
| 74 | -# assumption: this module is in a subfolder of thirdparty: | ||
| 75 | -_thirdparty_dir = os.path.normpath(os.path.join(_thismodule_dir, '..')) | ||
| 76 | -# print('_thirdparty_dir = %r' % _thirdparty_dir) | ||
| 77 | -if not _thirdparty_dir in sys.path: | ||
| 78 | - sys.path.insert(0, _thirdparty_dir) | ||
| 79 | - | ||
| 80 | -import colorclass | ||
| 81 | - | ||
| 82 | -# On Windows, colorclass needs to be enabled: | ||
| 83 | -if os.name == 'nt': | ||
| 84 | - colorclass.Windows.enable(auto_colors=True) | ||
| 85 | - | ||
| 86 | - | ||
| 87 | -# === CLASSES ================================================================= | ||
| 88 | - | ||
| 89 | - | ||
| 90 | -class TableStyle(object): | ||
| 91 | - """ | ||
| 92 | - Style for a TableStream. | ||
| 93 | - This base class can be derived to create new styles. | ||
| 94 | - Default style: | ||
| 95 | - +------+---+ | ||
| 96 | - |Header| + | ||
| 97 | - +------+---+ | ||
| 98 | - | | | | ||
| 99 | - +------+---+ | ||
| 100 | - """ | ||
| 101 | - # Header rows: | ||
| 102 | - header_top = True | ||
| 103 | - header_top_left = '+' | ||
| 104 | - header_top_horiz = '-' | ||
| 105 | - header_top_middle = '+' | ||
| 106 | - header_top_right = '+' | ||
| 107 | - | ||
| 108 | - header_vertical_left = '|' | ||
| 109 | - header_vertical_middle = '|' | ||
| 110 | - header_vertical_right = '|' | ||
| 111 | - | ||
| 112 | - # Separator line between header and normal rows: | ||
| 113 | - header_sep = True | ||
| 114 | - header_sep_left = '+' | ||
| 115 | - header_sep_horiz = '-' | ||
| 116 | - header_sep_middle = '+' | ||
| 117 | - header_sep_right = '+' | ||
| 118 | - | ||
| 119 | - # Top row if there is no header: | ||
| 120 | - noheader_top = True | ||
| 121 | - noheader_top_left = '+' | ||
| 122 | - noheader_top_horiz = '-' | ||
| 123 | - noheader_top_middle = '+' | ||
| 124 | - noheader_top_right = '+' | ||
| 125 | - | ||
| 126 | - # Normal rows | ||
| 127 | - vertical_left = '|' | ||
| 128 | - vertical_middle = '|' | ||
| 129 | - vertical_right = '|' | ||
| 130 | - | ||
| 131 | - # Separator line between rows: | ||
| 132 | - sep = False | ||
| 133 | - sep_left = '+' | ||
| 134 | - sep_horiz = '-' | ||
| 135 | - sep_middle = '+' | ||
| 136 | - sep_right = '+' | ||
| 137 | - | ||
| 138 | - # Bottom line | ||
| 139 | - bottom = True | ||
| 140 | - bottom_left = '+' | ||
| 141 | - bottom_horiz = '-' | ||
| 142 | - bottom_middle = '+' | ||
| 143 | - bottom_right = '+' | ||
| 144 | - | ||
| 145 | - | ||
| 146 | -class TableStyleSlim(object): | ||
| 147 | - """ | ||
| 148 | - Style for a TableStream. | ||
| 149 | - Example: | ||
| 150 | - ------+--- | ||
| 151 | - Header| | ||
| 152 | - ------+--- | ||
| 153 | - | | ||
| 154 | - ------+--- | ||
| 155 | - """ | ||
| 156 | - # Header rows: | ||
| 157 | - header_top = True | ||
| 158 | - header_top_left = '' | ||
| 159 | - header_top_horiz = '-' | ||
| 160 | - header_top_middle = '+' | ||
| 161 | - header_top_right = '' | ||
| 162 | - | ||
| 163 | - header_vertical_left = '' | ||
| 164 | - header_vertical_middle = '|' | ||
| 165 | - header_vertical_right = '' | ||
| 166 | - | ||
| 167 | - # Separator line between header and normal rows: | ||
| 168 | - header_sep = True | ||
| 169 | - header_sep_left = '' | ||
| 170 | - header_sep_horiz = '-' | ||
| 171 | - header_sep_middle = '+' | ||
| 172 | - header_sep_right = '' | ||
| 173 | - | ||
| 174 | - # Top row if there is no header: | ||
| 175 | - noheader_top = True | ||
| 176 | - noheader_top_left = '' | ||
| 177 | - noheader_top_horiz = '-' | ||
| 178 | - noheader_top_middle = '+' | ||
| 179 | - noheader_top_right = '' | ||
| 180 | - | ||
| 181 | - # Normal rows | ||
| 182 | - vertical_left = '' | ||
| 183 | - vertical_middle = '|' | ||
| 184 | - vertical_right = '' | ||
| 185 | - | ||
| 186 | - # Separator line between rows: | ||
| 187 | - sep = False | ||
| 188 | - sep_left = '' | ||
| 189 | - sep_horiz = '-' | ||
| 190 | - sep_middle = '+' | ||
| 191 | - sep_right = '' | ||
| 192 | - | ||
| 193 | - # Bottom line | ||
| 194 | - bottom = True | ||
| 195 | - bottom_left = '' | ||
| 196 | - bottom_horiz = '-' | ||
| 197 | - bottom_middle = '+' | ||
| 198 | - bottom_right = '' | ||
| 199 | - | ||
| 200 | - | ||
| 201 | - | ||
| 202 | -class TableStream(object): | ||
| 203 | - """ | ||
| 204 | - a TableStream object can format table data for pretty printing as text, | ||
| 205 | - to be displayed on the console or written to any file-like object. | ||
| 206 | - The table data can be provided as rows, each row is an iterable of | ||
| 207 | - cells. The text in each cell is wrapped to fit into a maximum width | ||
| 208 | - set for each column. | ||
| 209 | - Contrary to many table pretty printing libraries, TableStream writes | ||
| 210 | - each row to the output as soon as it is provided, and the whole table | ||
| 211 | - does not need to be built in memory before printing. | ||
| 212 | - It is therefore suitable for large tables, or tables that take time to | ||
| 213 | - be processed row by row. | ||
| 214 | - """ | ||
| 215 | - | ||
| 216 | - def __init__(self, column_width, header_row=None, style=TableStyle, outfile=sys.stdout): | ||
| 217 | - self.column_width = column_width | ||
| 218 | - self.num_columns = len(column_width) | ||
| 219 | - self.header_row = header_row | ||
| 220 | - assert (header_row is None) or len(header_row) == self.num_columns | ||
| 221 | - self.style = style | ||
| 222 | - self.outfile = outfile | ||
| 223 | - if header_row is not None: | ||
| 224 | - self.write_header() | ||
| 225 | - elif self.style.noheader_top: | ||
| 226 | - self.write_noheader_top() | ||
| 227 | - | ||
| 228 | - | ||
| 229 | - def write(self, s): | ||
| 230 | - """ | ||
| 231 | - shortcut for self.outfile.write() | ||
| 232 | - """ | ||
| 233 | - self.outfile.write(s) | ||
| 234 | - | ||
| 235 | - def write_row(self, row, last=False, colors=None): | ||
| 236 | - assert len(row) == self.num_columns | ||
| 237 | - columns = [] | ||
| 238 | - max_lines = 0 | ||
| 239 | - for i in range(self.num_columns): | ||
| 240 | - cell = row[i] | ||
| 241 | - # Convert to string: | ||
| 242 | - # TODO: handle unicode properly | ||
| 243 | - # TODO: use only unicode for textwrapper, to avoid str length issues | ||
| 244 | - if isinstance(cell, bytes): | ||
| 245 | - # encode to UTF8, avoiding errors | ||
| 246 | - cell = cell.decode('utf-8', errors='replace') | ||
| 247 | - else: | ||
| 248 | - cell = cell | ||
| 249 | - # Wrap cell text according to the column width | ||
| 250 | - # TODO: use a TextWrapper object for each column instead | ||
| 251 | - # split the string if it contains newline characters, otherwise | ||
| 252 | - # textwrap replaces them with spaces: | ||
| 253 | - column = [] | ||
| 254 | - for line in cell.splitlines(): | ||
| 255 | - column.extend(textwrap.wrap(line, width=self.column_width[i])) | ||
| 256 | - # apply colors to each line of the cell if needed: | ||
| 257 | - if colors is not None and self.outfile.isatty(): | ||
| 258 | - color = colors[i] | ||
| 259 | - if color: | ||
| 260 | - for j in range(len(column)): | ||
| 261 | - # print '%r: %s' % (column[j], type(column[j])) | ||
| 262 | - column[j] = colorclass.Color('{auto%s}%s{/%s}' % (color, column[j], color)) | ||
| 263 | - columns.append(column) | ||
| 264 | - # determine which column has the highest number of lines | ||
| 265 | - max_lines = max(len(columns[i]), max_lines) | ||
| 266 | - # transpose: write output line by line | ||
| 267 | - for j in range(max_lines): | ||
| 268 | - self.write(self.style.vertical_left) | ||
| 269 | - for i in range(self.num_columns): | ||
| 270 | - column = columns[i] | ||
| 271 | - if j<len(column): | ||
| 272 | - # text to be written | ||
| 273 | - text_width = len(column[j]) | ||
| 274 | - self.write(column[j] + ' '*(self.column_width[i]-text_width)) | ||
| 275 | - else: | ||
| 276 | - # no more lines for this column | ||
| 277 | - # TODO: precompute empty cells once | ||
| 278 | - self.write(' '*(self.column_width[i])) | ||
| 279 | - if i < (self.num_columns - 1): | ||
| 280 | - self.write(self.style.vertical_middle) | ||
| 281 | - self.write(self.style.vertical_right) | ||
| 282 | - self.write('\n') | ||
| 283 | - if self.style.sep and not last: | ||
| 284 | - self.write_sep() | ||
| 285 | - | ||
| 286 | - def make_line(self, left, horiz, middle, right): | ||
| 287 | - """ | ||
| 288 | - build a line based on the provided elements | ||
| 289 | - example: '+---+--+-------+' | ||
| 290 | - :param left: | ||
| 291 | - :param horiz: | ||
| 292 | - :param middle: | ||
| 293 | - :param right: | ||
| 294 | - :return: | ||
| 295 | - """ | ||
| 296 | - return left + middle.join([horiz * width for width in self.column_width]) + right + '\n' | ||
| 297 | - | ||
| 298 | - def write_header_top(self): | ||
| 299 | - s = self.style | ||
| 300 | - line = self.make_line(left=s.header_top_left, horiz=s.header_top_horiz, | ||
| 301 | - middle=s.header_top_middle, right=s.header_top_right) | ||
| 302 | - self.write(line) | ||
| 303 | - | ||
| 304 | - def write_header_sep(self): | ||
| 305 | - s = self.style | ||
| 306 | - line = self.make_line(left=s.header_sep_left, horiz=s.header_sep_horiz, | ||
| 307 | - middle=s.header_sep_middle, right=s.header_sep_right) | ||
| 308 | - self.write(line) | ||
| 309 | - | ||
| 310 | - def write_header(self): | ||
| 311 | - if self.style.header_top: | ||
| 312 | - self.write_header_top() | ||
| 313 | - self.write_row(self.header_row) | ||
| 314 | - if self.style.header_sep: | ||
| 315 | - self.write_header_sep() | ||
| 316 | - | ||
| 317 | - def write_noheader_top(self): | ||
| 318 | - s = self.style | ||
| 319 | - line = self.make_line(left=s.noheader_top_left, horiz=s.noheader_top_horiz, | ||
| 320 | - middle=s.noheader_top_middle, right=s.noheader_top_right) | ||
| 321 | - self.write(line) | ||
| 322 | - | ||
| 323 | - def write_sep(self): | ||
| 324 | - s = self.style | ||
| 325 | - line = self.make_line(left=s.sep_left, horiz=s.sep_horiz, | ||
| 326 | - middle=s.sep_middle, right=s.sep_right) | ||
| 327 | - self.write(line) | ||
| 328 | - | ||
| 329 | - def write_bottom(self): | ||
| 330 | - s = self.style | ||
| 331 | - line = self.make_line(left=s.bottom_left, horiz=s.bottom_horiz, | ||
| 332 | - middle=s.bottom_middle, right=s.bottom_right) | ||
| 333 | - self.write(line) | ||
| 334 | - | ||
| 335 | - def close(self): | ||
| 336 | - self.write_bottom() | ||
| 337 | - | ||
| 338 | - | ||
| 339 | -if __name__ == '__main__': | ||
| 340 | - t = TableStream([10, 5, 20], header_row=['i', 'i*i', '2**i'], style=TableStyleSlim) | ||
| 341 | - t.write_row(['test', 'test', 'test']) | ||
| 342 | - cell = 'a very very long text' | ||
| 343 | - t.write_row([cell, cell, cell], colors=['blue', None, 'red']) | ||
| 344 | - for i in range(1, 11): | ||
| 345 | - t.write_row([i, i*i, 2**i]) | ||
| 346 | - t.close() | ||
| 347 | - | ||
| 348 | - |