home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / var / lib / python-support / python2.4 / xdg / Mime.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2006-08-31  |  13.9 KB  |  510 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.4)
  3.  
  4. """
  5. This module is based on a rox module (LGPL):
  6.  
  7. http://cvs.sourceforge.net/viewcvs.py/rox/ROX-Lib2/python/rox/mime.py?rev=1.21&view=log
  8.  
  9. This module provides access to the shared MIME database.
  10.  
  11. types is a dictionary of all known MIME types, indexed by the type name, e.g.
  12. types['application/x-python']
  13.  
  14. Applications can install information about MIME types by storing an
  15. XML file as <MIME>/packages/<application>.xml and running the
  16. update-mime-database command, which is provided by the freedesktop.org
  17. shared mime database package.
  18.  
  19. See http://www.freedesktop.org/standards/shared-mime-info-spec/ for
  20. information about the format of these files.
  21.  
  22. (based on version 0.13)
  23. """
  24. import os
  25. import stat
  26. import fnmatch
  27. import xdg.BaseDirectory as xdg
  28. import xdg.Locale as xdg
  29. from xml.dom import Node, minidom, XML_NAMESPACE
  30. FREE_NS = 'http://www.freedesktop.org/standards/shared-mime-info'
  31. types = { }
  32. exts = None
  33. globs = None
  34. literals = None
  35. magic = None
  36.  
  37. def _get_node_data(node):
  38.     '''Get text of XML node'''
  39.     return []([ n.nodeValue for n in node.childNodes ]).strip()
  40.  
  41.  
  42. def lookup(media, subtype = None):
  43.     '''Get the MIMEtype object for this type, creating a new one if needed.'''
  44.     if subtype is None and '/' in media:
  45.         (media, subtype) = media.split('/', 1)
  46.     
  47.     if (media, subtype) not in types:
  48.         types[(media, subtype)] = MIMEtype(media, subtype)
  49.     
  50.     return types[(media, subtype)]
  51.  
  52.  
  53. class MIMEtype:
  54.     '''Type holding data about a MIME type'''
  55.     
  56.     def __init__(self, media, subtype):
  57.         """Don't use this constructor directly; use mime.lookup() instead."""
  58.         if not media or '/' not in media:
  59.             raise AssertionError
  60.         if not subtype or '/' not in subtype:
  61.             raise AssertionError
  62.         if not (media, subtype) not in types:
  63.             raise AssertionError
  64.         self.media = media
  65.         self.subtype = subtype
  66.         self._comment = None
  67.  
  68.     
  69.     def _load(self):
  70.         '''Loads comment for current language. Use get_comment() instead.'''
  71.         resource = os.path.join('mime', self.media, self.subtype + '.xml')
  72.         for path in xdg.BaseDirectory.load_data_paths(resource):
  73.             doc = minidom.parse(path)
  74.             if doc is None:
  75.                 continue
  76.             
  77.             for comment in doc.documentElement.getElementsByTagNameNS(FREE_NS, 'comment'):
  78.                 if not comment.getAttributeNS(XML_NAMESPACE, 'lang'):
  79.                     pass
  80.                 lang = 'en'
  81.                 goodness = 1 + (lang in xdg.Locale.langs)
  82.                 if goodness > self._comment[0]:
  83.                     self._comment = (goodness, _get_node_data(comment))
  84.                 
  85.                 if goodness == 2:
  86.                     return None
  87.                     continue
  88.             
  89.         
  90.  
  91.     
  92.     def get_comment(self):
  93.         '''Returns comment for current language, loading it if needed.'''
  94.         if self._comment is None:
  95.             self._comment = (0, str(self))
  96.             self._load()
  97.         
  98.         return self._comment[1]
  99.  
  100.     
  101.     def __str__(self):
  102.         return self.media + '/' + self.subtype
  103.  
  104.     
  105.     def __repr__(self):
  106.         if not self._comment:
  107.             pass
  108.         return '[%s: %s]' % (self, '(comment not loaded)')
  109.  
  110.  
  111.  
  112. class MagicRule:
  113.     
  114.     def __init__(self, f):
  115.         self.next = None
  116.         self.prev = None
  117.         ind = ''
  118.         while True:
  119.             c = f.read(1)
  120.             if c == '>':
  121.                 break
  122.             
  123.             ind += c
  124.         if not ind:
  125.             self.nest = 0
  126.         else:
  127.             self.nest = int(ind)
  128.         start = ''
  129.         while True:
  130.             c = f.read(1)
  131.             if c == '=':
  132.                 break
  133.             
  134.             start += c
  135.         self.start = int(start)
  136.         hb = f.read(1)
  137.         lb = f.read(1)
  138.         self.lenvalue = ord(lb) + (ord(hb) << 8)
  139.         self.value = f.read(self.lenvalue)
  140.         c = f.read(1)
  141.         if c == '&':
  142.             self.mask = f.read(self.lenvalue)
  143.             c = f.read(1)
  144.         else:
  145.             self.mask = None
  146.         if c == '~':
  147.             w = ''
  148.             while c != '+' and c != '\n':
  149.                 c = f.read(1)
  150.                 if c == '+' or c == '\n':
  151.                     break
  152.                 
  153.                 w += c
  154.             self.word = int(w)
  155.         else:
  156.             self.word = 1
  157.         if c == '+':
  158.             r = ''
  159.             while c != '\n':
  160.                 c = f.read(1)
  161.                 if c == '\n':
  162.                     break
  163.                 
  164.                 r += c
  165.             self.range = int(r)
  166.         else:
  167.             self.range = 1
  168.         if c != '\n':
  169.             raise 'Malformed MIME magic line'
  170.         
  171.  
  172.     
  173.     def getLength(self):
  174.         return self.start + self.lenvalue + self.range
  175.  
  176.     
  177.     def appendRule(self, rule):
  178.         if self.nest < rule.nest:
  179.             self.next = rule
  180.             rule.prev = self
  181.         elif self.prev:
  182.             self.prev.appendRule(rule)
  183.         
  184.  
  185.     
  186.     def match(self, buffer):
  187.         if self.match0(buffer):
  188.             if self.next:
  189.                 return self.next.match(buffer)
  190.             
  191.             return True
  192.         
  193.  
  194.     
  195.     def match0(self, buffer):
  196.         l = len(buffer)
  197.         for o in range(self.range):
  198.             s = self.start + o
  199.             e = s + self.lenvalue
  200.             if l < e:
  201.                 return False
  202.             
  203.             if self.mask:
  204.                 test = ''
  205.                 for i in range(self.lenvalue):
  206.                     c = ord(buffer[s + i]) & ord(self.mask[i])
  207.                     test += chr(c)
  208.                 
  209.             else:
  210.                 test = buffer[s:e]
  211.             if test == self.value:
  212.                 return True
  213.                 continue
  214.         
  215.  
  216.     
  217.     def __repr__(self):
  218.         return '<MagicRule %d>%d=[%d]%s&%s~%d+%d>' % (self.nest, self.start, self.lenvalue, `self.value`, `self.mask`, self.word, self.range)
  219.  
  220.  
  221.  
  222. class MagicType:
  223.     
  224.     def __init__(self, mtype):
  225.         self.mtype = mtype
  226.         self.top_rules = []
  227.         self.last_rule = None
  228.  
  229.     
  230.     def getLine(self, f):
  231.         nrule = MagicRule(f)
  232.         if nrule.nest and self.last_rule:
  233.             self.last_rule.appendRule(nrule)
  234.         else:
  235.             self.top_rules.append(nrule)
  236.         self.last_rule = nrule
  237.         return nrule
  238.  
  239.     
  240.     def match(self, buffer):
  241.         for rule in self.top_rules:
  242.             if rule.match(buffer):
  243.                 return self.mtype
  244.                 continue
  245.         
  246.  
  247.     
  248.     def __repr__(self):
  249.         return '<MagicType %s>' % self.mtype
  250.  
  251.  
  252.  
  253. class MagicDB:
  254.     
  255.     def __init__(self):
  256.         self.types = { }
  257.         self.maxlen = 0
  258.  
  259.     
  260.     def mergeFile(self, fname):
  261.         f = file(fname, 'r')
  262.         line = f.readline()
  263.         if line != 'MIME-Magic\x00\n':
  264.             raise 'Not a MIME magic file'
  265.         
  266.         while True:
  267.             shead = f.readline()
  268.             if not shead:
  269.                 break
  270.             
  271.             if shead[0] != '[' or shead[-2:] != ']\n':
  272.                 raise 'Malformed section heading'
  273.             
  274.             (pri, tname) = shead[1:-2].split(':')
  275.             pri = int(pri)
  276.             mtype = lookup(tname)
  277.             
  278.             try:
  279.                 ents = self.types[pri]
  280.             except:
  281.                 ents = []
  282.                 self.types[pri] = ents
  283.  
  284.             magictype = MagicType(mtype)
  285.             c = f.read(1)
  286.             f.seek(-1, 1)
  287.             while c and c != '[':
  288.                 rule = magictype.getLine(f)
  289.                 if rule and rule.getLength() > self.maxlen:
  290.                     self.maxlen = rule.getLength()
  291.                 
  292.                 c = f.read(1)
  293.                 f.seek(-1, 1)
  294.             ents.append(magictype)
  295.             if not c:
  296.                 break
  297.                 continue
  298.  
  299.     
  300.     def match(self, path, max_pri = 100, min_pri = 0):
  301.         
  302.         try:
  303.             buf = file(path, 'r').read(self.maxlen)
  304.             pris = self.types.keys()
  305.             pris.sort((lambda a, b: -cmp(a, b)))
  306.             for pri in pris:
  307.                 if pri > max_pri:
  308.                     continue
  309.                 
  310.                 if pri < min_pri:
  311.                     break
  312.                 
  313.                 for type in self.types[pri]:
  314.                     m = type.match(buf)
  315.                     if m:
  316.                         return m
  317.                         continue
  318.                 
  319.         except:
  320.             pass
  321.  
  322.  
  323.     
  324.     def __repr__(self):
  325.         return '<MagicDB %s>' % self.types
  326.  
  327.  
  328. text = lookup('text', 'plain')
  329. inode_block = lookup('inode', 'blockdevice')
  330. inode_char = lookup('inode', 'chardevice')
  331. inode_dir = lookup('inode', 'directory')
  332. inode_fifo = lookup('inode', 'fifo')
  333. inode_socket = lookup('inode', 'socket')
  334. inode_symlink = lookup('inode', 'symlink')
  335. inode_door = lookup('inode', 'door')
  336. app_exe = lookup('application', 'executable')
  337. _cache_uptodate = False
  338.  
  339. def _cache_database():
  340.     global _cache_uptodate, exts, globs, literals, magic
  341.     _cache_uptodate = True
  342.     exts = { }
  343.     globs = []
  344.     literals = { }
  345.     magic = MagicDB()
  346.     
  347.     def _import_glob_file(path):
  348.         '''Loads name matching information from a MIME directory.'''
  349.         for line in file(path):
  350.             if line.startswith('#'):
  351.                 continue
  352.             
  353.             line = line[:-1]
  354.             (type_name, pattern) = line.split(':', 1)
  355.             mtype = lookup(type_name)
  356.             if pattern.startswith('*.'):
  357.                 rest = pattern[2:]
  358.                 if not '*' in rest and '[' in rest or '?' in rest:
  359.                     exts[rest] = mtype
  360.                     continue
  361.                 
  362.             
  363.             if '*' in pattern and '[' in pattern or '?' in pattern:
  364.                 globs.append((pattern, mtype))
  365.                 continue
  366.             literals[pattern] = mtype
  367.         
  368.  
  369.     for path in xdg.BaseDirectory.load_data_paths(os.path.join('mime', 'globs')):
  370.         _import_glob_file(path)
  371.     
  372.     for path in xdg.BaseDirectory.load_data_paths(os.path.join('mime', 'magic')):
  373.         magic.mergeFile(path)
  374.     
  375.     globs.sort((lambda a, b: cmp(len(b[0]), len(a[0]))))
  376.  
  377.  
  378. def get_type_by_name(path):
  379.     '''Returns type of file by its name, or None if not known'''
  380.     if not _cache_uptodate:
  381.         _cache_database()
  382.     
  383.     leaf = os.path.basename(path)
  384.     if leaf in literals:
  385.         return literals[leaf]
  386.     
  387.     lleaf = leaf.lower()
  388.     if lleaf in literals:
  389.         return literals[lleaf]
  390.     
  391.     ext = leaf
  392.     while None:
  393.         p = ext.find('.')
  394.         if p < 0:
  395.             break
  396.         
  397.         ext = ext[p + 1:]
  398.         if ext in exts:
  399.             return exts[ext]
  400.             continue
  401.     ext = lleaf
  402.     while None:
  403.         p = ext.find('.')
  404.         if p < 0:
  405.             break
  406.         
  407.         ext = ext[p + 1:]
  408.         if ext in exts:
  409.             return exts[ext]
  410.             continue
  411.     for glob, mime_type in globs:
  412.         if fnmatch.fnmatch(leaf, glob):
  413.             return mime_type
  414.         
  415.         if fnmatch.fnmatch(lleaf, glob):
  416.             return mime_type
  417.             continue
  418.     
  419.  
  420.  
  421. def get_type_by_contents(path, max_pri = 100, min_pri = 0):
  422.     '''Returns type of file by its contents, or None if not known'''
  423.     if not _cache_uptodate:
  424.         _cache_database()
  425.     
  426.     return magic.match(path, max_pri, min_pri)
  427.  
  428.  
  429. def get_type(path, follow = 1, name_pri = 100):
  430.     '''Returns type of file indicated by path.
  431. \tpath\t - pathname to check (need not exist)
  432. \tfollow   - when reading file, follow symbolic links
  433. \tname_pri - Priority to do name matches.  100=override magic'''
  434.     if not _cache_uptodate:
  435.         _cache_database()
  436.     
  437.     
  438.     try:
  439.         if follow:
  440.             st = os.stat(path)
  441.         else:
  442.             st = os.lstat(path)
  443.     except:
  444.         t = get_type_by_name(path)
  445.         if not t:
  446.             pass
  447.         return text
  448.  
  449.     if stat.S_ISREG(st.st_mode):
  450.         t = get_type_by_contents(path, min_pri = name_pri)
  451.         if not t:
  452.             t = get_type_by_name(path)
  453.         
  454.         if not t:
  455.             t = get_type_by_contents(path, max_pri = name_pri)
  456.         
  457.         if t is None:
  458.             if stat.S_IMODE(st.st_mode) & 73:
  459.                 return app_exe
  460.             else:
  461.                 return text
  462.         
  463.         return t
  464.     elif stat.S_ISDIR(st.st_mode):
  465.         return inode_dir
  466.     elif stat.S_ISCHR(st.st_mode):
  467.         return inode_char
  468.     elif stat.S_ISBLK(st.st_mode):
  469.         return inode_block
  470.     elif stat.S_ISFIFO(st.st_mode):
  471.         return inode_fifo
  472.     elif stat.S_ISLNK(st.st_mode):
  473.         return inode_symlink
  474.     elif stat.S_ISSOCK(st.st_mode):
  475.         return inode_socket
  476.     
  477.     return inode_door
  478.  
  479.  
  480. def install_mime_info(application, package_file):
  481.     """Copy 'package_file' as ~/.local/share/mime/packages/<application>.xml.
  482. \tIf package_file is None, install <app_dir>/<application>.xml.
  483. \tIf already installed, does nothing. May overwrite an existing
  484. \tfile with the same name (if the contents are different)"""
  485.     global _cache_uptodate
  486.     application += '.xml'
  487.     new_data = file(package_file).read()
  488.     package_dir = os.path.join('mime', 'packages')
  489.     resource = os.path.join(package_dir, application)
  490.     for x in xdg.BaseDirectory.load_data_paths(resource):
  491.         
  492.         try:
  493.             old_data = file(x).read()
  494.         except:
  495.             continue
  496.  
  497.         if old_data == new_data:
  498.             return None
  499.             continue
  500.     
  501.     _cache_uptodate = False
  502.     new_file = os.path.join(xdg.BaseDirectory.save_data_path(package_dir), application)
  503.     file(new_file, 'w').write(new_data)
  504.     command = 'update-mime-database'
  505.     if os.spawnlp(os.P_WAIT, command, command, xdg.BaseDirectory.save_data_path('mime')):
  506.         os.unlink(new_file)
  507.         raise Exception("The '%s' command returned an error code!\nMake sure you have the freedesktop.org shared MIME package:\nhttp://standards.freedesktop.org/shared-mime-info/") % command
  508.     
  509.  
  510.