Commit 5f8e0b8842692eeb83879771df36384ce7d2d10d

Authored by decalage2
1 parent f3d51f29

updated colorclass to v2.2.0, updated tablestream

oletools/thirdparty/colorclass/__init__.py
  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.python.org/pypi/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 0 → 100644
  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 0 → 100644
  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 0 → 100644
  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/colorclass.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.python.org/pypi/colorclass  
9 -"""  
10 -  
11 -import atexit  
12 -from collections import Mapping  
13 -import ctypes  
14 -import os  
15 -import re  
16 -import sys  
17 -  
18 -if os.name == 'nt':  
19 - import ctypes.wintypes  
20 -  
21 -__author__ = '@Robpol86'  
22 -__license__ = 'MIT'  
23 -__version__ = '1.2.0'  
24 -_BASE_CODES = {  
25 - '/all': 0, 'b': 1, 'f': 2, 'i': 3, 'u': 4, 'flash': 5, 'outline': 6, 'negative': 7, 'invis': 8, 'strike': 9,  
26 - '/b': 22, '/f': 22, '/i': 23, '/u': 24, '/flash': 25, '/outline': 26, '/negative': 27, '/invis': 28,  
27 - '/strike': 29, '/fg': 39, '/bg': 49,  
28 -  
29 - 'black': 30, 'red': 31, 'green': 32, 'yellow': 33, 'blue': 34, 'magenta': 35, 'cyan': 36, 'white': 37,  
30 -  
31 - 'bgblack': 40, 'bgred': 41, 'bggreen': 42, 'bgyellow': 43, 'bgblue': 44, 'bgmagenta': 45, 'bgcyan': 46,  
32 - 'bgwhite': 47,  
33 -  
34 - 'hiblack': 90, 'hired': 91, 'higreen': 92, 'hiyellow': 93, 'hiblue': 94, 'himagenta': 95, 'hicyan': 96,  
35 - 'hiwhite': 97,  
36 -  
37 - 'hibgblack': 100, 'hibgred': 101, 'hibggreen': 102, 'hibgyellow': 103, 'hibgblue': 104, 'hibgmagenta': 105,  
38 - 'hibgcyan': 106, 'hibgwhite': 107,  
39 -  
40 - 'autored': None, 'autoblack': None, 'automagenta': None, 'autowhite': None, 'autoblue': None, 'autoyellow': None,  
41 - 'autogreen': None, 'autocyan': None,  
42 -  
43 - 'autobgred': None, 'autobgblack': None, 'autobgmagenta': None, 'autobgwhite': None, 'autobgblue': None,  
44 - 'autobgyellow': None, 'autobggreen': None, 'autobgcyan': None,  
45 -  
46 - '/black': 39, '/red': 39, '/green': 39, '/yellow': 39, '/blue': 39, '/magenta': 39, '/cyan': 39, '/white': 39,  
47 - '/hiblack': 39, '/hired': 39, '/higreen': 39, '/hiyellow': 39, '/hiblue': 39, '/himagenta': 39, '/hicyan': 39,  
48 - '/hiwhite': 39,  
49 -  
50 - '/bgblack': 49, '/bgred': 49, '/bggreen': 49, '/bgyellow': 49, '/bgblue': 49, '/bgmagenta': 49, '/bgcyan': 49,  
51 - '/bgwhite': 49, '/hibgblack': 49, '/hibgred': 49, '/hibggreen': 49, '/hibgyellow': 49, '/hibgblue': 49,  
52 - '/hibgmagenta': 49, '/hibgcyan': 49, '/hibgwhite': 49,  
53 -  
54 - '/autored': 39, '/autoblack': 39, '/automagenta': 39, '/autowhite': 39, '/autoblue': 39, '/autoyellow': 39,  
55 - '/autogreen': 39, '/autocyan': 39,  
56 -  
57 - '/autobgred': 49, '/autobgblack': 49, '/autobgmagenta': 49, '/autobgwhite': 49, '/autobgblue': 49,  
58 - '/autobgyellow': 49, '/autobggreen': 49, '/autobgcyan': 49,  
59 -}  
60 -_WINDOWS_CODES = {  
61 - '/all': -33, '/fg': -39, '/bg': -49,  
62 -  
63 - 'black': 0, 'red': 4, 'green': 2, 'yellow': 6, 'blue': 1, 'magenta': 5, 'cyan': 3, 'white': 7,  
64 -  
65 - 'bgblack': -8, 'bgred': 64, 'bggreen': 32, 'bgyellow': 96, 'bgblue': 16, 'bgmagenta': 80, 'bgcyan': 48,  
66 - 'bgwhite': 112,  
67 -  
68 - 'hiblack': 8, 'hired': 12, 'higreen': 10, 'hiyellow': 14, 'hiblue': 9, 'himagenta': 13, 'hicyan': 11, 'hiwhite': 15,  
69 -  
70 - 'hibgblack': 128, 'hibgred': 192, 'hibggreen': 160, 'hibgyellow': 224, 'hibgblue': 144, 'hibgmagenta': 208,  
71 - 'hibgcyan': 176, 'hibgwhite': 240,  
72 -  
73 - '/black': -39, '/red': -39, '/green': -39, '/yellow': -39, '/blue': -39, '/magenta': -39, '/cyan': -39,  
74 - '/white': -39, '/hiblack': -39, '/hired': -39, '/higreen': -39, '/hiyellow': -39, '/hiblue': -39, '/himagenta': -39,  
75 - '/hicyan': -39, '/hiwhite': -39,  
76 -  
77 - '/bgblack': -49, '/bgred': -49, '/bggreen': -49, '/bgyellow': -49, '/bgblue': -49, '/bgmagenta': -49,  
78 - '/bgcyan': -49, '/bgwhite': -49, '/hibgblack': -49, '/hibgred': -49, '/hibggreen': -49, '/hibgyellow': -49,  
79 - '/hibgblue': -49, '/hibgmagenta': -49, '/hibgcyan': -49, '/hibgwhite': -49,  
80 -}  
81 -_RE_GROUP_SEARCH = re.compile(r'(?:\033\[[\d;]+m)+')  
82 -_RE_NUMBER_SEARCH = re.compile(r'\033\[([\d;]+)m')  
83 -_RE_SPLIT = re.compile(r'(\033\[[\d;]+m)')  
84 -PARENT_CLASS = type(u'')  
85 -  
86 -  
87 -class _AutoCodes(Mapping):  
88 - """Read-only subclass of dict, resolves closing tags (based on colorclass.CODES) and automatic colors."""  
89 - DISABLE_COLORS = False  
90 - LIGHT_BACKGROUND = False  
91 -  
92 - def __init__(self):  
93 - self.__dict = _BASE_CODES.copy()  
94 -  
95 - def __getitem__(self, item):  
96 - if item == 'autoblack':  
97 - answer = self.autoblack  
98 - elif item == 'autored':  
99 - answer = self.autored  
100 - elif item == 'autogreen':  
101 - answer = self.autogreen  
102 - elif item == 'autoyellow':  
103 - answer = self.autoyellow  
104 - elif item == 'autoblue':  
105 - answer = self.autoblue  
106 - elif item == 'automagenta':  
107 - answer = self.automagenta  
108 - elif item == 'autocyan':  
109 - answer = self.autocyan  
110 - elif item == 'autowhite':  
111 - answer = self.autowhite  
112 - elif item == 'autobgblack':  
113 - answer = self.autobgblack  
114 - elif item == 'autobgred':  
115 - answer = self.autobgred  
116 - elif item == 'autobggreen':  
117 - answer = self.autobggreen  
118 - elif item == 'autobgyellow':  
119 - answer = self.autobgyellow  
120 - elif item == 'autobgblue':  
121 - answer = self.autobgblue  
122 - elif item == 'autobgmagenta':  
123 - answer = self.autobgmagenta  
124 - elif item == 'autobgcyan':  
125 - answer = self.autobgcyan  
126 - elif item == 'autobgwhite':  
127 - answer = self.autobgwhite  
128 - else:  
129 - answer = self.__dict[item]  
130 - return answer  
131 -  
132 - def __iter__(self):  
133 - return iter(self.__dict)  
134 -  
135 - def __len__(self):  
136 - return len(self.__dict)  
137 -  
138 - @property  
139 - def autoblack(self):  
140 - """Returns automatic black foreground color depending on background color."""  
141 - return self.__dict['black' if _AutoCodes.LIGHT_BACKGROUND else 'hiblack']  
142 -  
143 - @property  
144 - def autored(self):  
145 - """Returns automatic red foreground color depending on background color."""  
146 - return self.__dict['red' if _AutoCodes.LIGHT_BACKGROUND else 'hired']  
147 -  
148 - @property  
149 - def autogreen(self):  
150 - """Returns automatic green foreground color depending on background color."""  
151 - return self.__dict['green' if _AutoCodes.LIGHT_BACKGROUND else 'higreen']  
152 -  
153 - @property  
154 - def autoyellow(self):  
155 - """Returns automatic yellow foreground color depending on background color."""  
156 - return self.__dict['yellow' if _AutoCodes.LIGHT_BACKGROUND else 'hiyellow']  
157 -  
158 - @property  
159 - def autoblue(self):  
160 - """Returns automatic blue foreground color depending on background color."""  
161 - return self.__dict['blue' if _AutoCodes.LIGHT_BACKGROUND else 'hiblue']  
162 -  
163 - @property  
164 - def automagenta(self):  
165 - """Returns automatic magenta foreground color depending on background color."""  
166 - return self.__dict['magenta' if _AutoCodes.LIGHT_BACKGROUND else 'himagenta']  
167 -  
168 - @property  
169 - def autocyan(self):  
170 - """Returns automatic cyan foreground color depending on background color."""  
171 - return self.__dict['cyan' if _AutoCodes.LIGHT_BACKGROUND else 'hicyan']  
172 -  
173 - @property  
174 - def autowhite(self):  
175 - """Returns automatic white foreground color depending on background color."""  
176 - return self.__dict['white' if _AutoCodes.LIGHT_BACKGROUND else 'hiwhite']  
177 -  
178 - @property  
179 - def autobgblack(self):  
180 - """Returns automatic black background color depending on background color."""  
181 - return self.__dict['bgblack' if _AutoCodes.LIGHT_BACKGROUND else 'hibgblack']  
182 -  
183 - @property  
184 - def autobgred(self):  
185 - """Returns automatic red background color depending on background color."""  
186 - return self.__dict['bgred' if _AutoCodes.LIGHT_BACKGROUND else 'hibgred']  
187 -  
188 - @property  
189 - def autobggreen(self):  
190 - """Returns automatic green background color depending on background color."""  
191 - return self.__dict['bggreen' if _AutoCodes.LIGHT_BACKGROUND else 'hibggreen']  
192 -  
193 - @property  
194 - def autobgyellow(self):  
195 - """Returns automatic yellow background color depending on background color."""  
196 - return self.__dict['bgyellow' if _AutoCodes.LIGHT_BACKGROUND else 'hibgyellow']  
197 -  
198 - @property  
199 - def autobgblue(self):  
200 - """Returns automatic blue background color depending on background color."""  
201 - return self.__dict['bgblue' if _AutoCodes.LIGHT_BACKGROUND else 'hibgblue']  
202 -  
203 - @property  
204 - def autobgmagenta(self):  
205 - """Returns automatic magenta background color depending on background color."""  
206 - return self.__dict['bgmagenta' if _AutoCodes.LIGHT_BACKGROUND else 'hibgmagenta']  
207 -  
208 - @property  
209 - def autobgcyan(self):  
210 - """Returns automatic cyan background color depending on background color."""  
211 - return self.__dict['bgcyan' if _AutoCodes.LIGHT_BACKGROUND else 'hibgcyan']  
212 -  
213 - @property  
214 - def autobgwhite(self):  
215 - """Returns automatic white background color depending on background color."""  
216 - return self.__dict['bgwhite' if _AutoCodes.LIGHT_BACKGROUND else 'hibgwhite']  
217 -  
218 -  
219 -def _pad_input(incoming):  
220 - """Avoid IndexError and KeyError by ignoring un-related fields.  
221 -  
222 - Example: '{0}{autored}' becomes '{{0}}{autored}'.  
223 -  
224 - Positional arguments:  
225 - incoming -- the input unicode value.  
226 -  
227 - Returns:  
228 - Padded unicode value.  
229 - """  
230 - incoming_expanded = incoming.replace('{', '{{').replace('}', '}}')  
231 - for key in _BASE_CODES:  
232 - before, after = '{{%s}}' % key, '{%s}' % key  
233 - if before in incoming_expanded:  
234 - incoming_expanded = incoming_expanded.replace(before, after)  
235 - return incoming_expanded  
236 -  
237 -  
238 -def _parse_input(incoming):  
239 - """Performs the actual conversion of tags to ANSI escaped codes.  
240 -  
241 - Provides a version of the input without any colors for len() and other methods.  
242 -  
243 - Positional arguments:  
244 - incoming -- the input unicode value.  
245 -  
246 - Returns:  
247 - 2-item tuple. First item is the parsed output. Second item is a version of the input without any colors.  
248 - """  
249 - codes = dict((k, v) for k, v in _AutoCodes().items() if '{%s}' % k in incoming)  
250 - color_codes = dict((k, '' if _AutoCodes.DISABLE_COLORS else '\033[{0}m'.format(v)) for k, v in codes.items())  
251 - incoming_padded = _pad_input(incoming)  
252 - output_colors = incoming_padded.format(**color_codes)  
253 -  
254 - # Simplify: '{b}{red}' -> '\033[1m\033[31m' -> '\033[1;31m'  
255 - groups = sorted(set(_RE_GROUP_SEARCH.findall(output_colors)), key=len, reverse=True) # Get codes, grouped adjacent.  
256 - groups_simplified = [[x for n in _RE_NUMBER_SEARCH.findall(i) for x in n.split(';')] for i in groups]  
257 - groups_compiled = ['\033[{0}m'.format(';'.join(g)) for g in groups_simplified] # Final codes.  
258 - assert len(groups_compiled) == len(groups) # For testing.  
259 - output_colors_simplified = output_colors  
260 - for i in range(len(groups)):  
261 - output_colors_simplified = output_colors_simplified.replace(groups[i], groups_compiled[i])  
262 - output_no_colors = _RE_SPLIT.sub('', output_colors_simplified)  
263 -  
264 - # Strip any remaining color codes.  
265 - if _AutoCodes.DISABLE_COLORS:  
266 - output_colors_simplified = _RE_NUMBER_SEARCH.sub('', output_colors_simplified)  
267 -  
268 - return output_colors_simplified, output_no_colors  
269 -  
270 -  
271 -def disable_all_colors():  
272 - """Disable all colors. Strips any color tags or codes."""  
273 - _AutoCodes.DISABLE_COLORS = True  
274 -  
275 -  
276 -def set_light_background():  
277 - """Chooses dark colors for all 'auto'-prefixed codes for readability on light backgrounds."""  
278 - _AutoCodes.DISABLE_COLORS = False  
279 - _AutoCodes.LIGHT_BACKGROUND = True  
280 -  
281 -  
282 -def set_dark_background():  
283 - """Chooses dark colors for all 'auto'-prefixed codes for readability on light backgrounds."""  
284 - _AutoCodes.DISABLE_COLORS = False  
285 - _AutoCodes.LIGHT_BACKGROUND = False  
286 -  
287 -  
288 -def list_tags():  
289 - """Lists the available tags.  
290 -  
291 - Returns:  
292 - Tuple of tuples. Child tuples are four items: ('opening tag', 'closing tag', main ansi value, closing ansi value).  
293 - """  
294 - codes = _AutoCodes()  
295 - grouped = set([(k, '/{0}'.format(k), codes[k], codes['/{0}'.format(k)]) for k in codes if not k.startswith('/')])  
296 -  
297 - # Add half-tags like /all.  
298 - found = [c for r in grouped for c in r[:2]]  
299 - missing = set([('', r[0], None, r[1]) if r[0].startswith('/') else (r[0], '', r[1], None)  
300 - for r in _AutoCodes().items() if r[0] not in found])  
301 - grouped |= missing  
302 -  
303 - # Sort.  
304 - payload = sorted([i for i in grouped if i[2] is None], key=lambda x: x[3]) # /all /fg /bg  
305 - grouped -= set(payload)  
306 - payload.extend(sorted([i for i in grouped if i[2] < 10], key=lambda x: x[2])) # b i u flash  
307 - grouped -= set(payload)  
308 - payload.extend(sorted([i for i in grouped if i[0].startswith('auto')], key=lambda x: x[2])) # auto colors  
309 - grouped -= set(payload)  
310 - payload.extend(sorted([i for i in grouped if not i[0].startswith('hi')], key=lambda x: x[2])) # dark colors  
311 - grouped -= set(payload)  
312 - payload.extend(sorted(grouped, key=lambda x: x[2])) # light colors  
313 - return tuple(payload)  
314 -  
315 -  
316 -class ColorBytes(bytes):  
317 - """Str (bytes in Python3) subclass, .decode() overridden to return Color() instance."""  
318 -  
319 - def decode(*args, **kwargs):  
320 - return Color(super(ColorBytes, args[0]).decode(*args[1:], **kwargs))  
321 -  
322 -  
323 -class Color(PARENT_CLASS):  
324 - """Unicode (str in Python3) subclass with ANSI terminal text color support.  
325 -  
326 - Example syntax: Color('{red}Sample Text{/red}')  
327 -  
328 - For a list of codes, call: colorclass.list_tags()  
329 - """  
330 -  
331 - @classmethod  
332 - def red(cls, s, auto=False):  
333 - return cls.colorize('red', s, auto=auto)  
334 -  
335 - @classmethod  
336 - def bgred(cls, s, auto=False):  
337 - return cls.colorize('bgred', s, auto=auto)  
338 -  
339 - @classmethod  
340 - def green(cls, s, auto=False):  
341 - return cls.colorize('green', s, auto=auto)  
342 -  
343 - @classmethod  
344 - def bggreen(cls, s, auto=False):  
345 - return cls.colorize('bggreen', s, auto=auto)  
346 -  
347 - @classmethod  
348 - def blue(cls, s, auto=False):  
349 - return cls.colorize('blue', s, auto=auto)  
350 -  
351 - @classmethod  
352 - def bgblue(cls, s, auto=False):  
353 - return cls.colorize('bgblue', s, auto=auto)  
354 -  
355 - @classmethod  
356 - def yellow(cls, s, auto=False):  
357 - return cls.colorize('yellow', s, auto=auto)  
358 -  
359 - @classmethod  
360 - def bgyellow(cls, s, auto=False):  
361 - return cls.colorize('bgyellow', s, auto=auto)  
362 -  
363 - @classmethod  
364 - def cyan(cls, s, auto=False):  
365 - return cls.colorize('cyan', s, auto=auto)  
366 -  
367 - @classmethod  
368 - def bgcyan(cls, s, auto=False):  
369 - return cls.colorize('bgcyan', s, auto=auto)  
370 -  
371 - @classmethod  
372 - def magenta(cls, s, auto=False):  
373 - return cls.colorize('magenta', s, auto=auto)  
374 -  
375 - @classmethod  
376 - def bgmagenta(cls, s, auto=False):  
377 - return cls.colorize('bgmagenta', s, auto=auto)  
378 -  
379 - @classmethod  
380 - def colorize(cls, color, s, auto=False):  
381 - tag = '{0}{1}'.format('auto' if auto else '', color)  
382 - return cls('{%s}%s{/%s}' % (tag, s, tag))  
383 -  
384 - def __new__(cls, *args, **kwargs):  
385 - parent_class = cls.__bases__[0]  
386 - value_markup = args[0] if args else parent_class()  
387 - value_colors, value_no_colors = _parse_input(value_markup)  
388 - if args:  
389 - args = [value_colors] + list(args[1:])  
390 -  
391 - obj = parent_class.__new__(cls, *args, **kwargs)  
392 - obj.value_colors, obj.value_no_colors = value_colors, value_no_colors  
393 - obj.has_colors = bool(_RE_NUMBER_SEARCH.match(value_colors))  
394 - return obj  
395 -  
396 - def __len__(self):  
397 - return self.value_no_colors.__len__()  
398 -  
399 - def capitalize(self):  
400 - split = _RE_SPLIT.split(self.value_colors)  
401 - for i in range(len(split)):  
402 - if _RE_SPLIT.match(split[i]):  
403 - continue  
404 - split[i] = PARENT_CLASS(split[i]).capitalize()  
405 - return Color().join(split)  
406 -  
407 - def center(self, width, fillchar=None):  
408 - if fillchar is not None:  
409 - result = PARENT_CLASS(self.value_no_colors).center(width, fillchar)  
410 - else:  
411 - result = PARENT_CLASS(self.value_no_colors).center(width)  
412 - return result.replace(self.value_no_colors, self.value_colors)  
413 -  
414 - def count(self, *args, **kwargs):  
415 - return PARENT_CLASS(self.value_no_colors).count(*args, **kwargs)  
416 -  
417 - def endswith(self, *args, **kwargs):  
418 - return PARENT_CLASS(self.value_no_colors).endswith(*args, **kwargs)  
419 -  
420 - def encode(*args, **kwargs):  
421 - return ColorBytes(super(Color, args[0]).encode(*args[1:], **kwargs))  
422 -  
423 - def decode(*args, **kwargs):  
424 - return Color(super(Color, args[0]).decode(*args[1:], **kwargs))  
425 -  
426 - def find(self, *args, **kwargs):  
427 - return PARENT_CLASS(self.value_no_colors).find(*args, **kwargs)  
428 -  
429 - def format(*args, **kwargs):  
430 - return Color(super(Color, args[0]).format(*args[1:], **kwargs))  
431 -  
432 - def index(self, *args, **kwargs):  
433 - return PARENT_CLASS(self.value_no_colors).index(*args, **kwargs)  
434 -  
435 - def isalnum(self):  
436 - return PARENT_CLASS(self.value_no_colors).isalnum()  
437 -  
438 - def isalpha(self):  
439 - return PARENT_CLASS(self.value_no_colors).isalpha()  
440 -  
441 - def isdecimal(self):  
442 - return PARENT_CLASS(self.value_no_colors).isdecimal()  
443 -  
444 - def isdigit(self):  
445 - return PARENT_CLASS(self.value_no_colors).isdigit()  
446 -  
447 - def isnumeric(self):  
448 - return PARENT_CLASS(self.value_no_colors).isnumeric()  
449 -  
450 - def isspace(self):  
451 - return PARENT_CLASS(self.value_no_colors).isspace()  
452 -  
453 - def istitle(self):  
454 - return PARENT_CLASS(self.value_no_colors).istitle()  
455 -  
456 - def isupper(self):  
457 - return PARENT_CLASS(self.value_no_colors).isupper()  
458 -  
459 - def ljust(self, width, fillchar=None):  
460 - if fillchar is not None:  
461 - result = PARENT_CLASS(self.value_no_colors).ljust(width, fillchar)  
462 - else:  
463 - result = PARENT_CLASS(self.value_no_colors).ljust(width)  
464 - return result.replace(self.value_no_colors, self.value_colors)  
465 -  
466 - def rfind(self, *args, **kwargs):  
467 - return PARENT_CLASS(self.value_no_colors).rfind(*args, **kwargs)  
468 -  
469 - def rindex(self, *args, **kwargs):  
470 - return PARENT_CLASS(self.value_no_colors).rindex(*args, **kwargs)  
471 -  
472 - def rjust(self, width, fillchar=None):  
473 - if fillchar is not None:  
474 - result = PARENT_CLASS(self.value_no_colors).rjust(width, fillchar)  
475 - else:  
476 - result = PARENT_CLASS(self.value_no_colors).rjust(width)  
477 - return result.replace(self.value_no_colors, self.value_colors)  
478 -  
479 - def splitlines(self):  
480 - return [Color(l) for l in PARENT_CLASS(self.value_colors).splitlines()]  
481 -  
482 - def startswith(self, *args, **kwargs):  
483 - return PARENT_CLASS(self.value_no_colors).startswith(*args, **kwargs)  
484 -  
485 - def swapcase(self):  
486 - split = _RE_SPLIT.split(self.value_colors)  
487 - for i in range(len(split)):  
488 - if _RE_SPLIT.match(split[i]):  
489 - continue  
490 - split[i] = PARENT_CLASS(split[i]).swapcase()  
491 - return Color().join(split)  
492 -  
493 - def title(self):  
494 - split = _RE_SPLIT.split(self.value_colors)  
495 - for i in range(len(split)):  
496 - if _RE_SPLIT.match(split[i]):  
497 - continue  
498 - split[i] = PARENT_CLASS(split[i]).title()  
499 - return Color().join(split)  
500 -  
501 - def translate(self, table):  
502 - split = _RE_SPLIT.split(self.value_colors)  
503 - for i in range(len(split)):  
504 - if _RE_SPLIT.match(split[i]):  
505 - continue  
506 - split[i] = PARENT_CLASS(split[i]).translate(table)  
507 - return Color().join(split)  
508 -  
509 - def upper(self):  
510 - split = _RE_SPLIT.split(self.value_colors)  
511 - for i in range(len(split)):  
512 - if _RE_SPLIT.match(split[i]):  
513 - continue  
514 - split[i] = PARENT_CLASS(split[i]).upper()  
515 - return Color().join(split)  
516 -  
517 - def zfill(self, width):  
518 - if not self.value_no_colors:  
519 - return PARENT_CLASS().zfill(width)  
520 -  
521 - split = _RE_SPLIT.split(self.value_colors)  
522 - filled = PARENT_CLASS(self.value_no_colors).zfill(width)  
523 - if len(split) == 1:  
524 - return filled  
525 -  
526 - padding = filled.replace(self.value_no_colors, '')  
527 - if not split[0]:  
528 - split[2] = padding + split[2]  
529 - else:  
530 - split[0] = padding + split[0]  
531 -  
532 - return Color().join(split)  
533 -  
534 -  
535 -class Windows(object):  
536 - """Enable and disable Windows support for ANSI color character codes.  
537 -  
538 - Call static method Windows.enable() to enable color support for the remainder of the process' lifetime.  
539 -  
540 - This class is also a context manager. You can do this:  
541 - with Windows():  
542 - print(Color('{autored}Test{/autored}'))  
543 -  
544 - Or this:  
545 - with Windows(auto_colors=True):  
546 - print(Color('{autored}Test{/autored}'))  
547 - """  
548 -  
549 - @staticmethod  
550 - def disable():  
551 - """Restore sys.stderr and sys.stdout to their original objects. Resets colors to their original values."""  
552 - if os.name != 'nt' or not Windows.is_enabled():  
553 - return False  
554 -  
555 - getattr(sys.stderr, '_reset_colors', lambda: False)()  
556 - getattr(sys.stdout, '_reset_colors', lambda: False)()  
557 -  
558 - if hasattr(sys.stderr, 'ORIGINAL_STREAM'):  
559 - sys.stderr = getattr(sys.stderr, 'ORIGINAL_STREAM')  
560 - if hasattr(sys.stdout, 'ORIGINAL_STREAM'):  
561 - sys.stdout = getattr(sys.stdout, 'ORIGINAL_STREAM')  
562 -  
563 - return True  
564 -  
565 - @staticmethod  
566 - def is_enabled():  
567 - """Returns True if either stderr or stdout has colors enabled."""  
568 - return hasattr(sys.stderr, 'ORIGINAL_STREAM') or hasattr(sys.stdout, 'ORIGINAL_STREAM')  
569 -  
570 - @staticmethod  
571 - def enable(auto_colors=False, reset_atexit=False):  
572 - """Enables color text with print() or sys.stdout.write() (stderr too).  
573 -  
574 - Keyword arguments:  
575 - auto_colors -- automatically selects dark or light colors based on current terminal's background color. Only  
576 - works with {autored} and related tags.  
577 - reset_atexit -- resets original colors upon Python exit (in case you forget to reset it yourself with a closing  
578 - tag).  
579 - """  
580 - if os.name != 'nt':  
581 - return False  
582 -  
583 - # Overwrite stream references.  
584 - if not hasattr(sys.stderr, 'ORIGINAL_STREAM'):  
585 - sys.stderr.flush()  
586 - sys.stderr = _WindowsStreamStdErr()  
587 - if not hasattr(sys.stdout, 'ORIGINAL_STREAM'):  
588 - sys.stdout.flush()  
589 - sys.stdout = _WindowsStreamStdOut()  
590 - if not hasattr(sys.stderr, 'ORIGINAL_STREAM') and not hasattr(sys.stdout, 'ORIGINAL_STREAM'):  
591 - return False  
592 -  
593 - # Automatically select which colors to display.  
594 - bg_color = getattr(sys.stdout, 'default_bg', getattr(sys.stderr, 'default_bg', None))  
595 - if auto_colors and bg_color is not None:  
596 - set_light_background() if bg_color in (112, 96, 240, 176, 224, 208, 160) else set_dark_background()  
597 -  
598 - # Reset on exit if requested.  
599 - if reset_atexit:  
600 - atexit.register(lambda: Windows.disable())  
601 -  
602 - return True  
603 -  
604 - def __init__(self, auto_colors=False):  
605 - self.auto_colors = auto_colors  
606 -  
607 - def __enter__(self):  
608 - Windows.enable(auto_colors=self.auto_colors)  
609 -  
610 - def __exit__(self, *_):  
611 - Windows.disable()  
612 -  
613 -  
614 -class _WindowsCSBI(object):  
615 - """Interfaces with Windows CONSOLE_SCREEN_BUFFER_INFO API/DLL calls. Gets info for stderr and stdout.  
616 -  
617 - References:  
618 - http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231  
619 - https://code.google.com/p/colorama/issues/detail?id=47.  
620 - pytest's py project: py/_io/terminalwriter.py.  
621 -  
622 - Class variables:  
623 - CSBI -- ConsoleScreenBufferInfo class/struct (not instance, the class definition itself) defined in _define_csbi().  
624 - HANDLE_STDERR -- GetStdHandle() return integer for stderr.  
625 - HANDLE_STDOUT -- GetStdHandle() return integer for stdout.  
626 - WINDLL -- my own loaded instance of ctypes.WinDLL.  
627 - """  
628 -  
629 - CSBI = None  
630 - HANDLE_STDERR = None  
631 - HANDLE_STDOUT = None  
632 - WINDLL = ctypes.LibraryLoader(getattr(ctypes, 'WinDLL', None))  
633 -  
634 - @staticmethod  
635 - def _define_csbi():  
636 - """Defines structs and populates _WindowsCSBI.CSBI."""  
637 - if _WindowsCSBI.CSBI is not None:  
638 - return  
639 -  
640 - class COORD(ctypes.Structure):  
641 - """Windows COORD structure. http://msdn.microsoft.com/en-us/library/windows/desktop/ms682119"""  
642 - _fields_ = [('X', ctypes.c_short), ('Y', ctypes.c_short)]  
643 -  
644 - class SmallRECT(ctypes.Structure):  
645 - """Windows SMALL_RECT structure. http://msdn.microsoft.com/en-us/library/windows/desktop/ms686311"""  
646 - _fields_ = [('Left', ctypes.c_short), ('Top', ctypes.c_short), ('Right', ctypes.c_short),  
647 - ('Bottom', ctypes.c_short)]  
648 -  
649 - class ConsoleScreenBufferInfo(ctypes.Structure):  
650 - """Windows CONSOLE_SCREEN_BUFFER_INFO structure.  
651 - http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093  
652 - """  
653 - _fields_ = [  
654 - ('dwSize', COORD),  
655 - ('dwCursorPosition', COORD),  
656 - ('wAttributes', ctypes.wintypes.WORD),  
657 - ('srWindow', SmallRECT),  
658 - ('dwMaximumWindowSize', COORD)  
659 - ]  
660 -  
661 - _WindowsCSBI.CSBI = ConsoleScreenBufferInfo  
662 -  
663 - @staticmethod  
664 - def initialize():  
665 - """Initializes the WINDLL resource and populated the CSBI class variable."""  
666 - _WindowsCSBI._define_csbi()  
667 - _WindowsCSBI.HANDLE_STDERR = _WindowsCSBI.HANDLE_STDERR or _WindowsCSBI.WINDLL.kernel32.GetStdHandle(-12)  
668 - _WindowsCSBI.HANDLE_STDOUT = _WindowsCSBI.HANDLE_STDOUT or _WindowsCSBI.WINDLL.kernel32.GetStdHandle(-11)  
669 - if _WindowsCSBI.WINDLL.kernel32.GetConsoleScreenBufferInfo.argtypes:  
670 - return  
671 -  
672 - _WindowsCSBI.WINDLL.kernel32.GetStdHandle.argtypes = [ctypes.wintypes.DWORD]  
673 - _WindowsCSBI.WINDLL.kernel32.GetStdHandle.restype = ctypes.wintypes.HANDLE  
674 - _WindowsCSBI.WINDLL.kernel32.GetConsoleScreenBufferInfo.restype = ctypes.wintypes.BOOL  
675 - _WindowsCSBI.WINDLL.kernel32.GetConsoleScreenBufferInfo.argtypes = [  
676 - ctypes.wintypes.HANDLE, ctypes.POINTER(_WindowsCSBI.CSBI)  
677 - ]  
678 -  
679 - @staticmethod  
680 - def get_info(handle):  
681 - """Get information about this current console window (for Microsoft Windows only).  
682 -  
683 - Raises IOError if attempt to get information fails (if there is no console window).  
684 -  
685 - Don't forget to call _WindowsCSBI.initialize() once in your application before calling this method.  
686 -  
687 - Positional arguments:  
688 - handle -- either _WindowsCSBI.HANDLE_STDERR or _WindowsCSBI.HANDLE_STDOUT.  
689 -  
690 - Returns:  
691 - Dictionary with different integer values. Keys are:  
692 - buffer_width -- width of the buffer (Screen Buffer Size in cmd.exe layout tab).  
693 - buffer_height -- height of the buffer (Screen Buffer Size in cmd.exe layout tab).  
694 - terminal_width -- width of the terminal window.  
695 - terminal_height -- height of the terminal window.  
696 - bg_color -- current background color (http://msdn.microsoft.com/en-us/library/windows/desktop/ms682088).  
697 - fg_color -- current text color code.  
698 - """  
699 - # Query Win32 API.  
700 - csbi = _WindowsCSBI.CSBI()  
701 - try:  
702 - if not _WindowsCSBI.WINDLL.kernel32.GetConsoleScreenBufferInfo(handle, ctypes.byref(csbi)):  
703 - raise IOError('Unable to get console screen buffer info from win32 API.')  
704 - except ctypes.ArgumentError:  
705 - raise IOError('Unable to get console screen buffer info from win32 API.')  
706 -  
707 - # Parse data.  
708 - result = dict(  
709 - buffer_width=int(csbi.dwSize.X - 1),  
710 - buffer_height=int(csbi.dwSize.Y),  
711 - terminal_width=int(csbi.srWindow.Right - csbi.srWindow.Left),  
712 - terminal_height=int(csbi.srWindow.Bottom - csbi.srWindow.Top),  
713 - bg_color=int(csbi.wAttributes & 240),  
714 - fg_color=int(csbi.wAttributes % 16),  
715 - )  
716 - return result  
717 -  
718 -  
719 -class _WindowsStreamStdOut(object):  
720 - """Replacement stream which overrides sys.stdout. When writing or printing, ANSI codes are converted.  
721 -  
722 - ANSI (Linux/Unix) color codes are converted into win32 system calls, changing the next character's color before  
723 - printing it. Resources referenced:  
724 - https://github.com/tartley/colorama  
725 - http://www.cplusplus.com/articles/2ywTURfi/  
726 - http://thomasfischer.biz/python-and-windows-terminal-colors/  
727 - http://stackoverflow.com/questions/17125440/c-win32-console-color  
728 - http://www.tysos.org/svn/trunk/mono/corlib/System/WindowsConsoleDriver.cs  
729 - http://stackoverflow.com/questions/287871/print-in-terminal-with-colors-using-python  
730 - http://msdn.microsoft.com/en-us/library/windows/desktop/ms682088#_win32_character_attributes  
731 -  
732 - Class variables:  
733 - ALL_BG_CODES -- list of background Windows codes. Used to determine if requested color is foreground or background.  
734 - COMPILED_CODES -- 'translation' dictionary. Keys are ANSI codes (values of _BASE_CODES), values are Windows codes.  
735 - ORIGINAL_STREAM -- the original stream to write non-code text to.  
736 - WIN32_STREAM_HANDLE -- handle to the Windows stdout device. Used by other Windows functions.  
737 -  
738 - Instance variables:  
739 - default_fg -- the foreground Windows color code at the time of instantiation.  
740 - default_bg -- the background Windows color code at the time of instantiation.  
741 - """  
742 -  
743 - ALL_BG_CODES = [v for k, v in _WINDOWS_CODES.items() if k.startswith('bg') or k.startswith('hibg')]  
744 - COMPILED_CODES = dict((v, _WINDOWS_CODES[k]) for k, v in _BASE_CODES.items() if k in _WINDOWS_CODES)  
745 - ORIGINAL_STREAM = sys.stdout  
746 - WIN32_STREAM_HANDLE = _WindowsCSBI.HANDLE_STDOUT  
747 -  
748 - def __init__(self):  
749 - _WindowsCSBI.initialize()  
750 - self.default_fg, self.default_bg = self._get_colors()  
751 - for attr in dir(self.ORIGINAL_STREAM):  
752 - if hasattr(self, attr):  
753 - continue  
754 - setattr(self, attr, getattr(self.ORIGINAL_STREAM, attr))  
755 -  
756 - def __getattr__(self, item):  
757 - """If an attribute/function/etc is not defined in this function, retrieve the one from the original stream.  
758 -  
759 - Fixes ipython arrow key presses.  
760 - """  
761 - return getattr(self.ORIGINAL_STREAM, item)  
762 -  
763 - def _get_colors(self):  
764 - """Returns a tuple of two integers representing current colors: (foreground, background)."""  
765 - try:  
766 - csbi = _WindowsCSBI.get_info(self.WIN32_STREAM_HANDLE)  
767 - return csbi['fg_color'], csbi['bg_color']  
768 - except IOError:  
769 - return 7, 0  
770 -  
771 - def _reset_colors(self):  
772 - """Sets the foreground and background colors to their original values (when class was instantiated)."""  
773 - self._set_color(-33)  
774 -  
775 - def _set_color(self, color_code):  
776 - """Changes the foreground and background colors for subsequently printed characters.  
777 -  
778 - Since setting a color requires including both foreground and background codes (merged), setting just the  
779 - foreground color resets the background color to black, and vice versa.  
780 -  
781 - This function first gets the current background and foreground colors, merges in the requested color code, and  
782 - sets the result.  
783 -  
784 - However if we need to remove just the foreground color but leave the background color the same (or vice versa)  
785 - such as when {/red} is used, we must merge the default foreground color with the current background color. This  
786 - is the reason for those negative values.  
787 -  
788 - Positional arguments:  
789 - color_code -- integer color code from _WINDOWS_CODES.  
790 - """  
791 - # Get current color code.  
792 - current_fg, current_bg = self._get_colors()  
793 -  
794 - # Handle special negative codes. Also determine the final color code.  
795 - if color_code == -39:  
796 - final_color_code = self.default_fg | current_bg # Reset the foreground only.  
797 - elif color_code == -49:  
798 - final_color_code = current_fg | self.default_bg # Reset the background only.  
799 - elif color_code == -33:  
800 - final_color_code = self.default_fg | self.default_bg # Reset both.  
801 - elif color_code == -8:  
802 - final_color_code = current_fg # Black background.  
803 - else:  
804 - new_is_bg = color_code in self.ALL_BG_CODES  
805 - final_color_code = color_code | (current_fg if new_is_bg else current_bg)  
806 -  
807 - # Set new code.  
808 - _WindowsCSBI.WINDLL.kernel32.SetConsoleTextAttribute(self.WIN32_STREAM_HANDLE, final_color_code)  
809 -  
810 - def write(self, p_str):  
811 - for segment in _RE_SPLIT.split(p_str):  
812 - if not segment:  
813 - # Empty string. p_str probably starts with colors so the first item is always ''.  
814 - continue  
815 - if not _RE_SPLIT.match(segment):  
816 - # No color codes, print regular text.  
817 - self.ORIGINAL_STREAM.write(segment)  
818 - self.ORIGINAL_STREAM.flush()  
819 - continue  
820 - for color_code in (int(c) for c in _RE_NUMBER_SEARCH.findall(segment)[0].split(';')):  
821 - if color_code in self.COMPILED_CODES:  
822 - self._set_color(self.COMPILED_CODES[color_code])  
823 -  
824 -  
825 -class _WindowsStreamStdErr(_WindowsStreamStdOut):  
826 - """Replacement stream which overrides sys.stderr. Subclasses _WindowsStreamStdOut."""  
827 -  
828 - ORIGINAL_STREAM = sys.stderr  
829 - WIN32_STREAM_HANDLE = _WindowsCSBI.HANDLE_STDERR  
oletools/thirdparty/colorclass/core.py 0 → 100644
  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 0 → 100644
  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 0 → 100644
  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 0 → 100644
  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 0 → 100644
  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
