summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gemato/manifest.py13
-rw-r--r--tests/test_manifest.py95
2 files changed, 106 insertions, 2 deletions
diff --git a/gemato/manifest.py b/gemato/manifest.py
index 0480c4a..5c38801 100644
--- a/gemato/manifest.py
+++ b/gemato/manifest.py
@@ -56,20 +56,29 @@ class ManifestPathEntry(object):
__slots__ = ['path']
disallowed_path_re = re.compile(r'[\0\s\\]', re.U)
+ escape_seq_re = re.compile(r'\\(x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})?')
def __init__(self, path):
assert path[0] != '/'
self.path = path
@staticmethod
- def process_path(l):
+ def decode_char(m):
+ val = m.group(1)
+ if val is None:
+ raise gemato.exceptions.ManifestSyntaxError(
+ 'Invalid escape sequence at pos {} of: {}'.format(m.start(), m.string))
+ return chr(int(val[1:], base=16))
+
+ @classmethod
+ def process_path(cls, l):
if len(l) != 2:
raise gemato.exceptions.ManifestSyntaxError(
'{} line: expects 1 value, got: {}'.format(l[0], l[1:]))
if not l[1] or l[1][0] == '/':
raise gemato.exceptions.ManifestSyntaxError(
'{} line: expected relative path, got: {}'.format(l[0], l[1:]))
- return l[1]
+ return cls.escape_seq_re.sub(cls.decode_char, l[1])
@staticmethod
def encode_char(m):
diff --git a/tests/test_manifest.py b/tests/test_manifest.py
index 6351dce..20f1f29 100644
--- a/tests/test_manifest.py
+++ b/tests/test_manifest.py
@@ -471,3 +471,98 @@ class ManifestPathEncodingTest(unittest.TestCase):
self.assertEqual(m.path, 'tes\\t')
self.assertListEqual(list(m.to_list()),
['DATA', 'tes\\x5Ct', '32'])
+
+ def test_decode_space_in_filename(self):
+ m = gemato.manifest.ManifestEntryDATA.from_list(['DATA',
+ 'tes\\x20t', 32])
+ self.assertEqual(m.path, 'tes t')
+
+ def test_decode_space_in_filename_u(self):
+ m = gemato.manifest.ManifestEntryDATA.from_list(['DATA',
+ 'tes\\u0020t', 32])
+ self.assertEqual(m.path, 'tes t')
+
+ def test_decode_space_in_filename_lu(self):
+ m = gemato.manifest.ManifestEntryDATA.from_list(['DATA',
+ 'tes\\U00000020t', 32])
+ self.assertEqual(m.path, 'tes t')
+
+ def test_decode_tab_in_filename(self):
+ m = gemato.manifest.ManifestEntryDATA.from_list(['DATA',
+ 'tes\\x09t', 32])
+ self.assertEqual(m.path, 'tes\tt')
+
+ def test_decode_nbsp_in_filename(self):
+ m = gemato.manifest.ManifestEntryDATA.from_list(['DATA',
+ 'tes\\u00A0t', 32])
+ self.assertEqual(m.path, 'tes\u00a0t')
+
+ def test_decode_nbsp_in_filename_lc(self):
+ m = gemato.manifest.ManifestEntryDATA.from_list(['DATA',
+ 'tes\\u00a0t', 32])
+ self.assertEqual(m.path, 'tes\u00a0t')
+
+ def test_decode_en_quad_in_filename(self):
+ m = gemato.manifest.ManifestEntryDATA.from_list(['DATA',
+ 'tes\\u2000t', 32])
+ self.assertEqual(m.path, 'tes\u2000t')
+
+ def test_decode_null_in_filename(self):
+ m = gemato.manifest.ManifestEntryDATA.from_list(['DATA',
+ 'tes\\x00t', 32])
+ self.assertEqual(m.path, 'tes\x00t')
+
+ def test_decode_backslash_in_filename(self):
+ m = gemato.manifest.ManifestEntryDATA.from_list(['DATA',
+ 'tes\\x5Ct', 32])
+ self.assertEqual(m.path, 'tes\\t')
+
+ def test_decode_backslash_in_filename_lc(self):
+ m = gemato.manifest.ManifestEntryDATA.from_list(['DATA',
+ 'tes\\x5ct', 32])
+ self.assertEqual(m.path, 'tes\\t')
+
+ def test_decode_invalid_backslash_in_filename(self):
+ self.assertRaises(gemato.exceptions.ManifestSyntaxError,
+ gemato.manifest.ManifestEntryDATA.from_list,
+ ['DATA', 'tes\\t', 32])
+
+ def test_decode_double_backslash_in_filename(self):
+ self.assertRaises(gemato.exceptions.ManifestSyntaxError,
+ gemato.manifest.ManifestEntryDATA.from_list,
+ ['DATA', 'tes\\\\t', 32])
+
+ def test_decode_trailing_backslash_in_filename(self):
+ self.assertRaises(gemato.exceptions.ManifestSyntaxError,
+ gemato.manifest.ManifestEntryDATA.from_list,
+ ['DATA', 'tes\\', 32])
+
+ def test_decode_empty_x_in_filename(self):
+ self.assertRaises(gemato.exceptions.ManifestSyntaxError,
+ gemato.manifest.ManifestEntryDATA.from_list,
+ ['DATA', 'tes\\xt', 32])
+
+ def test_decode_short_x_in_filename(self):
+ self.assertRaises(gemato.exceptions.ManifestSyntaxError,
+ gemato.manifest.ManifestEntryDATA.from_list,
+ ['DATA', 'tes\\x5t', 32])
+
+ def test_decode_empty_u_in_filename(self):
+ self.assertRaises(gemato.exceptions.ManifestSyntaxError,
+ gemato.manifest.ManifestEntryDATA.from_list,
+ ['DATA', 'tes\\ut', 32])
+
+ def test_decode_short_u_in_filename(self):
+ self.assertRaises(gemato.exceptions.ManifestSyntaxError,
+ gemato.manifest.ManifestEntryDATA.from_list,
+ ['DATA', 'tes\\u345t', 32])
+
+ def test_decode_empty_lu_in_filename(self):
+ self.assertRaises(gemato.exceptions.ManifestSyntaxError,
+ gemato.manifest.ManifestEntryDATA.from_list,
+ ['DATA', 'tes\\Ut', 32])
+
+ def test_decode_short_lu_in_filename(self):
+ self.assertRaises(gemato.exceptions.ManifestSyntaxError,
+ gemato.manifest.ManifestEntryDATA.from_list,
+ ['DATA', 'tes\\U0000345t', 32])