/** * 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.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 * @throws IOException */ public void writeTo(OutputStream o) throws IOException { 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); } /** * @return true if this binary is all 7-bit bytes */ public boolean is_7bit() { for (int i = 0; i < byteSize(); i++) { byte b = data[byteOffset() + i]; if ((b & 0x80) != 0) return false; } return true; } @Override public void encode(EOutputStream eos) { eos.write_binary(getByteArray()); } @Override public String toString() { StringBuilder sb = new StringBuilder("<<\""); for (int i = 0; i < byteSize(); i++) { char b = (char) (0xff & byteAt(i*8)); if (b >= 32 && b < 127) EString.appendChar(sb, b); else return super.toString(); } sb.append("\">>"); return sb.toString(); } public static EBinary make(byte[] res) { return new EBinary(res); } public EBinary sub_binary(int off, int len) { return new EBinary(data, this.byteOffset() + off, len); } }