blob: 27ee6510b2204643c38170e3ec1a605ad53b9b10 [file] [log] [blame]
// 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;
}