| // Copyright 2015 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| /** |
| * @fileoverview Class to represent a PDML Document. |
| * @see http://www.nbee.org/doku.php?id=netpdl:pdml_specification |
| */ |
| |
| 'use strict'; |
| |
| /** |
| * Namespace for the Packet Trace Analyzer app. |
| */ |
| var pcap = pcap || {}; |
| |
| /** |
| * Acts as a container for the PDML Packets. |
| * |
| * @constructor |
| * @extends {pcap.XmlDocument} |
| */ |
| pcap.PdmlDocument = function() { |
| pcap.XmlDocument.call(this); |
| |
| /** |
| * @type {Array<PdmlPacket>} |
| * @private |
| */ |
| this.packets_ = []; |
| }; |
| |
| pcap.PdmlDocument.prototype = { |
| __proto__: pcap.XmlDocument.prototype |
| }; |
| |
| /** |
| * Method to load a PdmlDocument from PDML. |
| * |
| * @override |
| * @param {XMLDocument} pdmlXmlDoc Detailed information of a decoded packet. |
| * @return {boolean} True if successfully set; false otherwise. |
| */ |
| pcap.PdmlDocument.prototype.read = function(pdmlXmlDoc) { |
| console.log('pdml-read: Reading PDML Document.'); |
| this.packets_ = []; |
| |
| if (!pdmlXmlDoc || !(pdmlXmlDoc instanceof XMLDocument)) { |
| console.error('pdml-read: Invalid input type.'); |
| return false; |
| } |
| |
| var pdmlXml = pdmlXmlDoc.getElementsByTagName('pdml'); |
| if (!pdmlXml || !pdmlXml[0]) { |
| console.error('pdml-read: Invalid PDML Document - Missing pdml tag.'); |
| return false; |
| } |
| |
| var packetsXml = pdmlXml[0].getElementsByTagName('packet'); |
| if (!packetsXml || !packetsXml[0]) { |
| console.error('pdml-read: Invalid PDML Document - Missing pdml packets.'); |
| return false; |
| } |
| |
| this.packets_ = []; |
| for (var i = 0; i < packetsXml.length; i++) { |
| var packet = new pcap.PdmlPacket(); |
| if (!packet.read(packetsXml[i])) { |
| console.error('pdml-read: Failed to read PDML packet.'); |
| return false; |
| } |
| this.packets_.push(packet); |
| } |
| |
| console.log('pdml-read: Successfully read PDML Document.'); |
| return true; |
| }; |
| |
| /** |
| * Generates an HTML representation of the PdmlDocument and inserts |
| * it into the target element. |
| * |
| * @override |
| * @throws Error if packets are missing or invalid. |
| */ |
| pcap.PdmlDocument.prototype.display = function() { |
| console.log('pdml-display: Displaying PDML Document.'); |
| |
| var targetEl = document.getElementById('pdml_display'); |
| |
| if (!this.packets_ || !this.packets_.length) { |
| throw new Error('Packets are missing'); |
| } |
| |
| var root = document.createElement('div'); |
| root.className = 'pdml'; |
| |
| var packetCount = this.packets_.length; |
| for (var i = 0; i < packetCount; i++) { |
| var packet = this.packets_[i]; |
| if (!(packet instanceof pcap.PdmlPacket)) { |
| throw new Error('Invalid Packet type'); |
| } |
| root.appendChild(packet.html()); |
| } |
| |
| targetEl.innerText = ''; |
| targetEl.appendChild(root); |
| |
| console.log('pdml-display: Successfully displayed PDML Document.'); |
| }; |
| |
| /** |
| * Acts as a container for PDML Packet Protos. |
| * |
| * @constructor |
| */ |
| pcap.PdmlPacket = function() { |
| /** |
| * @type {Array<PdmlProto>} |
| * @private |
| */ |
| this.protos_ = []; |
| }; |
| |
| /** |
| * Method to load the Protos from a PDML packet tag. |
| * |
| * @param {Element} packetXml Packet section from a PDML document. |
| * @return {boolean} True if succeeded; false otherwise. |
| */ |
| pcap.PdmlPacket.prototype.read = function(packetXml) { |
| if (!packetXml || (!packetXml instanceof Element)) { |
| return false; |
| } |
| |
| var protosXml = packetXml.getElementsByTagName('proto'); |
| if (!protosXml || !protosXml[0]) { |
| return false; |
| } |
| |
| for (var i = 0; i < protosXml.length; i++) { |
| var proto = new pcap.PdmlProto(); |
| if (!proto.read(protosXml[i])) { |
| return false; |
| } |
| this.protos_.push(proto); |
| } |
| |
| return true; |
| }; |
| |
| /** |
| * Method to create an HTML representation of the PdmlPacket. |
| * |
| * @throws Error if protos are missing or invalid. |
| * @return {Element} The root node of the generated HTML. |
| */ |
| pcap.PdmlPacket.prototype.html = function() { |
| if (!this.protos_ || !this.protos_.length) { |
| throw new Error('Missing protos'); |
| } |
| |
| var root = document.createElement('div'); |
| root.className = 'packet'; |
| var protoCount = this.protos_.length; |
| |
| for (var i = 0; i < protoCount; i++) { |
| var proto = this.protos_[i]; |
| if (!(proto instanceof pcap.PdmlProto)) { |
| throw new Error('Invalid Proto type'); |
| } |
| root.appendChild(proto.html()); |
| } |
| |
| return root; |
| }; |
| |
| /** |
| * Acts as a container for a PDML Packet Proto's attributes and fields. |
| * |
| * @constructor |
| */ |
| pcap.PdmlProto = function() { |
| /** |
| * @type {Object<string, string>} |
| * @private |
| */ |
| this.attributes_ = {}; |
| |
| /** |
| * @type {Array<PdmlField>} |
| * @private |
| */ |
| this.fields_ = []; |
| }; |
| |
| /** |
| * Method to load the attributes and fields from a PDML proto tag. |
| * |
| * @param {Element} protoXml Structure section from a PDML document. |
| * @return {boolean} True if succeeded; false otherwise. |
| */ |
| pcap.PdmlProto.prototype.read = function(protoXml) { |
| if (!protoXml || (!protoXml instanceof Element)) { |
| return false; |
| } |
| |
| var attributes = protoXml.attributes; |
| |
| for (var i = 0; i < attributes.length; i++) { |
| var attribute = attributes.item(i); |
| this.attributes_[attribute.name] = attribute.value; |
| } |
| |
| var fieldsXml = protoXml.childNodes; |
| if (!fieldsXml || !fieldsXml[0]) { |
| return false; |
| } |
| |
| for (var i = 0; i < fieldsXml.length; i++) { |
| if (fieldsXml[i].nodeName === 'field') { |
| var field = new pcap.PdmlField(); |
| if (!field.read(fieldsXml[i])) { |
| return false; |
| } |
| this.fields_.push(field); |
| } |
| } |
| |
| if (!this.fields_.length) { |
| return false; |
| } |
| |
| return true; |
| }; |
| |
| /** |
| * Method to create an HTML representation of the PdmlProto. |
| * |
| * @throws Error if fields are missing or invalid. |
| * @return {Element} The root node of the generated HTML. |
| */ |
| pcap.PdmlProto.prototype.html = function() { |
| if (!this.fields_ || !this.fields_.length) { |
| throw new Error('Fields are missing'); |
| } |
| |
| var root = document.createElement('div'); |
| |
| var protoEl = document.createElement('div'); |
| protoEl.innerText = this.attributes_['showname'] || 'Data'; |
| protoEl.className = 'showname'; |
| |
| root.appendChild(protoEl); |
| root.className = 'proto'; |
| |
| var fieldCount = this.fields_.length; |
| var fieldsEl = document.createElement('div'); |
| fieldsEl.className = 'fields'; |
| for (var i = 0; i < fieldCount; i++) { |
| var field = this.fields_[i]; |
| if (!(field instanceof pcap.PdmlField)) { |
| throw new Error('Invalid Field type'); |
| } |
| fieldsEl.appendChild(field.html()); |
| } |
| |
| root.appendChild(fieldsEl); |
| return root; |
| }; |
| |
| /** |
| * Acts as a container for a PDML Packet Proto Field's attributes and fields. |
| * |
| * @constructor |
| */ |
| pcap.PdmlField = function() { |
| /** |
| * @type {Object<string, string>} |
| * @private |
| */ |
| this.attributes_ = {}; |
| |
| /** |
| * @type {Array<PdmlField>} |
| * @private |
| */ |
| this.fields_ = []; |
| }; |
| |
| /** |
| * Method to load the attributes and fields from a PDML field tag. |
| * |
| * @param {Element} fieldXml Field section from a PDML document. |
| * @return {boolean} True if succeeded; false otherwise. |
| */ |
| pcap.PdmlField.prototype.read = function(fieldXml) { |
| if (!fieldXml) { |
| return false; |
| } |
| |
| var attributes = fieldXml.attributes; |
| |
| // read attributes |
| for (var i = 0; i < attributes.length; i++) { |
| var attribute = attributes.item(i); |
| this.attributes_[attribute.name] = attribute.value; |
| } |
| |
| // read fields |
| var fieldsXml = fieldXml.childNodes; |
| if (!fieldsXml) { |
| // nested fields are optional |
| return true; |
| } |
| |
| for (var i = 0; i < fieldsXml.length; i++) { |
| if (fieldsXml[i].nodeName === 'field') { |
| var field = new pcap.PdmlField(); |
| if (field.read(fieldsXml[i])) { |
| this.fields_.push(field); |
| } |
| } |
| } |
| |
| return true; |
| }; |
| |
| /** |
| * Method to create an HTML representation of the PdmlField. |
| * |
| * @return {Element} The root node of the generated HTML. |
| */ |
| pcap.PdmlField.prototype.html = function() { |
| var root = document.createElement('div'); |
| |
| var fieldEl = document.createElement('div'); |
| fieldEl.innerText = this.attributes_['showname'] || 'Data'; |
| fieldEl.className = 'showname'; |
| |
| root.appendChild(fieldEl); |
| root.className = 'field'; |
| |
| var fieldCount = this.fields_.length; |
| var fieldsEl = document.createElement('div'); |
| fieldsEl.className = 'fields hidden'; |
| for (var i = 0; i < fieldCount; i++) { |
| var field = this.fields_[i]; |
| if (!(field instanceof pcap.PdmlField)) { |
| throw new Error('Invalid Field type'); |
| } |
| fieldsEl.appendChild(field.html()); |
| } |
| |
| root.appendChild(fieldsEl); |
| return root; |
| } |