Commit 6ec331df7ab11f1df4ad232557752fb97fa7ab1e
1 parent
7a143086
msodde: handle case where sys.stdout cannot handle unicode
This is the case e.g. if piping the output of msodde.py to file or other program (e.g. grep) on a linux shell. In that case sys.stdout (i.e. print) can only handle ascii, which is a problem when printing unicode dde links.
Showing
1 changed file
with
50 additions
and
0 deletions
oletools/msodde.py
| @@ -163,6 +163,56 @@ def get_logger(name, level=logging.CRITICAL+1): | @@ -163,6 +163,56 @@ def get_logger(name, level=logging.CRITICAL+1): | ||
| 163 | log = get_logger('msodde') | 163 | log = get_logger('msodde') |
| 164 | 164 | ||
| 165 | 165 | ||
| 166 | +# === UNICODE IN PY2 ========================================================= | ||
| 167 | + | ||
| 168 | +def ensure_stdout_handles_unicode(): | ||
| 169 | + """ Ensure stdout can handle unicode by wrapping it if necessary | ||
| 170 | + | ||
| 171 | + Required e.g. if output of this script is piped or redirected in a linux | ||
| 172 | + shell, since then sys.stdout.encoding is ascii and cannot handle | ||
| 173 | + print(unicode). In that case we need to find some compatible encoding and | ||
| 174 | + wrap sys.stdout into a encoder following (many thanks!) | ||
| 175 | + https://stackoverflow.com/a/1819009 or https://stackoverflow.com/a/20447935 | ||
| 176 | + | ||
| 177 | + Can be undone by setting sys.stdout = sys.__stdout__ | ||
| 178 | + """ | ||
| 179 | + import codecs | ||
| 180 | + import locale | ||
| 181 | + | ||
| 182 | + # do not re-wrap | ||
| 183 | + if isinstance(sys.stdout, codecs.StreamWriter): | ||
| 184 | + return | ||
| 185 | + | ||
| 186 | + # try to find encoding for sys.stdout | ||
| 187 | + encoding = None | ||
| 188 | + try: | ||
| 189 | + encoding = sys.stdout.encoding # variable encoding might not exist | ||
| 190 | + except Exception: | ||
| 191 | + pass | ||
| 192 | + | ||
| 193 | + if encoding not in (None, '', 'ascii'): | ||
| 194 | + return # no need to wrap | ||
| 195 | + | ||
| 196 | + # try to find an encoding that can handle unicode | ||
| 197 | + try: | ||
| 198 | + encoding = locale.getpreferredencoding() | ||
| 199 | + except Exception: | ||
| 200 | + pass | ||
| 201 | + | ||
| 202 | + # fallback if still no encoding available | ||
| 203 | + if encoding in (None, '', 'ascii'): | ||
| 204 | + encoding = 'utf8' | ||
| 205 | + | ||
| 206 | + # logging is probably not initialized yet, but just in case | ||
| 207 | + log.debug('wrapping sys.stdout with encoder using {0}'.format(encoding)) | ||
| 208 | + | ||
| 209 | + wrapper = codecs.getwriter(encoding) | ||
| 210 | + sys.stdout = wrapper(sys.stdout) | ||
| 211 | + | ||
| 212 | + | ||
| 213 | +ensure_stdout_handles_unicode() # e.g. for print(text) in main() | ||
| 214 | + | ||
| 215 | + | ||
| 166 | # === ARGUMENT PARSING ======================================================= | 216 | # === ARGUMENT PARSING ======================================================= |
| 167 | 217 | ||
| 168 | class ArgParserWithBanner(argparse.ArgumentParser): | 218 | class ArgParserWithBanner(argparse.ArgumentParser): |