3 from rox
import g
, basedir
4 from xml
.parsers
import expat
5 from xml
.dom
import XML_NAMESPACE
, Node
8 from override
import FREE_NS
12 home_mime
= os
.path
.join(basedir
.xdg_data_home
, 'mime')
15 return ''.join([text
.nodeValue
for text
in node
.childNodes
16 if text
.nodeType
== Node
.TEXT_NODE
])
20 types
[name
] = MIME_Type(name
)
24 def __init__(self
, name
):
25 assert name
not in types
26 self
.media
, self
.subtype
= name
.split('/')
35 def add_comment(self
, lang
, comment
, user
):
36 self
.comments
.append((lang
, comment
, user
))
38 def add_xml(self
, uri
, name
, user
):
39 self
.xml
.append((uri
, name
, user
))
41 def add_magic(self
, prio
, root
, user
):
42 self
.magic
.append((prio
, root
, user
))
44 def add_tree_magic(self
, prio
, matches
, user
):
45 self
.tree_magic
.append((prio
, matches
, user
))
47 def add_other(self
, element
, user
):
48 self
.others
.append((element
, user
))
50 def add_glob(self
, pattern
, user
):
51 self
.globs
.append((pattern
, user
))
53 def get_comment(self
):
55 for lang
, comment
, user
in self
.comments
:
59 return best
or self
.get_name()
62 return self
.media
+ '/' + self
.subtype
64 def make(self
, klass
, list):
65 return [klass(self
, item
) for item
in list]
67 def get_comments(self
): return self
.make(fields
.Comment
, self
.comments
)
68 def get_globs(self
): return self
.make(fields
.Glob
, self
.globs
)
69 def get_magic(self
): return self
.make(fields
.Magic
, self
.magic
)
70 def get_tree_magic(self
): return self
.make(fields
.TreeMagic
, self
.tree_magic
)
71 def get_xml(self
): return self
.make(fields
.XML
, self
.xml
)
72 def get_others(self
): return self
.make(fields
.Other
, self
.others
)
74 def remove_user(self
):
75 for list in ['comments', 'globs', 'magic', 'xml', 'others']:
77 [x
for x
in getattr(self
, list) if not x
[-1]])
80 def __init__(self
, type, attrs
):
83 def start(self
, element
, attrs
): pass
84 def data(self
, data
): pass
87 class CommentParser(FieldParser
):
88 def __init__(self
, type, attrs
, user
):
89 FieldParser
.__init
__(self
, type, attrs
)
90 self
.lang
= attrs
.get(XML_NAMESPACE
+ ' lang', None)
98 self
.type.add_comment(self
.lang
, self
.comment
, self
.user
)
101 def __init__(self
, parent
, user
):
106 self
.offset
= self
.type = self
.value
= self
.mask
= None
108 def write_xml(self
, node
):
109 for m
in self
.matches
:
110 new
= node
.ownerDocument
.createElementNS(FREE_NS
, 'match')
111 new
.setAttributeNS(None, 'offset', m
.offset
)
112 new
.setAttributeNS(None, 'type', m
.type)
113 new
.setAttributeNS(None, 'value', m
.value
)
115 new
.setAttributeNS(None, 'mask', m
.mask
)
116 node
.appendChild(new
)
119 def equals_node(self
, node
):
121 if node
.localName
!= 'match' or node
.namespaceURI
!= FREE_NS
:
124 a
= node
.getAttributeNS(None, x
)
125 if a
is None or a
== '': return d
127 offset
= get('offset', '?')
128 type = get('type', '?')
129 value
= get('value', '?')
130 mask
= get('mask', None)
131 if self
.offset
!= offset
or self
.type != type or \
132 self
.value
!= value
or self
.mask
!= mask
:
136 for k
in node
.childNodes
:
137 if k
.nodeType
!= Node
.ELEMENT_NODE
: continue
138 if k
.localName
!= 'match' or k
.namespaceURI
!= FREE_NS
: continue
141 if len(self
.matches
) != len(kids
):
144 for m
, k
in zip(self
.matches
, kids
):
145 if not m
.equals_node(k
): return False
149 class MagicParser(FieldParser
):
150 def __init__(self
, type, attrs
, user
):
151 FieldParser
.__init
__(self
, type, attrs
)
152 self
.prio
= int(attrs
.get('priority', 50))
153 self
.match
= Match(None, user
)
156 def start(self
, element
, attrs
):
157 new
= Match(self
.match
, self
.user
)
158 new
.offset
= attrs
.get('offset', '?')
159 new
.type = attrs
.get('type', '?')
160 new
.value
= attrs
.get('value', '?')
161 new
.mask
= attrs
.get('mask', None)
162 self
.match
.matches
.append(new
)
166 if self
.match
.parent
:
167 self
.match
= self
.match
.parent
169 self
.type.add_magic(self
.prio
, self
.match
, self
.user
)
172 def __init__(self
, parent
, user
):
177 self
.path
= self
.type = self
.match_case
= self
.executable
= self
.non_empty
= self
.mimetype
= None
180 return "<%s: %s %s %s %s %s>" % (self
.path
, self
.type, self
.match_case
, self
.executable
, self
.non_empty
, self
.mimetype
)
182 class TreeMagicParser(FieldParser
):
183 def __init__(self
, type, attrs
, user
):
184 FieldParser
.__init
__(self
, type, attrs
)
185 self
.prio
= int(attrs
.get('priority', 50))
191 def start(self
, element
, attrs
):
192 new
= TreeMatch(self
.match
, self
.user
)
194 new
.path
= attrs
.get('path', '?')
195 new
.type = attrs
.get('type', '?')
196 new
.match_case
= attrs
.get('match-case', '?')
197 new
.executable
= attrs
.get('executable', '?')
198 new
.non_empty
= attrs
.get('non-empty', '?')
199 new
.mimetype
= attrs
.get('mimetype', '?')
201 self
.match
.matches
.append(new
)
205 if self
.match
.parent
:
206 self
.match
= self
.match
.parent
208 self
.type.add_tree_magic(self
.prio
, self
.matches
, self
.user
)
211 return "treemagic: " + '\n'.join([str(m
) for m
in self
.matches
])
219 def parse(self
, path
, user
):
220 parser
= expat
.ParserCreate(namespace_separator
= ' ')
221 parser
.StartElementHandler
= self
.start
222 parser
.EndElementHandler
= self
.end
223 parser
.CharacterDataHandler
= self
.data
225 parser
.ParseFile(file(path
))
227 def start(self
, element
, attrs
):
230 assert element
== FREE_NS
+ ' mime-info'
231 elif self
.level
== 2:
232 assert element
== FREE_NS
+ ' mime-type'
233 self
.type = get_type(attrs
['type'])
234 elif self
.level
== 3:
235 if element
== FREE_NS
+ ' comment':
236 self
.handler
= CommentParser(self
.type, attrs
,
238 elif element
== FREE_NS
+ ' glob':
239 self
.type.add_glob(attrs
['pattern'], self
.user
)
240 elif element
== FREE_NS
+ ' magic':
241 self
.handler
= MagicParser(self
.type, attrs
,
243 elif element
== FREE_NS
+ ' root-XML':
244 self
.type.add_xml(attrs
['namespaceURI'],
247 elif element
== FREE_NS
+ ' treemagic':
248 self
.handler
= TreeMagicParser(self
.type, attrs
, self
.user
)
250 self
.type.add_other(element
, self
.user
)
252 assert self
.handler
, "Unknown element <%s>" % element
253 self
.handler
.start(element
, attrs
)
255 def end(self
, element
):
261 elif self
.level
== 2:
264 def data(self
, data
):
266 self
.handler
.data(data
)
268 def scan_file(path
, user
):
269 if not path
.endswith('.xml'): return
270 if not os
.path
.exists(path
):
274 scanner
.parse(path
, user
)
276 rox
.report_exception()
278 def add_type(name
, comment
, glob
):
279 doc
= override
.get_override()
281 root
= doc
.documentElement
282 type_node
= doc
.createElementNS(FREE_NS
, 'mime-type')
283 root
.appendChild(type_node
)
285 type_node
.setAttributeNS(None, 'type', name
)
287 f
= doc
.createElementNS(FREE_NS
, 'comment')
288 f
.appendChild(doc
.createTextNode(comment
))
289 type_node
.appendChild(f
)
292 f
= doc
.createElementNS(FREE_NS
, 'glob')
293 f
.setAttributeNS(None, 'pattern', glob
)
294 type_node
.appendChild(f
)
296 override
.write_override(doc
)
298 __main__
.box
.show_type(name
)
300 def delete_type(name
):
301 doc
= override
.get_override()
303 for c
in doc
.documentElement
.childNodes
:
304 if c
.nodeType
!= Node
.ELEMENT_NODE
: continue
305 if c
.nodeName
!= 'mime-type': continue
306 if c
.namespaceURI
!= FREE_NS
: continue
307 if c
.getAttributeNS(None, 'type') != name
: continue
308 doc
.documentElement
.removeChild(c
)
311 rox
.alert(_("No user-provided information about this type -- can't remove anything"))
313 if not rox
.confirm(_("Really remove all user-specified information about type %s?") % name
,
316 override
.write_override(doc
)
318 # Type names defined even without Override.xml
322 "(Re)read the database."
323 global types
, system_types
324 if system_types
is None:
326 for mime_dir
in basedir
.load_data_paths('mime'):
327 packages_dir
= os
.path
.join(mime_dir
, 'packages')
328 if not os
.path
.isdir(packages_dir
):
330 packages
= os
.listdir(packages_dir
)
332 for package
in packages
:
333 if package
== 'Override.xml' and mime_dir
== home_mime
: continue
334 scan_file(os
.path
.join(packages_dir
, package
), False)
335 system_types
= types
.keys()
337 for t
in types
.keys():
338 if t
not in system_types
:
340 for t
in types
.values():
342 scan_file(override
.user_override
, True)