Source: packet/openpgp.packet.userattribute.js

// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

/** 
 * @class
 * @classdesc Implementation of the User Attribute Packet (Tag 17)
 *  The User Attribute packet is a variation of the User ID packet.  It
 *  is capable of storing more types of data than the User ID packet,
 *  which is limited to text.  Like the User ID packet, a User Attribute
 *  packet may be certified by the key owner ("self-signed") or any other
 *  key owner who cares to certify it.  Except as noted, a User Attribute
 *  packet may be used anywhere that a User ID packet may be used.
 *
 *  While User Attribute packets are not a required part of the OpenPGP
 *  standard, implementations SHOULD provide at least enough
 *  compatibility to properly handle a certification signature on the
 *  User Attribute packet.  A simple way to do this is by treating the
 *  User Attribute packet as a User ID packet with opaque contents, but
 *  an implementation may use any method desired.
 */
function openpgp_packet_userattribute() {
	this.tagType = 17;
	this.certificationSignatures = new Array();
	this.certificationRevocationSignatures = new Array();
	this.revocationSignatures = new Array();
	this.parentNode = null;

	/**
	 * parsing function for a user attribute packet (tag 17).
	 * @param {String} input payload of a tag 17 packet
	 * @param {Integer} position position to start reading from the input string
	 * @param {Integer} len length of the packet or the remaining length of input at position
	 * @return {openpgp_packet_encrypteddata} object representation
	 */
	function read_packet (input, position, len) {
		var total_len = 0;
		this.packetLength = len;
		this.userattributes = new Array();
		var count = 0;
		var mypos = position;
		while (len != total_len) {
			var current_len = 0;
			// 4.2.2.1. One-Octet Lengths
			if (input[mypos].charCodeAt() < 192) {
				packet_length = input[mypos++].charCodeAt();
				current_len = 1;
			// 4.2.2.2. Two-Octet Lengths
			} else if (input[mypos].charCodeAt() >= 192 && input[mypos].charCodeAt() < 224) {
				packet_length = ((input[mypos++].charCodeAt() - 192) << 8)
					+ (input[mypos++].charCodeAt()) + 192;
				current_len = 2;
			// 4.2.2.4. Partial Body Lengths
			} else if (input[mypos].charCodeAt() > 223 && input[mypos].charCodeAt() < 255) {
				packet_length = 1 << (input[mypos++].charCodeAt() & 0x1F);
				current_len = 1;
			// 4.2.2.3. Five-Octet Lengths
			} else {
				current_len = 5;
				mypos++;
				packet_length = (input[mypos++].charCodeAt() << 24) | (input[mypos++].charCodeAt() << 16)
					| (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt();
			}
			
			var subpackettype = input[mypos++].charCodeAt();
			packet_length--;
			current_len++;
			this.userattributes[count] = new Array();
			this.userattributes[count] = input.substring(mypos, mypos + packet_length);
			mypos += packet_length;
			total_len += current_len+packet_length;
		}
		this.packetLength = mypos - position;
		return this;
	}
	
	/**
	 * generates debug output (pretty print)
	 * @return {String} String which gives some information about the user attribute packet
	 */
	function toString() {
		var result = '5.12.  User Attribute Packet (Tag 17)\n'+
		             '    AttributePackets: (count = '+this.userattributes.length+')\n';
		for (var i = 0; i < this.userattributes.length; i++) {
			result += '    ('+this.userattributes[i].length+') bytes: ['+util.hexidump(this.userattributes[i])+']\n'; 
		}
		return result;
	}
	
	/**
	 * Continue parsing packets belonging to the user attribute packet such as signatures
	 * @param {Object} parent_node the parent object
	 * @param {String} input input string to read the packet(s) from
	 * @param {Integer} position start position for the parser
	 * @param {Integer} len length of the packet(s) or remaining length of input
	 * @return {Integer} length of nodes read
	 */
	function read_nodes(parent_node, input, position, len) {
		
		this.parentNode = parent_node;
		var exit = false;
		var pos = position;
		var l = len;
		while (input.length != pos) {
			var result = openpgp_packet.read_packet(input, pos, l);
			if (result == null) {
				util.print_error("openpgp.packet.userattribute.js\n"+'[user_attr] parsing ends here @:' + pos + " l:" + l);
				break;
			} else {
				switch (result.tagType) {
				case 2: // Signature Packet
					if (result.signatureType > 15
							&& result.signatureType < 20) // certification
						// //
						// signature
						this.certificationSignatures[this.certificationSignatures.length] = result;
					else if (result.signatureType == 32) // certification revocation signature
						this.certificationRevocationSignatures[this.certificationRevocationSignatures.length] = result;
					pos += result.packetLength + result.headerLength;
					l = len - (pos - position);
					break;
				default:
					this.data = input;
					this.position = position - parent_node.packetLength;
					this.len = pos - position;
					return this.len;
					break;
				}
			}
		}
		this.data = input;
		this.position = position - parent_node.packetLength;
		this.len = pos - position;
		return this.len;

	}
	
	this.read_packet = read_packet;
	this.read_nodes = read_nodes;
	this.toString = toString;
	
};