Commit 2e7c42943d248083bae01fa5a6a84199fbbc8887
1 parent
435baf80
colorclass is now an external dependency, obsolete copy removed from thirdparty folder
Showing
13 changed files
with
13 additions
and
1487 deletions
oletools/oledir.py
| ... | ... | @@ -51,6 +51,7 @@ from __future__ import print_function |
| 51 | 51 | # 2018-04-11 v0.53 PL: - added table displaying storage tree and CLSIDs |
| 52 | 52 | # 2018-04-13 PL: - moved KNOWN_CLSIDS to common.clsid |
| 53 | 53 | # 2018-08-28 v0.54 PL: - olefile is now a dependency |
| 54 | +# 2018-10-06 - colorclass is now a dependency | |
| 54 | 55 | |
| 55 | 56 | __version__ = '0.54dev1' |
| 56 | 57 | |
| ... | ... | @@ -63,6 +64,13 @@ __version__ = '0.54dev1' |
| 63 | 64 | |
| 64 | 65 | import sys, os, optparse |
| 65 | 66 | |
| 67 | +import olefile | |
| 68 | +import colorclass | |
| 69 | + | |
| 70 | +# On Windows, colorclass needs to be enabled: | |
| 71 | +if os.name == 'nt': | |
| 72 | + colorclass.Windows.enable(auto_colors=True) | |
| 73 | + | |
| 66 | 74 | # IMPORTANT: it should be possible to run oletools directly as scripts |
| 67 | 75 | # in any directory without installing them with pip or setup.py. |
| 68 | 76 | # In that case, relative imports are NOT usable. |
| ... | ... | @@ -75,20 +83,6 @@ _parent_dir = os.path.normpath(os.path.join(_thismodule_dir, '..')) |
| 75 | 83 | if not _parent_dir in sys.path: |
| 76 | 84 | sys.path.insert(0, _parent_dir) |
| 77 | 85 | |
| 78 | -# we also need the thirdparty dir for colorclass | |
| 79 | -# TODO: remove colorclass from thirdparty, make it a dependency | |
| 80 | -_thirdparty_dir = os.path.normpath(os.path.join(_thismodule_dir, 'thirdparty')) | |
| 81 | -# print('_thirdparty_dir = %r' % _thirdparty_dir) | |
| 82 | -if not _thirdparty_dir in sys.path: | |
| 83 | - sys.path.insert(0, _thirdparty_dir) | |
| 84 | - | |
| 85 | -import colorclass | |
| 86 | - | |
| 87 | -# On Windows, colorclass needs to be enabled: | |
| 88 | -if os.name == 'nt': | |
| 89 | - colorclass.Windows.enable(auto_colors=True) | |
| 90 | - | |
| 91 | -import olefile | |
| 92 | 86 | from oletools.thirdparty.tablestream import tablestream |
| 93 | 87 | from oletools.thirdparty.xglob import xglob |
| 94 | 88 | from oletools.common.clsid import KNOWN_CLSIDS | ... | ... |
oletools/thirdparty/colorclass/LICENSE.txt deleted
| 1 | -The MIT License (MIT) | |
| 2 | - | |
| 3 | -Copyright (c) 2014 Robpol86 | |
| 4 | - | |
| 5 | -Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 6 | -of this software and associated documentation files (the "Software"), to deal | |
| 7 | -in the Software without restriction, including without limitation the rights | |
| 8 | -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 9 | -copies of the Software, and to permit persons to whom the Software is | |
| 10 | -furnished to do so, subject to the following conditions: | |
| 11 | - | |
| 12 | -The above copyright notice and this permission notice shall be included in all | |
| 13 | -copies or substantial portions of the Software. | |
| 14 | - | |
| 15 | -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 16 | -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 17 | -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 18 | -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 19 | -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 20 | -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 21 | -SOFTWARE. |
oletools/thirdparty/colorclass/__init__.py deleted
| 1 | -"""Colorful worry-free console applications for Linux, Mac OS X, and Windows. | |
| 2 | - | |
| 3 | -Supported natively on Linux and Mac OSX (Just Works), and on Windows it works the same if Windows.enable() is called. | |
| 4 | - | |
| 5 | -Gives you expected and sane results from methods like len() and .capitalize(). | |
| 6 | - | |
| 7 | -https://github.com/Robpol86/colorclass | |
| 8 | -https://pypi.org/project/colorclass/ | |
| 9 | -""" | |
| 10 | - | |
| 11 | -from colorclass.codes import list_tags # noqa | |
| 12 | -from colorclass.color import Color # noqa | |
| 13 | -from colorclass.toggles import disable_all_colors # noqa | |
| 14 | -from colorclass.toggles import disable_if_no_tty # noqa | |
| 15 | -from colorclass.toggles import enable_all_colors # noqa | |
| 16 | -from colorclass.toggles import is_enabled # noqa | |
| 17 | -from colorclass.toggles import is_light # noqa | |
| 18 | -from colorclass.toggles import set_dark_background # noqa | |
| 19 | -from colorclass.toggles import set_light_background # noqa | |
| 20 | -from colorclass.windows import Windows # noqa | |
| 21 | - | |
| 22 | - | |
| 23 | -__all__ = ( | |
| 24 | - 'Color', | |
| 25 | - 'disable_all_colors', | |
| 26 | - 'enable_all_colors', | |
| 27 | - 'is_enabled', | |
| 28 | - 'is_light', | |
| 29 | - 'list_tags', | |
| 30 | - 'set_dark_background', | |
| 31 | - 'set_light_background', | |
| 32 | - 'Windows', | |
| 33 | -) | |
| 34 | - | |
| 35 | - | |
| 36 | -__author__ = '@Robpol86' | |
| 37 | -__license__ = 'MIT' | |
| 38 | -__version__ = '2.2.0' |
oletools/thirdparty/colorclass/__main__.py deleted
| 1 | -"""Called by "python -m". Allows package to be used as a script. | |
| 2 | - | |
| 3 | -Example usage: | |
| 4 | -echo "{red}Red{/red}" |python -m colorclass | |
| 5 | -""" | |
| 6 | - | |
| 7 | -from __future__ import print_function | |
| 8 | - | |
| 9 | -import fileinput | |
| 10 | -import os | |
| 11 | - | |
| 12 | -from colorclass.color import Color | |
| 13 | -from colorclass.toggles import disable_all_colors | |
| 14 | -from colorclass.toggles import enable_all_colors | |
| 15 | -from colorclass.toggles import set_dark_background | |
| 16 | -from colorclass.toggles import set_light_background | |
| 17 | -from colorclass.windows import Windows | |
| 18 | - | |
| 19 | -TRUTHY = ('true', '1', 'yes', 'on') | |
| 20 | - | |
| 21 | - | |
| 22 | -if __name__ == '__main__': | |
| 23 | - if os.environ.get('COLOR_ENABLE', '').lower() in TRUTHY: | |
| 24 | - enable_all_colors() | |
| 25 | - elif os.environ.get('COLOR_DISABLE', '').lower() in TRUTHY: | |
| 26 | - disable_all_colors() | |
| 27 | - if os.environ.get('COLOR_LIGHT', '').lower() in TRUTHY: | |
| 28 | - set_light_background() | |
| 29 | - elif os.environ.get('COLOR_DARK', '').lower() in TRUTHY: | |
| 30 | - set_dark_background() | |
| 31 | - Windows.enable() | |
| 32 | - for LINE in fileinput.input(): | |
| 33 | - print(Color(LINE)) |
oletools/thirdparty/colorclass/codes.py deleted
| 1 | -"""Handles mapping between color names and ANSI codes and determining auto color codes.""" | |
| 2 | - | |
| 3 | -import sys | |
| 4 | -from collections import Mapping | |
| 5 | - | |
| 6 | -BASE_CODES = { | |
| 7 | - '/all': 0, 'b': 1, 'f': 2, 'i': 3, 'u': 4, 'flash': 5, 'outline': 6, 'negative': 7, 'invis': 8, 'strike': 9, | |
| 8 | - '/b': 22, '/f': 22, '/i': 23, '/u': 24, '/flash': 25, '/outline': 26, '/negative': 27, '/invis': 28, | |
| 9 | - '/strike': 29, '/fg': 39, '/bg': 49, | |
| 10 | - | |
| 11 | - 'black': 30, 'red': 31, 'green': 32, 'yellow': 33, 'blue': 34, 'magenta': 35, 'cyan': 36, 'white': 37, | |
| 12 | - | |
| 13 | - 'bgblack': 40, 'bgred': 41, 'bggreen': 42, 'bgyellow': 43, 'bgblue': 44, 'bgmagenta': 45, 'bgcyan': 46, | |
| 14 | - 'bgwhite': 47, | |
| 15 | - | |
| 16 | - 'hiblack': 90, 'hired': 91, 'higreen': 92, 'hiyellow': 93, 'hiblue': 94, 'himagenta': 95, 'hicyan': 96, | |
| 17 | - 'hiwhite': 97, | |
| 18 | - | |
| 19 | - 'hibgblack': 100, 'hibgred': 101, 'hibggreen': 102, 'hibgyellow': 103, 'hibgblue': 104, 'hibgmagenta': 105, | |
| 20 | - 'hibgcyan': 106, 'hibgwhite': 107, | |
| 21 | - | |
| 22 | - 'autored': None, 'autoblack': None, 'automagenta': None, 'autowhite': None, 'autoblue': None, 'autoyellow': None, | |
| 23 | - 'autogreen': None, 'autocyan': None, | |
| 24 | - | |
| 25 | - 'autobgred': None, 'autobgblack': None, 'autobgmagenta': None, 'autobgwhite': None, 'autobgblue': None, | |
| 26 | - 'autobgyellow': None, 'autobggreen': None, 'autobgcyan': None, | |
| 27 | - | |
| 28 | - '/black': 39, '/red': 39, '/green': 39, '/yellow': 39, '/blue': 39, '/magenta': 39, '/cyan': 39, '/white': 39, | |
| 29 | - '/hiblack': 39, '/hired': 39, '/higreen': 39, '/hiyellow': 39, '/hiblue': 39, '/himagenta': 39, '/hicyan': 39, | |
| 30 | - '/hiwhite': 39, | |
| 31 | - | |
| 32 | - '/bgblack': 49, '/bgred': 49, '/bggreen': 49, '/bgyellow': 49, '/bgblue': 49, '/bgmagenta': 49, '/bgcyan': 49, | |
| 33 | - '/bgwhite': 49, '/hibgblack': 49, '/hibgred': 49, '/hibggreen': 49, '/hibgyellow': 49, '/hibgblue': 49, | |
| 34 | - '/hibgmagenta': 49, '/hibgcyan': 49, '/hibgwhite': 49, | |
| 35 | - | |
| 36 | - '/autored': 39, '/autoblack': 39, '/automagenta': 39, '/autowhite': 39, '/autoblue': 39, '/autoyellow': 39, | |
| 37 | - '/autogreen': 39, '/autocyan': 39, | |
| 38 | - | |
| 39 | - '/autobgred': 49, '/autobgblack': 49, '/autobgmagenta': 49, '/autobgwhite': 49, '/autobgblue': 49, | |
| 40 | - '/autobgyellow': 49, '/autobggreen': 49, '/autobgcyan': 49, | |
| 41 | -} | |
| 42 | - | |
| 43 | - | |
| 44 | -class ANSICodeMapping(Mapping): | |
| 45 | - """Read-only dictionary, resolves closing tags and automatic colors. Iterates only used color tags. | |
| 46 | - | |
| 47 | - :cvar bool DISABLE_COLORS: Disable colors (strip color codes). | |
| 48 | - :cvar bool LIGHT_BACKGROUND: Use low intensity color codes. | |
| 49 | - """ | |
| 50 | - | |
| 51 | - DISABLE_COLORS = False | |
| 52 | - LIGHT_BACKGROUND = False | |
| 53 | - | |
| 54 | - def __init__(self, value_markup): | |
| 55 | - """Constructor. | |
| 56 | - | |
| 57 | - :param str value_markup: String with {color} tags. | |
| 58 | - """ | |
| 59 | - self.whitelist = [k for k in BASE_CODES if '{' + k + '}' in value_markup] | |
| 60 | - | |
| 61 | - def __getitem__(self, item): | |
| 62 | - """Return value for key or None if colors are disabled. | |
| 63 | - | |
| 64 | - :param str item: Key. | |
| 65 | - | |
| 66 | - :return: Color code integer. | |
| 67 | - :rtype: int | |
| 68 | - """ | |
| 69 | - if item not in self.whitelist: | |
| 70 | - raise KeyError(item) | |
| 71 | - if self.DISABLE_COLORS: | |
| 72 | - return None | |
| 73 | - return getattr(self, item, BASE_CODES[item]) | |
| 74 | - | |
| 75 | - def __iter__(self): | |
| 76 | - """Iterate dictionary.""" | |
| 77 | - return iter(self.whitelist) | |
| 78 | - | |
| 79 | - def __len__(self): | |
| 80 | - """Dictionary length.""" | |
| 81 | - return len(self.whitelist) | |
| 82 | - | |
| 83 | - @classmethod | |
| 84 | - def disable_all_colors(cls): | |
| 85 | - """Disable all colors. Strips any color tags or codes.""" | |
| 86 | - cls.DISABLE_COLORS = True | |
| 87 | - | |
| 88 | - @classmethod | |
| 89 | - def enable_all_colors(cls): | |
| 90 | - """Enable all colors. Strips any color tags or codes.""" | |
| 91 | - cls.DISABLE_COLORS = False | |
| 92 | - | |
| 93 | - @classmethod | |
| 94 | - def disable_if_no_tty(cls): | |
| 95 | - """Disable all colors only if there is no TTY available. | |
| 96 | - | |
| 97 | - :return: True if colors are disabled, False if stderr or stdout is a TTY. | |
| 98 | - :rtype: bool | |
| 99 | - """ | |
| 100 | - if sys.stdout.isatty() or sys.stderr.isatty(): | |
| 101 | - return False | |
| 102 | - cls.disable_all_colors() | |
| 103 | - return True | |
| 104 | - | |
| 105 | - @classmethod | |
| 106 | - def set_dark_background(cls): | |
| 107 | - """Choose dark colors for all 'auto'-prefixed codes for readability on light backgrounds.""" | |
| 108 | - cls.LIGHT_BACKGROUND = False | |
| 109 | - | |
| 110 | - @classmethod | |
| 111 | - def set_light_background(cls): | |
| 112 | - """Choose dark colors for all 'auto'-prefixed codes for readability on light backgrounds.""" | |
| 113 | - cls.LIGHT_BACKGROUND = True | |
| 114 | - | |
| 115 | - @property | |
| 116 | - def autoblack(self): | |
| 117 | - """Return automatic black foreground color depending on background color.""" | |
| 118 | - return BASE_CODES['black' if ANSICodeMapping.LIGHT_BACKGROUND else 'hiblack'] | |
| 119 | - | |
| 120 | - @property | |
| 121 | - def autored(self): | |
| 122 | - """Return automatic red foreground color depending on background color.""" | |
| 123 | - return BASE_CODES['red' if ANSICodeMapping.LIGHT_BACKGROUND else 'hired'] | |
| 124 | - | |
| 125 | - @property | |
| 126 | - def autogreen(self): | |
| 127 | - """Return automatic green foreground color depending on background color.""" | |
| 128 | - return BASE_CODES['green' if ANSICodeMapping.LIGHT_BACKGROUND else 'higreen'] | |
| 129 | - | |
| 130 | - @property | |
| 131 | - def autoyellow(self): | |
| 132 | - """Return automatic yellow foreground color depending on background color.""" | |
| 133 | - return BASE_CODES['yellow' if ANSICodeMapping.LIGHT_BACKGROUND else 'hiyellow'] | |
| 134 | - | |
| 135 | - @property | |
| 136 | - def autoblue(self): | |
| 137 | - """Return automatic blue foreground color depending on background color.""" | |
| 138 | - return BASE_CODES['blue' if ANSICodeMapping.LIGHT_BACKGROUND else 'hiblue'] | |
| 139 | - | |
| 140 | - @property | |
| 141 | - def automagenta(self): | |
| 142 | - """Return automatic magenta foreground color depending on background color.""" | |
| 143 | - return BASE_CODES['magenta' if ANSICodeMapping.LIGHT_BACKGROUND else 'himagenta'] | |
| 144 | - | |
| 145 | - @property | |
| 146 | - def autocyan(self): | |
| 147 | - """Return automatic cyan foreground color depending on background color.""" | |
| 148 | - return BASE_CODES['cyan' if ANSICodeMapping.LIGHT_BACKGROUND else 'hicyan'] | |
| 149 | - | |
| 150 | - @property | |
| 151 | - def autowhite(self): | |
| 152 | - """Return automatic white foreground color depending on background color.""" | |
| 153 | - return BASE_CODES['white' if ANSICodeMapping.LIGHT_BACKGROUND else 'hiwhite'] | |
| 154 | - | |
| 155 | - @property | |
| 156 | - def autobgblack(self): | |
| 157 | - """Return automatic black background color depending on background color.""" | |
| 158 | - return BASE_CODES['bgblack' if ANSICodeMapping.LIGHT_BACKGROUND else 'hibgblack'] | |
| 159 | - | |
| 160 | - @property | |
| 161 | - def autobgred(self): | |
| 162 | - """Return automatic red background color depending on background color.""" | |
| 163 | - return BASE_CODES['bgred' if ANSICodeMapping.LIGHT_BACKGROUND else 'hibgred'] | |
| 164 | - | |
| 165 | - @property | |
| 166 | - def autobggreen(self): | |
| 167 | - """Return automatic green background color depending on background color.""" | |
| 168 | - return BASE_CODES['bggreen' if ANSICodeMapping.LIGHT_BACKGROUND else 'hibggreen'] | |
| 169 | - | |
| 170 | - @property | |
| 171 | - def autobgyellow(self): | |
| 172 | - """Return automatic yellow background color depending on background color.""" | |
| 173 | - return BASE_CODES['bgyellow' if ANSICodeMapping.LIGHT_BACKGROUND else 'hibgyellow'] | |
| 174 | - | |
| 175 | - @property | |
| 176 | - def autobgblue(self): | |
| 177 | - """Return automatic blue background color depending on background color.""" | |
| 178 | - return BASE_CODES['bgblue' if ANSICodeMapping.LIGHT_BACKGROUND else 'hibgblue'] | |
| 179 | - | |
| 180 | - @property | |
| 181 | - def autobgmagenta(self): | |
| 182 | - """Return automatic magenta background color depending on background color.""" | |
| 183 | - return BASE_CODES['bgmagenta' if ANSICodeMapping.LIGHT_BACKGROUND else 'hibgmagenta'] | |
| 184 | - | |
| 185 | - @property | |
| 186 | - def autobgcyan(self): | |
| 187 | - """Return automatic cyan background color depending on background color.""" | |
| 188 | - return BASE_CODES['bgcyan' if ANSICodeMapping.LIGHT_BACKGROUND else 'hibgcyan'] | |
| 189 | - | |
| 190 | - @property | |
| 191 | - def autobgwhite(self): | |
| 192 | - """Return automatic white background color depending on background color.""" | |
| 193 | - return BASE_CODES['bgwhite' if ANSICodeMapping.LIGHT_BACKGROUND else 'hibgwhite'] | |
| 194 | - | |
| 195 | - | |
| 196 | -def list_tags(): | |
| 197 | - """List the available tags. | |
| 198 | - | |
| 199 | - :return: List of 4-item tuples: opening tag, closing tag, main ansi value, closing ansi value. | |
| 200 | - :rtype: list | |
| 201 | - """ | |
| 202 | - # Build reverse dictionary. Keys are closing tags, values are [closing ansi, opening tag, opening ansi]. | |
| 203 | - reverse_dict = dict() | |
| 204 | - for tag, ansi in sorted(BASE_CODES.items()): | |
| 205 | - if tag.startswith('/'): | |
| 206 | - reverse_dict[tag] = [ansi, None, None] | |
| 207 | - else: | |
| 208 | - reverse_dict['/' + tag][1:] = [tag, ansi] | |
| 209 | - | |
| 210 | - # Collapse | |
| 211 | - four_item_tuples = [(v[1], k, v[2], v[0]) for k, v in reverse_dict.items()] | |
| 212 | - | |
| 213 | - # Sort. | |
| 214 | - def sorter(four_item): | |
| 215 | - """Sort /all /fg /bg first, then b i u flash, then auto colors, then dark colors, finally light colors. | |
| 216 | - | |
| 217 | - :param iter four_item: [opening tag, closing tag, main ansi value, closing ansi value] | |
| 218 | - | |
| 219 | - :return Sorting weight. | |
| 220 | - :rtype: int | |
| 221 | - """ | |
| 222 | - if not four_item[2]: # /all /fg /bg | |
| 223 | - return four_item[3] - 200 | |
| 224 | - if four_item[2] < 10 or four_item[0].startswith('auto'): # b f i u or auto colors | |
| 225 | - return four_item[2] - 100 | |
| 226 | - return four_item[2] | |
| 227 | - four_item_tuples.sort(key=sorter) | |
| 228 | - | |
| 229 | - return four_item_tuples |
oletools/thirdparty/colorclass/color.py deleted
| 1 | -"""Color class used by library users.""" | |
| 2 | - | |
| 3 | -from colorclass.core import ColorStr | |
| 4 | - | |
| 5 | - | |
| 6 | -class Color(ColorStr): | |
| 7 | - """Unicode (str in Python3) subclass with ANSI terminal text color support. | |
| 8 | - | |
| 9 | - Example syntax: Color('{red}Sample Text{/red}') | |
| 10 | - | |
| 11 | - Example without parsing logic: Color('{red}Sample Text{/red}', keep_tags=True) | |
| 12 | - | |
| 13 | - For a list of codes, call: colorclass.list_tags() | |
| 14 | - """ | |
| 15 | - | |
| 16 | - @classmethod | |
| 17 | - def colorize(cls, color, string, auto=False): | |
| 18 | - """Color-code entire string using specified color. | |
| 19 | - | |
| 20 | - :param str color: Color of string. | |
| 21 | - :param str string: String to colorize. | |
| 22 | - :param bool auto: Enable auto-color (dark/light terminal). | |
| 23 | - | |
| 24 | - :return: Class instance for colorized string. | |
| 25 | - :rtype: Color | |
| 26 | - """ | |
| 27 | - tag = '{0}{1}'.format('auto' if auto else '', color) | |
| 28 | - return cls('{%s}%s{/%s}' % (tag, string, tag)) | |
| 29 | - | |
| 30 | - @classmethod | |
| 31 | - def black(cls, string, auto=False): | |
| 32 | - """Color-code entire string. | |
| 33 | - | |
| 34 | - :param str string: String to colorize. | |
| 35 | - :param bool auto: Enable auto-color (dark/light terminal). | |
| 36 | - | |
| 37 | - :return: Class instance for colorized string. | |
| 38 | - :rtype: Color | |
| 39 | - """ | |
| 40 | - return cls.colorize('black', string, auto=auto) | |
| 41 | - | |
| 42 | - @classmethod | |
| 43 | - def bgblack(cls, string, auto=False): | |
| 44 | - """Color-code entire string. | |
| 45 | - | |
| 46 | - :param str string: String to colorize. | |
| 47 | - :param bool auto: Enable auto-color (dark/light terminal). | |
| 48 | - | |
| 49 | - :return: Class instance for colorized string. | |
| 50 | - :rtype: Color | |
| 51 | - """ | |
| 52 | - return cls.colorize('bgblack', string, auto=auto) | |
| 53 | - | |
| 54 | - @classmethod | |
| 55 | - def red(cls, string, auto=False): | |
| 56 | - """Color-code entire string. | |
| 57 | - | |
| 58 | - :param str string: String to colorize. | |
| 59 | - :param bool auto: Enable auto-color (dark/light terminal). | |
| 60 | - | |
| 61 | - :return: Class instance for colorized string. | |
| 62 | - :rtype: Color | |
| 63 | - """ | |
| 64 | - return cls.colorize('red', string, auto=auto) | |
| 65 | - | |
| 66 | - @classmethod | |
| 67 | - def bgred(cls, string, auto=False): | |
| 68 | - """Color-code entire string. | |
| 69 | - | |
| 70 | - :param str string: String to colorize. | |
| 71 | - :param bool auto: Enable auto-color (dark/light terminal). | |
| 72 | - | |
| 73 | - :return: Class instance for colorized string. | |
| 74 | - :rtype: Color | |
| 75 | - """ | |
| 76 | - return cls.colorize('bgred', string, auto=auto) | |
| 77 | - | |
| 78 | - @classmethod | |
| 79 | - def green(cls, string, auto=False): | |
| 80 | - """Color-code entire string. | |
| 81 | - | |
| 82 | - :param str string: String to colorize. | |
| 83 | - :param bool auto: Enable auto-color (dark/light terminal). | |
| 84 | - | |
| 85 | - :return: Class instance for colorized string. | |
| 86 | - :rtype: Color | |
| 87 | - """ | |
| 88 | - return cls.colorize('green', string, auto=auto) | |
| 89 | - | |
| 90 | - @classmethod | |
| 91 | - def bggreen(cls, string, auto=False): | |
| 92 | - """Color-code entire string. | |
| 93 | - | |
| 94 | - :param str string: String to colorize. | |
| 95 | - :param bool auto: Enable auto-color (dark/light terminal). | |
| 96 | - | |
| 97 | - :return: Class instance for colorized string. | |
| 98 | - :rtype: Color | |
| 99 | - """ | |
| 100 | - return cls.colorize('bggreen', string, auto=auto) | |
| 101 | - | |
| 102 | - @classmethod | |
| 103 | - def yellow(cls, string, auto=False): | |
| 104 | - """Color-code entire string. | |
| 105 | - | |
| 106 | - :param str string: String to colorize. | |
| 107 | - :param bool auto: Enable auto-color (dark/light terminal). | |
| 108 | - | |
| 109 | - :return: Class instance for colorized string. | |
| 110 | - :rtype: Color | |
| 111 | - """ | |
| 112 | - return cls.colorize('yellow', string, auto=auto) | |
| 113 | - | |
| 114 | - @classmethod | |
| 115 | - def bgyellow(cls, string, auto=False): | |
| 116 | - """Color-code entire string. | |
| 117 | - | |
| 118 | - :param str string: String to colorize. | |
| 119 | - :param bool auto: Enable auto-color (dark/light terminal). | |
| 120 | - | |
| 121 | - :return: Class instance for colorized string. | |
| 122 | - :rtype: Color | |
| 123 | - """ | |
| 124 | - return cls.colorize('bgyellow', string, auto=auto) | |
| 125 | - | |
| 126 | - @classmethod | |
| 127 | - def blue(cls, string, auto=False): | |
| 128 | - """Color-code entire string. | |
| 129 | - | |
| 130 | - :param str string: String to colorize. | |
| 131 | - :param bool auto: Enable auto-color (dark/light terminal). | |
| 132 | - | |
| 133 | - :return: Class instance for colorized string. | |
| 134 | - :rtype: Color | |
| 135 | - """ | |
| 136 | - return cls.colorize('blue', string, auto=auto) | |
| 137 | - | |
| 138 | - @classmethod | |
| 139 | - def bgblue(cls, string, auto=False): | |
| 140 | - """Color-code entire string. | |
| 141 | - | |
| 142 | - :param str string: String to colorize. | |
| 143 | - :param bool auto: Enable auto-color (dark/light terminal). | |
| 144 | - | |
| 145 | - :return: Class instance for colorized string. | |
| 146 | - :rtype: Color | |
| 147 | - """ | |
| 148 | - return cls.colorize('bgblue', string, auto=auto) | |
| 149 | - | |
| 150 | - @classmethod | |
| 151 | - def magenta(cls, string, auto=False): | |
| 152 | - """Color-code entire string. | |
| 153 | - | |
| 154 | - :param str string: String to colorize. | |
| 155 | - :param bool auto: Enable auto-color (dark/light terminal). | |
| 156 | - | |
| 157 | - :return: Class instance for colorized string. | |
| 158 | - :rtype: Color | |
| 159 | - """ | |
| 160 | - return cls.colorize('magenta', string, auto=auto) | |
| 161 | - | |
| 162 | - @classmethod | |
| 163 | - def bgmagenta(cls, string, auto=False): | |
| 164 | - """Color-code entire string. | |
| 165 | - | |
| 166 | - :param str string: String to colorize. | |
| 167 | - :param bool auto: Enable auto-color (dark/light terminal). | |
| 168 | - | |
| 169 | - :return: Class instance for colorized string. | |
| 170 | - :rtype: Color | |
| 171 | - """ | |
| 172 | - return cls.colorize('bgmagenta', string, auto=auto) | |
| 173 | - | |
| 174 | - @classmethod | |
| 175 | - def cyan(cls, string, auto=False): | |
| 176 | - """Color-code entire string. | |
| 177 | - | |
| 178 | - :param str string: String to colorize. | |
| 179 | - :param bool auto: Enable auto-color (dark/light terminal). | |
| 180 | - | |
| 181 | - :return: Class instance for colorized string. | |
| 182 | - :rtype: Color | |
| 183 | - """ | |
| 184 | - return cls.colorize('cyan', string, auto=auto) | |
| 185 | - | |
| 186 | - @classmethod | |
| 187 | - def bgcyan(cls, string, auto=False): | |
| 188 | - """Color-code entire string. | |
| 189 | - | |
| 190 | - :param str string: String to colorize. | |
| 191 | - :param bool auto: Enable auto-color (dark/light terminal). | |
| 192 | - | |
| 193 | - :return: Class instance for colorized string. | |
| 194 | - :rtype: Color | |
| 195 | - """ | |
| 196 | - return cls.colorize('bgcyan', string, auto=auto) | |
| 197 | - | |
| 198 | - @classmethod | |
| 199 | - def white(cls, string, auto=False): | |
| 200 | - """Color-code entire string. | |
| 201 | - | |
| 202 | - :param str string: String to colorize. | |
| 203 | - :param bool auto: Enable auto-color (dark/light terminal). | |
| 204 | - | |
| 205 | - :return: Class instance for colorized string. | |
| 206 | - :rtype: Color | |
| 207 | - """ | |
| 208 | - return cls.colorize('white', string, auto=auto) | |
| 209 | - | |
| 210 | - @classmethod | |
| 211 | - def bgwhite(cls, string, auto=False): | |
| 212 | - """Color-code entire string. | |
| 213 | - | |
| 214 | - :param str string: String to colorize. | |
| 215 | - :param bool auto: Enable auto-color (dark/light terminal). | |
| 216 | - | |
| 217 | - :return: Class instance for colorized string. | |
| 218 | - :rtype: Color | |
| 219 | - """ | |
| 220 | - return cls.colorize('bgwhite', string, auto=auto) |
oletools/thirdparty/colorclass/core.py deleted
| 1 | -"""String subclass that handles ANSI color codes.""" | |
| 2 | - | |
| 3 | -from colorclass.codes import ANSICodeMapping | |
| 4 | -from colorclass.parse import parse_input, RE_SPLIT | |
| 5 | -from colorclass.search import build_color_index, find_char_color | |
| 6 | - | |
| 7 | -PARENT_CLASS = type(u'') | |
| 8 | - | |
| 9 | - | |
| 10 | -def apply_text(incoming, func): | |
| 11 | - """Call `func` on text portions of incoming color string. | |
| 12 | - | |
| 13 | - :param iter incoming: Incoming string/ColorStr/string-like object to iterate. | |
| 14 | - :param func: Function to call with string portion as first and only parameter. | |
| 15 | - | |
| 16 | - :return: Modified string, same class type as incoming string. | |
| 17 | - """ | |
| 18 | - split = RE_SPLIT.split(incoming) | |
| 19 | - for i, item in enumerate(split): | |
| 20 | - if not item or RE_SPLIT.match(item): | |
| 21 | - continue | |
| 22 | - split[i] = func(item) | |
| 23 | - return incoming.__class__().join(split) | |
| 24 | - | |
| 25 | - | |
| 26 | -class ColorBytes(bytes): | |
| 27 | - """Str (bytes in Python3) subclass, .decode() overridden to return unicode (str in Python3) subclass instance.""" | |
| 28 | - | |
| 29 | - def __new__(cls, *args, **kwargs): | |
| 30 | - """Save original class so decode() returns an instance of it.""" | |
| 31 | - original_class = kwargs.pop('original_class') | |
| 32 | - combined_args = [cls] + list(args) | |
| 33 | - instance = bytes.__new__(*combined_args, **kwargs) | |
| 34 | - instance.original_class = original_class | |
| 35 | - return instance | |
| 36 | - | |
| 37 | - def decode(self, encoding='utf-8', errors='strict'): | |
| 38 | - """Decode using the codec registered for encoding. Default encoding is 'utf-8'. | |
| 39 | - | |
| 40 | - errors may be given to set a different error handling scheme. Default is 'strict' meaning that encoding errors | |
| 41 | - raise a UnicodeDecodeError. Other possible values are 'ignore' and 'replace' as well as any other name | |
| 42 | - registered with codecs.register_error that is able to handle UnicodeDecodeErrors. | |
| 43 | - | |
| 44 | - :param str encoding: Codec. | |
| 45 | - :param str errors: Error handling scheme. | |
| 46 | - """ | |
| 47 | - original_class = getattr(self, 'original_class') | |
| 48 | - return original_class(super(ColorBytes, self).decode(encoding, errors)) | |
| 49 | - | |
| 50 | - | |
| 51 | -class ColorStr(PARENT_CLASS): | |
| 52 | - """Core color class.""" | |
| 53 | - | |
| 54 | - def __new__(cls, *args, **kwargs): | |
| 55 | - """Parse color markup and instantiate.""" | |
| 56 | - keep_tags = kwargs.pop('keep_tags', False) | |
| 57 | - | |
| 58 | - # Parse string. | |
| 59 | - value_markup = args[0] if args else PARENT_CLASS() # e.g. '{red}test{/red}' | |
| 60 | - value_colors, value_no_colors = parse_input(value_markup, ANSICodeMapping.DISABLE_COLORS, keep_tags) | |
| 61 | - color_index = build_color_index(value_colors) | |
| 62 | - | |
| 63 | - # Instantiate. | |
| 64 | - color_args = [cls, value_colors] + list(args[1:]) | |
| 65 | - instance = PARENT_CLASS.__new__(*color_args, **kwargs) | |
| 66 | - | |
| 67 | - # Add additional attributes and return. | |
| 68 | - instance.value_colors = value_colors | |
| 69 | - instance.value_no_colors = value_no_colors | |
| 70 | - instance.has_colors = value_colors != value_no_colors | |
| 71 | - instance.color_index = color_index | |
| 72 | - return instance | |
| 73 | - | |
| 74 | - def __add__(self, other): | |
| 75 | - """Concatenate.""" | |
| 76 | - return self.__class__(self.value_colors + other, keep_tags=True) | |
| 77 | - | |
| 78 | - def __getitem__(self, item): | |
| 79 | - """Retrieve character.""" | |
| 80 | - try: | |
| 81 | - color_pos = self.color_index[int(item)] | |
| 82 | - except TypeError: # slice | |
| 83 | - return super(ColorStr, self).__getitem__(item) | |
| 84 | - return self.__class__(find_char_color(self.value_colors, color_pos), keep_tags=True) | |
| 85 | - | |
| 86 | - def __iter__(self): | |
| 87 | - """Yield one color-coded character at a time.""" | |
| 88 | - for color_pos in self.color_index: | |
| 89 | - yield self.__class__(find_char_color(self.value_colors, color_pos)) | |
| 90 | - | |
| 91 | - def __len__(self): | |
| 92 | - """Length of string without color codes (what users expect).""" | |
| 93 | - return self.value_no_colors.__len__() | |
| 94 | - | |
| 95 | - def __mod__(self, other): | |
| 96 | - """String substitution (like printf).""" | |
| 97 | - return self.__class__(self.value_colors % other, keep_tags=True) | |
| 98 | - | |
| 99 | - def __mul__(self, other): | |
| 100 | - """Multiply string.""" | |
| 101 | - return self.__class__(self.value_colors * other, keep_tags=True) | |
| 102 | - | |
| 103 | - def __repr__(self): | |
| 104 | - """Representation of a class instance (like datetime.datetime.now()).""" | |
| 105 | - return '{name}({value})'.format(name=self.__class__.__name__, value=repr(self.value_colors)) | |
| 106 | - | |
| 107 | - def capitalize(self): | |
| 108 | - """Return a copy of the string with only its first character capitalized.""" | |
| 109 | - return apply_text(self, lambda s: s.capitalize()) | |
| 110 | - | |
| 111 | - def center(self, width, fillchar=None): | |
| 112 | - """Return centered in a string of length width. Padding is done using the specified fill character or space. | |
| 113 | - | |
| 114 | - :param int width: Length of output string. | |
| 115 | - :param str fillchar: Use this character instead of spaces. | |
| 116 | - """ | |
| 117 | - if fillchar is not None: | |
| 118 | - result = self.value_no_colors.center(width, fillchar) | |
| 119 | - else: | |
| 120 | - result = self.value_no_colors.center(width) | |
| 121 | - return self.__class__(result.replace(self.value_no_colors, self.value_colors), keep_tags=True) | |
| 122 | - | |
| 123 | - def count(self, sub, start=0, end=-1): | |
| 124 | - """Return the number of non-overlapping occurrences of substring sub in string[start:end]. | |
| 125 | - | |
| 126 | - Optional arguments start and end are interpreted as in slice notation. | |
| 127 | - | |
| 128 | - :param str sub: Substring to search. | |
| 129 | - :param int start: Beginning position. | |
| 130 | - :param int end: Stop comparison at this position. | |
| 131 | - """ | |
| 132 | - return self.value_no_colors.count(sub, start, end) | |
| 133 | - | |
| 134 | - def endswith(self, suffix, start=0, end=None): | |
| 135 | - """Return True if ends with the specified suffix, False otherwise. | |
| 136 | - | |
| 137 | - With optional start, test beginning at that position. With optional end, stop comparing at that position. | |
| 138 | - suffix can also be a tuple of strings to try. | |
| 139 | - | |
| 140 | - :param str suffix: Suffix to search. | |
| 141 | - :param int start: Beginning position. | |
| 142 | - :param int end: Stop comparison at this position. | |
| 143 | - """ | |
| 144 | - args = [suffix, start] + ([] if end is None else [end]) | |
| 145 | - return self.value_no_colors.endswith(*args) | |
| 146 | - | |
| 147 | - def encode(self, encoding=None, errors='strict'): | |
| 148 | - """Encode using the codec registered for encoding. encoding defaults to the default encoding. | |
| 149 | - | |
| 150 | - errors may be given to set a different error handling scheme. Default is 'strict' meaning that encoding errors | |
| 151 | - raise a UnicodeEncodeError. Other possible values are 'ignore', 'replace' and 'xmlcharrefreplace' as well as any | |
| 152 | - other name registered with codecs.register_error that is able to handle UnicodeEncodeErrors. | |
| 153 | - | |
| 154 | - :param str encoding: Codec. | |
| 155 | - :param str errors: Error handling scheme. | |
| 156 | - """ | |
| 157 | - return ColorBytes(super(ColorStr, self).encode(encoding, errors), original_class=self.__class__) | |
| 158 | - | |
| 159 | - def decode(self, encoding=None, errors='strict'): | |
| 160 | - """Decode using the codec registered for encoding. encoding defaults to the default encoding. | |
| 161 | - | |
| 162 | - errors may be given to set a different error handling scheme. Default is 'strict' meaning that encoding errors | |
| 163 | - raise a UnicodeDecodeError. Other possible values are 'ignore' and 'replace' as well as any other name | |
| 164 | - registered with codecs.register_error that is able to handle UnicodeDecodeErrors. | |
| 165 | - | |
| 166 | - :param str encoding: Codec. | |
| 167 | - :param str errors: Error handling scheme. | |
| 168 | - """ | |
| 169 | - return self.__class__(super(ColorStr, self).decode(encoding, errors), keep_tags=True) | |
| 170 | - | |
| 171 | - def find(self, sub, start=None, end=None): | |
| 172 | - """Return the lowest index where substring sub is found, such that sub is contained within string[start:end]. | |
| 173 | - | |
| 174 | - Optional arguments start and end are interpreted as in slice notation. | |
| 175 | - | |
| 176 | - :param str sub: Substring to search. | |
| 177 | - :param int start: Beginning position. | |
| 178 | - :param int end: Stop comparison at this position. | |
| 179 | - """ | |
| 180 | - return self.value_no_colors.find(sub, start, end) | |
| 181 | - | |
| 182 | - def format(self, *args, **kwargs): | |
| 183 | - """Return a formatted version, using substitutions from args and kwargs. | |
| 184 | - | |
| 185 | - The substitutions are identified by braces ('{' and '}'). | |
| 186 | - """ | |
| 187 | - return self.__class__(super(ColorStr, self).format(*args, **kwargs), keep_tags=True) | |
| 188 | - | |
| 189 | - def index(self, sub, start=None, end=None): | |
| 190 | - """Like S.find() but raise ValueError when the substring is not found. | |
| 191 | - | |
| 192 | - :param str sub: Substring to search. | |
| 193 | - :param int start: Beginning position. | |
| 194 | - :param int end: Stop comparison at this position. | |
| 195 | - """ | |
| 196 | - return self.value_no_colors.index(sub, start, end) | |
| 197 | - | |
| 198 | - def isalnum(self): | |
| 199 | - """Return True if all characters in string are alphanumeric and there is at least one character in it.""" | |
| 200 | - return self.value_no_colors.isalnum() | |
| 201 | - | |
| 202 | - def isalpha(self): | |
| 203 | - """Return True if all characters in string are alphabetic and there is at least one character in it.""" | |
| 204 | - return self.value_no_colors.isalpha() | |
| 205 | - | |
| 206 | - def isdecimal(self): | |
| 207 | - """Return True if there are only decimal characters in string, False otherwise.""" | |
| 208 | - return self.value_no_colors.isdecimal() | |
| 209 | - | |
| 210 | - def isdigit(self): | |
| 211 | - """Return True if all characters in string are digits and there is at least one character in it.""" | |
| 212 | - return self.value_no_colors.isdigit() | |
| 213 | - | |
| 214 | - def isnumeric(self): | |
| 215 | - """Return True if there are only numeric characters in string, False otherwise.""" | |
| 216 | - return self.value_no_colors.isnumeric() | |
| 217 | - | |
| 218 | - def isspace(self): | |
| 219 | - """Return True if all characters in string are whitespace and there is at least one character in it.""" | |
| 220 | - return self.value_no_colors.isspace() | |
| 221 | - | |
| 222 | - def istitle(self): | |
| 223 | - """Return True if string is a titlecased string and there is at least one character in it. | |
| 224 | - | |
| 225 | - That is uppercase characters may only follow uncased characters and lowercase characters only cased ones. Return | |
| 226 | - False otherwise. | |
| 227 | - """ | |
| 228 | - return self.value_no_colors.istitle() | |
| 229 | - | |
| 230 | - def isupper(self): | |
| 231 | - """Return True if all cased characters are uppercase and there is at least one cased character in it.""" | |
| 232 | - return self.value_no_colors.isupper() | |
| 233 | - | |
| 234 | - def join(self, iterable): | |
| 235 | - """Return a string which is the concatenation of the strings in the iterable. | |
| 236 | - | |
| 237 | - :param iterable: Join items in this iterable. | |
| 238 | - """ | |
| 239 | - return self.__class__(super(ColorStr, self).join(iterable), keep_tags=True) | |
| 240 | - | |
| 241 | - def ljust(self, width, fillchar=None): | |
| 242 | - """Return left-justified string of length width. Padding is done using the specified fill character or space. | |
| 243 | - | |
| 244 | - :param int width: Length of output string. | |
| 245 | - :param str fillchar: Use this character instead of spaces. | |
| 246 | - """ | |
| 247 | - if fillchar is not None: | |
| 248 | - result = self.value_no_colors.ljust(width, fillchar) | |
| 249 | - else: | |
| 250 | - result = self.value_no_colors.ljust(width) | |
| 251 | - return self.__class__(result.replace(self.value_no_colors, self.value_colors), keep_tags=True) | |
| 252 | - | |
| 253 | - def rfind(self, sub, start=None, end=None): | |
| 254 | - """Return the highest index where substring sub is found, such that sub is contained within string[start:end]. | |
| 255 | - | |
| 256 | - Optional arguments start and end are interpreted as in slice notation. | |
| 257 | - | |
| 258 | - :param str sub: Substring to search. | |
| 259 | - :param int start: Beginning position. | |
| 260 | - :param int end: Stop comparison at this position. | |
| 261 | - """ | |
| 262 | - return self.value_no_colors.rfind(sub, start, end) | |
| 263 | - | |
| 264 | - def rindex(self, sub, start=None, end=None): | |
| 265 | - """Like .rfind() but raise ValueError when the substring is not found. | |
| 266 | - | |
| 267 | - :param str sub: Substring to search. | |
| 268 | - :param int start: Beginning position. | |
| 269 | - :param int end: Stop comparison at this position. | |
| 270 | - """ | |
| 271 | - return self.value_no_colors.rindex(sub, start, end) | |
| 272 | - | |
| 273 | - def rjust(self, width, fillchar=None): | |
| 274 | - """Return right-justified string of length width. Padding is done using the specified fill character or space. | |
| 275 | - | |
| 276 | - :param int width: Length of output string. | |
| 277 | - :param str fillchar: Use this character instead of spaces. | |
| 278 | - """ | |
| 279 | - if fillchar is not None: | |
| 280 | - result = self.value_no_colors.rjust(width, fillchar) | |
| 281 | - else: | |
| 282 | - result = self.value_no_colors.rjust(width) | |
| 283 | - return self.__class__(result.replace(self.value_no_colors, self.value_colors), keep_tags=True) | |
| 284 | - | |
| 285 | - def splitlines(self, keepends=False): | |
| 286 | - """Return a list of the lines in the string, breaking at line boundaries. | |
| 287 | - | |
| 288 | - Line breaks are not included in the resulting list unless keepends is given and True. | |
| 289 | - | |
| 290 | - :param bool keepends: Include linebreaks. | |
| 291 | - """ | |
| 292 | - return [self.__class__(l) for l in self.value_colors.splitlines(keepends)] | |
| 293 | - | |
| 294 | - def startswith(self, prefix, start=0, end=-1): | |
| 295 | - """Return True if string starts with the specified prefix, False otherwise. | |
| 296 | - | |
| 297 | - With optional start, test beginning at that position. With optional end, stop comparing at that position. prefix | |
| 298 | - can also be a tuple of strings to try. | |
| 299 | - | |
| 300 | - :param str prefix: Prefix to search. | |
| 301 | - :param int start: Beginning position. | |
| 302 | - :param int end: Stop comparison at this position. | |
| 303 | - """ | |
| 304 | - return self.value_no_colors.startswith(prefix, start, end) | |
| 305 | - | |
| 306 | - def swapcase(self): | |
| 307 | - """Return a copy of the string with uppercase characters converted to lowercase and vice versa.""" | |
| 308 | - return apply_text(self, lambda s: s.swapcase()) | |
| 309 | - | |
| 310 | - def title(self): | |
| 311 | - """Return a titlecased version of the string. | |
| 312 | - | |
| 313 | - That is words start with uppercase characters, all remaining cased characters have lowercase. | |
| 314 | - """ | |
| 315 | - return apply_text(self, lambda s: s.title()) | |
| 316 | - | |
| 317 | - def translate(self, table): | |
| 318 | - """Return a copy of the string, where all characters have been mapped through the given translation table. | |
| 319 | - | |
| 320 | - Table must be a mapping of Unicode ordinals to Unicode ordinals, strings, or None. Unmapped characters are left | |
| 321 | - untouched. Characters mapped to None are deleted. | |
| 322 | - | |
| 323 | - :param table: Translation table. | |
| 324 | - """ | |
| 325 | - return apply_text(self, lambda s: s.translate(table)) | |
| 326 | - | |
| 327 | - def upper(self): | |
| 328 | - """Return a copy of the string converted to uppercase.""" | |
| 329 | - return apply_text(self, lambda s: s.upper()) | |
| 330 | - | |
| 331 | - def zfill(self, width): | |
| 332 | - """Pad a numeric string with zeros on the left, to fill a field of the specified width. | |
| 333 | - | |
| 334 | - The string is never truncated. | |
| 335 | - | |
| 336 | - :param int width: Length of output string. | |
| 337 | - """ | |
| 338 | - if not self.value_no_colors: | |
| 339 | - result = self.value_no_colors.zfill(width) | |
| 340 | - else: | |
| 341 | - result = self.value_colors.replace(self.value_no_colors, self.value_no_colors.zfill(width)) | |
| 342 | - return self.__class__(result, keep_tags=True) |
oletools/thirdparty/colorclass/parse.py deleted
| 1 | -"""Parse color markup tags into ANSI escape sequences.""" | |
| 2 | - | |
| 3 | -import re | |
| 4 | - | |
| 5 | -from colorclass.codes import ANSICodeMapping, BASE_CODES | |
| 6 | - | |
| 7 | -CODE_GROUPS = ( | |
| 8 | - tuple(set(str(i) for i in BASE_CODES.values() if i and (40 <= i <= 49 or 100 <= i <= 109))), # bg colors | |
| 9 | - tuple(set(str(i) for i in BASE_CODES.values() if i and (30 <= i <= 39 or 90 <= i <= 99))), # fg colors | |
| 10 | - ('1', '22'), ('2', '22'), ('3', '23'), ('4', '24'), ('5', '25'), ('6', '26'), ('7', '27'), ('8', '28'), ('9', '29'), | |
| 11 | -) | |
| 12 | -RE_ANSI = re.compile(r'(\033\[([\d;]+)m)') | |
| 13 | -RE_COMBINE = re.compile(r'\033\[([\d;]+)m\033\[([\d;]+)m') | |
| 14 | -RE_SPLIT = re.compile(r'(\033\[[\d;]+m)') | |
| 15 | - | |
| 16 | - | |
| 17 | -def prune_overridden(ansi_string): | |
| 18 | - """Remove color codes that are rendered ineffective by subsequent codes in one escape sequence then sort codes. | |
| 19 | - | |
| 20 | - :param str ansi_string: Incoming ansi_string with ANSI color codes. | |
| 21 | - | |
| 22 | - :return: Color string with pruned color sequences. | |
| 23 | - :rtype: str | |
| 24 | - """ | |
| 25 | - multi_seqs = set(p for p in RE_ANSI.findall(ansi_string) if ';' in p[1]) # Sequences with multiple color codes. | |
| 26 | - | |
| 27 | - for escape, codes in multi_seqs: | |
| 28 | - r_codes = list(reversed(codes.split(';'))) | |
| 29 | - | |
| 30 | - # Nuke everything before {/all}. | |
| 31 | - try: | |
| 32 | - r_codes = r_codes[:r_codes.index('0') + 1] | |
| 33 | - except ValueError: | |
| 34 | - pass | |
| 35 | - | |
| 36 | - # Thin out groups. | |
| 37 | - for group in CODE_GROUPS: | |
| 38 | - for pos in reversed([i for i, n in enumerate(r_codes) if n in group][1:]): | |
| 39 | - r_codes.pop(pos) | |
| 40 | - | |
| 41 | - # Done. | |
| 42 | - reduced_codes = ';'.join(sorted(r_codes, key=int)) | |
| 43 | - if codes != reduced_codes: | |
| 44 | - ansi_string = ansi_string.replace(escape, '\033[' + reduced_codes + 'm') | |
| 45 | - | |
| 46 | - return ansi_string | |
| 47 | - | |
| 48 | - | |
| 49 | -def parse_input(tagged_string, disable_colors, keep_tags): | |
| 50 | - """Perform the actual conversion of tags to ANSI escaped codes. | |
| 51 | - | |
| 52 | - Provides a version of the input without any colors for len() and other methods. | |
| 53 | - | |
| 54 | - :param str tagged_string: The input unicode value. | |
| 55 | - :param bool disable_colors: Strip all colors in both outputs. | |
| 56 | - :param bool keep_tags: Skip parsing curly bracket tags into ANSI escape sequences. | |
| 57 | - | |
| 58 | - :return: 2-item tuple. First item is the parsed output. Second item is a version of the input without any colors. | |
| 59 | - :rtype: tuple | |
| 60 | - """ | |
| 61 | - codes = ANSICodeMapping(tagged_string) | |
| 62 | - output_colors = getattr(tagged_string, 'value_colors', tagged_string) | |
| 63 | - | |
| 64 | - # Convert: '{b}{red}' -> '\033[1m\033[31m' | |
| 65 | - if not keep_tags: | |
| 66 | - for tag, replacement in (('{' + k + '}', '' if v is None else '\033[%dm' % v) for k, v in codes.items()): | |
| 67 | - output_colors = output_colors.replace(tag, replacement) | |
| 68 | - | |
| 69 | - # Strip colors. | |
| 70 | - output_no_colors = RE_ANSI.sub('', output_colors) | |
| 71 | - if disable_colors: | |
| 72 | - return output_no_colors, output_no_colors | |
| 73 | - | |
| 74 | - # Combine: '\033[1m\033[31m' -> '\033[1;31m' | |
| 75 | - while True: | |
| 76 | - simplified = RE_COMBINE.sub(r'\033[\1;\2m', output_colors) | |
| 77 | - if simplified == output_colors: | |
| 78 | - break | |
| 79 | - output_colors = simplified | |
| 80 | - | |
| 81 | - # Prune: '\033[31;32;33;34;35m' -> '\033[35m' | |
| 82 | - output_colors = prune_overridden(output_colors) | |
| 83 | - | |
| 84 | - # Deduplicate: '\033[1;mT\033[1;mE\033[1;mS\033[1;mT' -> '\033[1;mTEST' | |
| 85 | - previous_escape = None | |
| 86 | - segments = list() | |
| 87 | - for item in (i for i in RE_SPLIT.split(output_colors) if i): | |
| 88 | - if RE_SPLIT.match(item): | |
| 89 | - if item != previous_escape: | |
| 90 | - segments.append(item) | |
| 91 | - previous_escape = item | |
| 92 | - else: | |
| 93 | - segments.append(item) | |
| 94 | - output_colors = ''.join(segments) | |
| 95 | - | |
| 96 | - return output_colors, output_no_colors |
oletools/thirdparty/colorclass/search.py deleted
| 1 | -"""Determine color of characters that may or may not be adjacent to ANSI escape sequences.""" | |
| 2 | - | |
| 3 | -from colorclass.parse import RE_SPLIT | |
| 4 | - | |
| 5 | - | |
| 6 | -def build_color_index(ansi_string): | |
| 7 | - """Build an index between visible characters and a string with invisible color codes. | |
| 8 | - | |
| 9 | - :param str ansi_string: String with color codes (ANSI escape sequences). | |
| 10 | - | |
| 11 | - :return: Position of visible characters in color string (indexes match non-color string). | |
| 12 | - :rtype: tuple | |
| 13 | - """ | |
| 14 | - mapping = list() | |
| 15 | - color_offset = 0 | |
| 16 | - for item in (i for i in RE_SPLIT.split(ansi_string) if i): | |
| 17 | - if RE_SPLIT.match(item): | |
| 18 | - color_offset += len(item) | |
| 19 | - else: | |
| 20 | - for _ in range(len(item)): | |
| 21 | - mapping.append(color_offset) | |
| 22 | - color_offset += 1 | |
| 23 | - return tuple(mapping) | |
| 24 | - | |
| 25 | - | |
| 26 | -def find_char_color(ansi_string, pos): | |
| 27 | - """Determine what color a character is in the string. | |
| 28 | - | |
| 29 | - :param str ansi_string: String with color codes (ANSI escape sequences). | |
| 30 | - :param int pos: Position of the character in the ansi_string. | |
| 31 | - | |
| 32 | - :return: Character along with all surrounding color codes. | |
| 33 | - :rtype: str | |
| 34 | - """ | |
| 35 | - result = list() | |
| 36 | - position = 0 # Set to None when character is found. | |
| 37 | - for item in (i for i in RE_SPLIT.split(ansi_string) if i): | |
| 38 | - if RE_SPLIT.match(item): | |
| 39 | - result.append(item) | |
| 40 | - if position is not None: | |
| 41 | - position += len(item) | |
| 42 | - elif position is not None: | |
| 43 | - for char in item: | |
| 44 | - if position == pos: | |
| 45 | - result.append(char) | |
| 46 | - position = None | |
| 47 | - break | |
| 48 | - position += 1 | |
| 49 | - return ''.join(result) |
oletools/thirdparty/colorclass/toggles.py deleted
| 1 | -"""Convenience functions to enable/disable features.""" | |
| 2 | - | |
| 3 | -from colorclass.codes import ANSICodeMapping | |
| 4 | - | |
| 5 | - | |
| 6 | -def disable_all_colors(): | |
| 7 | - """Disable all colors. Strip any color tags or codes.""" | |
| 8 | - ANSICodeMapping.disable_all_colors() | |
| 9 | - | |
| 10 | - | |
| 11 | -def enable_all_colors(): | |
| 12 | - """Enable colors.""" | |
| 13 | - ANSICodeMapping.enable_all_colors() | |
| 14 | - | |
| 15 | - | |
| 16 | -def disable_if_no_tty(): | |
| 17 | - """Disable all colors if there is no TTY available. | |
| 18 | - | |
| 19 | - :return: True if colors are disabled, False if stderr or stdout is a TTY. | |
| 20 | - :rtype: bool | |
| 21 | - """ | |
| 22 | - return ANSICodeMapping.disable_if_no_tty() | |
| 23 | - | |
| 24 | - | |
| 25 | -def is_enabled(): | |
| 26 | - """Are colors enabled.""" | |
| 27 | - return not ANSICodeMapping.DISABLE_COLORS | |
| 28 | - | |
| 29 | - | |
| 30 | -def set_light_background(): | |
| 31 | - """Choose dark colors for all 'auto'-prefixed codes for readability on light backgrounds.""" | |
| 32 | - ANSICodeMapping.set_light_background() | |
| 33 | - | |
| 34 | - | |
| 35 | -def set_dark_background(): | |
| 36 | - """Choose dark colors for all 'auto'-prefixed codes for readability on light backgrounds.""" | |
| 37 | - ANSICodeMapping.set_dark_background() | |
| 38 | - | |
| 39 | - | |
| 40 | -def is_light(): | |
| 41 | - """Are background colors for light backgrounds.""" | |
| 42 | - return ANSICodeMapping.LIGHT_BACKGROUND |
oletools/thirdparty/colorclass/windows.py deleted
| 1 | -"""Windows console screen buffer handlers.""" | |
| 2 | - | |
| 3 | -from __future__ import print_function | |
| 4 | - | |
| 5 | -import atexit | |
| 6 | -import ctypes | |
| 7 | -import re | |
| 8 | -import sys | |
| 9 | - | |
| 10 | -from colorclass.codes import ANSICodeMapping, BASE_CODES | |
| 11 | -from colorclass.core import RE_SPLIT | |
| 12 | - | |
| 13 | -ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004 | |
| 14 | -INVALID_HANDLE_VALUE = -1 | |
| 15 | -IS_WINDOWS = sys.platform == 'win32' | |
| 16 | -RE_NUMBER_SEARCH = re.compile(r'\033\[([\d;]+)m') | |
| 17 | -STD_ERROR_HANDLE = -12 | |
| 18 | -STD_OUTPUT_HANDLE = -11 | |
| 19 | -WINDOWS_CODES = { | |
| 20 | - '/all': -33, '/fg': -39, '/bg': -49, | |
| 21 | - | |
| 22 | - 'black': 0, 'red': 4, 'green': 2, 'yellow': 6, 'blue': 1, 'magenta': 5, 'cyan': 3, 'white': 7, | |
| 23 | - | |
| 24 | - 'bgblack': -8, 'bgred': 64, 'bggreen': 32, 'bgyellow': 96, 'bgblue': 16, 'bgmagenta': 80, 'bgcyan': 48, | |
| 25 | - 'bgwhite': 112, | |
| 26 | - | |
| 27 | - 'hiblack': 8, 'hired': 12, 'higreen': 10, 'hiyellow': 14, 'hiblue': 9, 'himagenta': 13, 'hicyan': 11, 'hiwhite': 15, | |
| 28 | - | |
| 29 | - 'hibgblack': 128, 'hibgred': 192, 'hibggreen': 160, 'hibgyellow': 224, 'hibgblue': 144, 'hibgmagenta': 208, | |
| 30 | - 'hibgcyan': 176, 'hibgwhite': 240, | |
| 31 | - | |
| 32 | - '/black': -39, '/red': -39, '/green': -39, '/yellow': -39, '/blue': -39, '/magenta': -39, '/cyan': -39, | |
| 33 | - '/white': -39, '/hiblack': -39, '/hired': -39, '/higreen': -39, '/hiyellow': -39, '/hiblue': -39, '/himagenta': -39, | |
| 34 | - '/hicyan': -39, '/hiwhite': -39, | |
| 35 | - | |
| 36 | - '/bgblack': -49, '/bgred': -49, '/bggreen': -49, '/bgyellow': -49, '/bgblue': -49, '/bgmagenta': -49, | |
| 37 | - '/bgcyan': -49, '/bgwhite': -49, '/hibgblack': -49, '/hibgred': -49, '/hibggreen': -49, '/hibgyellow': -49, | |
| 38 | - '/hibgblue': -49, '/hibgmagenta': -49, '/hibgcyan': -49, '/hibgwhite': -49, | |
| 39 | -} | |
| 40 | - | |
| 41 | - | |
| 42 | -class COORD(ctypes.Structure): | |
| 43 | - """COORD structure. http://msdn.microsoft.com/en-us/library/windows/desktop/ms682119.""" | |
| 44 | - | |
| 45 | - _fields_ = [ | |
| 46 | - ('X', ctypes.c_short), | |
| 47 | - ('Y', ctypes.c_short), | |
| 48 | - ] | |
| 49 | - | |
| 50 | - | |
| 51 | -class SmallRECT(ctypes.Structure): | |
| 52 | - """SMALL_RECT structure. http://msdn.microsoft.com/en-us/library/windows/desktop/ms686311.""" | |
| 53 | - | |
| 54 | - _fields_ = [ | |
| 55 | - ('Left', ctypes.c_short), | |
| 56 | - ('Top', ctypes.c_short), | |
| 57 | - ('Right', ctypes.c_short), | |
| 58 | - ('Bottom', ctypes.c_short), | |
| 59 | - ] | |
| 60 | - | |
| 61 | - | |
| 62 | -class ConsoleScreenBufferInfo(ctypes.Structure): | |
| 63 | - """CONSOLE_SCREEN_BUFFER_INFO structure. http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093.""" | |
| 64 | - | |
| 65 | - _fields_ = [ | |
| 66 | - ('dwSize', COORD), | |
| 67 | - ('dwCursorPosition', COORD), | |
| 68 | - ('wAttributes', ctypes.c_ushort), | |
| 69 | - ('srWindow', SmallRECT), | |
| 70 | - ('dwMaximumWindowSize', COORD) | |
| 71 | - ] | |
| 72 | - | |
| 73 | - | |
| 74 | -def init_kernel32(kernel32=None): | |
| 75 | - """Load a unique instance of WinDLL into memory, set arg/return types, and get stdout/err handles. | |
| 76 | - | |
| 77 | - 1. Since we are setting DLL function argument types and return types, we need to maintain our own instance of | |
| 78 | - kernel32 to prevent overriding (or being overwritten by) user's own changes to ctypes.windll.kernel32. | |
| 79 | - 2. While we're doing all this we might as well get the handles to STDOUT and STDERR streams. | |
| 80 | - 3. If either stream has already been replaced set return value to INVALID_HANDLE_VALUE to indicate it shouldn't be | |
| 81 | - replaced. | |
| 82 | - | |
| 83 | - :raise AttributeError: When called on a non-Windows platform. | |
| 84 | - | |
| 85 | - :param kernel32: Optional mock kernel32 object. For testing. | |
| 86 | - | |
| 87 | - :return: Loaded kernel32 instance, stderr handle (int), stdout handle (int). | |
| 88 | - :rtype: tuple | |
| 89 | - """ | |
| 90 | - if not kernel32: | |
| 91 | - kernel32 = ctypes.LibraryLoader(ctypes.WinDLL).kernel32 # Load our own instance. Unique memory address. | |
| 92 | - kernel32.GetStdHandle.argtypes = [ctypes.c_ulong] | |
| 93 | - kernel32.GetStdHandle.restype = ctypes.c_void_p | |
| 94 | - kernel32.GetConsoleScreenBufferInfo.argtypes = [ | |
| 95 | - ctypes.c_void_p, | |
| 96 | - ctypes.POINTER(ConsoleScreenBufferInfo), | |
| 97 | - ] | |
| 98 | - kernel32.GetConsoleScreenBufferInfo.restype = ctypes.c_long | |
| 99 | - | |
| 100 | - # Get handles. | |
| 101 | - if hasattr(sys.stderr, '_original_stream'): | |
| 102 | - stderr = INVALID_HANDLE_VALUE | |
| 103 | - else: | |
| 104 | - stderr = kernel32.GetStdHandle(STD_ERROR_HANDLE) | |
| 105 | - if hasattr(sys.stdout, '_original_stream'): | |
| 106 | - stdout = INVALID_HANDLE_VALUE | |
| 107 | - else: | |
| 108 | - stdout = kernel32.GetStdHandle(STD_OUTPUT_HANDLE) | |
| 109 | - | |
| 110 | - return kernel32, stderr, stdout | |
| 111 | - | |
| 112 | - | |
| 113 | -def get_console_info(kernel32, handle): | |
| 114 | - """Get information about this current console window. | |
| 115 | - | |
| 116 | - http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231 | |
| 117 | - https://code.google.com/p/colorama/issues/detail?id=47 | |
| 118 | - https://bitbucket.org/pytest-dev/py/src/4617fe46/py/_io/terminalwriter.py | |
| 119 | - | |
| 120 | - Windows 10 Insider since around February 2016 finally introduced support for ANSI colors. No need to replace stdout | |
| 121 | - and stderr streams to intercept colors and issue multiple SetConsoleTextAttribute() calls for these consoles. | |
| 122 | - | |
| 123 | - :raise OSError: When GetConsoleScreenBufferInfo or GetConsoleMode API calls fail. | |
| 124 | - | |
| 125 | - :param ctypes.windll.kernel32 kernel32: Loaded kernel32 instance. | |
| 126 | - :param int handle: stderr or stdout handle. | |
| 127 | - | |
| 128 | - :return: Foreground and background colors (integers) as well as native ANSI support (bool). | |
| 129 | - :rtype: tuple | |
| 130 | - """ | |
| 131 | - # Query Win32 API. | |
| 132 | - csbi = ConsoleScreenBufferInfo() # Populated by GetConsoleScreenBufferInfo. | |
| 133 | - lpcsbi = ctypes.byref(csbi) | |
| 134 | - dword = ctypes.c_ulong() # Populated by GetConsoleMode. | |
| 135 | - lpdword = ctypes.byref(dword) | |
| 136 | - if not kernel32.GetConsoleScreenBufferInfo(handle, lpcsbi) or not kernel32.GetConsoleMode(handle, lpdword): | |
| 137 | - raise ctypes.WinError() | |
| 138 | - | |
| 139 | - # Parse data. | |
| 140 | - # buffer_width = int(csbi.dwSize.X - 1) | |
| 141 | - # buffer_height = int(csbi.dwSize.Y) | |
| 142 | - # terminal_width = int(csbi.srWindow.Right - csbi.srWindow.Left) | |
| 143 | - # terminal_height = int(csbi.srWindow.Bottom - csbi.srWindow.Top) | |
| 144 | - fg_color = csbi.wAttributes % 16 | |
| 145 | - bg_color = csbi.wAttributes & 240 | |
| 146 | - native_ansi = bool(dword.value & ENABLE_VIRTUAL_TERMINAL_PROCESSING) | |
| 147 | - | |
| 148 | - return fg_color, bg_color, native_ansi | |
| 149 | - | |
| 150 | - | |
| 151 | -def bg_color_native_ansi(kernel32, stderr, stdout): | |
| 152 | - """Get background color and if console supports ANSI colors natively for both streams. | |
| 153 | - | |
| 154 | - :param ctypes.windll.kernel32 kernel32: Loaded kernel32 instance. | |
| 155 | - :param int stderr: stderr handle. | |
| 156 | - :param int stdout: stdout handle. | |
| 157 | - | |
| 158 | - :return: Background color (int) and native ANSI support (bool). | |
| 159 | - :rtype: tuple | |
| 160 | - """ | |
| 161 | - try: | |
| 162 | - if stderr == INVALID_HANDLE_VALUE: | |
| 163 | - raise OSError | |
| 164 | - bg_color, native_ansi = get_console_info(kernel32, stderr)[1:] | |
| 165 | - except OSError: | |
| 166 | - try: | |
| 167 | - if stdout == INVALID_HANDLE_VALUE: | |
| 168 | - raise OSError | |
| 169 | - bg_color, native_ansi = get_console_info(kernel32, stdout)[1:] | |
| 170 | - except OSError: | |
| 171 | - bg_color, native_ansi = WINDOWS_CODES['black'], False | |
| 172 | - return bg_color, native_ansi | |
| 173 | - | |
| 174 | - | |
| 175 | -class WindowsStream(object): | |
| 176 | - """Replacement stream which overrides sys.stdout or sys.stderr. When writing or printing, ANSI codes are converted. | |
| 177 | - | |
| 178 | - ANSI (Linux/Unix) color codes are converted into win32 system calls, changing the next character's color before | |
| 179 | - printing it. Resources referenced: | |
| 180 | - https://github.com/tartley/colorama | |
| 181 | - http://www.cplusplus.com/articles/2ywTURfi/ | |
| 182 | - http://thomasfischer.biz/python-and-windows-terminal-colors/ | |
| 183 | - http://stackoverflow.com/questions/17125440/c-win32-console-color | |
| 184 | - http://www.tysos.org/svn/trunk/mono/corlib/System/WindowsConsoleDriver.cs | |
| 185 | - http://stackoverflow.com/questions/287871/print-in-terminal-with-colors-using-python | |
| 186 | - http://msdn.microsoft.com/en-us/library/windows/desktop/ms682088#_win32_character_attributes | |
| 187 | - | |
| 188 | - :cvar list ALL_BG_CODES: List of bg Windows codes. Used to determine if requested color is foreground or background. | |
| 189 | - :cvar dict COMPILED_CODES: Translation dict. Keys are ANSI codes (values of BASE_CODES), values are Windows codes. | |
| 190 | - :ivar int default_fg: Foreground Windows color code at the time of instantiation. | |
| 191 | - :ivar int default_bg: Background Windows color code at the time of instantiation. | |
| 192 | - """ | |
| 193 | - | |
| 194 | - ALL_BG_CODES = [v for k, v in WINDOWS_CODES.items() if k.startswith('bg') or k.startswith('hibg')] | |
| 195 | - COMPILED_CODES = dict((v, WINDOWS_CODES[k]) for k, v in BASE_CODES.items() if k in WINDOWS_CODES) | |
| 196 | - | |
| 197 | - def __init__(self, kernel32, stream_handle, original_stream): | |
| 198 | - """Constructor. | |
| 199 | - | |
| 200 | - :param ctypes.windll.kernel32 kernel32: Loaded kernel32 instance. | |
| 201 | - :param int stream_handle: stderr or stdout handle. | |
| 202 | - :param original_stream: sys.stderr or sys.stdout before being overridden by this class' instance. | |
| 203 | - """ | |
| 204 | - self._kernel32 = kernel32 | |
| 205 | - self._stream_handle = stream_handle | |
| 206 | - self._original_stream = original_stream | |
| 207 | - self.default_fg, self.default_bg = self.colors | |
| 208 | - | |
| 209 | - def __getattr__(self, item): | |
| 210 | - """If an attribute/function/etc is not defined in this function, retrieve the one from the original stream. | |
| 211 | - | |
| 212 | - Fixes ipython arrow key presses. | |
| 213 | - """ | |
| 214 | - return getattr(self._original_stream, item) | |
| 215 | - | |
| 216 | - @property | |
| 217 | - def colors(self): | |
| 218 | - """Return the current foreground and background colors.""" | |
| 219 | - try: | |
| 220 | - return get_console_info(self._kernel32, self._stream_handle)[:2] | |
| 221 | - except OSError: | |
| 222 | - return WINDOWS_CODES['white'], WINDOWS_CODES['black'] | |
| 223 | - | |
| 224 | - @colors.setter | |
| 225 | - def colors(self, color_code): | |
| 226 | - """Change the foreground and background colors for subsequently printed characters. | |
| 227 | - | |
| 228 | - None resets colors to their original values (when class was instantiated). | |
| 229 | - | |
| 230 | - Since setting a color requires including both foreground and background codes (merged), setting just the | |
| 231 | - foreground color resets the background color to black, and vice versa. | |
| 232 | - | |
| 233 | - This function first gets the current background and foreground colors, merges in the requested color code, and | |
| 234 | - sets the result. | |
| 235 | - | |
| 236 | - However if we need to remove just the foreground color but leave the background color the same (or vice versa) | |
| 237 | - such as when {/red} is used, we must merge the default foreground color with the current background color. This | |
| 238 | - is the reason for those negative values. | |
| 239 | - | |
| 240 | - :param int color_code: Color code from WINDOWS_CODES. | |
| 241 | - """ | |
| 242 | - if color_code is None: | |
| 243 | - color_code = WINDOWS_CODES['/all'] | |
| 244 | - | |
| 245 | - # Get current color code. | |
| 246 | - current_fg, current_bg = self.colors | |
| 247 | - | |
| 248 | - # Handle special negative codes. Also determine the final color code. | |
| 249 | - if color_code == WINDOWS_CODES['/fg']: | |
| 250 | - final_color_code = self.default_fg | current_bg # Reset the foreground only. | |
| 251 | - elif color_code == WINDOWS_CODES['/bg']: | |
| 252 | - final_color_code = current_fg | self.default_bg # Reset the background only. | |
| 253 | - elif color_code == WINDOWS_CODES['/all']: | |
| 254 | - final_color_code = self.default_fg | self.default_bg # Reset both. | |
| 255 | - elif color_code == WINDOWS_CODES['bgblack']: | |
| 256 | - final_color_code = current_fg # Black background. | |
| 257 | - else: | |
| 258 | - new_is_bg = color_code in self.ALL_BG_CODES | |
| 259 | - final_color_code = color_code | (current_fg if new_is_bg else current_bg) | |
| 260 | - | |
| 261 | - # Set new code. | |
| 262 | - self._kernel32.SetConsoleTextAttribute(self._stream_handle, final_color_code) | |
| 263 | - | |
| 264 | - def write(self, p_str): | |
| 265 | - """Write to stream. | |
| 266 | - | |
| 267 | - :param str p_str: string to print. | |
| 268 | - """ | |
| 269 | - for segment in RE_SPLIT.split(p_str): | |
| 270 | - if not segment: | |
| 271 | - # Empty string. p_str probably starts with colors so the first item is always ''. | |
| 272 | - continue | |
| 273 | - if not RE_SPLIT.match(segment): | |
| 274 | - # No color codes, print regular text. | |
| 275 | - print(segment, file=self._original_stream, end='') | |
| 276 | - self._original_stream.flush() | |
| 277 | - continue | |
| 278 | - for color_code in (int(c) for c in RE_NUMBER_SEARCH.findall(segment)[0].split(';')): | |
| 279 | - if color_code in self.COMPILED_CODES: | |
| 280 | - self.colors = self.COMPILED_CODES[color_code] | |
| 281 | - | |
| 282 | - | |
| 283 | -class Windows(object): | |
| 284 | - """Enable and disable Windows support for ANSI color character codes. | |
| 285 | - | |
| 286 | - Call static method Windows.enable() to enable color support for the remainder of the process' lifetime. | |
| 287 | - | |
| 288 | - This class is also a context manager. You can do this: | |
| 289 | - with Windows(): | |
| 290 | - print(Color('{autored}Test{/autored}')) | |
| 291 | - | |
| 292 | - Or this: | |
| 293 | - with Windows(auto_colors=True): | |
| 294 | - print(Color('{autored}Test{/autored}')) | |
| 295 | - """ | |
| 296 | - | |
| 297 | - @classmethod | |
| 298 | - def disable(cls): | |
| 299 | - """Restore sys.stderr and sys.stdout to their original objects. Resets colors to their original values. | |
| 300 | - | |
| 301 | - :return: If streams restored successfully. | |
| 302 | - :rtype: bool | |
| 303 | - """ | |
| 304 | - # Skip if not on Windows. | |
| 305 | - if not IS_WINDOWS: | |
| 306 | - return False | |
| 307 | - | |
| 308 | - # Restore default colors. | |
| 309 | - if hasattr(sys.stderr, '_original_stream'): | |
| 310 | - getattr(sys, 'stderr').color = None | |
| 311 | - if hasattr(sys.stdout, '_original_stream'): | |
| 312 | - getattr(sys, 'stdout').color = None | |
| 313 | - | |
| 314 | - # Restore original streams. | |
| 315 | - changed = False | |
| 316 | - if hasattr(sys.stderr, '_original_stream'): | |
| 317 | - changed = True | |
| 318 | - sys.stderr = getattr(sys.stderr, '_original_stream') | |
| 319 | - if hasattr(sys.stdout, '_original_stream'): | |
| 320 | - changed = True | |
| 321 | - sys.stdout = getattr(sys.stdout, '_original_stream') | |
| 322 | - | |
| 323 | - return changed | |
| 324 | - | |
| 325 | - @staticmethod | |
| 326 | - def is_enabled(): | |
| 327 | - """Return True if either stderr or stdout has colors enabled.""" | |
| 328 | - return hasattr(sys.stderr, '_original_stream') or hasattr(sys.stdout, '_original_stream') | |
| 329 | - | |
| 330 | - @classmethod | |
| 331 | - def enable(cls, auto_colors=False, reset_atexit=False): | |
| 332 | - """Enable color text with print() or sys.stdout.write() (stderr too). | |
| 333 | - | |
| 334 | - :param bool auto_colors: Automatically selects dark or light colors based on current terminal's background | |
| 335 | - color. Only works with {autored} and related tags. | |
| 336 | - :param bool reset_atexit: Resets original colors upon Python exit (in case you forget to reset it yourself with | |
| 337 | - a closing tag). Does nothing on native ANSI consoles. | |
| 338 | - | |
| 339 | - :return: If streams replaced successfully. | |
| 340 | - :rtype: bool | |
| 341 | - """ | |
| 342 | - if not IS_WINDOWS: | |
| 343 | - return False # Windows only. | |
| 344 | - | |
| 345 | - # Get values from init_kernel32(). | |
| 346 | - kernel32, stderr, stdout = init_kernel32() | |
| 347 | - if stderr == INVALID_HANDLE_VALUE and stdout == INVALID_HANDLE_VALUE: | |
| 348 | - return False # No valid handles, nothing to do. | |
| 349 | - | |
| 350 | - # Get console info. | |
| 351 | - bg_color, native_ansi = bg_color_native_ansi(kernel32, stderr, stdout) | |
| 352 | - | |
| 353 | - # Set auto colors: | |
| 354 | - if auto_colors: | |
| 355 | - if bg_color in (112, 96, 240, 176, 224, 208, 160): | |
| 356 | - ANSICodeMapping.set_light_background() | |
| 357 | - else: | |
| 358 | - ANSICodeMapping.set_dark_background() | |
| 359 | - | |
| 360 | - # Don't replace streams if ANSI codes are natively supported. | |
| 361 | - if native_ansi: | |
| 362 | - return False | |
| 363 | - | |
| 364 | - # Reset on exit if requested. | |
| 365 | - if reset_atexit: | |
| 366 | - atexit.register(cls.disable) | |
| 367 | - | |
| 368 | - # Overwrite stream references. | |
| 369 | - if stderr != INVALID_HANDLE_VALUE: | |
| 370 | - sys.stderr.flush() | |
| 371 | - sys.stderr = WindowsStream(kernel32, stderr, sys.stderr) | |
| 372 | - if stdout != INVALID_HANDLE_VALUE: | |
| 373 | - sys.stdout.flush() | |
| 374 | - sys.stdout = WindowsStream(kernel32, stdout, sys.stdout) | |
| 375 | - | |
| 376 | - return True | |
| 377 | - | |
| 378 | - def __init__(self, auto_colors=False): | |
| 379 | - """Constructor.""" | |
| 380 | - self.auto_colors = auto_colors | |
| 381 | - | |
| 382 | - def __enter__(self): | |
| 383 | - """Context manager, enables colors on Windows.""" | |
| 384 | - self.enable(auto_colors=self.auto_colors) | |
| 385 | - | |
| 386 | - def __exit__(self, *_): | |
| 387 | - """Context manager, disabled colors on Windows.""" | |
| 388 | - self.disable() |
oletools/thirdparty/tablestream/tablestream.py
| ... | ... | @@ -19,7 +19,7 @@ License: BSD, see source code or documentation |
| 19 | 19 | |
| 20 | 20 | #=== LICENSE ================================================================== |
| 21 | 21 | |
| 22 | -# tablestream is copyright (c) 2015-2016 Philippe Lagadec (http://www.decalage.info) | |
| 22 | +# tablestream is copyright (c) 2015-2018 Philippe Lagadec (http://www.decalage.info) | |
| 23 | 23 | # All rights reserved. |
| 24 | 24 | # |
| 25 | 25 | # Redistribution and use in source and binary forms, with or without modification, |
| ... | ... | @@ -54,8 +54,9 @@ from __future__ import print_function |
| 54 | 54 | # 2016-07-31 v0.06 PL: - handle newline characters properly in each cell |
| 55 | 55 | # 2016-08-28 v0.07 PL: - support for both Python 2.6+ and 3.x |
| 56 | 56 | # - all cells are converted to unicode |
| 57 | +# 2018-09-22 v0.08 PL: - removed mention to oletools' thirdparty folder | |
| 57 | 58 | |
| 58 | -__version__ = '0.07' | |
| 59 | +__version__ = '0.08' | |
| 59 | 60 | |
| 60 | 61 | #------------------------------------------------------------------------------ |
| 61 | 62 | # TODO: |
| ... | ... | @@ -70,15 +71,6 @@ __version__ = '0.07' |
| 70 | 71 | import textwrap |
| 71 | 72 | import sys, os |
| 72 | 73 | |
| 73 | -# add the thirdparty subfolder to sys.path (absolute+normalized path): | |
| 74 | -_thismodule_dir = os.path.normpath(os.path.abspath(os.path.dirname(__file__))) | |
| 75 | -# print('_thismodule_dir = %r' % _thismodule_dir) | |
| 76 | -# assumption: this module is in a subfolder of thirdparty: | |
| 77 | -_thirdparty_dir = os.path.normpath(os.path.join(_thismodule_dir, '..')) | |
| 78 | -# print('_thirdparty_dir = %r' % _thirdparty_dir) | |
| 79 | -if not _thirdparty_dir in sys.path: | |
| 80 | - sys.path.insert(0, _thirdparty_dir) | |
| 81 | - | |
| 82 | 74 | import colorclass |
| 83 | 75 | |
| 84 | 76 | # On Windows, colorclass needs to be enabled: | ... | ... |
setup.py
| ... | ... | @@ -26,6 +26,7 @@ to install this package. |
| 26 | 26 | # 2018-03-19 v0.52.3 PL: - added install_requires, removed thirdparty.pyparsing |
| 27 | 27 | # 2018-09-11 v0.54 PL: - olefile is now a dependency |
| 28 | 28 | # 2018-09-15 PL: - easygui is now a dependency |
| 29 | +# 2018-09-22 PL: - colorclass is now a dependency | |
| 29 | 30 | |
| 30 | 31 | #--- TODO --------------------------------------------------------------------- |
| 31 | 32 | |
| ... | ... | @@ -85,7 +86,6 @@ packages=[ |
| 85 | 86 | 'oletools.thirdparty.prettytable', |
| 86 | 87 | 'oletools.thirdparty.xglob', |
| 87 | 88 | 'oletools.thirdparty.DridexUrlDecoder', |
| 88 | - 'oletools.thirdparty.colorclass', | |
| 89 | 89 | 'oletools.thirdparty.tablestream', |
| 90 | 90 | 'oletools.thirdparty.zipfile27', |
| 91 | 91 | ] |
| ... | ... | @@ -175,9 +175,6 @@ package_data={ |
| 175 | 175 | 'oletools.thirdparty.DridexUrlDecoder': [ |
| 176 | 176 | 'LICENSE.txt', |
| 177 | 177 | ], |
| 178 | - 'oletools.thirdparty.colorclass': [ | |
| 179 | - 'LICENSE.txt', | |
| 180 | - ], | |
| 181 | 178 | 'oletools.thirdparty.zipfile27': [ |
| 182 | 179 | 'LICENSE.txt', |
| 183 | 180 | ], |
| ... | ... | @@ -318,6 +315,7 @@ def main(): |
| 318 | 315 | "pyparsing>=2.2.0", |
| 319 | 316 | "olefile>=0.46", |
| 320 | 317 | "easygui", |
| 318 | + 'colorclass', | |
| 321 | 319 | ], |
| 322 | 320 | ) |
| 323 | 321 | ... | ... |