2 Baseclass for reading PDML produced from TShark.
4 Copyright (c) 2003 by Gilbert Ramirez <gram@alumni.rice.edu>
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 from xml.sax import saxlib
23 from xml.sax import saxexts
24 from xml.sax import saxutils
29 class FoundItException(Exception):
33 """Holds Packet objects, and has methods for finding
36 def __init__(self, children=None):
40 self.children = children
42 def __getitem__(self, index):
43 """We act like a list."""
44 return self.children[index]
47 def item_exists(self, name):
48 """Does an item with name 'name' exist in this
50 for child in self.children:
51 if child.name == name:
55 for child in self.children:
56 child._item_exists(name)
58 except FoundItException:
63 def _item_exists(self, name):
64 for child in self.children:
65 if child.name == name:
66 raise FoundItException
67 child._item_exists(name)
70 def get_items(self, name, items=None):
71 """Return all items that match the name 'name'.
72 They are returned in order of a depth-first-search."""
79 for child in self.children:
80 if child.name == name:
82 child.get_items(name, items)
85 return PacketList(items)
87 def get_items_before(self, name, before_item, items=None):
88 """Return all items that match the name 'name' that
89 exist before the before_item. The before_item is an object.
90 They results are returned in order of a depth-first-search.
91 This function allows you to find fields from protocols that occur
92 before other protocols. For example, if you have an HTTP
93 protocol, you can find all tcp.dstport fields *before* that HTTP
94 protocol. This helps analyze in the presence of tunneled protocols."""
101 for child in self.children:
102 if top_level == 1 and child == before_item:
104 if child.name == name:
106 # Call get_items because the 'before_item' applies
107 # only to the top level search.
108 child.get_items(name, items)
111 return PacketList(items)
114 class ProtoTreeItem(PacketList):
115 def __init__(self, xmlattrs):
116 PacketList.__init__(self)
118 self.name = xmlattrs.get("name", "")
119 self.showname = xmlattrs.get("showname", "")
120 self.pos = xmlattrs.get("pos", "")
121 self.size = xmlattrs.get("size", "")
122 self.value = xmlattrs.get("value", "")
123 self.show = xmlattrs.get("show", "")
124 self.hide = xmlattrs.get("hide", "")
126 def add_child(self, child):
127 self.children.append(child)
132 def get_showname(self):
152 print >> fh, " name=%s" % (saxutils.quoteattr(self.name),),
155 print >> fh, "showname=%s" % (saxutils.quoteattr(self.showname),),
158 print >> fh, "pos=%s" % (saxutils.quoteattr(self.pos),),
161 print >> fh, "size=%s" % (saxutils.quoteattr(self.size),),
164 print >> fh, "value=%s" % (saxutils.quoteattr(self.value),),
167 print >> fh, "show=%s" % (saxutils.quoteattr(self.show),),
170 print >> fh, "hide=%s" % (saxutils.quoteattr(self.hide),),
172 class Packet(ProtoTreeItem, PacketList):
173 def dump(self, fh, indent=0):
174 print >> fh, " " * indent, "<packet>"
176 for child in self.children:
177 child.dump(fh, indent)
178 print >> fh, " " * indent, "</packet>"
181 class Protocol(ProtoTreeItem):
183 def dump(self, fh, indent=0):
184 print >> fh, "%s<proto " % (" " * indent,),
186 ProtoTreeItem.dump(self, fh)
191 for child in self.children:
192 child.dump(fh, indent)
193 print >> fh, " " * indent, "</proto>"
196 class Field(ProtoTreeItem):
198 def dump(self, fh, indent=0):
199 print >> fh, "%s<field " % (" " * indent,),
201 ProtoTreeItem.dump(self, fh)
204 print >> fh, "label=%s" % (saxutils.quoteattr(self.label),),
209 for child in self.children:
210 child.dump(fh, indent)
211 print >> fh, " " * indent, "</field>"
217 class ParseXML(saxlib.HandlerBase):
219 ELEMENT_FILE = "pdml"
220 ELEMENT_FRAME = "packet"
221 ELEMENT_PROTOCOL = "proto"
222 ELEMENT_FIELD = "field"
224 def __init__(self, cb):
227 self.element_stack = []
229 def startElement(self, name, xmlattrs):
232 if name == self.ELEMENT_FILE:
233 # Eventually, we should check version number of pdml here
236 elif name == self.ELEMENT_FRAME:
237 elem = Packet(xmlattrs)
239 elif name == self.ELEMENT_PROTOCOL:
240 elem = Protocol(xmlattrs)
242 elif name == self.ELEMENT_FIELD:
243 elem = Field(xmlattrs)
246 sys.exit("Unknown element: %s" % (name,))
248 self.element_stack.append(elem)
251 def endElement(self, name):
252 elem = self.element_stack.pop()
254 # if isinstance(elem, Field):
255 # if elem.get_name() == "frame.number":
256 # print >> sys.stderr, "Packet:", elem.get_show()
258 # Add element as child to previous element as long
259 # as there is more than 1 element in the stack. Only
260 # one element in the stack means that the the element in
261 # the stack is the single CaptureFile element, and we don't
262 # want to add this element to that, as we only want one
263 # Packet element in memory at a time.
264 if len(self.element_stack) > 1:
265 parent_elem = self.element_stack[-1]
266 parent_elem.add_child(elem)
270 # If we just finished a Packet element, hand it to the
272 if isinstance(elem, Packet):
275 def characters(self, chars, start, length):
276 self.chars = self.chars + chars[start:start+length]
279 def parse_fh(fh, cb):
282 parser = saxexts.make_parser()
287 # Tell the parser to use our handler
288 parser.setDocumentHandler(ch)
302 filename = sys.argv[1]
303 fh = open(filename, "r")
304 parse_fh(fh, test_cb)
306 if __name__ == '__main__':