+++ /dev/null
-"""
-Base Class for DesktopEntry, IconTheme and IconData
-"""
-
-import re, os, stat, codecs
-from Exceptions import *
-import xdg.Locale
-
-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):
- # for performance reasons
- content = self.content
-
- if not os.path.isfile(filename):
- raise ParsingError("File not found", filename)
-
- try:
- fd = file(filename, 'r')
- except IOError, 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:
- index = line.find("=")
- key = line[0:index].strip()
- value = line[index+1:].strip()
- try:
- if debug and self.hasKey(key, currentGroup):
- raise DuplicateKeyError(key, currentGroup, filename)
- else:
- content[currentGroup][key] = value
- 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 content.has_key(header):
- 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):
- # set default group
- if not group:
- group = self.defaultGroup
-
- # return key (with locale)
- if self.content.has_key(group) and self.content[group].has_key(key):
- if locale:
- value = self.content[group][self.__addLocale(key, group)]
- else:
- value = self.content[group][key]
- else:
- if debug:
- if not self.content.has_key(group):
- raise NoGroupError(group, self.filename)
- elif not self.content[group].has_key(key):
- 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 == "string" and locale == True:
- value = value.decode("utf-8", "ignore")
- elif 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":
- value = value.split(",")
-
- 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"(?<!\\)\;", string):
- list = re.split(r"(?<!\\);", string)
- elif re.search(r"(?<!\\)\|", string):
- list = re.split(r"(?<!\\)\|", string)
- elif re.search(r"(?<!\\),", string):
- list = re.split(r"(?<!\\),", string)
- else:
- list = [string]
- if list[-1] == "":
- list.pop()
- return list
-
- def __getBoolean(self, boolean):
- if boolean == 1 or boolean == "true" or boolean == "True":
- return True
- elif boolean == 0 or boolean == "false" or boolean == "False":
- return False
- return False
- # end subget
-
- def __addLocale(self, key, group=None):
- "add locale to key according the current lc_messages"
- # set default group
- if not group:
- group = self.defaultGroup
-
- for lang in xdg.Locale.langs:
- if self.content[group].has_key(key+'['+lang+']'):
- return key+'['+lang+']'
-
- return key
-
- # start validation stuff
- def validate(self, report="All"):
- "validate ... report = All / Warnings / Errors"
-
- self.warnings = []
- self.errors = []
-
- # get file extension
- self.fileExtension = os.path.splitext(self.filename)[1]
-
- # overwrite this for own checkings
- self.checkExtras()
-
- # check all keys
- for group in self.content:
- self.checkGroup(group)
- for key in self.content[group]:
- self.checkKey(key, self.content[group][key], group)
- # check if value is empty
- if self.content[group][key] == "":
- self.warnings.append("Value of Key '%s' is empty" % key)
-
- # raise Warnings / Errors
- msg = ""
-
- if report == "All" or report == "Warnings":
- for line in self.warnings:
- msg += "\n- " + line
-
- if report == "All" or report == "Errors":
- for line in self.errors:
- msg += "\n- " + line
-
- if msg:
- raise ValidationError(msg, self.filename)
-
- # check if group header is valid
- def checkGroup(self, group):
- pass
-
- # check if key is valid
- def checkKey(self, key, value, group):
- pass
-
- # check random stuff
- def checkValue(self, key, value, type="string", list=False):
- if list == True:
- values = self.getList(value)
- else:
- values = [value]
-
- for value in values:
- if type == "string":
- code = self.checkString(value)
- elif type == "boolean":
- code = self.checkBoolean(value)
- elif type == "numeric":
- code = self.checkNumber(value)
- elif type == "integer":
- code = self.checkInteger(value)
- elif type == "regex":
- code = self.checkRegex(value)
- elif type == "point":
- code = self.checkPoint(value)
- if code == 1:
- self.errors.append("'%s' is not a valid %s" % (value, type))
- elif code == 2:
- self.warnings.append("Value of key '%s' is deprecated" % key)
-
- def checkExtras(self):
- pass
-
- def checkBoolean(self, value):
- # 1 or 0 : deprecated
- if (value == "1" or value == "0"):
- return 2
- # true or false: ok
- elif not (value == "true" or value == "false"):
- return 1
-
- def checkNumber(self, value):
- # float() ValueError
- try:
- float(value)
- except:
- return 1
-
- def checkInteger(self, value):
- # int() ValueError
- try:
- int(value)
- except:
- return 1
-
- def checkPoint(self, value):
- if not re.match("^[0-9]+,[0-9]+$", value):
- return 1
-
- def checkString(self, value):
- # convert to ascii
- if not value.decode("utf-8", "ignore").encode("ascii", 'ignore') == value:
- return 1
-
- def checkRegex(self, value):
- try:
- re.compile(value)
- except:
- return 1
-
- # write support
- def write(self, filename=None, trusted=False):
- if not filename and not self.filename:
- raise ParsingError("File not found", "")
-
- if filename:
- self.filename = filename
- else:
- filename = self.filename
-
- if os.path.dirname(filename) and not os.path.isdir(os.path.dirname(filename)):
- os.makedirs(os.path.dirname(filename))
-
- fp = codecs.open(filename, 'w')
-
- # An executable bit signifies that the desktop file is
- # trusted, but then the file can be executed. Add hashbang to
- # make sure that the file is opened by something that
- # understands desktop files.
- if trusted:
- fp.write("#!/usr/bin/env xdg-open\n")
-
- if self.defaultGroup:
- fp.write("[%s]\n" % self.defaultGroup)
- for (key, value) in self.content[self.defaultGroup].items():
- fp.write("%s=%s\n" % (key, value))
- fp.write("\n")
- for (name, group) in self.content.items():
- if name != self.defaultGroup:
- fp.write("[%s]\n" % name)
- for (key, value) in group.items():
- fp.write("%s=%s\n" % (key, value))
- fp.write("\n")
-
- # Add executable bits to the file to show that it's trusted.
- if trusted:
- oldmode = os.stat(filename).st_mode
- mode = oldmode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
- os.chmod(filename, mode)
-
- self.tainted = False
-
- def set(self, key, value, group=None, locale=False):
- # set default group
- if not group:
- group = self.defaultGroup
-
- if locale == True and len(xdg.Locale.langs) > 0:
- key = key + "[" + xdg.Locale.langs[0] + "]"
-
- try:
- if isinstance(value, unicode):
- self.content[group][key] = value.encode("utf-8", "ignore")
- else:
- 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:
- pass
- 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, value) in self.content[group].items():
- if re.match("^" + key + xdg.Locale.regex + "$", name) and name != key:
- value = self.content[group][name]
- del self.content[group][name]
- value = self.content[group][key]
- del self.content[group][key]
- self.tainted = True
- return value
- except KeyError, 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):
- if self.content.has_key(group):
- return True
- else:
- return False
-
- def hasKey(self, key, group=None):
- # set default group
- if not group:
- group = self.defaultGroup
-
- if self.content[group].has_key(key):
- return True
- else:
- return False
-
- def getFileName(self):
- return self.filename