|
10 | 10 | import pathlib |
11 | 11 | import re |
12 | 12 | import subprocess as sp |
| 13 | +import urllib.parse |
13 | 14 | import zipfile |
14 | 15 | from enum import Enum |
15 | 16 |
|
16 | 17 | from .version import __version__ # noqa: F401 |
17 | 18 |
|
18 | 19 |
|
| 20 | +def file_uri_to_path(s): |
| 21 | + uri = urllib.parse.urlparse(s) |
| 22 | + if (uri.scheme, uri.netloc, uri.query, uri.fragment) != ('file', '', '', ''): |
| 23 | + raise ValueError(uri) |
| 24 | + return urllib.parse.unquote_plus(uri.path) |
| 25 | + |
| 26 | + |
19 | 27 | class BarCodeReaderException(Exception): |
20 | | - def __init__(self, message, filename=None, underlying=None): |
21 | | - self.message, self.filename, self.underlying = message, filename, underlying |
22 | | - super().__init__(message, filename, underlying) |
| 28 | + def __init__(self, message, filename=None): |
| 29 | + self.message, self.filename = message, filename |
| 30 | + super().__init__(message, filename) |
23 | 31 |
|
24 | 32 |
|
25 | 33 | class BarCodeReader(object): |
@@ -65,35 +73,40 @@ def decode(self, filenames, try_harder=False, possible_formats=None, pure_barcod |
65 | 73 |
|
66 | 74 | try: |
67 | 75 | p = sp.Popen(cmd, stdout=sp.PIPE, stderr=sp.STDOUT, universal_newlines=False) |
68 | | - except FileNotFoundError as e: |
69 | | - raise BarCodeReaderException("Java binary specified (%s) does not exist" % self.java, self.java, e) |
70 | | - except PermissionError as e: |
71 | | - raise BarCodeReaderException("Java binary specified (%s) is not executable" % self.java, self.java, e) |
| 76 | + except OSError as e: |
| 77 | + raise BarCodeReaderException("Could not execute specified Java binary", self.java) from e |
72 | 78 | stdout, stderr = p.communicate() |
73 | 79 |
|
74 | 80 | if stdout.startswith((b'Error: Could not find or load main class com.google.zxing.client.j2se.CommandLineRunner', |
75 | 81 | b'Exception in thread "main" java.lang.NoClassDefFoundError:')): |
76 | 82 | raise BarCodeReaderException("Java JARs not found in classpath (%s)" % self.classpath, self.classpath) |
77 | 83 | elif stdout.startswith((b'''Exception in thread "main" javax.imageio.IIOException: Can't get input stream from URL!''', |
78 | 84 | b'''Exception in thread "main" java.util.concurrent.ExecutionException: javax.imageio.IIOException: Can't get input stream from URL!''')): |
79 | | - raise BarCodeReaderException("Could not find image path: %s" % filenames, filenames) |
| 85 | + # Find the line that looks like: "Caused by: java.io.FileNotFoundException: $FILENAME ({No such file or directory,Permission denied,*)" |
| 86 | + fn, err = next((map(bytes.decode, l[42:].rsplit(b' (', 1)) for l in stdout.splitlines() if l.startswith(b"Caused by: java.io.FileNotFoundException: ")), ('', '')) |
| 87 | + if err == 'No such file or directory)': |
| 88 | + err = FileNotFoundError(fn) |
| 89 | + elif err == 'Permission denied)': |
| 90 | + err = PermissionError(fn) |
| 91 | + else: |
| 92 | + err = OSError(err[:-1]) |
| 93 | + raise BarCodeReaderException("Java library could not read image", fn) from err |
80 | 94 | elif stdout.startswith(b'''Exception in thread "main" java.io.IOException: Could not load '''): |
81 | | - raise BarCodeReaderException("Java library could not read image; is it in a supported format?", filenames) |
| 95 | + # First line ends with file:// URI |
| 96 | + fn = file_uri_to_path(stdout.splitlines()[0][63:].decode()) |
| 97 | + raise BarCodeReaderException("Java library could not read image (is it in a supported format?)", fn) |
82 | 98 | elif stdout.startswith(b'''Exception '''): |
83 | | - raise BarCodeReaderException("Unknown Java exception: %s" % stdout) |
| 99 | + raise BarCodeReaderException("Unknown Java exception", self.java) from RuntimeError(stdout) |
84 | 100 | elif p.returncode: |
85 | | - raise BarCodeReaderException("Unexpected Java subprocess return code %d" % p.returncode, self.java) |
86 | | - |
87 | | - if p.returncode: |
88 | | - codes = [None for fn in filenames] |
89 | | - else: |
90 | | - file_results = [] |
91 | | - for line in stdout.splitlines(True): |
92 | | - if line.startswith((b'file:///', b'Exception')): |
93 | | - file_results.append(line) |
94 | | - else: |
95 | | - file_results[-1] += line |
96 | | - codes = [BarCode.parse(result) for result in file_results] |
| 101 | + raise BarCodeReaderException("Unexpected Java subprocess return code", self.java) from sp.CalledProcessError(p.returncode, cmd, stdout) |
| 102 | + |
| 103 | + file_results = [] |
| 104 | + for line in stdout.splitlines(True): |
| 105 | + if line.startswith((b'file:///', b'Exception')): |
| 106 | + file_results.append(line) |
| 107 | + else: |
| 108 | + file_results[-1] += line |
| 109 | + codes = [BarCode.parse(result) for result in file_results] |
97 | 110 |
|
98 | 111 | if one_file: |
99 | 112 | return codes[0] |
|
0 commit comments