/**
 * This file is part of Erjang - A JVM-based Erlang VM
 *
 * Copyright (c) 2009 by Trifork
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/

package erjang;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.zip.CRC32;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

public class EBinary extends EBitString {

	public static final EBinary EMPTY = new EBinary(new byte[0]);

	public EBinary(byte[] data, int byteOff, int byteLength) {
		super(data, byteOff, byteLength, 0);
	}

	/**
	 * @param binaryValue
	 */
	public EBinary(byte[] bytes) {
		this(bytes, 0, bytes.length);
	}

	private static final Type EBINARY_TYPE = Type.getType(EBinary.class);
	private static final String EBINARY_NAME = EBINARY_TYPE.getInternalName();

	@Override
	public Type emit_const(MethodVisitor fa) {
		char[] chs = new char[byteSize()];
		for (int i = 0; i < byteSize(); i++) {
			chs[i] = (char) (0xff & octetAt(i));
		}
		String str = new String(chs);

		fa.visitLdcInsn(str);
		fa.visitMethodInsn(Opcodes.INVOKESTATIC, EBINARY_NAME, "fromString",
				"(Ljava/lang/String;)L" + EBINARY_NAME + ";");

		return EBINARY_TYPE;
	}

	public static EBinary fromString(String str) {
		int size = str.length();
		byte[] data = new byte[size];
		for (int i = 0; i < str.length(); i++) {
			data[i] = (byte) str.charAt(i);
		}
		return new EBinary(data, 0, size);
	}

	public EBinary testBinary() {
		return this;
	}

	/**
	 * @return
	 */
	public byte[] getByteArray() {
		int octets = byteSize();
		byte[] res = new byte[octets];
		System.arraycopy(data, byteOffset(), res, 0, octets);
		return res;
	}

	public long crc() {
		CRC32 crc = new CRC32();

		int octets = byteSize();
		crc.update(data, byteOffset(), octets);
		return crc.getValue();
	}

	/**
	 * @param barr
	 * @throws IOException
	 */
	public void appendTo(OutputStream barr) {
		try {
			barr.write(data, byteOffset(), byteSize());
		} catch (IOException e) {
			throw new Error(e);
		}
	}

	/**
	 * @param barr
	 * @throws IOException
	 */
	public void writeTo(ByteArrayOutputStream o) {
		o.write(data, byteOffset(), byteSize());
	}

	/**
	 * @param data
	 * @return
	 */
	public static EBinary make(ByteBuffer data) {
		if (data == null || data.remaining() == 0)
			return EMPTY;
		return new EBinary(data.array(), data.arrayOffset() + data.position(),
				data.remaining());
	}

	/**
	 * @return
	 */
	public ByteBuffer toByteBuffer() {
		return ByteBuffer.wrap(this.data, byteOffset(), byteSize());
	}

	/**
	 * @param eInputStream
	 * @return
	 */
	public static EBinary read(EInputStream eInputStream) throws IOException {
	    byte[] data = eInputStream.read_binary();
	    return new EBinary(data); //TODO: use a make().
	}

	/**
	 * @return
	 */
	public EInputStream getInputStream() {
		int octets = byteSize();
		return new EInputStream(data, byteOffset(), octets,
				EInputStream.DECODE_INT_LISTS_AS_STRINGS);
	}

}

@@ -758,32 +758,61 @@
 o.OutputStream;%0A
+import java.math.BigInteger;%0A
 import java.nio.
@@ -3560,10 +3560,237 @@
 S);%0A%09%7D%0A%0A
+%09/**%0A%09 * @return true if this binary is all 7-bit bytes%0A%09 */%0A%09public boolean is_7bit() %7B%0A%09%09for (int i = 0; i %3C byteSize(); i++) %7B%0A%09%09%09byte b = data%5BbyteOffset() + i%5D;%0A%09%09%09if ((b & 0x80) != 0) return false;%0A%09%09%7D%0A%09%09return true;%0A%09%7D%0A%0A
 %7D%0A

add method is_7bit