package ecologylab.serialization.deserializers.parsers.tlv; import ecologylab.serialization.ClassDescriptor; import ecologylab.serialization.FieldDescriptor; import ecologylab.serialization.FieldType; import ecologylab.serialization.FieldTypes; import ecologylab.serialization.SimplTypesScope; /** * This is the basic tlv parser for parsing tlv messages generated from * <code>ecologylab.serialization</code> translation framework. * * <p/> * The framework works in conjunction with the translation scope to map tlv ids with their tag * names. TLV messages are type-length-value triplet. <code>type</code> is a 32 bit integer takes up * to 4 bytes. <code>length</code> is also a 32 bit integer and takes up to 4 bytes of the message * header of the tlv message. * * * * @author Nabeel Shahzad * * @version 1.0 */ public class TLVParser implements FieldTypes { /** * an object which implements TLVEvents will get the appropriate events from the parser. */ private TLVEvents listenerObject; /** * translation scope which maps tlv ids to tag names. */ private SimplTypesScope translationScope; /** * local state variable. */ private ClassDescriptor currentClassDescriptor; /** * constant for type field size. */ final int TYPE_SIZE = 4; /** * constant for length field size */ final int LENGTH_SIZE = 4; /** * contant for header size. */ final int HEADER_SIZE = TYPE_SIZE + LENGTH_SIZE; /** * Constructor for tlv parser. * * @param listenerObject * @param translationScope */ public TLVParser(TLVEvents listenerObject, SimplTypesScope translationScope) { this.listenerObject = listenerObject; this.translationScope = translationScope; } /** * Parse method that creates an element state object which wraps whole message * * @param dataArray */ public void parse(byte[] dataArray) { // Start event for TLV data. listenerObject.startTLV(); int type = Utils.getInt(dataArray, 0); int length = Utils.getInt(dataArray, 4); currentClassDescriptor = translationScope.getClassDescriptorByTLVId(type); String rootObjectName = currentClassDescriptor.getTagName(); // start of first object. listenerObject.startObject(rootObjectName); parseTLVBlock(dataArray, HEADER_SIZE, length, currentClassDescriptor.pseudoFieldDescriptor()); // end of first object . listenerObject.endObject(rootObjectName); // End event for TLV data listenerObject.endTLV(); } /** * Method which recursively looks down for tlv blocks and parses them also calls methods on the * TLVEvents interface. * * @param dataArray * @param start * @param offset * @param currentFieldDescriptor */ public void parseTLVBlock(byte[] dataArray, int start, int offset, FieldDescriptor currentFieldDescriptor) { try { int type = Utils.getInt(dataArray, start); int length = Utils.getInt(dataArray, start + 4); FieldDescriptor localCurrentFieldDescriptor = currentFieldDescriptor; boolean isScalar = false; FieldType currentType = currentFieldDescriptor.getType(); currentFieldDescriptor = (currentType == FieldType.WRAPPER) ? currentFieldDescriptor.getWrappedFD() : currentClassDescriptor.getFieldDescriptorByTLVId(type); //if(currentFieldDescriptor.isPolymorphic()) currentFieldDescriptor = currentFieldDescriptor.elementClassDescriptor(type).pseudoFieldDescriptor(); String currentObjectName = currentFieldDescriptor.elementName(type); listenerObject.startObject(currentObjectName); isScalar = currentFieldDescriptor.isScalar(); if (!isScalar) { if (currentFieldDescriptor.getType() == FieldType.COMPOSITE_ELEMENT || currentFieldDescriptor.getType() == FieldType.COLLECTION_ELEMENT || currentFieldDescriptor.getType() == FieldType.MAP_ELEMENT) { currentClassDescriptor = currentFieldDescriptor.elementClassDescriptor(type); } // if its not scalar then there is another tlv block ahead parseTLVBlock(dataArray, start + HEADER_SIZE, length, currentFieldDescriptor); } else { String value = new String(dataArray, start + HEADER_SIZE, length); listenerObject.primitive(value); } listenerObject.endObject(currentObjectName); // restore parsing states for more tlv blocks currentClassDescriptor = currentFieldDescriptor.getDeclaringClassDescriptor(); currentFieldDescriptor = localCurrentFieldDescriptor; int tlvBlockSize = HEADER_SIZE + length; // if there are more TLV blocks parse them if (tlvBlockSize < offset) parseTLVBlock(dataArray, start + tlvBlockSize, offset - tlvBlockSize, currentFieldDescriptor); } catch (Exception ex) { ex.printStackTrace(); } } }