/******************************************************************************* * Copyright (c) 2009, 2015 Centrum Wiskunde en Informatica (CWI) * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Arnold Lankamp - interfaces and implementation * Anya Helene Bagge - labeled map types; safer reading *******************************************************************************/ package org.rascalmpl.value.io.binary; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URI; import java.net.URISyntaxException; import java.util.Map; import java.util.Map.Entry; import org.rascalmpl.value.IBool; import org.rascalmpl.value.IConstructor; import org.rascalmpl.value.IDateTime; import org.rascalmpl.value.IInteger; import org.rascalmpl.value.IList; import org.rascalmpl.value.IListWriter; import org.rascalmpl.value.IMap; import org.rascalmpl.value.IMapWriter; import org.rascalmpl.value.INode; import org.rascalmpl.value.IRational; import org.rascalmpl.value.IReal; import org.rascalmpl.value.ISet; import org.rascalmpl.value.ISetWriter; import org.rascalmpl.value.ISourceLocation; import org.rascalmpl.value.IString; import org.rascalmpl.value.ITuple; import org.rascalmpl.value.IValue; import org.rascalmpl.value.IValueFactory; import org.rascalmpl.value.exceptions.FactParseError; import org.rascalmpl.value.exceptions.RedeclaredConstructorException; import org.rascalmpl.value.type.Type; import org.rascalmpl.value.type.TypeFactory; import org.rascalmpl.value.type.TypeStore; import org.rascalmpl.value.util.ResizingArray; import io.usethesource.capsule.TransientMap; import io.usethesource.capsule.TrieMap_5Bits; // TODO Change this thing so it doesn't use recursion. /** * @author Arnold Lankamp */ public class BinaryReader{ private final static int DEFAULT_SHARED_VALUES_STORE_SIZE = 1024; private final static int DEFAULT_SHARED_TYPES_STORE_SIZE = 128; private final static int DEFAULT_SHARED_PATHS_STORE_SIZE = 128; private final static int DEFAULT_SHARED_NAMES_STORE_SIZE = 128; private final static int BOOL_HEADER = 0x01; private final static int INTEGER_HEADER = 0x02; private final static int BIG_INTEGER_HEADER = 0x03; // Special case of INTEGER_HEADER (flags for alternate encoding). private final static int DOUBLE_HEADER = 0x04; private final static int IEEE754_ENCODED_DOUBLE_HEADER = 0x14; private final static int STRING_HEADER = 0x05; private final static int SOURCE_LOCATION_HEADER = 0x06; private final static int DATE_TIME_HEADER = 0x10; private final static int TUPLE_HEADER = 0x07; private final static int NODE_HEADER = 0x08; private final static int ANNOTATED_NODE_HEADER = 0x09; private final static int CONSTRUCTOR_HEADER = 0x0a; private final static int ANNOTATED_CONSTRUCTOR_HEADER = 0x0b; private final static int LIST_HEADER = 0x0c; private final static int SET_HEADER = 0x0d; private final static int RELATION_HEADER = 0x0e; private final static int MAP_HEADER = 0x0f; private final static int RATIONAL_HEADER = 0x11; private final static int KEYWORDED_NODE_HEADER = 0x12; private final static int KEYWORDED_CONSTRUCTOR_HEADER = 0x13; private final static int VALUE_TYPE_HEADER = 0x01; private final static int VOID_TYPE_HEADER = 0x02; private final static int BOOL_TYPE_HEADER = 0x03; private final static int INTEGER_TYPE_HEADER = 0x04; private final static int DOUBLE_TYPE_HEADER = 0x05; private final static int STRING_TYPE_HEADER = 0x06; private final static int SOURCE_LOCATION_TYPE_HEADER = 0x07; private final static int DATE_TIME_TYPE_HEADER = 0x14; private final static int NODE_TYPE_HEADER = 0x08; private final static int TUPLE_TYPE_HEADER = 0x09; private final static int LIST_TYPE_HEADER = 0x0a; private final static int SET_TYPE_HEADER = 0x0b; private final static int RELATION_TYPE_HEADER = 0x0c; private final static int MAP_TYPE_HEADER = 0x0d; private final static int PARAMETER_TYPE_HEADER = 0x0e; private final static int ADT_TYPE_HEADER = 0x0f; private final static int CONSTRUCTOR_TYPE_HEADER = 0x10; private final static int ALIAS_TYPE_HEADER = 0x11; private final static int ANNOTATED_NODE_TYPE_HEADER = 0x12; private final static int ANNOTATED_CONSTRUCTOR_TYPE_HEADER = 0x13; private final static int RATIONAL_TYPE_HEADER = 0x15; private final static int NUM_TYPE_HEADER = 0x16; private final static int KEYWORDED_CONSTRUCTOR_TYPE_HEADER = 0x17; private final static int TYPE_MASK = 0x1f; private final static int SHARED_FLAG = 0x80; private final static int TYPE_SHARED_FLAG = 0x40; private final static int URL_SHARED_FLAG = 0x20; private final static int NAME_SHARED_FLAG = 0x20; private final static int HAS_FIELD_NAMES = 0x20; private final static int DATE_TIME_INDICATOR = 0x01; private final static int DATE_INDICATOR = 0x02; private final static TypeFactory tf = TypeFactory.getInstance(); private final ResizingArray<IValue> sharedValues; private int currentSharedValueId; private final ResizingArray<Type> sharedTypes; private int currentSharedTypeId; private final ResizingArray<ISourceLocation> sharedPaths; private int currentSharedPathId; private final ResizingArray<String> sharedNames; private int currentSharedNamesId; private final IValueFactory valueFactory; private final TypeStore typeStore; private final InputStream in; public BinaryReader(IValueFactory valueFactory, TypeStore typeStore, InputStream inputStream){ super(); this.valueFactory = valueFactory; this.typeStore = typeStore; this.in = inputStream; sharedValues = new ResizingArray<>(DEFAULT_SHARED_VALUES_STORE_SIZE); currentSharedValueId = 0; sharedTypes = new ResizingArray<>(DEFAULT_SHARED_TYPES_STORE_SIZE); currentSharedTypeId = 0; sharedPaths = new ResizingArray<>(DEFAULT_SHARED_PATHS_STORE_SIZE); currentSharedPathId = 0; sharedNames = new ResizingArray<>(DEFAULT_SHARED_NAMES_STORE_SIZE); currentSharedNamesId = 0; } public IValue deserialize() throws IOException{ int header = read(); if((header & SHARED_FLAG) == SHARED_FLAG){ return sharedValues.get(parseInteger()); } IValue value; int valueType = header & TYPE_MASK; switch(valueType){ case BOOL_HEADER: value = readBool(); break; case INTEGER_HEADER: value = readInteger(); break; case BIG_INTEGER_HEADER: value = readBigInteger(); break; case DOUBLE_HEADER: value = readDouble(); break; case IEEE754_ENCODED_DOUBLE_HEADER: value = readIEEE754EncodedDouble(); break; case STRING_HEADER: value = readString(); break; case SOURCE_LOCATION_HEADER: value = readSourceLocation(header); break; case DATE_TIME_HEADER: value = readDateTime(); break; case TUPLE_HEADER: value = readTuple(); break; case NODE_HEADER: value = readNode(header); break; case ANNOTATED_NODE_HEADER: value = readAnnotatedNode(header); break; case CONSTRUCTOR_HEADER: value = readConstructor(header); break; case ANNOTATED_CONSTRUCTOR_HEADER: value = readAnnotatedConstructor(header); break; case LIST_HEADER: value = readList(header); break; case SET_HEADER: value = readSet(header); break; case RELATION_HEADER: value = readRelation(header); break; case MAP_HEADER: value = readMap(header); break; case RATIONAL_HEADER: value = readRational(); break; case KEYWORDED_NODE_HEADER: value = readKeywordedNode(header); break; case KEYWORDED_CONSTRUCTOR_HEADER: value = readKeywordedConstructor(header); break; default: throw new RuntimeException("Unknow value type: "+valueType); } boolean hashValue = true; if (value.getType().isAbstractData()) { IConstructor consValue = (IConstructor)value; if (!(consValue.mayHaveKeywordParameters() && consValue.asWithKeywordParameters().hasParameters()) && (consValue.isAnnotatable() && consValue.asAnnotatable().hasAnnotations())) { Map<String,IValue> amap = consValue.asAnnotatable().getAnnotations(); for (Entry<String, IValue> aEntry : amap.entrySet()) { Type aType = aEntry.getValue().getType(); if (!aType.equivalent(tf.voidType()) && aType.isSourceLocation()) { hashValue = false; break; } } } } if (hashValue) { sharedValues.set(value, currentSharedValueId++); } return value; } // Called by value stuff. private Type readType(int header) throws IOException{ if((header & TYPE_SHARED_FLAG) == TYPE_SHARED_FLAG){ return sharedTypes.get(parseInteger()); } return doReadType(read()); } // Called by type stuff. private Type doReadType() throws IOException{ return doReadType(read()); } private Type doReadType(int typeHeader) throws IOException{ if((typeHeader & SHARED_FLAG) == SHARED_FLAG){ return sharedTypes.get(parseInteger()); } Type type; int typeType = typeHeader & TYPE_MASK; switch(typeType){ case VALUE_TYPE_HEADER: type = readValueType(); break; case VOID_TYPE_HEADER: type = readVoidType(); break; case BOOL_TYPE_HEADER: type = readBoolType(); break; case INTEGER_TYPE_HEADER: type = readIntegerType(); break; case DOUBLE_TYPE_HEADER: type = readDoubleType(); break; case STRING_TYPE_HEADER: type = readStringType(); break; case SOURCE_LOCATION_TYPE_HEADER: type = readSourceLocationType(); break; case DATE_TIME_TYPE_HEADER: type = readDateTimeType(); break; case NODE_TYPE_HEADER: type = readNodeType(); break; case TUPLE_TYPE_HEADER: type = readTupleType(typeHeader); break; case LIST_TYPE_HEADER: type = readListType(); break; case SET_TYPE_HEADER: type = readSetType(); break; case RELATION_TYPE_HEADER: type = readRelationType(); break; case MAP_TYPE_HEADER: type = readMapType(typeHeader); break; case PARAMETER_TYPE_HEADER: type = readParameterType(); break; case ADT_TYPE_HEADER: type = readADTType(); break; case CONSTRUCTOR_TYPE_HEADER: type = readConstructorType(); break; case ALIAS_TYPE_HEADER: type = readAliasType(); break; case ANNOTATED_NODE_TYPE_HEADER: type = readAnnotatedNodeType(); break; case ANNOTATED_CONSTRUCTOR_TYPE_HEADER: type = readAnnotatedConstructorType(); break; case RATIONAL_TYPE_HEADER: type = readRationalType(); break; case NUM_TYPE_HEADER: type = readNumType(); break; case KEYWORDED_CONSTRUCTOR_TYPE_HEADER: type = readKeywordedConstructorType(); break; default: throw new RuntimeException("Unkown type type: "+typeType); } sharedTypes.set(type, currentSharedTypeId++); return type; } private IBool readBool() throws IOException{ int bool = read(); return valueFactory.bool(bool == 0 ? false : true); } private IInteger readInteger() throws IOException{ int integerValue = parseInteger(); return valueFactory.integer(integerValue); } private IInteger readBigInteger() throws IOException{ int length = parseInteger(); byte[] integerData = new byte[length]; read(integerData, 0, length); return valueFactory.integer(integerData); } private IRational readRational() throws IOException{ int length = parseInteger(); byte[] valueData = new byte[length]; read(valueData, 0, length); IInteger num = valueFactory.integer(valueData); length = parseInteger(); valueData = new byte[length]; read(valueData, 0, length); IInteger denom = valueFactory.integer(valueData); return valueFactory.rational(num, denom); } private IReal readDouble() throws IOException{ int length = parseInteger(); byte[] unscaledValueData = new byte[length]; read(unscaledValueData, 0, length); int scale = parseInteger(); return valueFactory.real(new BigDecimal(new BigInteger(unscaledValueData), scale).toString()); // The toString call kind of stinks. } private IReal readIEEE754EncodedDouble() throws IOException{ double theDouble = parseDouble(); return valueFactory.real(theDouble); // The toString call kind of stinks. } private IString readString() throws IOException{ int size = parseInteger(); byte[] data = new byte[size]; for(int i = 0; i< size; i++){ data[i] = (byte) read(); } return valueFactory.string(new String(data, BinaryWriter.CharEncoding)); } private ISourceLocation readSourceLocation(int header) throws IOException{ ISourceLocation path; if((header & URL_SHARED_FLAG) == URL_SHARED_FLAG){ int path_id = parseInteger(); path = sharedPaths.get(path_id); }else{ int pathSize = parseInteger(); byte[] data = new byte[pathSize]; for(int i = 0; i< pathSize; i++){ data[i] = (byte) read(); } try{ path = valueFactory.sourceLocation(new URI(new String(data, BinaryWriter.CharEncoding))); }catch(URISyntaxException e){ throw new FactParseError("Illegal URI", e); // Can't happen. } sharedPaths.set(path, currentSharedPathId++); } int offset = parseInteger(); int length = parseInteger(); int beginLine = parseInteger(); int endLine = parseInteger(); int beginCol = parseInteger(); int endCol = parseInteger(); if (offset < 0) { return path; } if (beginLine < 0) { return valueFactory.sourceLocation(path, offset, length); } return valueFactory.sourceLocation(path, offset, length, beginLine, endLine, beginCol, endCol); } private IDateTime readDateTime() throws IOException{ int typeIndicator = read(); if(typeIndicator == DATE_TIME_INDICATOR){ int year = parseInteger(); int month = parseInteger(); int day = parseInteger(); int hour = parseInteger(); int minute = parseInteger(); int second = parseInteger(); int millisecond = parseInteger(); int timeZoneHourOffset = parseInteger(); int timeZoneMinuteOffset = parseInteger(); return valueFactory.datetime(year, month, day, hour, minute, second, millisecond, timeZoneHourOffset, timeZoneMinuteOffset); }else if(typeIndicator == DATE_INDICATOR){ int year = parseInteger(); int month = parseInteger(); int day = parseInteger(); return valueFactory.date(year, month, day); }else{ int hour = parseInteger(); int minute = parseInteger(); int second = parseInteger(); int millisecond = parseInteger(); int timeZoneHourOffset = parseInteger(); int timeZoneMinuteOffset = parseInteger(); return valueFactory.time(hour, minute, second, millisecond, timeZoneHourOffset, timeZoneMinuteOffset); } } private ITuple readTuple() throws IOException{ int arity = parseInteger(); IValue[] content = new IValue[arity]; for(int i = 0; i < arity; i++){ content[i] = deserialize(); } return valueFactory.tuple(content); } private INode readNode(int header) throws IOException{ String nodeName; if((header & NAME_SHARED_FLAG) == NAME_SHARED_FLAG){ nodeName = sharedNames.get(parseInteger()); }else{ int nodeNameLength = parseInteger(); byte[] data = new byte[nodeNameLength]; for(int i = 0; i < nodeNameLength; i++){ data[i] = (byte) read(); } nodeName = new String(data, BinaryWriter.CharEncoding); sharedNames.set(nodeName, currentSharedNamesId++); } int arity = parseInteger(); IValue[] content = new IValue[arity]; for(int i = 0; i < arity; i++){ content[i] = deserialize(); } return valueFactory.node(nodeName, content); } private INode readKeywordedNode(int header) throws IOException{ String nodeName; if((header & NAME_SHARED_FLAG) == NAME_SHARED_FLAG){ nodeName = sharedNames.get(parseInteger()); }else{ int nodeNameLength = parseInteger(); byte[] data = new byte[nodeNameLength]; for(int i = 0; i < nodeNameLength; i++){ data[i] = (byte) read(); } nodeName = new String(data, BinaryWriter.CharEncoding); sharedNames.set(nodeName, currentSharedNamesId++); } int arity = parseInteger(); IValue[] content = new IValue[arity]; for(int i = 0; i < arity; i++){ content[i] = deserialize(); } int numberOfKeywordParameters = parseInteger(); TransientMap<String, IValue> kwParams = TrieMap_5Bits.transientOf(); for(int i = numberOfKeywordParameters - 1; i >= 0; i--){ int nameLength = parseInteger(); byte[] nameData = new byte[nameLength]; read(nameData); String name = new String(nameData, BinaryWriter.CharEncoding); IValue value = deserialize(); kwParams.__put(name, value); } return valueFactory.node(nodeName, content, kwParams.freeze()); } private INode readAnnotatedNode(int header) throws IOException{ String nodeName; if((header & NAME_SHARED_FLAG) == NAME_SHARED_FLAG){ nodeName = sharedNames.get(parseInteger()); }else{ int nodeNameLength = parseInteger(); byte[] data = new byte[nodeNameLength]; for(int i = 0; i < nodeNameLength; i++){ data[i] = (byte) read(); } nodeName = new String(data, BinaryWriter.CharEncoding); sharedNames.set(nodeName, currentSharedNamesId++); } int arity = parseInteger(); IValue[] content = new IValue[arity]; for(int i = 0; i < arity; i++){ content[i] = deserialize(); } int numberOfAnnotations = parseInteger(); TransientMap<String, IValue> annotations = TrieMap_5Bits.transientOf(); for(int i = numberOfAnnotations - 1; i >= 0; i--){ int labelLength = parseInteger(); byte[] labelData = new byte[labelLength]; read(labelData); String label = new String(labelData, BinaryWriter.CharEncoding); IValue value = deserialize(); annotations.__put(label, value); } INode node = valueFactory.node(nodeName, content); return node.asAnnotatable().setAnnotations(annotations.freeze()); } private IConstructor readConstructor(int header) throws IOException{ Type constructorType = readType(header); int arity = parseInteger(); IValue[] content = new IValue[arity]; for(int i = 0; i < arity; i++){ content[i] = deserialize(); } return valueFactory.constructor(constructorType, content); } private IConstructor readKeywordedConstructor(int header) throws IOException{ Type constructorType = readType(header); int arity = parseInteger(); IValue[] content = new IValue[arity]; for(int i = 0; i < arity; i++){ content[i] = deserialize(); } int numberOfKeywordParams = parseInteger(); TransientMap<String, IValue> kwParams = TrieMap_5Bits.transientOf(); for(int i = numberOfKeywordParams - 1; i >= 0; i--){ int nameLength = parseInteger(); byte[] nameData = new byte[nameLength]; read(nameData); String name = new String(nameData, BinaryWriter.CharEncoding); IValue value = deserialize(); kwParams.__put(name, value); } return valueFactory.constructor(constructorType, content, kwParams.freeze()); } private IConstructor readAnnotatedConstructor(int header) throws IOException{ Type constructorType = readType(header); int arity = parseInteger(); IValue[] content = new IValue[arity]; for(int i = 0; i < arity; i++){ content[i] = deserialize(); } int numberOfAnnotations = parseInteger(); TransientMap<String, IValue> annotations = TrieMap_5Bits.transientOf(); for(int i = numberOfAnnotations - 1; i >= 0; i--){ int labelLength = parseInteger(); byte[] labelData = new byte[labelLength]; read(labelData); String label = new String(labelData, BinaryWriter.CharEncoding); IValue value = deserialize(); annotations.__put(label, value); } IConstructor constructor = valueFactory.constructor(constructorType, content); return constructor.asAnnotatable().setAnnotations(annotations.freeze()); } private IList readList(int header) throws IOException{ Type elementType = readType(header); int length = parseInteger(); IListWriter listWriter = valueFactory.listWriter(elementType); for(int i = 0; i < length; i++){ listWriter.append(deserialize()); } return listWriter.done(); } private ISet readSet(int header) throws IOException{ Type elementType = readType(header); int length = parseInteger(); ISetWriter setWriter = valueFactory.setWriter(elementType); for(int i = 0; i < length; i++){ setWriter.insert(deserialize()); } return setWriter.done(); } private ISet readRelation(int header) throws IOException{ Type elementType = readType(header); int length = parseInteger(); ISetWriter relationWriter = valueFactory.relationWriter(elementType); for(int i = 0; i < length; i++){ relationWriter.insert(deserialize()); } return relationWriter.done(); } private IMap readMap(int header) throws IOException{ Type mapType = readType(header); int length = parseInteger(); IMapWriter mapWriter = valueFactory.mapWriter(mapType); for(int i = 0; i < length; i++){ IValue key = deserialize(); IValue value = deserialize(); mapWriter.put(key, value); } return mapWriter.done(); } private Type readValueType(){ return tf.valueType(); } private Type readVoidType(){ return tf.voidType(); } private Type readBoolType(){ return tf.boolType(); } private Type readIntegerType(){ return tf.integerType(); } private Type readNumType(){ return tf.numberType(); } private Type readRationalType(){ return tf.rationalType(); } private Type readDoubleType(){ return tf.realType(); } private Type readStringType(){ return tf.stringType(); } private Type readSourceLocationType(){ return tf.sourceLocationType(); } private Type readDateTimeType(){ return tf.dateTimeType(); } private Type readNodeType(){ return tf.nodeType(); } private Type readAnnotatedNodeType() throws IOException{ Type nodeType = tf.nodeType(); int nrOfAnnotations = parseInteger(); for(--nrOfAnnotations; nrOfAnnotations >= 0; nrOfAnnotations--){ int nrOfLabelBytes = parseInteger(); byte[] labelBytes = new byte[nrOfLabelBytes]; read(labelBytes); String label = new String(labelBytes, BinaryWriter.CharEncoding); Type valueType = doReadType(); typeStore.declareAnnotation(nodeType, label, valueType); } return nodeType; } private Type readTupleType(int header) throws IOException{ boolean hasFieldNames = ((header & HAS_FIELD_NAMES) == HAS_FIELD_NAMES); if(hasFieldNames){ int arity = parseInteger(); Type[] fields = new Type[arity]; String[] fieldNames = new String[arity]; for(int i = 0; i < arity; i++){ fields[i] = doReadType(); int fieldNameLength = parseInteger(); byte[] fieldNameData = new byte[fieldNameLength]; read(fieldNameData); fieldNames[i] = new String(fieldNameData, BinaryWriter.CharEncoding); } return tf.tupleType(fields, fieldNames); } int arity = parseInteger(); Type[] fields = new Type[arity]; for(int i = 0; i < arity; i++){ fields[i] = doReadType(); } return tf.tupleType(fields); } private Type readListType() throws IOException{ Type elementType = doReadType(); return tf.listType(elementType); } private Type readSetType() throws IOException{ Type elementType = doReadType(); return tf.setType(elementType); } private Type readRelationType() throws IOException{ Type elementType = doReadType(); return tf.relTypeFromTuple(elementType); } private Type readMapType(int header) throws IOException{ boolean hasFieldNames = ((header & HAS_FIELD_NAMES) == HAS_FIELD_NAMES); if(hasFieldNames){ Type keyType = doReadType(); int keyLabelLength = parseInteger(); byte[] keyLabelData = new byte[keyLabelLength]; read(keyLabelData); String keyLabel = new String(keyLabelData, BinaryWriter.CharEncoding); Type valueType = doReadType(); int valueLabelLength = parseInteger(); byte[] valueLabelData = new byte[valueLabelLength]; read(valueLabelData); String valueLabel = new String(valueLabelData, BinaryWriter.CharEncoding); return tf.mapType(keyType, keyLabel, valueType, valueLabel); } else { Type keyType = doReadType(); Type valueType = doReadType(); return tf.mapType(keyType, valueType); } } private Type readParameterType() throws IOException{ int nameLength = parseInteger(); byte[] nameData = new byte[nameLength]; read(nameData); String name = new String(nameData, BinaryWriter.CharEncoding); Type bound = doReadType(); return tf.parameterType(name, bound); } private Type readADTType() throws IOException{ int nameLength = parseInteger(); byte[] nameData = new byte[nameLength]; read(nameData); String name = new String(nameData, BinaryWriter.CharEncoding); Type parameters = doReadType(); return tf.abstractDataTypeFromTuple(typeStore, name, parameters); } private Type readConstructorType() throws IOException{ int nameLength = parseInteger(); byte[] nameData = new byte[nameLength]; read(nameData); String name = new String(nameData, BinaryWriter.CharEncoding); Type fieldTypes = doReadType(); Type adtType = doReadType(); try { return tf.constructorFromTuple(typeStore, adtType, name, fieldTypes); } catch (RedeclaredConstructorException e) { adtType = typeStore.lookupAbstractDataType(adtType.getName()); for (Type candidate: typeStore.lookupConstructor(adtType, name)) { if (fieldTypes.isSubtypeOf(candidate.getFieldTypes())) { return candidate; } } throw e; } } private Type readKeywordedConstructorType() throws IOException{ int nameLength = parseInteger(); byte[] nameData = new byte[nameLength]; read(nameData); String name = new String(nameData, BinaryWriter.CharEncoding); Type fieldTypes = doReadType(); Type adtType = doReadType(); return tf.constructorFromTuple(typeStore, adtType, name, fieldTypes); } private Type readAnnotatedConstructorType() throws IOException{ int nameLength = parseInteger(); byte[] nameData = new byte[nameLength]; read(nameData); String name = new String(nameData, BinaryWriter.CharEncoding); Type fieldTypes = doReadType(); Type adtType = doReadType(); Type constructorType = tf.constructorFromTuple(typeStore, adtType, name, fieldTypes); int nrOfAnnotations = parseInteger(); for(--nrOfAnnotations; nrOfAnnotations >= 0; nrOfAnnotations--){ int nrOfLabelBytes = parseInteger(); byte[] labelBytes = new byte[nrOfLabelBytes]; read(labelBytes); String label = new String(labelBytes, BinaryWriter.CharEncoding); Type valueType = doReadType(); typeStore.declareAnnotation(constructorType, label, valueType); } return constructorType; } private Type readAliasType() throws IOException{ int nameLength = parseInteger(); byte[] nameData = new byte[nameLength]; read(nameData); String name = new String(nameData, BinaryWriter.CharEncoding); Type aliasedType = doReadType(); Type parameters = doReadType(); return tf.aliasTypeFromTuple(typeStore, name, aliasedType, parameters); } private final static int SEVENBITS = 0x0000007f; private final static int SIGNBIT = 0x00000080; private int parseInteger() throws IOException{ int part = read(); int result = (part & SEVENBITS); if((part & SIGNBIT) == 0) return result; part = read(); result |= ((part & SEVENBITS) << 7); if((part & SIGNBIT) == 0) return result; part = read(); result |= ((part & SEVENBITS) << 14); if((part & SIGNBIT) == 0) return result; part = read(); result |= ((part & SEVENBITS) << 21); if((part & SIGNBIT) == 0) return result; part = read(); result |= ((part & SEVENBITS) << 28); return result; } private final static int BYTEMASK = 0x000000ff; private final static int BYTEBITS = 8; private final static int LONGBITS = 8; private double parseDouble() throws IOException{ long result = 0; for(int i = 0; i < LONGBITS; i++){ result |= ((((long) read()) & BYTEMASK) << (i * BYTEBITS)); } return Double.longBitsToDouble(result); } private int read() throws IOException { int b = in.read(); if(b == -1) { throw new UnexpectedEOF(); } return b; } private void read(byte[] buffer) throws IOException { read(buffer, 0, buffer.length); } private void read(byte[] buffer, int offset, int length) throws IOException { int read; while(length > 0) { read = in.read(buffer, offset, length); if(read == -1) { throw new UnexpectedEOF(); } length = length - read; offset = offset + read; } } static class UnexpectedEOF extends IOException { private static final long serialVersionUID = -907629554395808678L; public UnexpectedEOF() { super("unexpected end of file"); } } }