dev@fi.java.net

Re: Bugs in Decoder.java

From: Andrzej Gladkowski <agladkowski_at_gmail.com>
Date: Wed, 4 Nov 2009 10:05:11 +0000

On Tue, Nov 3, 2009 at 3:26 PM, Arman Djusupov <arman_at_noemax.com> wrote:

> Hello Andrzej,
>
> It seems that the decodeNumberOfItemsOfSequence() method indeed has a
> problem, since it doesn't add the lower boundary of the range after reading
> the value.
>
> But why do you think that C.25.2 is implemented in the wrong way?
>
> As far as I can see C.25.2 implementation is correct. It doesn't add +1
> when reading 1-64 value range, because in the Java implementation the
> vocabulary tables are 0 based, so practically adding and subtracting 1 while
> reading/writing is not necessary. The same applies to other ranges. It adds
> 64 instead of 65 as lower boundary for medium ranged values and 8256 instead
> of 8257 for high ranged values.
> With best regards,
> Arman
>
>
#Yes, I agree that subtracting 1 while reading/writing is not necessary.
# No, I think the whole C.25 is implemented correctly, it's about something
else. Please read further comments.

# I think confusion is caused by the following points:

C.13.4 If the alternative string-index is present, then the bit '1'
(discriminant) is appended to the bit stream, and
the string-index is encoded as described in C.25
C.16.5 If the optional component prefix-string-index is present, then the
bit '0' (padding) is appended to the bit
stream, and the component is encoded as described in C.25.
C.16.6 If the optional component namespace-name-string-index is present,
then the bit '0' (padding) is appended
to the bit stream, and the component is encoded as described in C.25.
C.16.7 The bit '0' (padding) is appended to the bit stream, and the
component local-name-string-index is
encoded as described in C.25.

# The function 'decodeNumberOfItemsOfSequence(..)' implements correctly
point *C.13.4*, when the octed starts with '1'
# but it fails if the octet starts with '0' !
# I have looked into Encoder.java and there are two separate encoding
methods:
 - Encoder.encodeNonZeroIntegerOnSecondBitFirstBitZero(..)
 - Encoder.encodeNonZeroIntegerOnSecondBitFirstBitOne(..)
# We could fix Decoder.decodeNumberOfItemsOfSequence(..) by adding another
method to handle octets starting with '0' or simply by ignoring the first
bit in the octet all the time.

# Here is the junit test that can be used to test both scenarios (by
uncommenting the right FIRST_BIT constant in the code):
=========================================================================
import java.io.IOException;
import org.jvnet.fastinfoset.FastInfosetException;
import com.sun.xml.fastinfoset.Decoder;
import junit.framework.TestCase;

public class DecoderTest extends TestCase {
    /* Uncomment the right section to test first bit in the octet '1' or '0'
*/
    //private static final byte FIRST_BIT = (byte)0x80;//1000 0000 // C.13.4
    private static final byte FIRST_BIT = (byte)0x00;//0000 0000 // C.16.5-7

    private TestDecoder decoder;
    private byte[] buffer;
    private class TestDecoder extends Decoder {
        public TestDecoder(byte[] buffer) {
            this._octetBufferOffset = 0;
            this._octetBufferEnd = 15;
            this._octetBuffer = buffer;
        }
        public int decodeIntegerIndexOnSecondBitTest() throws
FastInfosetException, IOException {
            return decodeIntegerIndexOnSecondBit();
        }
    }

    protected void setUp() throws java.lang.Exception {
        buffer = new byte[16];
        decoder = new TestDecoder(buffer);
    }
    // integer in range [1, 64], ( [0, 63] ) 6 bits
    public void testIntegerIndex0() throws IOException, FastInfosetException
{
        buffer[0] = 0x00 | FIRST_BIT;
        final int result = decoder.decodeIntegerIndexOnSecondBitTest();

        assertEquals(0x00, result);
    }
    // integer in range [65, 8256], ( [64, 8255] ) 13 bits
    public void testIntegerIndex321() throws IOException,
FastInfosetException {
        buffer[0] = 0x41 | FIRST_BIT;//100 0001 - last five bits
        buffer[1] = 0x01;// 0000 0001 - eight following bits
        final int result = decoder.decodeIntegerIndexOnSecondBitTest();

        assertEquals(257 + 64, result);
    }
    // integer in range [8257, 1048576], ( [8256, 1048575] ) 20 bits
    public void testIntegerIndex73793() throws IOException,
FastInfosetException {
        buffer[0] = 0x61 | FIRST_BIT;//110 0001 - last four bits
        buffer[1] = 0x00;// 0000 0000 - eight following bits
        buffer[2] = 0x01;// 0000 0001 - eight following bits
        final int result = decoder.decodeIntegerIndexOnSecondBitTest();

        assertEquals(65537 + 8256, result);
    }
}
=========================================================================

# Another small issue can be found in
Decoder.decodeTableItems(QualifiedNameArray array, boolean isAttribute).
# Wrong:

            String namespaceName = "";
            int namespaceNameIndex = -1;
            if ((b & EncodingConstants.NAME_SURROGATE_NAME_FLAG) > 0) {
                namespaceNameIndex = decodeIntegerIndexOnSecondBit();
                namespaceName = *_v.prefix.get(prefixIndex);*
            }

# Correct: _v.prefix.get(prefixIndex); changed to
_v.namespaceName.get(namespaceNameIndex);

            String namespaceName = "";
            int namespaceNameIndex = -1;
            if ((b & EncodingConstants.NAME_SURROGATE_NAME_FLAG) > 0) {
                namespaceNameIndex = decodeIntegerIndexOnSecondBit();
                namespaceName = *_v.namespaceName.get(namespaceNameIndex);*
            }


Cheers,
~Andrzej