/**
	 * Encodes a value of type <i>double</i>.
	 * 
	 * @param output
	 *            The {@link OutputStream} to write the value to.
	 * @param value
	 *            The value to encode.
	 * @throws NullPointerException
	 *             Thrown if {@link output} is <i>null</i>.
	 */
	public static void encode(OutputStream output, double value)
			throws NullPointerException {
		Assert.AssertNotNull(output, "output");

		if (Double.POSITIVE_INFINITY == value) {
			output.append((byte) 0x40);
		} else if (Double.NEGATIVE_INFINITY == value) {
			output.append((byte) 0x41);
		} else {
			final long bits = Double.doubleToLongBits(value);

			if (bits != 0) {
				final long exponent = ((0x7FF0000000000000L & bits) >> 52L) - 1023;
				final int exponentLength = encodedLength(exponent, true);
				final int preamble = (0x80 | (exponentLength - 1) | (((bits & 0x8000000000000000L) != 0) ? 0x40
						: 0x00));

				long mantissa = (0x000FFFFFFFFFFFFFL & bits) | 0x0010000000000000L;

				while ((mantissa & 0xFF) == 0x00) {
					mantissa >>= 8;
				}

				while ((mantissa & 0x01) == 0x00) {
					mantissa >>= 1;
				}

				output.append(preamble);
				encodeLong(output, exponent, exponentLength);
				encodeLong(output, mantissa, encodedLength(mantissa, false));
			}
		}
	}
	/**
	 * Encodes a value of type {@link Tag}.
	 * 
	 * @param output
	 *            The {@link OutputStream} to write the value to.
	 * @param value
	 *            The value to encode.
	 * @throws NullPointerException
	 *             Thrown if either {@link output} or {@link value} is
	 *             <i>null</i>.
	 */
	public static void encode(OutputStream output, Tag value)
			throws NullPointerException {
		Assert.AssertNotNull(output, "output");
		Assert.AssertNotNull(value, "value");

		final int preamble = value.preamble() & 0xE0;
		final int number = value.number();

		if (number < 0x1F) {
			final int encodedTag = (preamble | (number & 0x1F));

			output.append(encodedTag);
		} else {
			output.append(preamble | 0x1F);
			MultiByte.encode(output, number);
		}
	}
	/**
	 * Encodes an integer value with a specified length.
	 * 
	 * @param output
	 *            The {@link OutputStream} to write the encoded data to.
	 * @param value
	 *            The value to encode.
	 * @param length
	 *            The number of bytes to encode.
	 */
	private static void encodeLong(OutputStream output, long value, int length) {
		long bits = length * 8;

		while (bits > 0) {
			bits -= 8;
			output.append((int) ((value >> bits) & 0xFF));
		}
	}
	/**
	 * Encodes a value of type {@link Octets}.
	 * 
	 * @param output
	 *            The {@link OutputStream} to write the value to.
	 * @param value
	 *            The value to encode.
	 * @throws NullPointerException
	 *             Thrown if either {@link output} or {@link value} is
	 *             <i>null</i>.
	 */
	public static void encode(OutputStream output, Octets value)
			throws NullPointerException {
		Assert.AssertNotNull(output, "output");
		Assert.AssertNotNull(value, "value");

		for (Iterator<Integer> it = value.iterator(); it.hasNext(); /* Nothing */) {
			output.append(it.next());
		}
	}
	/**
	 * Encodes a value of type {@link Length}.
	 * 
	 * @param output
	 *            The {@link OutputStream} to write the value to.
	 * @param value
	 *            The value to encode.
	 * @throws NullPointerException
	 *             Thrown if either {@link output} or {@link value} is
	 *             <i>null</i>.
	 */
	public static void encode(OutputStream output, Length value)
			throws NullPointerException {
		Assert.AssertNotNull(output, "output");
		Assert.AssertNotNull(value, "value");

		if (value.isIndefinite()) {
			output.append(0x80);
		} else {
			final int lengthValue = value.value();

			if (lengthValue <= 0x7F) {
				output.append(lengthValue);
			} else {
				output.append(0x80 | encodedLength(lengthValue));
				encode(output, lengthValue);
			}
		}
	}
	/**
	 * Encodes a value of type <i>long</i>.
	 * 
	 * @param output
	 *            The {@link OutputStream} to write the value to.
	 * @param value
	 *            The value to encode.
	 * @throws NullPointerException
	 *             Thrown if {@link output} is <i>null</i>.
	 */
	public static void encode(OutputStream output, long value)
			throws NullPointerException {
		Assert.AssertNotNull(output, "output");

		final int length = encodedLength(value);

		int bits = length * 8;

		while (bits > 0) {
			bits -= 8;
			output.append((int) ((value >> bits) & 0xFF));
		}
	}
	/**
	 * Encodes a value of type {@link String}.
	 * 
	 * @param output
	 *            The {@link OutputStream} to write the value to.
	 * @param value
	 *            The value to encode.
	 * @throws NullPointerException
	 *             Thrown if either {@link output} or {@link value} is null.
	 */
	public static void encode(OutputStream output, String value)
			throws NullPointerException {
		Assert.AssertNotNull(output, "output");
		Assert.AssertNotNull(value, "value");

		try {
			final byte[] encodedBytes = value.getBytes("UTF-8");

			for (int i = 0; i < encodedBytes.length; i++) {
				output.append((encodedBytes[i] + 0x100) & 0xff); // convert to unsigned byte range (0..255)
			}
		} catch (UnsupportedEncodingException _) {
		}
	}
	/**
	 * Encodes a value of type <i>boolean</i>.
	 * 
	 * @param output
	 *            The {@link OutputStream} to write the value to.
	 * @param value
	 *            The value to encode.
	 * @throws NullPointerException
	 *             Thrown if {@link output} is <i>null</i>.
	 */
	public static void encode(OutputStream output, boolean value)
			throws NullPointerException {
		Assert.AssertNotNull(value, "value");

		output.append(value ? 0xFF : 0x00);
	}