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

com.tangosol.io.pof.PofBufferReader Maven / Gradle / Ivy

There is a newer version: 24.09
Show newest version
/*
 * Copyright (c) 2000, 2020, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * http://oss.oracle.com/licenses/upl.
 */
package com.tangosol.io.pof;

import com.tangosol.io.ReadBuffer;
import com.tangosol.io.SerializationSupport;
import com.tangosol.io.SerializerAware;

import com.tangosol.util.Binary;
import com.tangosol.util.ExternalizableHelper;
import com.tangosol.util.ImmutableArrayList;
import com.tangosol.util.LongArray;
import com.tangosol.util.SparseArray;

import java.io.IOException;
import java.io.StreamCorruptedException;

import java.math.BigDecimal;
import java.math.BigInteger;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.OffsetTime;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import java.util.function.IntFunction;

/**
* {@link PofReader} implementation that reads POF-encoded data from a
* {@link com.tangosol.io.ReadBuffer.BufferInput BufferInput}.
*
* @author cp  2006.07.14
*
* @since Coherence 3.2
*/
public class PofBufferReader
        extends PofHelper
        implements PofReader
    {
    // ----- constructors ---------------------------------------------------

    /**
    * Construct a new PofBufferReader that will read a POF stream from the
    * passed BufferInput object.
    *
    * @param in   a BufferInput object
    * @param ctx  the PofContext
    */
    public PofBufferReader(ReadBuffer.BufferInput in, PofContext ctx)
        {
        m_in  = in;
        m_ctx = ctx;
        }

    protected PofBufferReader()
        {
        }


    // ----- PofReader interface --------------------------------------------

    /**
    * {@inheritDoc}
    */
    public boolean readBoolean(int iProp)
            throws IOException
        {
        return readInt(iProp) != 0;
        }

    /**
    * {@inheritDoc}
    */
    public byte readByte(int iProp)
            throws IOException
        {
        return (byte) readInt(iProp);
        }

    /**
    * {@inheritDoc}
    */
    public char readChar(int iProp)
            throws IOException
        {
        return (char) readInt(iProp);
        }

    /**
    * {@inheritDoc}
    */
    public short readShort(int iProp)
            throws IOException
        {
        return (short) readInt(iProp);
        }

    /**
    * {@inheritDoc}
    */
    public int readInt(int iProp)
            throws IOException
        {
        int n = 0;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    n = readInt(iProp);
                    registerIdentity(nId, Integer.valueOf(n));
                    }
                    break;

                case T_REFERENCE:
                    Number number = (Number) lookupIdentity(in.readPackedInt());
                    if (number != null)
                        {
                        n = number.intValue();
                        }
                    break;

                case V_REFERENCE_NULL:
                case V_INT_0:
                    break;

                default:
                    n = readAsInt(in, nType);
                    break;
                }
            }
        complete(iProp);

        return n;
        }

    /**
    * {@inheritDoc}
    */
    public long readLong(int iProp)
            throws IOException
        {
        long n = 0L;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    n = readLong(iProp);
                    registerIdentity(nId, Long.valueOf(n));
                    }
                    break;

                case T_REFERENCE:
                    Number number = (Number) lookupIdentity(in.readPackedInt());
                    if (number != null)
                        {
                        n = number.longValue();
                        }
                    break;

                case V_REFERENCE_NULL:
                case V_INT_0:
                    break;

                default:
                    n = readAsLong(in, nType);
                    break;
                }
            }
        complete(iProp);

        return n;
        }

    /**
    * {@inheritDoc}
    */
    public float readFloat(int iProp)
            throws IOException
        {
        float fl = 0.0F;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    fl = readFloat(iProp);
                    registerIdentity(nId, Float.valueOf(fl));
                    }
                    break;

                case T_REFERENCE:
                    Number number = (Number) lookupIdentity(in.readPackedInt());
                    if (number != null)
                        {
                        fl = number.floatValue();
                        }
                    break;

                case V_REFERENCE_NULL:
                case V_INT_0:
                    break;

                default:
                    fl = readAsFloat(in, nType);
                    break;
                }
            }
        complete(iProp);

        return fl;
        }

    /**
    * {@inheritDoc}
    */
    public double readDouble(int iProp)
            throws IOException
        {
        double dfl = 0.0;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    dfl = readDouble(iProp);
                    registerIdentity(nId, Double.valueOf(dfl));
                    }
                    break;

                case T_REFERENCE:
                    Number number = (Number) lookupIdentity(in.readPackedInt());
                    if (number != null)
                        {
                        dfl = number.doubleValue();
                        }
                    break;

                case V_REFERENCE_NULL:
                case V_INT_0:
                    break;

                default:
                    dfl = readAsDouble(in, nType);
                    break;
                }
            }
        complete(iProp);

        return dfl;
        }

    /**
    * {@inheritDoc}
    */
    public boolean[] readBooleanArray(int iProp)
            throws IOException
        {
        boolean[] af = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    af = readBooleanArray(iProp);
                    registerIdentity(nId, af);
                    }
                    break;

                case T_REFERENCE:
                    af = (boolean[]) lookupIdentity(in.readPackedInt());
                    break;

                case V_REFERENCE_NULL:
                    break;

                case V_STRING_ZERO_LENGTH:
                case V_COLLECTION_EMPTY:
                    af = BOOLEAN_ARRAY_EMPTY;
                    break;

                case T_COLLECTION:
                case T_ARRAY:
                    {
                    int cElements = in.readPackedInt();
                    af = new boolean[cElements];
                    for (int i = 0; i < cElements; ++i)
                        {
                        af[i] = readAsInt(in, in.readPackedInt()) != 0;
                        }
                    }
                    break;

                case T_UNIFORM_COLLECTION:
                case T_UNIFORM_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int cElements    = in.readPackedInt();
                    af = new boolean[cElements];
                    switch (nElementType)
                        {
                        case T_BOOLEAN:
                        case T_INT16:
                        case T_INT32:
                        case T_INT64:
                        case T_INT128:
                            for (int i = 0; i < cElements; ++i)
                                {
                                af[i] = in.readPackedInt() != 0;
                                }
                            break;

                        default:
                            for (int i = 0; i < cElements; ++i)
                                {
                                af[i] = readAsInt(in, nElementType) != 0;
                                }
                            break;
                        }
                    }
                    break;

                case T_SPARSE_ARRAY:
                    {
                    int cElements = in.readPackedInt();
                    af = new boolean[cElements];
                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        af[iElement] = readAsInt(in, in.readPackedInt()) != 0;
                        }
                    while (--cElements >= 0);
                    }
                    break;

                case T_UNIFORM_SPARSE_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int cElements    = in.readPackedInt();
                    af = new boolean[cElements];
                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        af[iElement] = readAsInt(in, nElementType) != 0;
                        }
                    while (--cElements >= 0);
                    }
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to an array type");
                }
            }
        complete(iProp);

        return af;
        }

    /**
    * {@inheritDoc}
    */
    public byte[] readByteArray(int iProp)
            throws IOException
        {
        byte[] ab = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    ab = readByteArray(iProp);
                    registerIdentity(nId, ab);
                    }
                    break;

                case T_REFERENCE:
                    {
                    Object o = lookupIdentity(in.readPackedInt());
                    ab = o instanceof Binary
                            ? ((Binary) o).toByteArray()
                            : (byte[]) o;
                    }
                    break;

                case V_REFERENCE_NULL:
                    break;

                case V_STRING_ZERO_LENGTH:
                case V_COLLECTION_EMPTY:
                    ab = BYTE_ARRAY_EMPTY;
                    break;

                case T_OCTET_STRING:
                    ab = new byte[in.readPackedInt()];
                    in.readFully(ab);
                    break;

                case T_COLLECTION:
                case T_ARRAY:
                    {
                    int cElements = in.readPackedInt();
                    ab = new byte[cElements];
                    for (int i = 0; i < cElements; ++i)
                        {
                        ab[i] = (byte) readAsInt(in, in.readPackedInt());
                        }
                    }
                    break;

                case T_UNIFORM_COLLECTION:
                case T_UNIFORM_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int cElements    = in.readPackedInt();

                    ab = new byte[cElements];
                    if (nElementType == T_OCTET)
                        {
                        in.readFully(ab);
                        }
                    else
                        {
                        for (int i = 0; i < cElements; ++i)
                            {
                            ab[i] = (byte) readAsInt(in, nElementType);
                            }
                        }
                    }
                    break;

                case T_SPARSE_ARRAY:
                    {
                    int cElements = in.readPackedInt();
                    ab = new byte[cElements];
                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        ab[iElement] = (byte) readAsInt(in, in.readPackedInt());
                        }
                    while (--cElements >= 0);
                    }
                    break;

                case T_UNIFORM_SPARSE_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int cElements    = in.readPackedInt();
                    ab = new byte[cElements];
                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        ab[iElement] = nElementType == T_OCTET
                                       ? in.readByte()
                                       : (byte) readAsInt(in, nElementType);
                        }
                    while (--cElements >= 0);
                    }
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to an array type");
                }
            }
        complete(iProp);

        return ab;
        }

    /**
    * {@inheritDoc}
    */
    public char[] readCharArray(int iProp)
            throws IOException
        {
        char[] ach = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    ach = readCharArray(iProp);
                    registerIdentity(nId, ach);
                    }
                    break;

                case T_REFERENCE:
                    {
                    Object o = lookupIdentity(in.readPackedInt());
                    ach = o instanceof String
                            ? ((String) o).toCharArray()
                            : (char[]) o;
                    }
                    break;

                case V_REFERENCE_NULL:
                    break;

                case V_STRING_ZERO_LENGTH:
                case V_COLLECTION_EMPTY:
                    ach = CHAR_ARRAY_EMPTY;
                    break;

                case T_OCTET_STRING:
                    {
                    int    cb = in.readPackedInt();
                    byte[] ab = new byte[cb];
                    in.readFully(ab);

                    ach = new char[cb];
                    for (int of = 0; of < cb; ++cb)
                        {
                        ach[of] = (char) (ab[of] & 0xFF);
                        }
                    }
                    break;

                case T_CHAR_STRING:
                    ach = in.readSafeUTF().toCharArray();
                    break;

                case T_COLLECTION:
                case T_ARRAY:
                    {
                    int cElements = in.readPackedInt();
                    ach = new char[cElements];
                    for (int i = 0; i < cElements; ++i)
                        {
                        ach[i] = (char) readAsInt(in, in.readPackedInt());
                        }
                    }
                    break;

                case T_UNIFORM_COLLECTION:
                case T_UNIFORM_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int cElements    = in.readPackedInt();
                    ach = new char[cElements];
                    for (int i = 0; i < cElements; ++i)
                        {
                        ach[i] = nElementType == T_CHAR
                                 ? readChar(in)
                                 : (char) readAsInt(in, nElementType);
                        }
                    }
                    break;

                case T_SPARSE_ARRAY:
                    {
                    int cElements = in.readPackedInt();
                    ach = new char[cElements];
                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        ach[iElement] = (char) readAsInt(in, in.readPackedInt());
                        }
                    while (--cElements >= 0);
                    }
                    break;

                case T_UNIFORM_SPARSE_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int cElements    = in.readPackedInt();
                    ach = new char[cElements];
                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        ach[iElement] = nElementType == T_CHAR
                                        ? readChar(in)
                                        : (char) readAsInt(in, nElementType);
                        }
                    while (--cElements >= 0);
                    }
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to an array type");
                }
            }
        complete(iProp);

        return ach;
        }

    /**
    * {@inheritDoc}
    */
    public short[] readShortArray(int iProp)
            throws IOException
        {
        short[] an = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    an = readShortArray(iProp);
                    registerIdentity(nId, an);
                    }
                    break;

                case T_REFERENCE:
                    an = (short[]) lookupIdentity(in.readPackedInt());
                    break;

                case V_REFERENCE_NULL:
                    break;

                case V_COLLECTION_EMPTY:
                    an = SHORT_ARRAY_EMPTY;
                    break;

                case T_COLLECTION:
                case T_ARRAY:
                    {
                    int cElements = in.readPackedInt();
                    an = new short[cElements];
                    for (int i = 0; i < cElements; ++i)
                        {
                        an[i] = (short) readAsInt(in, in.readPackedInt());
                        }
                    }
                    break;

                case T_UNIFORM_COLLECTION:
                case T_UNIFORM_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int cElements    = in.readPackedInt();
                    an = new short[cElements];
                    switch (nElementType)
                        {
                        case T_INT16:
                        case T_INT32:
                        case T_INT64:
                        case T_INT128:
                            for (int i = 0; i < cElements; ++i)
                                {
                                an[i] = (short) in.readPackedInt();
                                }
                            break;

                        default:
                            for (int i = 0; i < cElements; ++i)
                                {
                                an[i] = (short) readAsInt(in, nElementType);
                                }
                            break;
                        }
                    }
                    break;

                case T_SPARSE_ARRAY:
                    {
                    int cElements = in.readPackedInt();
                    an = new short[cElements];
                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        an[iElement] = (short) readAsInt(in, in.readPackedInt());
                        }
                    while (--cElements >= 0);
                    }
                    break;

                case T_UNIFORM_SPARSE_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int cElements    = in.readPackedInt();
                    an = new short[cElements];
                    switch (nElementType)
                        {
                        case T_INT16:
                        case T_INT32:
                        case T_INT64:
                        case T_INT128:
                            do
                                {
                                int iElement = in.readPackedInt();
                                if (iElement < 0)
                                    {
                                    break;
                                    }
                                an[iElement] = (short) in.readPackedInt();
                                }
                            while (--cElements >= 0);
                            break;

                        default:
                            do
                                {
                                int iElement = in.readPackedInt();
                                if (iElement < 0)
                                    {
                                    break;
                                    }
                                an[iElement] = (short) readAsInt(in, nElementType);
                                }
                            while (--cElements >= 0);
                            break;
                        }
                    }
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to an array type");
                }
            }
        complete(iProp);

        return an;
        }

    /**
    * {@inheritDoc}
    */
    public int[] readIntArray(int iProp)
            throws IOException
        {
        int[] an = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    an = readIntArray(iProp);
                    registerIdentity(nId, an);
                    }
                    break;

                case T_REFERENCE:
                    an = (int[]) lookupIdentity(in.readPackedInt());
                    break;

                case V_REFERENCE_NULL:
                    break;

                case V_COLLECTION_EMPTY:
                    an = INT_ARRAY_EMPTY;
                    break;

                case T_COLLECTION:
                case T_ARRAY:
                    {
                    int cElements = in.readPackedInt();
                    an = new int[cElements];
                    for (int i = 0; i < cElements; ++i)
                        {
                        an[i] = readAsInt(in, in.readPackedInt());
                        }
                    }
                    break;

                case T_UNIFORM_COLLECTION:
                case T_UNIFORM_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int cElements    = in.readPackedInt();
                    an = new int[cElements];
                    switch (nElementType)
                        {
                        case T_INT16:
                        case T_INT32:
                        case T_INT64:
                        case T_INT128:
                            for (int i = 0; i < cElements; ++i)
                                {
                                an[i] = in.readPackedInt();
                                }
                            break;

                        default:
                            for (int i = 0; i < cElements; ++i)
                                {
                                an[i] = readAsInt(in, nElementType);
                                }
                            break;
                        }
                    }
                    break;

                case T_SPARSE_ARRAY:
                    {
                    int cElements = in.readPackedInt();
                    an = new int[cElements];
                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        an[iElement] = readAsInt(in, in.readPackedInt());
                        }
                    while (--cElements >= 0);
                    }
                    break;

                case T_UNIFORM_SPARSE_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int cElements    = in.readPackedInt();
                    an = new int[cElements];
                    switch (nElementType)
                        {
                        case T_INT16:
                        case T_INT32:
                        case T_INT64:
                        case T_INT128:
                            do
                                {
                                int iElement = in.readPackedInt();
                                if (iElement < 0)
                                    {
                                    break;
                                    }
                                an[iElement] = in.readPackedInt();
                                }
                            while (--cElements >= 0);
                            break;

                        default:
                            do
                                {
                                int iElement = in.readPackedInt();
                                if (iElement < 0)
                                    {
                                    break;
                                    }
                                an[iElement] = readAsInt(in, nElementType);
                                }
                            while (--cElements >= 0);
                            break;
                        }
                    }
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to an array type");
                }
            }
        complete(iProp);

        return an;
        }

    /**
    * {@inheritDoc}
    */
    public long[] readLongArray(int iProp)
            throws IOException
        {
        long[] an = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    an = readLongArray(iProp);
                    registerIdentity(nId, an);
                    }
                    break;

                case T_REFERENCE:
                    an = (long[]) lookupIdentity(in.readPackedInt());
                    break;

                case V_REFERENCE_NULL:
                    break;

                case V_COLLECTION_EMPTY:
                    an = LONG_ARRAY_EMPTY;
                    break;

                case T_COLLECTION:
                case T_ARRAY:
                    {
                    int cElements = in.readPackedInt();
                    an = new long[cElements];
                    for (int i = 0; i < cElements; ++i)
                        {
                        an[i] = readAsLong(in, in.readPackedInt());
                        }
                    }
                    break;

                case T_UNIFORM_COLLECTION:
                case T_UNIFORM_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int cElements    = in.readPackedInt();
                    an = new long[cElements];
                    switch (nElementType)
                        {
                        case T_INT16:
                        case T_INT32:
                        case T_INT64:
                        case T_INT128:
                            for (int i = 0; i < cElements; ++i)
                                {
                                an[i] = in.readPackedLong();
                                }
                            break;

                        default:
                            for (int i = 0; i < cElements; ++i)
                                {
                                an[i] = readAsLong(in, nElementType);
                                }
                            break;
                        }
                    }
                    break;

                case T_SPARSE_ARRAY:
                    {
                    int cElements = in.readPackedInt();
                    an = new long[cElements];
                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        an[iElement] = readAsLong(in, in.readPackedInt());
                        }
                    while (--cElements >= 0);
                    }
                    break;

                case T_UNIFORM_SPARSE_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int cElements    = in.readPackedInt();
                    an = new long[cElements];
                    switch (nElementType)
                        {
                        case T_INT16:
                        case T_INT32:
                        case T_INT64:
                        case T_INT128:
                            do
                                {
                                int iElement = in.readPackedInt();
                                if (iElement < 0)
                                    {
                                    break;
                                    }
                                an[iElement] = in.readPackedLong();
                                }
                            while (--cElements >= 0);
                            break;

                        default:
                            do
                                {
                                int iElement = in.readPackedInt();
                                if (iElement < 0)
                                    {
                                    break;
                                    }
                                an[iElement] = readAsLong(in, nElementType);
                                }
                            while (--cElements >= 0);
                            break;
                        }
                    }
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to an array type");
                }
            }
        complete(iProp);

        return an;
        }

    /**
    * {@inheritDoc}
    */
    public float[] readFloatArray(int iProp)
            throws IOException
        {
        float[] afl = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    afl = readFloatArray(iProp);
                    registerIdentity(nId, afl);
                    }
                    break;

                case T_REFERENCE:
                    afl = (float[]) lookupIdentity(in.readPackedInt());
                    break;

                case V_REFERENCE_NULL:
                    break;

                case V_COLLECTION_EMPTY:
                    afl = FLOAT_ARRAY_EMPTY;
                    break;

                case T_COLLECTION:
                case T_ARRAY:
                    {
                    int cElements = in.readPackedInt();
                    afl = new float[cElements];
                    for (int i = 0; i < cElements; ++i)
                        {
                        afl[i] = readAsFloat(in, in.readPackedInt());
                        }
                    }
                    break;

                case T_UNIFORM_COLLECTION:
                case T_UNIFORM_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int cElements    = in.readPackedInt();
                    afl = new float[cElements];
                    for (int i = 0; i < cElements; ++i)
                        {
                        afl[i] = nElementType == T_FLOAT32
                                 ? in.readFloat()
                                 : readAsFloat(in, nElementType);
                        }
                    }
                    break;

                case T_SPARSE_ARRAY:
                    {
                    int cElements = in.readPackedInt();
                    afl = new float[cElements];
                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        afl[iElement] = readAsFloat(in, in.readPackedInt());
                        }
                    while (--cElements >= 0);
                    }
                    break;

                case T_UNIFORM_SPARSE_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int cElements    = in.readPackedInt();
                    afl = new float[cElements];
                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        afl[iElement] = nElementType == T_FLOAT32
                                 ? in.readFloat()
                                 : readAsFloat(in, nElementType);
                        }
                    while (--cElements >= 0);
                    }
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to an array type");
                }
            }
        complete(iProp);

        return afl;
        }

    /**
    * {@inheritDoc}
    */
    public double[] readDoubleArray(int iProp)
            throws IOException
        {
        double[] adfl = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    adfl = readDoubleArray(iProp);
                    registerIdentity(nId, adfl);
                    }
                    break;

                case T_REFERENCE:
                    adfl = (double[]) lookupIdentity(in.readPackedInt());
                    break;

                case V_REFERENCE_NULL:
                    break;

                case V_COLLECTION_EMPTY:
                    adfl = DOUBLE_ARRAY_EMPTY;
                    break;

                case T_COLLECTION:
                case T_ARRAY:
                    {
                    int cElements = in.readPackedInt();
                    adfl = new double[cElements];
                    for (int i = 0; i < cElements; ++i)
                        {
                        adfl[i] = readAsDouble(in, in.readPackedInt());
                        }
                    }
                    break;

                case T_UNIFORM_COLLECTION:
                case T_UNIFORM_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int cElements    = in.readPackedInt();
                    adfl = new double[cElements];
                    for (int i = 0; i < cElements; ++i)
                        {
                        adfl[i] = nElementType == T_FLOAT64
                                  ? in.readDouble()
                                  : readAsDouble(in, nElementType);
                        }
                    }
                    break;

                case T_SPARSE_ARRAY:
                    {
                    int cElements = in.readPackedInt();
                    adfl = new double[cElements];
                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        adfl[iElement] = readAsDouble(in, in.readPackedInt());
                        }
                    while (--cElements >= 0);
                    }
                    break;

                case T_UNIFORM_SPARSE_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int cElements    = in.readPackedInt();
                    adfl = new double[cElements];
                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        adfl[iElement] = nElementType == T_FLOAT64
                                  ? in.readDouble()
                                  : readAsDouble(in, nElementType);
                        }
                    while (--cElements >= 0);
                    }
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to an array type");
                }
            }
        complete(iProp);

        return adfl;
        }

    /**
    * {@inheritDoc}
    */
    public BigInteger readBigInteger(int iProp)
            throws IOException
        {
        BigInteger n = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    n = readBigInteger(iProp);
                    registerIdentity(nId, n);
                    }
                    break;

                case T_REFERENCE:
                    {
                    Number number = (Number) lookupIdentity(in.readPackedInt());
                    n = (BigInteger) convertNumber(number, J_BIG_INTEGER);
                    }
                    break;

                case V_REFERENCE_NULL:
                    break;

                case V_INT_0:
                    n = BigInteger.ZERO;
                    break;

                default:
                    n = readAsBigInteger(in, nType);
                    break;
                }
            }
        complete(iProp);

        return n;
        }

    /**
    * {@inheritDoc}
    */
    public RawQuad readRawQuad(int iProp)
            throws IOException
        {
        RawQuad qfl = RawQuad.ZERO;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    qfl = readRawQuad(iProp);
                    registerIdentity(nId, qfl);
                    }
                    break;

                case T_REFERENCE:
                    {
                    Number number = (Number) lookupIdentity(in.readPackedInt());
                    qfl = (RawQuad) convertNumber(number, J_QUAD);
                    }
                    break;

                case V_REFERENCE_NULL:
                    qfl = null;
                    break;

                case V_INT_0:
                    break;

                default:
                    qfl = readAsQuad(in, nType);
                    break;
                }
            }
        complete(iProp);

        return qfl;
        }

    /**
    * {@inheritDoc}
    */
    public BigDecimal readBigDecimal(int iProp)
            throws IOException
        {
        BigDecimal dec = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    dec = readBigDecimal(iProp);
                    registerIdentity(nId, dec);
                    }
                    break;

                case T_REFERENCE:
                    {
                    Number number = (Number) lookupIdentity(in.readPackedInt());
                    dec = (BigDecimal) convertNumber(number, J_BIG_DECIMAL);
                    }
                    break;

                case V_REFERENCE_NULL:
                    break;

                case V_INT_0:
                    dec = BigDecimal.ZERO;
                    break;

                default:
                    dec = readAsBigDecimal(in, nType);
                    break;
                }
            }
        complete(iProp);

        return dec;
        }

    /**
    * {@inheritDoc}
    */
    public Binary readBinary(int iProp)
            throws IOException
        {
        Binary bin = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    bin = readBinary(iProp);
                    registerIdentity(nId, bin);
                    }
                    break;

                case T_REFERENCE:
                    {
                    Object o = lookupIdentity(in.readPackedInt());
                    bin = o instanceof byte[]
                            ? new Binary((byte[]) o)
                            : (Binary) o;
                    }
                    break;

                case V_REFERENCE_NULL:
                    break;

                case V_STRING_ZERO_LENGTH:
                case V_COLLECTION_EMPTY:
                    bin = BINARY_EMPTY;
                    break;

                case T_OCTET_STRING:
                    bin = readBinary(in);
                    break;

                case T_COLLECTION:
                case T_ARRAY:
                    {
                    int    cb = in.readPackedInt();
                    byte[] ab = new byte[cb];
                    for (int i = 0; i < cb; ++i)
                        {
                        ab[i] = (byte) readAsInt(in, in.readPackedInt());
                        }
                    bin = new Binary(ab);
                    }
                    break;

                case T_UNIFORM_COLLECTION:
                case T_UNIFORM_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int    cb = in.readPackedInt();
                    byte[] ab = new byte[cb];

                    if (nElementType == T_OCTET)
                        {
                        in.readFully(ab);
                        }
                    else
                        {
                        for (int i = 0; i < cb; ++i)
                            {
                            ab[i] = (byte) readAsInt(in, nElementType);
                            }
                        }
                    bin = new Binary(ab);
                    }
                    break;

                case T_SPARSE_ARRAY:
                    {
                    int    cb = in.readPackedInt();
                    byte[] ab = new byte[cb];
                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        ab[iElement] = (byte) readAsInt(in, in.readPackedInt());
                        }
                    while (--cb >= 0);
                    bin = new Binary(ab);
                    }
                    break;

                case T_UNIFORM_SPARSE_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int    cb = in.readPackedInt();
                    byte[] ab = new byte[cb];
                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        ab[iElement] = nElementType == T_OCTET
                                       ? in.readByte()
                                       : (byte) readAsInt(in, nElementType);
                        }
                    while (--cb >= 0);
                    bin = new Binary(ab);
                    }
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to a Binary type");
                }
            }
        complete(iProp);

        return bin;
        }

    /**
    * {@inheritDoc}
    */
    public String readString(int iProp)
            throws IOException
        {
        String s = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    s = readString(iProp);
                    registerIdentity(nId, s);
                    }
                    break;

                case T_REFERENCE:
                    {
                    Object o = lookupIdentity(in.readPackedInt());
                    if (o instanceof byte[])
                        {
                        s = new String((byte[]) o, 0);
                        }
                    else if (o instanceof Binary)
                        {
                        s = new String(((Binary) o).toByteArray(), 0);
                        }
                    else
                        {
                        s = (String) o;
                        }
                    }
                    break;

                case V_REFERENCE_NULL:
                    break;

                case V_STRING_ZERO_LENGTH:
                case V_COLLECTION_EMPTY:
                    s = "";
                    break;

                case T_OCTET_STRING:
                    {
                    int cb = in.readPackedInt();
                    int of = in.getOffset();

                    ReadBuffer buf = in.getBuffer();
                    if (buf == null)
                        {
                        s = new String(in.readBuffer(cb).toByteArray(), 0);
                        }
                    else
                        {
                        in.skipBytes(cb);
                        Binary bin = in.getBuffer().toBinary(of, cb);
                        s = new String(bin.toByteArray(), 0);
                        }
                    }
                    break;

                case T_CHAR_STRING:
                    s = in.readSafeUTF();
                    break;

                case T_COLLECTION:
                case T_ARRAY:
                    {
                    int    cch = in.readPackedInt();
                    char[] ach = new char[cch];
                    for (int i = 0; i < cch; ++i)
                        {
                        ach[i] = readAsChar(in, in.readPackedInt());
                        }
                    s = new String(ach);
                    }
                    break;

                case T_UNIFORM_COLLECTION:
                case T_UNIFORM_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int    cch = in.readPackedInt();
                    char[] ach = new char[cch];
                    for (int i = 0; i < cch; ++i)
                        {
                        ach[i] = readAsChar(in, nElementType);
                        }
                    s = new String(ach);
                    }
                    break;

                case T_SPARSE_ARRAY:
                    {
                    int    cch = in.readPackedInt();
                    char[] ach = new char[cch];
                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        ach[iElement] = readAsChar(in, in.readPackedInt());
                        }
                    while (--cch >= 0);
                    s = new String(ach);
                    }
                    break;

                case T_UNIFORM_SPARSE_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int    cch = in.readPackedInt();
                    char[] ach = new char[cch];
                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        ach[iElement] = readAsChar(in, nElementType);
                        }
                    while (--cch >= 0);
                    s = new String(ach);
                    }
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to a String type");
                }
            }
        complete(iProp);

        return s;
        }

    /**
    * {@inheritDoc}
    */
    public Date readDate(int iProp)
            throws IOException
        {
        Date date = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    date = readDate(iProp);
                    registerIdentity(nId, date);
                    }
                    break;

                case T_REFERENCE:
                    date = convertToDate(lookupIdentity(in.readPackedInt()));
                    break;

                case V_REFERENCE_NULL:
                    break;

                case T_DATE:
                    date = convertToDate(readRawDate(in));
                    break;

                case T_TIME:
                    date = convertToDate(readRawTime(in));
                    break;

                case T_DATETIME:
                    date = convertToDate(new RawDateTime(readRawDate(in), readRawTime(in)));
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to a Java Date type");
                }
            }
        complete(iProp);

        return date;
        }

    @Override
    public LocalDate readLocalDate(int iProp) throws IOException
        {
        LocalDate date = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    date = readLocalDate(iProp);
                    registerIdentity(nId, date);
                    }
                    break;

                case T_REFERENCE:
                    date = (LocalDate) lookupIdentity(in.readPackedInt());
                    break;

                case V_REFERENCE_NULL:
                    break;

                case T_DATE:
                    date = readLocalDate(in);
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to a Java LocalDate type");
                }
            }
        complete(iProp);

        return date;
        }

    @Override
    public LocalDateTime readLocalDateTime(int iProp) throws IOException
        {
        LocalDateTime dt = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    dt = readLocalDateTime(iProp);
                    registerIdentity(nId, dt);
                    }
                    break;

                case T_REFERENCE:
                    dt = (LocalDateTime) lookupIdentity(in.readPackedInt());
                    break;

                case V_REFERENCE_NULL:
                    break;

                case T_DATETIME:
                    dt = readLocalDateTime(in);
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to a Java LocalDateTime type");
                }
            }
        complete(iProp);

        return dt;
        }

    @Override
    public LocalTime readLocalTime(int iProp) throws IOException
        {
        LocalTime time = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    time = readLocalTime(iProp);
                    registerIdentity(nId, time);
                    }
                    break;

                case T_REFERENCE:
                    time = (LocalTime) lookupIdentity(in.readPackedInt());
                    break;

                case V_REFERENCE_NULL:
                    break;

                case T_TIME:
                    time = readLocalTime(in);
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to a Java LocalTime type");
                }
            }
        complete(iProp);

        return time;
        }

    @Override
    public OffsetDateTime readOffsetDateTime(int iProp) throws IOException
        {
        OffsetDateTime dt = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    dt = readOffsetDateTime(iProp);
                    registerIdentity(nId, dt);
                    }
                    break;

                case T_REFERENCE:
                    dt = (OffsetDateTime) lookupIdentity(in.readPackedInt());
                    break;

                case V_REFERENCE_NULL:
                    break;

                case T_DATETIME:
                    dt = readOffsetDateTime(in);
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to a Java OffsetDateTime type");
                }
            }
        complete(iProp);

        return dt;
        }

    @Override
    public OffsetTime readOffsetTime(int iProp) throws IOException
        {
        OffsetTime time = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    time = readOffsetTime(iProp);
                    registerIdentity(nId, time);
                    }
                    break;

                case T_REFERENCE:
                    time = (OffsetTime) lookupIdentity(in.readPackedInt());
                    break;

                case V_REFERENCE_NULL:
                    break;

                case T_TIME:
                    time = readOffsetTime(in);
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to a Java OffsetTime type");
                }
            }
        complete(iProp);

        return time;
        }

    /**
    * {@inheritDoc}
    */
    public RawDate readRawDate(int iProp)
            throws IOException
        {
        RawDate date = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    date = readRawDate(iProp);
                    registerIdentity(nId, date);
                    }
                    break;

                case T_REFERENCE:
                    {
                    Object o = lookupIdentity(in.readPackedInt());
                    if (o instanceof Date)
                        {
                        Calendar calendar = Calendar.getInstance();
                        calendar.setTime((Date) o);
                        date = new RawDate(
                                calendar.get(Calendar.YEAR),
                                calendar.get(Calendar.MONTH) + 1,
                                calendar.get(Calendar.DAY_OF_MONTH));
                        }
                    else if (o instanceof RawDateTime)
                        {
                        date = ((RawDateTime) o).getRawDate();
                        }
                    else
                        {
                        date = (RawDate) o;
                        }
                    }
                    break;

                case V_REFERENCE_NULL:
                    break;

                case T_DATE:
                    date = readRawDate(in);
                    break;

                case T_DATETIME:
                    {
                    // read the date portion
                    date = readRawDate(in);

                    // skip the time portion
                    skipPackedInts(in, 4);
                    int nZoneType = in.readPackedInt();
                    if (nZoneType == 2)
                        {
                        skipPackedInts(in, 2);
                        }
                    }
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to a RawDate type");
                }
            }
        complete(iProp);

        return date;
        }

    /**
    * {@inheritDoc}
    */
    public RawTime  readRawTime(int iProp)
            throws IOException
        {
        RawTime time = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    time = readRawTime(iProp);
                    registerIdentity(nId, time);
                    }
                    break;

                case T_REFERENCE:
                    {
                    Object o = lookupIdentity(in.readPackedInt());
                    if (o instanceof Date)
                        {
                        Calendar calendar = Calendar.getInstance();
                        calendar.setTime((Date) o);
                        time = new RawTime(
                                calendar.get(Calendar.HOUR_OF_DAY),
                                calendar.get(Calendar.MINUTE),
                                calendar.get(Calendar.SECOND),
                                calendar.get(Calendar.MILLISECOND) * 1000000,
                                false);
                        }
                    else if (o instanceof RawDateTime)
                        {
                        time = ((RawDateTime) o).getRawTime();
                        }
                    else
                        {
                        time = (RawTime) o;
                        }
                    }
                    break;

                case V_REFERENCE_NULL:
                    break;

                case T_DATETIME:
                    // skip the date portion
                    skipPackedInts(in, 3);
                    // fall through
                case T_TIME:
                    time = readRawTime(in);
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to a RawTime type");
                }
            }
        complete(iProp);

        return time;
        }

    /**
    * {@inheritDoc}
    */
    public RawDateTime readRawDateTime(int iProp)
            throws IOException
        {
        RawDateTime dt = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    dt = readRawDateTime(iProp);
                    registerIdentity(nId, dt);
                    }
                    break;

                case T_REFERENCE:
                    {
                    Object o = lookupIdentity(in.readPackedInt());
                    if (o instanceof Date)
                        {
                        Calendar calendar = Calendar.getInstance();
                        calendar.setTime((Date) o);
                        dt = new RawDateTime(
                            new RawDate(
                                calendar.get(Calendar.YEAR),
                                calendar.get(Calendar.MONTH) + 1,
                                calendar.get(Calendar.DAY_OF_MONTH)),
                            new RawTime(
                                calendar.get(Calendar.HOUR_OF_DAY),
                                calendar.get(Calendar.MINUTE),
                                calendar.get(Calendar.SECOND),
                                calendar.get(Calendar.MILLISECOND) * 1000000,
                                false));
                        }
                    else if (o instanceof RawDate)
                        {
                        dt = new RawDateTime((RawDate) o, new RawTime(0, 0, 0, 0, false));
                        }
                    else
                        {
                        dt = (RawDateTime) o;
                        }
                    }
                    break;

                case V_REFERENCE_NULL:
                    break;

                case T_DATE:
                    dt = new RawDateTime(readRawDate(in), new RawTime(0, 0, 0, 0, false));
                    break;

                case T_DATETIME:
                    dt = new RawDateTime(readRawDate(in), readRawTime(in));
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to a RawDateTime type");
                }
            }
        complete(iProp);

        return dt;
        }

    /**
    * {@inheritDoc}
    */
    public RawYearMonthInterval readRawYearMonthInterval(int iProp)
            throws IOException
        {
        RawYearMonthInterval interval = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    interval = readRawYearMonthInterval(iProp);
                    registerIdentity(nId, interval);
                    }
                    break;

                case T_REFERENCE:
                    interval = (RawYearMonthInterval) lookupIdentity(in.readPackedInt());
                    break;

                case V_REFERENCE_NULL:
                    break;

                case T_YEAR_MONTH_INTERVAL:
                    {
                    int cYears  = in.readPackedInt();
                    int cMonths = in.readPackedInt();
                    interval = new RawYearMonthInterval(cYears, cMonths);
                    }
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to a RawYearMonthInterval type");
                }
            }
        complete(iProp);

        return interval;
        }

    /**
    * {@inheritDoc}
    */
    public RawTimeInterval readRawTimeInterval(int iProp)
            throws IOException
        {
        RawTimeInterval interval = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    interval = readRawTimeInterval(iProp);
                    registerIdentity(nId, interval);
                    }
                    break;

                case T_REFERENCE:
                    interval = (RawTimeInterval) lookupIdentity(in.readPackedInt());
                    break;

                case V_REFERENCE_NULL:
                    break;

                case T_TIME_INTERVAL:
                    int cHours   = in.readPackedInt();
                    int cMinutes = in.readPackedInt();
                    int cSeconds = in.readPackedInt();
                    int cNanos   = in.readPackedInt();
                    interval = new RawTimeInterval(cHours, cMinutes, cSeconds, cNanos);
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to a RawTimeInterval type");
                }
            }
        complete(iProp);

        return interval;
        }

    /**
    * {@inheritDoc}
    */
    public RawDayTimeInterval readRawDayTimeInterval(int iProp)
            throws IOException
        {
        RawDayTimeInterval interval = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    interval = readRawDayTimeInterval(iProp);
                    registerIdentity(nId, interval);
                    }
                    break;

                case T_REFERENCE:
                    interval = (RawDayTimeInterval) lookupIdentity(in.readPackedInt());
                    break;

                case V_REFERENCE_NULL:
                    break;

                case T_DAY_TIME_INTERVAL:
                    int cDays    = in.readPackedInt();
                    int cHours   = in.readPackedInt();
                    int cMinutes = in.readPackedInt();
                    int cSeconds = in.readPackedInt();
                    int cNanos   = in.readPackedInt();
                    interval = new RawDayTimeInterval(
                            cDays, cHours, cMinutes, cSeconds, cNanos);
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to a RawDayTimeInterval type");
                }
            }
        complete(iProp);

        return interval;
        }

    /**
    * {@inheritDoc}
    */
    public Object[] readObjectArray(int iProp, Object[] ao)
            throws IOException
        {
        Object[] aoResult = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    aoResult = readObjectArray(iProp, ao);
                    registerIdentity(nId, aoResult);
                    }
                    break;

                case T_REFERENCE:
                    {
                    Object o = lookupIdentity(in.readPackedInt());
                    if (o instanceof Collection)
                        {
                        aoResult = ((Collection) o).toArray(ao);
                        }
                    else if (o instanceof LongArray)
                        {
                        LongArray array     = (LongArray) o;
                        long      cElements = array.getLastIndex() + 1;

                        if (array.getFirstIndex() < 0L)
                            {
                            throw new ArrayIndexOutOfBoundsException(
                                    "index=" + array.getFirstIndex());
                            }
                        if (cElements > Integer.MAX_VALUE)
                            {
                            throw new ArrayIndexOutOfBoundsException(
                                    "index=" + array.getLastIndex());
                            }

                        aoResult = resizeArray(ao, (int) cElements);
                        for (LongArray.Iterator iter = array.iterator(); iter.hasNext(); )
                            {
                            Object oValue = iter.next();
                            aoResult[(int) iter.getIndex()] = oValue;
                            }
                        }
                    else
                        {
                        aoResult = (Object[]) o;
                        }
                    }
                    break;

                case V_REFERENCE_NULL:
                    break;

                case V_STRING_ZERO_LENGTH:
                case V_COLLECTION_EMPTY:
                    aoResult = OBJECT_ARRAY_EMPTY;
                    break;

                default:
                    aoResult = readAsObjectArray(nType, ao);
                    break;
                }
            }
        complete(iProp);

        return aoResult;
        }

    /**
    * {@inheritDoc}
    */
    public  T[] readArray(int iProp, IntFunction supplier)
            throws IOException
        {
        T[] aoResult = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    aoResult = readArray(iProp, supplier);
                    registerIdentity(nId, aoResult);
                    }
                    break;

                case T_REFERENCE:
                    {
                    Object o = lookupIdentity(in.readPackedInt());
                    if (o instanceof Collection)
                        {
                        Collection col = (Collection) o;
                        aoResult = col.toArray(supplier.apply(col.size()));
                        }
                    else if (o instanceof LongArray)
                        {
                        LongArray array     = (LongArray) o;
                        long      cElements = array.getLastIndex() + 1;

                        if (array.getFirstIndex() < 0L)
                            {
                            throw new ArrayIndexOutOfBoundsException(
                                    "index=" + array.getFirstIndex());
                            }
                        if (cElements > Integer.MAX_VALUE)
                            {
                            throw new ArrayIndexOutOfBoundsException(
                                    "index=" + array.getLastIndex());
                            }

                        aoResult = supplier.apply((int) cElements);
                        for (LongArray.Iterator iter = array.iterator(); iter.hasNext(); )
                            {
                            T value = (T) iter.next();
                            aoResult[(int) iter.getIndex()] = value;
                            }
                        }
                    else
                        {
                        aoResult = (T[]) o;
                        }
                    }
                    break;

                case V_REFERENCE_NULL:
                    break;

                case V_STRING_ZERO_LENGTH:
                case V_COLLECTION_EMPTY:
                    aoResult = (T[]) OBJECT_ARRAY_EMPTY;
                    break;

                default:
                    aoResult = readAsTypedObjectArray(nType, supplier);
                    break;
                }
            }
        complete(iProp);

        return aoResult;
        }

    /**
    * {@inheritDoc}
    */
    public LongArray readLongArray(int iProp, LongArray array)
            throws IOException
        {
        // do not default to null, since the caller is passing in a mutable
        // LongArray

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    array = readLongArray(iProp, array);
                    registerIdentity(nId, array);
                    }
                    break;

                case T_REFERENCE:
                    {
                    Object o = lookupIdentity(in.readPackedInt());
                    if (o instanceof Collection)
                        {
                        if (array == null)
                            {
                            array = new SparseArray();
                            }
                        int i = 0;
                        for (Iterator iter = ((Collection) o).iterator(); iter.hasNext(); )
                            {
                            array.set(++i, iter.next());
                            }
                        }
                    else
                        {
                        array = (LongArray) o;
                        }
                    }
                    break;

                case V_REFERENCE_NULL:
                case V_STRING_ZERO_LENGTH:
                case V_COLLECTION_EMPTY:
                    break;

                case T_COLLECTION:
                case T_ARRAY:
                    {
                    if (array == null)
                        {
                        array = new SparseArray();
                        }

                    int co = in.readPackedInt();
                    for (int i = 0; i < co; ++i)
                        {
                        array.set(i, readAsObject(in.readPackedInt()));
                        }
                    }
                    break;

                case T_UNIFORM_COLLECTION:
                case T_UNIFORM_ARRAY:
                    {
                    if (array == null)
                        {
                        array = new SparseArray();
                        }

                    int nElementType = in.readPackedInt();
                    int co           = in.readPackedInt();
                    for (int i = 0; i < co; ++i)
                        {
                        array.set(i, readAsUniformObject(nElementType));
                        }
                    }
                    break;

                case T_SPARSE_ARRAY:
                    {
                    if (array == null)
                        {
                        array = new SparseArray();
                        }

                    int co = in.readPackedInt();
                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        array.set(iElement, readAsObject(in.readPackedInt()));
                        }
                    while (--co >= 0);
                    }
                    break;

                case T_UNIFORM_SPARSE_ARRAY:
                    {
                    if (array == null)
                        {
                        array = new SparseArray();
                        }

                    int nElementType = in.readPackedInt();
                    int co           = in.readPackedInt();
                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        array.set(iElement, readAsUniformObject(nElementType));
                        }
                    while (--co >= 0);
                    }
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to an array type");
                }
            }
        complete(iProp);

        return array;
        }

    /**
    * {@inheritDoc}
    */
    public > C readCollection(int iProp, C coll)
            throws IOException
        {
        // do not default to null, since the caller is passing in a mutable
        // Collection

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    coll = readCollection(iProp, coll);
                    registerIdentity(nId, coll);
                    }
                    break;

                case T_REFERENCE:
                    {
                    Object o = lookupIdentity(in.readPackedInt());
                    if (o instanceof Object[])
                        {
                        Collection collData =
                            new ImmutableArrayList((Object[]) o).getList();
                        if (coll == null)
                            {
                            coll = (C) collData;
                            }
                        else
                            {
                            coll.addAll(collData);
                            }
                        }
                    else
                        {
                        coll = (C) o;
                        }
                    }
                    break;

                case V_REFERENCE_NULL:
                case V_STRING_ZERO_LENGTH:
                case V_COLLECTION_EMPTY:
                    break;

                case T_COLLECTION:
                case T_ARRAY:
                    {
                    if (coll == null)
                        {
                        Object[] ao = readAsObjectArray(nType, null);
                        coll = (C) new ImmutableArrayList(ao).getList();
                        }
                    else
                        {
                        int co = in.readPackedInt();
                        for (int i = 0; i < co; ++i)
                            {
                            coll.add((T) readAsObject(in.readPackedInt()));
                            }
                        }
                    }
                    break;

                case T_UNIFORM_COLLECTION:
                case T_UNIFORM_ARRAY:
                    {
                    if (coll == null)
                        {
                        Object[] ao = readAsObjectArray(nType, null);
                        coll = (C) new ImmutableArrayList(ao).getList();
                        }
                    else
                        {
                        int nElementType = in.readPackedInt();
                        int co           = in.readPackedInt();
                        for (int i = 0; i < co; ++i)
                            {
                            coll.add((T) readAsUniformObject(nElementType));
                            }
                        }
                    }
                    break;

                case T_SPARSE_ARRAY:
                    {
                    int co = in.readPackedInt();
                    if (coll == null)
                        {
                        coll = (C) new ArrayList<>(co);
                        }

                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        coll.add((T) readAsObject(in.readPackedInt()));
                        }
                    while (--co >= 0);
                    }
                    break;

                case T_UNIFORM_SPARSE_ARRAY:
                    {
                    int nElementType = in.readPackedInt();
                    int co           = in.readPackedInt();
                    if (coll == null)
                        {
                        coll = (C) new ArrayList<>(co);
                        }

                    do
                        {
                        int iElement = in.readPackedInt();
                        if (iElement < 0)
                            {
                            break;
                            }
                        coll.add((T) readAsUniformObject(nElementType));
                        }
                    while (--co >= 0);
                    }
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to a Collection type");
                }
            }
        complete(iProp);

        return coll;
        }

    /**
    * {@inheritDoc}
    */
    public > M readMap(int iProp, M map)
            throws IOException
        {
        // do not default to null, since the caller is passing in a mutable
        // Map

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    map = readMap(iProp, map);
                    registerIdentity(nId, map);
                    }
                    break;

                case T_REFERENCE:
                    map = (M) lookupIdentity(in.readPackedInt());
                    break;

                case V_REFERENCE_NULL:
                case V_STRING_ZERO_LENGTH:
                case V_COLLECTION_EMPTY:
                    break;

                case T_MAP:
                    {
                    int cEntries = in.readPackedInt();
                    if (map == null)
                        {
                        map = (M) new HashMap(cEntries);
                        }

                    for (int i = 0; i < cEntries; ++i)
                        {
                        K key = (K) readAsObject(in.readPackedInt());
                        V val = (V) readAsObject(in.readPackedInt());
                        map.put(key, val);
                        }
                    }
                    break;

                case T_UNIFORM_KEYS_MAP:
                    {
                    int nKeyType = in.readPackedInt();
                    int cEntries = in.readPackedInt();
                    if (map == null)
                        {
                        map = (M) new HashMap(cEntries);
                        }

                    for (int i = 0; i < cEntries; ++i)
                        {
                        K key = (K) readAsUniformObject(nKeyType);
                        V val = (V) readAsObject(in.readPackedInt());
                        map.put(key, val);
                        }
                    }
                    break;

                case T_UNIFORM_MAP:
                    {
                    int nKeyType = in.readPackedInt();
                    int nValType = in.readPackedInt();
                    int cEntries = in.readPackedInt();
                    if (map == null)
                        {
                        map = (M) new HashMap(cEntries);
                        }

                    for (int i = 0; i < cEntries; ++i)
                        {
                        K key = (K) readAsUniformObject(nKeyType);
                        V val = (V) readAsUniformObject(nValType);
                        map.put(key, val);
                        }
                    }
                    break;

                default:
                    throw new IOException("unable to convert type " + nType
                                          + " to a Map type");
                }
            }
        complete(iProp);

        return map;
        }

    /**
    * {@inheritDoc}
    */
    public PofContext getPofContext()
        {
        return m_ctx;
        }

    /**
    * {@inheritDoc}
    */
    public void setPofContext(PofContext ctx)
        {
        if (ctx == null)
            {
            throw new IllegalArgumentException("PofContext cannot be null");
            }
        m_ctx = ctx;
        }

    /**
    * {@inheritDoc}
    */
    public  T readObject(int iProp)
            throws IOException
        {
        T o = null;

        if (advanceTo(iProp))
            {
            ReadBuffer.BufferInput in = m_in;
            int nType = in.readPackedInt();
            switch (nType)
                {
                case T_IDENTITY:
                    {
                    int nId = in.readPackedInt();
                    IdentityHolder.set(this, nId);
                    o = readObject(iProp);
                    IdentityHolder.reset(this, nId, o);
                    }
                    break;

                case T_REFERENCE:
                    o = (T) lookupIdentity(in.readPackedInt());
                    break;

                case V_REFERENCE_NULL:
                    break;

                default:
                    o = (T) readAsObject(nType);
                    break;
                }
            }
        complete(iProp);

        return o;
        }

    /**
    * {@inheritDoc}
    */
    public int getUserTypeId()
        {
        return -1;
        }

    /**
    * {@inheritDoc}
    */
    public int getVersionId()
        {
        throw new IllegalStateException("not in a user type");
        }

    /**
    * {@inheritDoc}
    */
    public void registerIdentity(Object o)
        {
        throw new IllegalStateException("not in a user type");
        }

    /**
    * {@inheritDoc}
    */
    public PofReader createNestedPofReader(int iProp)
            throws IOException
        {
        throw new IllegalStateException("not in a user type");
        }

    /**
    * {@inheritDoc}
    */
    public Binary readRemainder()
            throws IOException
        {
        throw new IllegalStateException("not in a user type");
        }


    // ----- internal methods -----------------------------------------------

    /**
    * Advance through the POF stream until the specified property is found.
    * If the property is found, return true, otherwise return false and
    * advance to the first property that follows the specified property.
    *
    * @param iProp  the index of the property to advance to
    *
    * @return true if the property is found
    *
    * @throws IllegalStateException if the POF stream has already advanced
    *         past the desired property
    * @throws IOException  if an I/O error occurs
    */
    protected boolean advanceTo(int iProp)
            throws IOException
        {
        if (iProp > 0)
            {
            throw new IllegalStateException();
            }

        return true;
        }

    /**
    * Register the completion of the parsing of a value.
    *
    * @param iProp  the property index
    *
    * @throws IOException  if an I/O error occurs
    */
    protected void complete(int iProp)
            throws IOException
        {
        }

    /**
    * If this parser is contextually within a user type, obtain the parser
    * which created this parser in order to parse the user type.
    *
    * @return the parser for the context within which this parser is
    *         operating
    */
    protected PofBufferReader getParentParser()
        {
        return null;
        }

    /**
    * Obtain the registry for identity-reference pairs, creating it if
    * necessary.
    *
    * @return the identity-reference registry, never null
    */
    protected LongArray ensureReferenceRegistry()
        {
        LongArray array = m_arrayRefs;

        if (array == null)
            {
            PofBufferReader parent = getParentParser();
            m_arrayRefs = array = parent == null
                    ? new SparseArray()
                    : parent.ensureReferenceRegistry();
            }

        return array;
        }

    /**
    * Register the passed value with the passed identity.
    *
    * @param nId     the identity within the POF stream of the object
    * @param oValue  the object to associate with the passed identity
    *
    * @throws IllegalArgumentException  if the specified identity is already
    *                                   registered with a different object
    */
    protected void registerIdentity(int nId, Object oValue)
        {
        if (nId >= 0)
            {
            LongArray array = ensureReferenceRegistry();
            Object    o     = array.get(nId);
            if (o != null && o != oValue)
                {
                throw new IllegalArgumentException("duplicate identity: " + nId);
                }

            array.set(nId, oValue);
            }
        }

    /**
    * Look up the specified identity and return the object to which it
    * refers.
    *
    * @param nId  the identity
    *
    * @return the object registered under that identity
    *
    * @throws IOException  if the requested identity is not registered
    */
    protected Object lookupIdentity(int nId)
            throws IOException
        {
        LongArray array = ensureReferenceRegistry();
        if (!array.exists(nId))
            {
            throw new IOException("missing identity: " + nId);
            }

        return array.get(nId);
        }

    /**
    * Read a POF value as an Object.
    *
    * @param nType  the type identifier of the value
    *
    * @return an Object value
    *
    * @throws IOException  if an I/O error occurs
    */
    protected Object readAsObject(int nType)
            throws IOException
        {
        Object o = null;

        ReadBuffer.BufferInput in = m_in;
        switch (nType)
            {
            case T_INT16:
                o = Short.valueOf((short) in.readPackedInt());
                break;

            case T_INT32:
            case V_INT_NEG_1:
            case V_INT_0:
            case V_INT_1:
            case V_INT_2:
            case V_INT_3:
            case V_INT_4:
            case V_INT_5:
            case V_INT_6:
            case V_INT_7:
            case V_INT_8:
            case V_INT_9:
            case V_INT_10:
            case V_INT_11:
            case V_INT_12:
            case V_INT_13:
            case V_INT_14:
            case V_INT_15:
            case V_INT_16:
            case V_INT_17:
            case V_INT_18:
            case V_INT_19:
            case V_INT_20:
            case V_INT_21:
            case V_INT_22:
                o = Integer.valueOf(readAsInt(in, nType));
                break;

            case T_INT64:
                o = Long.valueOf(in.readPackedLong());
                break;

            case T_INT128:
                o = readBigInteger(in);
                break;

            case T_FLOAT32:
                o = Float.valueOf(in.readFloat());
                break;

            case T_FLOAT64:
                o = Double.valueOf(in.readDouble());
                break;

            case T_FLOAT128:
                o = readQuad(in);
                break;

            case V_FP_POS_INFINITY:
                o = Double.POSITIVE_INFINITY;
                break;

            case V_FP_NEG_INFINITY:
                o = Double.NEGATIVE_INFINITY;
                break;

            case V_FP_NAN:
                o = Double.NaN;
                break;

            case T_DECIMAL32:
                o = readBigDecimal(in, 4);
                break;

            case T_DECIMAL64:
                o = readBigDecimal(in, 8);
                break;

            case T_DECIMAL128:
                o = readBigDecimal(in, 16);
                break;

            case T_BOOLEAN:
                o = in.readPackedInt() == 0 ? Boolean.FALSE : Boolean.TRUE;
                break;

            case T_OCTET:
                o = Byte.valueOf(in.readByte());
                break;

            case T_OCTET_STRING:
                o = readBinary(in);
                break;

            case T_CHAR:
                o = Character.valueOf(readChar(in));
                break;

            case T_CHAR_STRING:
                o = in.readSafeUTF();
                break;

            case T_DATE:
                {
                RawDate rawDate = readRawDate(in);
                o = getPofContext().isPreferJavaTime()
                    ? rawDate.toLocalDate()
                    : rawDate.toSqlDate();
                }
                break;

            case T_TIME:
                {
                RawTime rawTime = readRawTime(in);
                o = getPofContext().isPreferJavaTime()
                    ? rawTime.hasTimezone() ? rawTime.toOffsetTime() : rawTime.toLocalTime()
                    : rawTime.toSqlTime();
                }
                break;

            case T_DATETIME:
                {
                RawDateTime rawDateTime = new RawDateTime(readRawDate(in), readRawTime(in));
                o = getPofContext().isPreferJavaTime()
                    ? rawDateTime.getRawTime().hasTimezone()
                      ? rawDateTime.toOffsetDateTime() : rawDateTime.toLocalDateTime()
                    : rawDateTime.toSqlTimestamp();
                }
                break;

            case T_YEAR_MONTH_INTERVAL:
                {
                int cYears  = in.readPackedInt();
                int dMonths = in.readPackedInt();
                o = new RawYearMonthInterval(cYears, dMonths);
                }
                break;

            case T_TIME_INTERVAL:
                {
                int cHours   = in.readPackedInt();
                int cMinutes = in.readPackedInt();
                int cSeconds = in.readPackedInt();
                int cNanos   = in.readPackedInt();
                o = new RawTimeInterval(cHours, cMinutes, cSeconds, cNanos);
                }
                break;

            case T_DAY_TIME_INTERVAL:
                {
                int cDays    = in.readPackedInt();
                int cHours   = in.readPackedInt();
                int cMinutes = in.readPackedInt();
                int cSeconds = in.readPackedInt();
                int cNanos   = in.readPackedInt();
                o = new RawDayTimeInterval(cDays, cHours, cMinutes, cSeconds, cNanos);
                }
                break;

            case T_COLLECTION:
            case T_UNIFORM_COLLECTION:
                o = new ImmutableArrayList(readAsObjectArray(nType, null)).getList();
                break;

            case T_ARRAY:
                o = readAsObjectArray(nType, null);
                break;

            case T_UNIFORM_ARRAY:
                {
                int nElementType = in.readPackedInt();
                int cElements    = in.readPackedInt();
                switch (nElementType)
                    {
                    case T_BOOLEAN:
                        {
                        boolean[] af = new boolean[cElements];
                        for (int i = 0; i < cElements; ++i)
                            {
                            af[i] = in.readPackedInt() != 0;
                            }
                        o = af;
                        }
                        break;

                    case T_OCTET:
                        {
                        byte[] ab = new byte[cElements];
                        in.readFully(ab);
                        o = ab;
                        }
                        break;

                    case T_CHAR:
                        {
                        char[] ach = new char[cElements];
                        for (int i = 0; i < cElements; ++i)
                            {
                            ach[i] = readChar(in);
                            }
                        o = ach;
                        }
                        break;

                    case T_INT16:
                        {
                        short[] an = new short[cElements];
                        for (int i = 0; i < cElements; ++i)
                            {
                            an[i] = (short) in.readPackedInt();
                            }
                        o = an;
                        }
                        break;

                    case T_INT32:
                        {
                        int[] an = new int[cElements];
                        for (int i = 0; i < cElements; ++i)
                            {
                            an[i] = in.readPackedInt();
                            }
                        o = an;
                        }
                        break;

                    case T_INT64:
                        {
                        long[] an = new long[cElements];
                        for (int i = 0; i < cElements; ++i)
                            {
                            an[i] = in.readPackedLong();
                            }
                        o = an;
                        }
                        break;

                    case T_FLOAT32:
                        {
                        float[] afl = new float[cElements];
                        for (int i = 0; i < cElements; ++i)
                            {
                            afl[i] = in.readFloat();
                            }
                        o = afl;
                        }
                        break;

                    case T_FLOAT64:
                        {
                        double[] adfl = new double[cElements];
                        for (int i = 0; i < cElements; ++i)
                            {
                            adfl[i] = in.readDouble();
                            }
                        o = adfl;
                        }
                        break;

                    default:
                        {
                        Object[] ao = new Object[cElements];
                        for (int i = 0; i < cElements; ++i)
                            {
                            ao[i] = readAsUniformObject(nElementType);
                            }
                        o = ao;
                        }
                    }
                }
                break;

            case T_SPARSE_ARRAY:
                {
                LongArray array     = new SparseArray();
                int       cElements = in.readPackedInt();
                do
                    {
                    int iElement = in.readPackedInt();
                    if (iElement < 0)
                        {
                        break;
                        }
                    array.set(iElement, readAsObject(in.readPackedInt()));
                    }
                while (--cElements >= 0);
                o = array;
                }
                break;

            case T_UNIFORM_SPARSE_ARRAY:
                {
                int nElementType = in.readPackedInt();
                int cElements    = in.readPackedInt();
                switch (nElementType)
                    {
                    case T_BOOLEAN:
                        {
                        boolean[] af = new boolean[cElements];
                        do
                            {
                            int iElement = in.readPackedInt();
                            if (iElement < 0)
                                {
                                break;
                                }
                            af[iElement] = in.readPackedInt() != 0;
                            }
                        while (--cElements >= 0);
                        o = af;
                        }
                        break;

                    case T_OCTET:
                        {
                        byte[] ab = new byte[cElements];
                        do
                            {
                            int iElement = in.readPackedInt();
                            if (iElement < 0)
                                {
                                break;
                                }
                            ab[iElement] = in.readByte();
                            }
                        while (--cElements >= 0);
                        o = ab;
                        }
                        break;

                    case T_CHAR:
                        {
                        char[] ach = new char[cElements];
                        do
                            {
                            int iElement = in.readPackedInt();
                            if (iElement < 0)
                                {
                                break;
                                }
                            ach[iElement] = readChar(in);
                            }
                        while (--cElements >= 0);
                        o = ach;
                        }
                        break;

                    case T_INT16:
                        {
                        short[] an = new short[cElements];
                        do
                            {
                            int iElement = in.readPackedInt();
                            if (iElement < 0)
                                {
                                break;
                                }
                            an[iElement] = (short) in.readPackedInt();
                            }
                        while (--cElements >= 0);
                        o = an;
                        }
                        break;

                    case T_INT32:
                        {
                        int[] an = new int[cElements];
                        do
                            {
                            int iElement = in.readPackedInt();
                            if (iElement < 0)
                                {
                                break;
                                }
                            an[iElement] = in.readPackedInt();
                            }
                        while (--cElements >= 0);
                        o = an;
                        }
                        break;

                    case T_INT64:
                        {
                        long[] an = new long[cElements];
                        do
                            {
                            int iElement = in.readPackedInt();
                            if (iElement < 0)
                                {
                                break;
                                }
                            an[iElement] = in.readPackedLong();
                            }
                        while (--cElements >= 0);
                        o = an;
                        }
                        break;

                    case T_FLOAT32:
                        {
                        float[] afl = new float[cElements];
                        do
                            {
                            int iElement = in.readPackedInt();
                            if (iElement < 0)
                                {
                                break;
                                }
                            afl[iElement] = in.readFloat();
                            }
                        while (--cElements >= 0);
                        o = afl;
                        }
                        break;

                    case T_FLOAT64:
                        {
                        double[] adfl = new double[cElements];
                        do
                            {
                            int iElement = in.readPackedInt();
                            if (iElement < 0)
                                {
                                break;
                                }
                            adfl[iElement] = in.readDouble();
                            }
                        while (--cElements >= 0);
                        o = adfl;
                        }
                        break;

                    default:
                        {
                        LongArray array = new SparseArray();
                        do
                            {
                            int iElement = in.readPackedInt();
                            if (iElement < 0)
                                {
                                break;
                                }
                            array.set(iElement, readAsUniformObject(nElementType));
                            }
                        while (--cElements >= 0);
                        o = array;
                        }
                    }
                }
                break;

            case T_MAP:
                {
                Map map      = new HashMap();
                int cEntries = in.readPackedInt();
                for (int i = 0; i < cEntries; ++i)
                    {
                    Object oKey = readAsObject(in.readPackedInt());
                    Object oVal = readAsObject(in.readPackedInt());
                    map.put(oKey, oVal);
                    }
                o = map;
                }
                break;

            case T_UNIFORM_KEYS_MAP:
                {
                Map map      = new HashMap();
                int nKeyType = in.readPackedInt();
                int cEntries = in.readPackedInt();
                for (int i = 0; i < cEntries; ++i)
                    {
                    Object oKey = readAsUniformObject(nKeyType);
                    Object oVal = readAsObject(in.readPackedInt());
                    map.put(oKey, oVal);
                    }
                o = map;
                }
                break;

            case T_UNIFORM_MAP:
                {
                Map map      = new HashMap();
                int nKeyType = in.readPackedInt();
                int nValType = in.readPackedInt();
                int cEntries = in.readPackedInt();
                for (int i = 0; i < cEntries; ++i)
                    {
                    Object oKey = readAsUniformObject(nKeyType);
                    Object oVal = readAsUniformObject(nValType);
                    map.put(oKey, oVal);
                    }
                o = map;
                }
                break;

            case T_IDENTITY:
                {
                int nId = in.readPackedInt();
                nType = in.readPackedInt();
                IdentityHolder.set(this, nId);
                o = readAsObject(nType);
                IdentityHolder.reset(this, nId, o);
                }
                break;

            case T_REFERENCE:
                o = lookupIdentity(in.readPackedInt());
                break;

            case V_BOOLEAN_FALSE:
                o = Boolean.FALSE;
                break;

            case V_BOOLEAN_TRUE:
                o = Boolean.TRUE;
                break;

            case V_STRING_ZERO_LENGTH:
                o = "";
                break;

            case V_COLLECTION_EMPTY:
                o = COLLECTION_EMPTY;
                break;

            case V_REFERENCE_NULL:
                break;

            default:
                {
                if (nType < 0)
                    {
                    throw new StreamCorruptedException("illegal type " + nType);
                    }

                PofContext    ctx = getPofContext();
                PofSerializer ser;
                try
                    {
                    ser = ctx.getPofSerializer(nType);
                    }
                catch (IllegalArgumentException e)
                    {
                    throw new StreamCorruptedException(e.getMessage());
                    }
                PofReader reader = new PofBufferReader.UserTypeReader(
                        this, in, ctx, nType, in.readPackedInt());

                o = ExternalizableHelper.realize(ser.deserialize(reader), m_ctx);
                }
                break;
            }

        return o;
        }

    /**
    * Read a POF value in a uniform array/map as an Object.
    *
    * @param nType  the type identifier of the value
    *
    * @return an Object value
    *
    * @throws IOException  if an I/O error occurs
    */
    protected Object readAsUniformObject(int nType)
            throws IOException
        {
        if (nType < 0)
            {
            return readAsObject(nType);
            }

        ReadBuffer.BufferInput in  = m_in;
        int                    of  = in.getOffset();
        int                    nId = -1;
        if (of == 0)
            {
            return readAsObject(nType);
            }

        int nValue = in.readPackedInt();
        if (nValue == T_IDENTITY)
            {
            nId = in.readPackedInt();
            IdentityHolder.set(this, nId);
            }
        else
            {
            // it can only be reference if its data type supports reference
            // (a user defined object)
            if (nValue > 0 && nType >= 0)
                {
                Object o = ensureReferenceRegistry().get(nValue);
                if (o != null)
                    {
                    // double check the object type
                    int nTypeId = PofHelper.getPofTypeId(o.getClass(), getPofContext());
                    if (nTypeId == nType)
                        {
                        return o;
                        }
                    }
                }
            in.setOffset(of);
            }

        Object o = readAsObject(nType);
        if (nValue == T_IDENTITY)
            {
            IdentityHolder.reset(this, nId, o);
            }
        return o;
        }

    /**
    * Read a POF value as an Object array.
    *
    * @param nType  the type identifier of the value
    * @param ao     the optional array to use to store the values, or to use
    *               as a typed template for creating an array to store the
    *               values, following the documentation for
    *               {@link java.util.Collection#toArray(Object[]) Collection.toArray()}
    *
    * @return an Object array
    *
    * @throws IOException  if an I/O error occurs
    */
    protected Object[] readAsObjectArray(int nType, Object[] ao)
            throws IOException
        {
        Object[] aoResult = null;

        ReadBuffer.BufferInput in = m_in;
        switch (nType)
            {
            case V_REFERENCE_NULL:
                break;

            case V_STRING_ZERO_LENGTH:
            case V_COLLECTION_EMPTY:
                aoResult = OBJECT_ARRAY_EMPTY;
                break;

            case T_COLLECTION:
            case T_ARRAY:
                {
                int co = in.readPackedInt();
                aoResult = resizeArray(ao, co);
                for (int i = 0; i < co; ++i)
                    {
                    aoResult[i] = readAsObject(in.readPackedInt());
                    }
                }
                break;

            case T_UNIFORM_COLLECTION:
            case T_UNIFORM_ARRAY:
                {
                int nElementType = in.readPackedInt();
                int co           = in.readPackedInt();
                aoResult = resizeArray(ao, co);
                for (int i = 0; i < co; ++i)
                    {
                    aoResult[i] = readAsUniformObject(nElementType);
                    }
                }
                break;

            case T_SPARSE_ARRAY:
                {
                int co = in.readPackedInt();
                aoResult = resizeArray(ao, co);
                do
                    {
                    int iElement = in.readPackedInt();
                    if (iElement < 0)
                        {
                        break;
                        }
                    aoResult[iElement] = readAsObject(in.readPackedInt());
                    }
                while (--co >= 0);
                }
                break;

            case T_UNIFORM_SPARSE_ARRAY:
                {
                int nElementType = in.readPackedInt();
                int co           = in.readPackedInt();
                aoResult = resizeArray(ao, co);
                do
                    {
                    int iElement = in.readPackedInt();
                    if (iElement < 0)
                        {
                        break;
                        }
                    aoResult[iElement] = readAsUniformObject(nElementType);
                    }
                while (--co >= 0);
                }
                break;

            default:
                throw new IOException("unable to convert type " + nType
                                      + " to an array type");
            }

        return aoResult;
        }

    /**
    * Read a POF value as an Object array.
    *
    * @param       the identifier type
    * @param nType    the type identifier of the value
    * @param factory  the optional factory to use to initialize the array
    *
    * @return an Object array
    *
    * @throws IOException  if an I/O error occurs
    */
    protected  T[] readAsTypedObjectArray(int nType, IntFunction factory)
            throws IOException
        {
        T[] aoResult = null;

        ReadBuffer.BufferInput in = m_in;
        switch (nType)
            {
            case V_REFERENCE_NULL:
                break;

            case V_STRING_ZERO_LENGTH:
            case V_COLLECTION_EMPTY:
                aoResult = (T[]) OBJECT_ARRAY_EMPTY;
                break;

            case T_COLLECTION:
            case T_ARRAY:
                {
                int co = in.readPackedInt();
                aoResult = factory.apply(co);
                for (int i = 0; i < co; ++i)
                    {
                    aoResult[i] = (T) readAsObject(in.readPackedInt());
                    }
                }
                break;

            case T_UNIFORM_COLLECTION:
            case T_UNIFORM_ARRAY:
                {
                int nElementType = in.readPackedInt();
                int co           = in.readPackedInt();
                aoResult = factory.apply(co);
                for (int i = 0; i < co; ++i)
                    {
                    aoResult[i] = (T) readAsUniformObject(nElementType);
                    }
                }
                break;

            case T_SPARSE_ARRAY:
                {
                int co = in.readPackedInt();
                aoResult = factory.apply(co);
                do
                    {
                    int iElement = in.readPackedInt();
                    if (iElement < 0)
                        {
                        break;
                        }
                    aoResult[iElement] = (T) readAsObject(in.readPackedInt());
                    }
                while (--co >= 0);
                }
                break;

            case T_UNIFORM_SPARSE_ARRAY:
                {
                int nElementType = in.readPackedInt();
                int co           = in.readPackedInt();
                aoResult = factory.apply(co);
                do
                    {
                    int iElement = in.readPackedInt();
                    if (iElement < 0)
                        {
                        break;
                        }
                    aoResult[iElement] = (T) readAsUniformObject(nElementType);
                    }
                while (--co >= 0);
                }
                break;

            default:
                throw new IOException("unable to convert type " + nType
                                      + " to an array type");
            }

        return aoResult;
        }

    /**
    * Read a Binary object from the specified BufferInput in an optimal way,
    * depending on the existence of an enclosing ReadBuffer.
    *
    * @param in  a BufferInput to read from
    *
    * @return a Binary object
    *
    * @throws IOException  if an I/O error occurs
    */
    protected static Binary readBinary(ReadBuffer.BufferInput in)
            throws IOException
        {
        int cb = in.readPackedInt();

        ReadBuffer buf = in.getBuffer();
        if (buf == null)
            {
            return in.readBuffer(cb).toBinary();
            }
        else
            {
            int    of  = in.getOffset();
            Binary bin = buf.toBinary(of, cb);
            in.skipBytes(cb); // skip after read to prevent pre-destruction
            return bin;
            }
        }


    // ----- inner class: UserTypeReader ------------------------------------

    /**
    * The UserTypeReader implementation is a contextually-aware PofReader
    * whose purpose is to advance through the properties of a value of a
    * specified user type. The "contextual awareness" refers to the fact that
    * the UserTypeReader maintains state about the type identifier and
    * version of the user type, the parser's property index position within
    * the user type value, and a PofContext that may differ from the
    * PofContext that provided the PofSerializer which is using this
    * UserTypeReader to parse a user type.
    */
    public static class UserTypeReader
            extends PofBufferReader
        {
        // ----- constructors -------------------------------------------

        /**
        * Construct a parser for parsing the property values of a user type.
        *
        * @param in          the BufferInput that contains the user type
        *                    data, except for the user type id itself (which
        *                    is passed passed as a constructor argument)
        * @param ctx         the PofContext to use for parsing the user type
        *                    property values within the user type that this
        *                    parser will be parsing
        * @param nTypeId     the type id of the user type
        * @param nVersionId  the version id of the user type
        *
        * @throws IOException  if an I/O error occurs
        */
        public UserTypeReader(
                ReadBuffer.BufferInput in, PofContext ctx,
                int nTypeId, int nVersionId)
                throws IOException
            {
            this(null, in, ctx, nTypeId, nVersionId);
            }

        /**
        * Construct a parser for parsing the property values of a user type.
        *
        * @param parent      the parent (ie the containing) PofBufferReader
        * @param in          the BufferInput that contains the user type
        *                    data, except for the user type id itself (which
        *                    is passed passed as a constructor argument)
        * @param ctx         the PofContext to use for parsing the user type
        *                    property values within the user type that this
        *                    parser will be parsing
        * @param nTypeId     the type id of the user type
        * @param nVersionId  the version id of the user type
        *
        * @throws IOException  if an I/O error occurs
        */
        public UserTypeReader(PofBufferReader parent,
                ReadBuffer.BufferInput in, PofContext ctx,
                int nTypeId, int nVersionId)
                throws IOException
            {
            super(in, ctx);

            assert nTypeId >= 0;
            assert nVersionId >= 0;

            m_parent     = parent;
            m_nTypeId    = nTypeId;
            m_nVersionId = nVersionId;

            // prime the property reader by knowing the offset of index of
            // the next property to read
            m_ofNextProp = in.getOffset();
            int iProp    = in.readPackedInt();
            m_iNextProp  = iProp < 0 ? EOPS : iProp;
            }

        /**
        * Create a nested UserTypeReader, which will be initiated with the
        * information found in the nested buffer.
        *
        * @param parent  the parent (ie the containing) PofBufferReader
        * @param in      the BufferInput that contains the user type data
        * @param ctx     the PofContext to use for parsing the user type property
        *                values within the user type that this parser will be
        *                parsing
        *
        * @throws IOException  if an I/O error occurs
        */
        private UserTypeReader(PofBufferReader parent,
                ReadBuffer.BufferInput in, PofContext ctx) throws IOException
            {
            super(in, ctx);

            m_parent     = parent;


            // read the type and version directly from the buffer
            m_nTypeId    = in.readPackedInt();
            m_nVersionId = in.readPackedInt();

            // prime the property reader by knowing the offset of index of
            // the next property to read
            m_ofNextProp = in.getOffset();

            int iProp    = in.readPackedInt();
            m_iNextProp  = iProp < 0 ? EOPS : iProp;
            }

        /**
        * Construct a parser for parsing a nested property that does not exist.
        * In other words, this is a "no-op" user type reader.
        *
        * @param parent      the parent (ie the containing) PofBufferReader
        * @param in          the BufferInput that contains the user type
        *                    data, except for the user type id itself (which
        *                    is passed passed as a constructor argument)
        * @param ctx         the PofContext to use for parsing the user type
        *                    property values within the user type that this
        *                    parser will be parsing
        * @param nTypeId     the type id of the user type
        *
        * @throws IOException  if an I/O error occurs
        */
        private UserTypeReader(PofBufferReader parent, ReadBuffer.BufferInput in,
                              PofContext ctx, int nTypeId)
                throws IOException
            {
            super(in, ctx);

            assert nTypeId >= 0;

            m_parent     = parent;
            m_nTypeId    = nTypeId;
            m_nVersionId = 0;

            // prime the property reader by knowing the offset of index of
            // the next property to read
            m_ofNextProp = in.getOffset();
            m_iNextProp  = EOPS;
            }

        // ----- PofReader interface ------------------------------------

        /**
        * {@inheritDoc}
        */
        @Override public int getUserTypeId()
            {
            return m_nTypeId;
            }

        /**
        * {@inheritDoc}
        */
        @Override public int getVersionId()
            {
            return m_nVersionId;
            }

        /**
        * {@inheritDoc}
        */
        @Override public void registerIdentity(Object o)
            {
            PofBufferReader.IdentityHolder.reset(this, -1, o);
            }

        /**
        * {@inheritDoc}
        */
        @Override public PofReader createNestedPofReader(int iProp)
                throws IOException
            {
            UserTypeReader reader;
            if (advanceTo(iProp))
                {
                reader = new PofBufferReader.UserTypeReader(this, m_in,
                        getPofContext());

                // note: there is no complete() call at this point, since the
                //       property has yet to be read
                }
            else
                {
                // nothing to read for that property
                complete(iProp);

                // return a "fake" reader that contains no data
                reader = new PofBufferReader.UserTypeReader(this, m_in,
                        getPofContext(), getUserTypeId());
                }

            m_readerNested = reader;
            m_iNestedProp  = iProp;

            return reader;
            }

        /**
        * {@inheritDoc}
        */
        @Override public Binary readRemainder()
                throws IOException
            {
            // close nested buffer if it exists
            closeNested();

            // check if the property stream is already exhausted
            int iNextProp = m_iNextProp;
            if (iNextProp == EOPS)
                {
                return null;
                }

            // skip over all the remaining properties
            ReadBuffer.BufferInput in = m_in;
            ReadBuffer buf = in.getBuffer();
            if (buf == null)
                {
                // if the BufferInput does not have an underlying ReadBuffer,
                // we must use mark() and reset() to read the remaining
                // properties; in this case, assume we need to reread as much
                // data as theoretically possible
                in.mark(Integer.MAX_VALUE);
                }
            int ofBegin = m_ofNextProp;
            int ofEnd;
            do
                {
                skipValue(in);
                ofEnd     = in.getOffset();
                iNextProp = in.readPackedInt();
                }
            while (iNextProp != -1);

            m_iNextProp  = EOPS;
            m_ofNextProp = ofEnd;

            // return all the properties that were skipped
            int cb = ofEnd - ofBegin;
            if (buf == null)
                {
                in.reset();
                return in.readBuffer(cb).toBinary();
                }
            else
                {
                return buf.toBinary(ofBegin, cb);
                }
            }

        // ----- internal methods ---------------------------------------

        /**
        * Return the index of the most recent property read or (if it were
        * missing) requested.
        *
        * @return  the index of the most recent property read
        */
        public int getPreviousPropertyIndex()
            {
            return m_iPrevProp;
            }

        /**
        * Return the index of the next property in the POF stream.
        *
        * @return  the index of the next property in the POF stream
        *
        * @throws IOException  if an I/O error occurs
        */
        public int getNextPropertyIndex()
                throws IOException
            {
            closeNested();
            return m_iNextProp == EOPS ? -1 : m_iNextProp;
            }

        /**
        * {@inheritDoc}
        */
        @Override protected boolean advanceTo(int iProp)
                throws IOException
            {
            // if a nested writer is still open, then "end" that property
            closeNested();

            // the terminating index is -1; if searching for -1, re-order the
            // goal to come after all other properties (which assumes that
            // there is no valid property index Integer.MAX_VALUE)
            if (iProp == -1)
                {
                iProp = EOPS;
                }

            // check for backwards movement
            if (iProp <= m_iPrevProp)
                {
                throw new IllegalStateException("previous property index="
                        + m_iPrevProp + ", requested property index=" + iProp
                        + " while reading user type " + getUserTypeId());
                }

            // check if the stream is already in the correct location
            // (common case)
            int iNextProp = m_iNextProp;
            if (iProp == iNextProp)
                {
                return true;
                }

            ReadBuffer.BufferInput in = m_in;
            int ofNextProp = m_ofNextProp;
            while (iNextProp != EOPS && iNextProp < iProp)
                {
                skipValue(in);

                ofNextProp = in.getOffset();
                iNextProp  = in.readPackedInt();
                if (iNextProp < 0)
                    {
                    iNextProp = EOPS;
                    }
                }

            m_ofNextProp = ofNextProp;
            m_iNextProp  = iNextProp;

            return iProp == iNextProp;
            }

        /**
        * {@inheritDoc}
        */
        @Override protected void complete(int iProp)
                throws IOException
            {
            if (m_iNextProp == iProp)
                {
                ReadBuffer.BufferInput in = m_in;
                m_ofNextProp  = in.getOffset();
                int iNextProp = in.readPackedInt();
                m_iNextProp   = iNextProp < 0 ? EOPS : iNextProp;
                }

            m_iPrevProp = iProp;
            }

        /**
        * Notify the UserTypeReader that it is being "closed".
        *
        * @throws IOException  if an I/O error occurs
        */
        protected void closeNested()
                throws IOException
            {
            // check if a nested PofReader is open
            UserTypeReader readerNested = m_readerNested;
            if (readerNested != null)
                {
                // check if there is some remainder that haven't been skipped
                if (readerNested.m_iNextProp != EOPS)
                    {
                    readerNested.readRemainder();
                    }
                // close it
                readerNested.closeNested();

                // finish reading the property that the nested PofReader was
                // reading from; this is the "complete()" call that was
                // deferred when the nested stream was opened
                complete(m_iNestedProp);

                m_readerNested = null;
                m_iNestedProp  = -1;
                }
            }

        /**
        * {@inheritDoc}
        */
        @Override protected PofBufferReader getParentParser()
            {
            return m_parent;
            }

        // ----- constants ----------------------------------------------

        /**
        * Fake End-Of-Property-Stream indicator.
        */
        private static final int EOPS = Integer.MAX_VALUE;

        // ----- data members -------------------------------------------

        /**
        * The parent (ie containing) PofBufferReader.
        */
        private PofBufferReader m_parent;

        /**
        * The type identifier of the user type that is being parsed.
        */
        private int m_nTypeId;

        /**
        * The version identifier of the user type that is being parsed.
        */
        private int m_nVersionId;

        /**
        * Most recent property read or (if it were missing) requested. This
        * is used to determine if the client is attempting to read properties
        * in the wrong order.
        */
        private int m_iPrevProp = -1;

        /**
        * The index of the next property in the POF stream.
        */
        private int m_iNextProp;

        /**
        * The offset of the index of the next property to read.
        */
        private int m_ofNextProp;

        /**
        * The currently open nested reader, if any.
        */
        private UserTypeReader m_readerNested;

        /**
        * The property index of the property from which the currently open
        * nested reader is reading from.
        */
        private int m_iNestedProp;
        }


    // ----- inner class: IdentityHolder ------------------------------------

    public static class IdentityHolder
        {
        private static ThreadLocal s_mapId = new ThreadLocal()
            {
            @Override protected synchronized Object initialValue()
                {
                return new HashMap();
                }
            };

        public static void set(PofBufferReader reader, int nId)
            {
            Map mapId = (Map) s_mapId.get();
            mapId.put(reader, Integer.valueOf(nId));
            }

        public static void reset(PofBufferReader reader, int nId, Object o)
            {
            Map mapId = (Map) s_mapId.get();
            if (!mapId.isEmpty())
                {
                while (reader != null)
                    {
                    Object oValue = mapId.get(reader);
                    if (oValue != null)
                        {
                        int nValue = ((Integer) oValue).intValue();
                        if (nId == -1 || nValue == nId)
                            {
                            reader.registerIdentity(nValue, o);
                            mapId.remove(reader);
                            }
                        break;
                        }
                    reader = reader.getParentParser();
                    }
                }
            }
        }


    // ----- data members ---------------------------------------------------

    /**
    * The BufferInput containing the POF stream.
    */
    protected ReadBuffer.BufferInput m_in;

    /**
    * The PofContext to use to realize user data types as Java objects.
    */
    protected PofContext m_ctx;

    /**
    * Lazily-constructed mapping of identities to references.
    */
    protected LongArray m_arrayRefs;
    }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy