1313"""
1414
1515import os
16+ import re
17+ import sys
1618import threading
1719from itertools import chain
1820
2224_cache = {}
2325_cache_lock = threading .RLock ()
2426_dirname = os .path .join (os .path .dirname (__file__ ), 'locale-data' )
27+ _windows_reserved_name_re = re .compile ("^(con|prn|aux|nul|com[0-9]|lpt[0-9])$" , re .I )
2528
2629
2730def normalize_locale (name ):
@@ -38,6 +41,22 @@ def normalize_locale(name):
3841 return locale_id
3942
4043
44+ def resolve_locale_filename (name ):
45+ """
46+ Resolve a locale identifier to a `.dat` path on disk.
47+ """
48+
49+ # Clean up any possible relative paths.
50+ name = os .path .basename (name )
51+
52+ # Ensure we're not left with one of the Windows reserved names.
53+ if sys .platform == "win32" and _windows_reserved_name_re .match (os .path .splitext (name )[0 ]):
54+ raise ValueError ("Name %s is invalid on Windows" % name )
55+
56+ # Build the path.
57+ return os .path .join (_dirname , '%s.dat' % name )
58+
59+
4160def exists (name ):
4261 """Check whether locale data is available for the given locale.
4362
@@ -47,10 +66,9 @@ def exists(name):
4766 """
4867 if not name or not isinstance (name , string_types ):
4968 return False
50- name = os .path .basename (name )
5169 if name in _cache :
5270 return True
53- file_found = os .path .exists (os . path . join ( _dirname , '%s.dat' % name ))
71+ file_found = os .path .exists (resolve_locale_filename ( name ))
5472 return True if file_found else bool (normalize_locale (name ))
5573
5674
@@ -121,7 +139,7 @@ def load(name, merge_inherited=True):
121139 else :
122140 parent = '_' .join (parts [:- 1 ])
123141 data = load (parent ).copy ()
124- filename = os . path . join ( _dirname , '%s.dat' % name )
142+ filename = resolve_locale_filename ( name )
125143 with open (filename , 'rb' ) as fileobj :
126144 if name != 'root' and merge_inherited :
127145 merge (data , pickle .load (fileobj ))
0 commit comments