""" Base Class for DesktopEntry, IconTheme and IconData """ import re, os, stat, io from .Exceptions import (ParsingError, DuplicateGroupError, NoGroupError, NoKeyError, DuplicateKeyError, ValidationError, debug) # import xdg.Locale from . import Locale from .util import u def is_ascii(s): """Return True if a string consists entirely of ASCII characters.""" try: s.encode('ascii', 'strict') return True except UnicodeError: return False class IniFile: defaultGroup = '' fileExtension = '' filename = '' tainted = False def __init__(self, filename=None): self.content = dict() if filename: self.parse(filename) def __cmp__(self, other): return cmp(self.content, other.content) def parse(self, filename, headers=None): '''Parse an INI file. headers -- list of headers the parser will try to select as a default header ''' # for performance reasons content = self.content if not os.path.isfile(filename): raise ParsingError("File not found", filename) try: # The content should be UTF-8, but legacy files can have other # encodings, including mixed encodings in one file. We don't attempt # to decode them, but we silence the errors. fd = io.open(filename, 'r', encoding='utf-8', errors='replace') except IOError as e: if debug: raise e else: return # parse file for line in fd: line = line.strip() # empty line if not line: continue # comment elif line[0] == '#': continue # new group elif line[0] == '[': currentGroup = line.lstrip("[").rstrip("]") if debug and self.hasGroup(currentGroup): raise DuplicateGroupError(currentGroup, filename) else: content[currentGroup] = {} # key else: try: key, value = line.split("=", 1) except ValueError: raise ParsingError("Invalid line: " + line, filename) key = key.strip() # Spaces before/after '=' should be ignored try: if debug and self.hasKey(key, currentGroup): raise DuplicateKeyError(key, currentGroup, filename) else: content[currentGroup][key] = value.strip() except (IndexError, UnboundLocalError): raise ParsingError("Parsing error on key, group missing", filename) fd.close() self.filename = filename self.tainted = False # check header if headers: for header in headers: if header in content: self.defaultGroup = header break else: raise ParsingError("[%s]-Header missing" % headers[0], filename) # start stuff to access the keys def get(self, key, group=None, locale=False, type="string", list=False, strict=False): # set default group if not group: group = self.defaultGroup # return key (with locale) if (group in self.content) and (key in self.content[group]): if locale: value = self.content[group][self.__addLocale(key, group)] else: value = self.content[group][key] else: if strict or debug: if group not in self.content: raise NoGroupError(group, self.filename) elif key not in self.content[group]: raise NoKeyError(key, group, self.filename) else: value = "" if list == True: values = self.getList(value) result = [] else: values = [value] for value in values: if type == "boolean": value = self.__getBoolean(value) elif type == "integer": try: value = int(value) except ValueError: value = 0 elif type == "numeric": try: value = float(value) except ValueError: value = 0.0 elif type == "regex": value = re.compile(value) elif type == "point": x, y = value.split(",") value = int(x), int(y) if list == True: result.append(value) else: result = value return result # end stuff to access the keys # start subget def getList(self, string): if re.search(r"(? 0: key = key + "[" + xdg.Locale.langs[0] + "]" try: self.content[group][key] = value except KeyError: raise NoGroupError(group, self.filename) self.tainted = (value == self.get(key, group)) def addGroup(self, group): if self.hasGroup(group): if debug: raise DuplicateGroupError(group, self.filename) else: self.content[group] = {} self.tainted = True def removeGroup(self, group): existed = group in self.content if existed: del self.content[group] self.tainted = True else: if debug: raise NoGroupError(group, self.filename) return existed def removeKey(self, key, group=None, locales=True): # set default group if not group: group = self.defaultGroup try: if locales: for name in list(self.content[group]): if re.match("^" + key + xdg.Locale.regex + "$", name) and name != key: del self.content[group][name] value = self.content[group].pop(key) self.tainted = True return value except KeyError as e: if debug: if e == group: raise NoGroupError(group, self.filename) else: raise NoKeyError(key, group, self.filename) else: return "" # misc def groups(self): return self.content.keys() def hasGroup(self, group): return group in self.content def hasKey(self, key, group=None): # set default group if not group: group = self.defaultGroup return key in self.content[group] def getFileName(self): return self.filename