All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.code.proto.streamio.PBWireByteMarkerHelper Maven / Gradle / Ivy

Go to download

A package to read and write Google Protocol Buffer messages to and from Input and Output Streams

There is a newer version: 1.5.5
Show newest version
package com.google.code.proto.streamio;

import com.google.protobuf.GeneratedMessage;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * A utility class to help write the delimiting byte markers for Google protocol buffer 
 * generated messages used with PBStreamReader.
 *
 * @author nichole
 */
public class PBWireByteMarkerHelper {
    
    /**
     * Web-socket friendly start byte marker for delimiter
     */
    private static final byte markerForStart = (byte)0x80;
    
    // To follow up on complete compliance:
    //http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75
    //  Frames denoted by bytes that have the high bit set (0x80 to
    //0xFF) have a leading length indicator, which is encoded as a series
    //of 7-bit bytes stored in octets with the 8th bit being set for all
    //but the last byte.  The remainder of the frame is then as much data
    //as was specified.
    
    /**
     * Number of bytes holding a message size, where this number of bytes follows the
     * byteMarker within a delimiter.
     */
    private static int byteMarkerSize = 4;
    
    /**
     * The total number of bytes of a delimeter for a generated message 
     * (used when marshalling/unmarshalling).
     */
    private static int delimiterSize = byteMarkerSize + 1;

    /**
     * Get the number of bytes holding a message size, where these bytes are within
     * the delimiter byte array and follow the byte marker.
     * 
     * @return number of bytes holding a message size.
     */
    public static int getByteMarkerSize() {
        return byteMarkerSize;
    }
    
    /**
     * Get the total number of bytes of a delimeter for a generated message.
     * 
     * @return the number of bytes in a delimiter
     */
    public static int getDelimiterSize() {
        return delimiterSize;
    }
    
    /**
     * Get the byte marker used to identify the start of the delimiter.
     * 
     * @return byte marker used to identify the start of the delimiter
     */
    public static byte getMarkerForStart() {
        return markerForStart;
    }
    
    /**
     * Estimate the total number of bytes that will be used in a stream for a list
     * of messages - this includes delimeters.  This is useful to set the content-length in an HTTP response.
     * 
     * @param messages instances of GeneratedMessage
     * @return total number of bytes needed for a list of generated messages.  
     * The total includes the delimiters too.
     */
    public static int estimateTotalContentLength(List messages) {

        int sum = 0;

        for (GeneratedMessage message : messages) {
            
            int messageSize =  message.getSerializedSize();
            
            Logger.getLogger(PBWireByteMarkerHelper.class.getName())
                .log(Level.INFO, "size of a message = {0}", Integer.toString(messageSize));

            sum += messageSize + delimiterSize ;
        }

        return sum;
    }
  
    /**
     * Create a delimiter for the given GeneratedMessage.
     * 
     * @param message instance of GeneratedMessage
     * @return byte array of size delimiterSize, to be used preceding serialized GeneratedMessages
     *   in a stream.  The delimiter to separate serialized objects is 
     *   a start byte of 0x80 followed by a 4-byte big-endian integer of the length of bytes.
     */
    public static byte[] createMessageDelimiter(GeneratedMessage message) {
        
        Integer sz = message.getSerializedSize();
        
        byte[] szInBytes = integerTo4ByteBigEndian(sz);

        byte[] delimeter = new byte[PBWireByteMarkerHelper.delimiterSize];
        delimeter[0] = markerForStart;
        System.arraycopy(szInBytes, 0, delimeter, 1, 4);
        
        return delimeter;
    }

    /**
     * Convert the integer into a byte array composed of byte shifted parts of the integer.
     * 
     * @param sz the integer to be represented by the returned byte array
     * @return 
     */
     static byte[] integerTo4ByteBigEndian(int sz) {
         
        byte[] marker = new byte[4];
        
        int a00 = (sz) & 0xff;
        int a08 = (sz >>= 8) & 0xff;
        int a16 = (sz >>= 8) & 0xff;
        int a24 = (sz >>= 8) & 0xff;
        
        /*
         * int          byte
         * -----        -----
         * 0            0
         * 127          127
         * 128         -128
         * 255         -1
         */
        
        byte b00 = ((a00 >= 0) && (a00 < 128)) ? (byte)a00 : (byte)(a00 - 256);
        byte b08 = ((a08 >= 0) && (a08 < 128)) ? (byte)a08 : (byte)(a08 - 256);
        byte b16 = ((a16 >= 0) && (a16 < 128)) ? (byte)a16 : (byte)(a16 - 256);
        byte b24 = ((a24 >= 0) && (a24 < 128)) ? (byte)a24 : (byte)(a24 - 256);
        
        marker[0] = b00;
        marker[1] = b08;
        marker[2] = b16;
        marker[3] = b24;
        
        return marker;
    }
    
    /**
     * Convert the marker byte array to an integer where each item is part of byte shifted integer
     * 
     * @param marker
     * @return 
     */
     static int bytesToInteger(byte[] marker) {
        
        byte b00 = (byte)marker[0];
        byte b08 = (byte)marker[1];
        byte b16 = (byte)marker[2];
        byte b24 = (byte)marker[3];
        
        /*
         * int          byte
         * -----        -----
         * 0            0
         * 127          127
         * 128         -128
         * 255         -1
         */
        
        int d00 = ((b00 >= 0) && (b00 < 128)) ? (int)b00 : 256 + (int)b00;
        int d08 = ((b08 >= 0) && (b08 < 128)) ? (int)b08 : 256 + (int)b08;
        d08 = (d08 & 0xff) << 8;
        
        int d16 = ((b16 >= 0) && (b16 < 128)) ? (int)b16 : 256 + (int)b16;
        d16 = (d16 & 0xff) << 16;
        
        int d24 = ((b24 >= 0) && (b24 < 128)) ? (int)b24 : 256 + (int)b24;
        d24 = (d24 & 0xff) << 24;
        
        int total = d00 + d08 + d16 + d24;
        
        return total;
    }
   
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy