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

io.protostuff.GraphIOUtil Maven / Gradle / Ivy

The newest version!
//========================================================================
//Copyright 2007-2011 David Yu [email protected]
//------------------------------------------------------------------------
//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 io.protostuff;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * IO Utilities for graph objects (references and cyclic dependencies).
 * 
 * @author David Yu
 * @created Jan 19, 2011
 */
public final class GraphIOUtil
{

    private GraphIOUtil()
    {
    }

    /**
     * Merges the {@code message} with the byte array using the given {@code schema}.
     */
    public static  void mergeFrom(byte[] data, T message, Schema schema)
    {
        mergeFrom(data, 0, data.length, message, schema);
    }

    /**
     * Merges the {@code message} with the byte array using the given {@code schema}.
     */
    public static  void mergeFrom(byte[] data, int offset, int length, T message,
            Schema schema)
    {
        try
        {
            final ByteArrayInput input = new ByteArrayInput(data, offset, length, true);
            final GraphByteArrayInput graphInput = new GraphByteArrayInput(input);
            schema.mergeFrom(graphInput, message);
            input.checkLastTagWas(0);
        }
        catch (ArrayIndexOutOfBoundsException ae)
        {
            throw new RuntimeException("Truncated.", ProtobufException.truncatedMessage(ae));
        }
        catch (IOException e)
        {
            throw new RuntimeException("Reading from a byte array threw an IOException (should " +
                    "never happen).", e);
        }
    }

    /**
     * Merges the {@code message} from the {@link CodedInput} using the given {@code schema}.
     */
    public static  void mergeFrom(CodedInput input, T message, Schema schema)
            throws IOException
    {
        final GraphCodedInput graphInput = new GraphCodedInput(input);
        schema.mergeFrom(graphInput, message);
        input.checkLastTagWas(0);
    }

    /**
     * Merges the {@code message} from the {@link InputStream} using the given {@code schema}.
     */
    public static  void mergeFrom(InputStream in, T message, Schema schema)
            throws IOException
    {
        final CodedInput input = new CodedInput(in, true);
        mergeFrom(input, message, schema);
    }

    /**
     * Merges the {@code message} from the {@link InputStream} using the given {@code schema}.
     * 

* The {@code buffer}'s internal byte array will be used for reading the message. */ public static void mergeFrom(InputStream in, T message, Schema schema, LinkedBuffer buffer) throws IOException { final CodedInput input = new CodedInput(in, buffer.buffer, true); final GraphCodedInput graphInput = new GraphCodedInput(input); schema.mergeFrom(graphInput, message); input.checkLastTagWas(0); } /** * Merges the {@code message} (delimited) from the {@link InputStream} using the given {@code schema}. * * @return the size of the message */ public static int mergeDelimitedFrom(InputStream in, T message, Schema schema) throws IOException { final int size = in.read(); if (size == -1) throw ProtobufException.truncatedMessage(); final int len = size < 0x80 ? size : CodedInput.readRawVarint32(in, size); if (len < 0) throw ProtobufException.negativeSize(); if (len != 0) { // not an empty message if (len > CodedInput.DEFAULT_BUFFER_SIZE) { // message too big final CodedInput input = new CodedInput(new LimitedInputStream(in, len), true); final GraphCodedInput graphInput = new GraphCodedInput(input); schema.mergeFrom(graphInput, message); input.checkLastTagWas(0); return len; } final byte[] buf = new byte[len]; IOUtil.fillBufferFrom(in, buf, 0, len); final ByteArrayInput input = new ByteArrayInput(buf, 0, len, true); final GraphByteArrayInput graphInput = new GraphByteArrayInput(input); try { schema.mergeFrom(graphInput, message); } catch (ArrayIndexOutOfBoundsException e) { throw ProtobufException.truncatedMessage(e); } input.checkLastTagWas(0); } return len; } /** * Merges the {@code message} (delimited) from the {@link InputStream} using the given {@code schema}. *

* The delimited message size must not be larger than the {@code buffer}'s size/capacity. {@link ProtobufException} * "size limit exceeded" is thrown otherwise. * * @return the size of the message */ public static int mergeDelimitedFrom(InputStream in, T message, Schema schema, LinkedBuffer buffer) throws IOException { final int size = in.read(); if (size == -1) throw ProtobufException.truncatedMessage(); final byte[] buf = buffer.buffer; final int len = size < 0x80 ? size : CodedInput.readRawVarint32(in, size); if (len < 0) throw ProtobufException.negativeSize(); if (len != 0) { // not an empty message if (len > buf.length) { // size limit exceeded. throw new ProtobufException("size limit exceeded. " + len + " > " + buf.length); } IOUtil.fillBufferFrom(in, buf, 0, len); final ByteArrayInput input = new ByteArrayInput(buf, 0, len, true); final GraphByteArrayInput graphInput = new GraphByteArrayInput(input); try { schema.mergeFrom(graphInput, message); } catch (ArrayIndexOutOfBoundsException e) { throw ProtobufException.truncatedMessage(e); } input.checkLastTagWas(0); } return len; } /** * Used by the code generated messages that implement {@link java.io.Externalizable}. Merges from the * {@link DataInput}. * * @return the size of the message */ public static int mergeDelimitedFrom(DataInput in, T message, Schema schema) throws IOException { final byte size = in.readByte(); final int len = 0 == (size & 0x80) ? size : CodedInput.readRawVarint32(in, size); if (len < 0) throw ProtobufException.negativeSize(); if (len != 0) { // not an empty message if (len > CodedInput.DEFAULT_BUFFER_SIZE && in instanceof InputStream) { // message too big final CodedInput input = new CodedInput(new LimitedInputStream((InputStream) in, len), true); final GraphCodedInput graphInput = new GraphCodedInput(input); schema.mergeFrom(graphInput, message); input.checkLastTagWas(0); } else { final byte[] buf = new byte[len]; in.readFully(buf, 0, len); final ByteArrayInput input = new ByteArrayInput(buf, 0, len, true); final GraphByteArrayInput graphInput = new GraphByteArrayInput(input); try { schema.mergeFrom(graphInput, message); } catch (ArrayIndexOutOfBoundsException e) { throw ProtobufException.truncatedMessage(e); } input.checkLastTagWas(0); } } // check it since this message is embedded in the DataInput. if (!schema.isInitialized(message)) throw new UninitializedMessageException(message, schema); return len; } /** * Serializes the {@code message} into a byte array using the given schema. * * @return the byte array containing the data. */ public static byte[] toByteArray(T message, Schema schema, LinkedBuffer buffer) { if (buffer.start != buffer.offset) throw new IllegalArgumentException("Buffer previously used and had not been reset."); final ProtostuffOutput output = new ProtostuffOutput(buffer); final GraphProtostuffOutput graphOutput = new GraphProtostuffOutput(output); try { schema.writeTo(graphOutput, message); } catch (IOException e) { throw new RuntimeException("Serializing to a byte array threw an IOException " + "(should never happen).", e); } return output.toByteArray(); } /** * Writes the {@code message} into the {@link LinkedBuffer} using the given schema. * * @return the size of the message */ public static int writeTo(LinkedBuffer buffer, T message, Schema schema) { if (buffer.start != buffer.offset) throw new IllegalArgumentException("Buffer previously used and had not been reset."); final ProtostuffOutput output = new ProtostuffOutput(buffer); final GraphProtostuffOutput graphOutput = new GraphProtostuffOutput(output); try { schema.writeTo(graphOutput, message); } catch (IOException e) { throw new RuntimeException("Serializing to a LinkedBuffer threw an IOException " + "(should never happen).", e); } return output.getSize(); } /** * Serializes the {@code message} into an {@link OutputStream} using the given schema. * * @return the size of the message */ public static int writeTo(final OutputStream out, final T message, final Schema schema, final LinkedBuffer buffer) throws IOException { if (buffer.start != buffer.offset) throw new IllegalArgumentException("Buffer previously used and had not been reset."); final ProtostuffOutput output = new ProtostuffOutput(buffer, out); final GraphProtostuffOutput graphOutput = new GraphProtostuffOutput(output); schema.writeTo(graphOutput, message); LinkedBuffer.writeTo(out, buffer); return output.size; } /** * Serializes the {@code message}, prefixed with its length, into an {@link OutputStream}. * * @return the size of the message */ public static int writeDelimitedTo(final OutputStream out, final T message, final Schema schema, final LinkedBuffer buffer) throws IOException { if (buffer.start != buffer.offset) throw new IllegalArgumentException("Buffer previously used and had not been reset."); final ProtostuffOutput output = new ProtostuffOutput(buffer); final GraphProtostuffOutput graphOutput = new GraphProtostuffOutput(output); schema.writeTo(graphOutput, message); ProtobufOutput.writeRawVarInt32Bytes(out, output.size); LinkedBuffer.writeTo(out, buffer); return output.size; } /** * Used by the code generated messages that implement {@link java.io.Externalizable}. Writes to the * {@link DataOutput} . * * @return the size of the message. */ public static int writeDelimitedTo(DataOutput out, T message, Schema schema) throws IOException { final LinkedBuffer buffer = new LinkedBuffer(LinkedBuffer.MIN_BUFFER_SIZE); final ProtostuffOutput output = new ProtostuffOutput(buffer); final GraphProtostuffOutput graphOutput = new GraphProtostuffOutput(output); schema.writeTo(graphOutput, message); ProtobufOutput.writeRawVarInt32Bytes(out, output.size); LinkedBuffer.writeTo(out, buffer); return output.size; } /** * Optimal/Optional mergeDelimitedFrom - If the message does not fit the buffer, no merge is done and this method * will return false. *

* This is strictly for reading a single message from the stream because the buffer is aggressively filled when * reading the delimited size (which could result into reading more bytes than it has to). *

* The remaining bytes will be drained (consumed and discared) when the message is too large. */ public static boolean optMergeDelimitedFrom(InputStream in, T message, Schema schema, LinkedBuffer buffer) throws IOException { return optMergeDelimitedFrom(in, message, schema, true, buffer); } /** * Optimal/Optional mergeDelimitedFrom - If the message does not fit the buffer, no merge is done and this method * will return false. *

* This is strictly for reading a single message from the stream because the buffer is aggressively filled when * reading the delimited size (which could result into reading more bytes than it has to). */ public static boolean optMergeDelimitedFrom(InputStream in, T message, Schema schema, boolean drainRemainingBytesIfTooLarge, LinkedBuffer buffer) throws IOException { if (buffer.start != buffer.offset) throw new IllegalArgumentException("Buffer previously used and had not been reset."); final int size = IOUtil.fillBufferWithDelimitedMessageFrom(in, drainRemainingBytesIfTooLarge, buffer); if (size == 0) { // empty message return true; } if (buffer.start == buffer.offset) { // offset not set ... message too large return false; } final ByteArrayInput input = new ByteArrayInput(buffer.buffer, buffer.offset, size, true); final GraphByteArrayInput graphInput = new GraphByteArrayInput(input); try { schema.mergeFrom(graphInput, message); input.checkLastTagWas(0); } catch (ArrayIndexOutOfBoundsException e) { throw ProtobufException.truncatedMessage(e); } finally { // reset buffer.offset = buffer.start; } return true; } /** * Optimal writeDelimitedTo - The varint32 prefix is written to the buffer instead of directly writing to * outputstream. * * @return the size of the message */ public static int optWriteDelimitedTo(final OutputStream out, final T message, final Schema schema, final LinkedBuffer buffer) throws IOException { if (buffer.start != buffer.offset) throw new IllegalArgumentException("Buffer previously used and had not been reset."); final ProtostuffOutput output = new ProtostuffOutput(buffer); final GraphProtostuffOutput graphOutput = new GraphProtostuffOutput(output); // leave space for varint32 buffer.offset = buffer.start + 5; output.size += 5; schema.writeTo(graphOutput, message); final int size = output.size - 5; final int delimOffset = IOUtil.putVarInt32AndGetOffset(size, buffer.buffer, buffer.start); // write to stream out.write(buffer.buffer, delimOffset, buffer.offset - delimOffset); // flush remaining if (buffer.next != null) LinkedBuffer.writeTo(out, buffer.next); return size; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy