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(os
.environ
['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('/')
34 def add_comment(self
, lang
, comment
, user
):
35 self
.comments
.append((lang
, comment
, user
))
37 def add_xml(self
, uri
, name
, user
):
38 self
.xml
.append((uri
, name
, user
))
40 def add_magic(self
, prio
, root
, user
):
41 self
.magic
.append((prio
, root
, user
))
43 def add_other(self
, element
, user
):
44 self
.others
.append((element
, user
))
46 def add_glob(self
, pattern
, user
):
47 self
.globs
.append((pattern
, user
))
49 def get_comment(self
):
51 for lang
, comment
, user
in self
.comments
:
55 return best
or self
.get_name()
58 return self
.media
+ '/' + self
.subtype
60 def make(self
, klass
, list):
61 return [klass(self
, item
) for item
in list]
63 def get_comments(self
): return self
.make(fields
.Comment
, self
.comments
)
64 def get_globs(self
): return self
.make(fields
.Glob
, self
.globs
)
65 def get_magic(self
): return self
.make(fields
.Magic
, self
.magic
)
66 def get_xml(self
): return self
.make(fields
.XML
, self
.xml
)
67 def get_others(self
): return self
.make(fields
.Other
, self
.others
)
69 def remove_user(self
):
70 for list in ['comments', 'globs', 'magic', 'xml', 'others']:
72 [x
for x
in getattr(self
, list) if not x
[-1]])
75 def __init__(self
, type, attrs
):
78 def start(self
, element
, attrs
): pass
79 def data(self
, data
): pass
82 class CommentParser(FieldParser
):
83 def __init__(self
, type, attrs
, user
):
84 FieldParser
.__init
__(self
, type, attrs
)
85 self
.lang
= attrs
.get(XML_NAMESPACE
+ ' lang', None)
93 self
.type.add_comment(self
.lang
, self
.comment
, self
.user
)
96 def __init__(self
, parent
, user
):
101 self
.offset
= self
.type = self
.value
= self
.mask
= None
103 def write_xml(self
, node
):
104 for m
in self
.matches
:
105 new
= node
.ownerDocument
.createElementNS(FREE_NS
, 'match')
106 new
.setAttributeNS(None, 'offset', m
.offset
)
107 new
.setAttributeNS(None, 'type', m
.type)
108 new
.setAttributeNS(None, 'value', m
.value
)
110 new
.setAttributeNS(None, 'mask', m
.mask
)
111 node
.appendChild(new
)
114 def equals_node(self
, node
):
116 if node
.localName
!= 'match' or node
.namespaceURI
!= FREE_NS
:
119 a
= node
.getAttributeNS(None, x
)
120 if a
is None or a
== '': return d
122 offset
= get('offset', '?')
123 type = get('type', '?')
124 value
= get('value', '?')
125 mask
= get('mask', None)
126 if self
.offset
!= offset
or self
.type != type or \
127 self
.value
!= value
or self
.mask
!= mask
:
131 for k
in node
.childNodes
:
132 if k
.nodeType
!= Node
.ELEMENT_NODE
: continue
133 if k
.localName
!= 'match' or k
.namespaceURI
!= FREE_NS
: continue
136 if len(self
.matches
) != len(kids
):
139 for m
, k
in zip(self
.matches
, kids
):
140 if not m
.equals_node(k
): return False
144 class MagicParser(FieldParser
):
145 def __init__(self
, type, attrs
, user
):
146 FieldParser
.__init
__(self
, type, attrs
)
147 self
.prio
= int(attrs
.get('priority', 50))
148 self
.match
= Match(None, user
)
151 def start(self
, element
, attrs
):
152 new
= Match(self
.match
, self
.user
)
153 new
.offset
= attrs
.get('offset', '?')
154 new
.type = attrs
.get('type', '?')
155 new
.value
= attrs
.get('value', '?')
156 new
.mask
= attrs
.get('mask', None)
157 self
.match
.matches
.append(new
)
161 if self
.match
.parent
:
162 self
.match
= self
.match
.parent
164 self
.type.add_magic(self
.prio
, self
.match
, self
.user
)
172 def parse(self
, path
, user
):
173 parser
= expat
.ParserCreate(namespace_separator
= ' ')
174 parser
.StartElementHandler
= self
.start
175 parser
.EndElementHandler
= self
.end
176 parser
.CharacterDataHandler
= self
.data
178 parser
.ParseFile(file(path
))
180 def start(self
, element
, attrs
):
183 assert element
== FREE_NS
+ ' mime-info'
184 elif self
.level
== 2:
185 assert element
== FREE_NS
+ ' mime-type'
186 self
.type = get_type(attrs
['type'])
187 elif self
.level
== 3:
188 if element
== FREE_NS
+ ' comment':
189 self
.handler
= CommentParser(self
.type, attrs
,
191 elif element
== FREE_NS
+ ' glob':
192 self
.type.add_glob(attrs
['pattern'], self
.user
)
193 elif element
== FREE_NS
+ ' magic':
194 self
.handler
= MagicParser(self
.type, attrs
,
196 elif element
== FREE_NS
+ ' root-XML':
197 self
.type.add_xml(attrs
['namespaceURI'],
201 self
.type.add_other(element
, self
.user
)
204 self
.handler
.start(element
, attrs
)
206 def end(self
, element
):
212 elif self
.level
== 2:
215 def data(self
, data
):
217 self
.handler
.data(data
)
219 def scan_file(path
, user
):
220 if not path
.endswith('.xml'): return
221 if not os
.path
.exists(path
):
225 scanner
.parse(path
, user
)
227 rox
.report_exception()
229 def add_type(name
, comment
, glob
):
230 doc
= override
.get_override()
232 root
= doc
.documentElement
233 type_node
= doc
.createElementNS(FREE_NS
, 'mime-type')
234 root
.appendChild(type_node
)
236 type_node
.setAttributeNS(None, 'type', name
)
238 f
= doc
.createElementNS(FREE_NS
, 'comment')
239 f
.appendChild(doc
.createTextNode(comment
))
240 type_node
.appendChild(f
)
243 f
= doc
.createElementNS(FREE_NS
, 'glob')
244 f
.setAttributeNS(None, 'pattern', glob
)
245 type_node
.appendChild(f
)
247 override
.write_override(doc
)
249 __main__
.box
.show_type(name
)
251 def delete_type(name
):
252 doc
= override
.get_override()
254 for c
in doc
.documentElement
.childNodes
:
255 if c
.nodeType
!= Node
.ELEMENT_NODE
: continue
256 if c
.nodeName
!= 'mime-type': continue
257 if c
.namespaceURI
!= FREE_NS
: continue
258 if c
.getAttributeNS(None, 'type') != name
: continue
259 doc
.documentElement
.removeChild(c
)
262 rox
.alert("No user-provided information about this type -- can't remove anything")
264 if not rox
.confirm("Really remove all user-specified information about type %s?" % name
,
267 override
.write_override(doc
)
269 # Type names defined even without Override.xml
273 "(Re)read the database."
274 global types
, system_types
275 if system_types
is None:
277 for mime_dir
in ['/usr/share/mime', '/usr/local/share/mime', home_mime
]:
278 packages_dir
= os
.path
.join(mime_dir
, 'packages')
279 if not os
.path
.isdir(packages_dir
):
281 packages
= os
.listdir(packages_dir
)
283 for package
in packages
:
284 if package
== 'Override.xml' and mime_dir
is home_mime
: continue
285 scan_file(os
.path
.join(packages_dir
, package
), False)
286 system_types
= types
.keys()
288 for t
in types
.keys():
289 if t
not in system_types
:
291 for t
in types
.values():
293 scan_file(override
.user_override
, True)