@@ -48,8 +48,9 @@ License: BSD, see source code or documentation @@ -48,8 +48,9 @@ License: BSD, see source code or documentation
48 # 2015-11-01 v0.01 PL: - first version 48 # 2015-11-01 v0.01 PL: - first version
49 # 2016-01-01 v0.02 PL: - added styles, color support 49 # 2016-01-01 v0.02 PL: - added styles, color support
50 # 2016-04-19 v0.03 PL: - enable colorclass on Windows, fixed issue #39 50 # 2016-04-19 v0.03 PL: - enable colorclass on Windows, fixed issue #39
  51 +# 2016-05-25 v0.04 PL: - updated for colorclass 2.2.0 (now a package)
51 52
52 -__version__ = '0.03' 53 +__version__ = '0.04'
53 54
54 #------------------------------------------------------------------------------ 55 #------------------------------------------------------------------------------
55 # TODO: 56 # TODO:
@@ -64,7 +65,7 @@ __version__ = &#39;0.03&#39; @@ -64,7 +65,7 @@ __version__ = &#39;0.03&#39;
64 import textwrap 65 import textwrap
65 import sys, os 66 import sys, os
66 67
67 -from thirdparty.colorclass import colorclass 68 +from thirdparty import colorclass
68 69
69 # On Windows, colorclass needs to be enabled: 70 # On Windows, colorclass needs to be enabled:
70 if os.name == 'nt': 71 if os.name == 'nt':