File: SimpleNioBuf.java

package info (click to toggle)
jcdf 1.2.5%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 572 kB
  • sloc: java: 5,315; makefile: 198; sh: 98
file content (152 lines) | stat: -rw-r--r-- 4,978 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package uk.ac.bristol.star.cdf.record;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;

/**
 * Buf implementation based on a single NIO ByteBuffer.
 * This works fine as long as it doesn't need to be more than 2^31 bytes (2Gb),
 * which is the maximum length of a ByteBuffer.
 *
 * @author   Mark Taylor
 * @since    18 Jun 2013
 * @see      java.nio.ByteBuffer
 */
public class SimpleNioBuf implements Buf {

    private final ByteBuffer byteBuf_;
    private final ByteBuffer dataBuf_;
    private boolean isBit64_;
    private boolean isBigendian_;

    /**
     * Constructor.
     *
     * @param  byteBuf  NIO byte buffer containing the byte data
     * @param  isBit64  64bit-ness of this buf
     * @param  isBigendian  true for big-endian, false for little-endian
     */
    public SimpleNioBuf( ByteBuffer byteBuf, boolean isBit64,
                         boolean isBigendian ) {
        byteBuf_ = byteBuf;
        dataBuf_ = byteBuf.duplicate();
        setBit64( isBit64 );
        setEncoding( isBigendian );
    }

    public long getLength() {
        return byteBuf_.capacity();
    }

    public int readUnsignedByte( Pointer ptr ) {
        return byteBuf_.get( toInt( ptr.getAndIncrement( 1 ) ) ) & 0xff;
    }

    public int readInt( Pointer ptr ) {
        return byteBuf_.getInt( toInt( ptr.getAndIncrement( 4 ) ) );
    }

    public long readOffset( Pointer ptr ) {
        return isBit64_
             ? byteBuf_.getLong( toInt( ptr.getAndIncrement( 8 ) ) )
             : (long) byteBuf_.getInt( toInt( ptr.getAndIncrement( 4 ) ) );
    }

    public String readAsciiString( Pointer ptr, int nbyte ) {
        return Bufs.readAsciiString( byteBuf_,
                                     toInt( ptr.getAndIncrement( nbyte ) ),
                                     nbyte );
    }

    public synchronized void setBit64( boolean isBit64 ) {
        isBit64_ = isBit64;
    }

    public synchronized void setEncoding( boolean bigend ) {

        // NIO buffers can do all the hard work - just tell them the
        // endianness of the data buffer.  Note however that the
        // endianness of control data is not up for grabs, so maintain
        // separate buffers for control data and application data.
        dataBuf_.order( bigend ? ByteOrder.BIG_ENDIAN
                               : ByteOrder.LITTLE_ENDIAN );
        isBigendian_ = bigend;
    }

    public boolean isBigendian() {
        return isBigendian_;
    }

    public boolean isBit64() {
        return isBit64_;
    }

    public void readDataBytes( long offset, int count, byte[] array ) {
        Bufs.readBytes( dataBuf_, toInt( offset ), count, array );
    }

    public void readDataShorts( long offset, int count, short[] array ) {
        Bufs.readShorts( dataBuf_, toInt( offset ), count, array );
    }

    public void readDataInts( long offset, int count, int[] array ) {
        Bufs.readInts( dataBuf_, toInt( offset ), count, array );
    }

    public void readDataLongs( long offset, int count, long[] array ) {
        Bufs.readLongs( dataBuf_, toInt( offset ), count, array );
    }

    public void readDataFloats( long offset, int count, float[] array ) {
        Bufs.readFloats( dataBuf_, toInt( offset ), count, array );
    }

    public void readDataDoubles( long offset, int count, double[] array ) {
        Bufs.readDoubles( dataBuf_, toInt( offset ), count, array );
    }

    public InputStream createInputStream( long offset ) {
        ByteBuffer strmBuf = byteBuf_.duplicate();
        strmBuf.position( (int) offset );
        return Bufs.createByteBufferInputStream( strmBuf );
    }

    public Buf fillNewBuf( long count, InputStream in ) throws IOException {
        int icount = toInt( count );
        ByteBuffer bbuf = ByteBuffer.allocateDirect( icount );
        ReadableByteChannel chan = Channels.newChannel( in );
        while ( icount > 0 ) {
            int nr = chan.read( bbuf );
            if ( nr < 0 ) {
                throw new EOFException();
            }
            else { 
                icount -= nr;
            }
        }
        return new SimpleNioBuf( bbuf, isBit64_, isBigendian_ );
    }

    /**
     * Downcasts a long to an int.
     * If the value is too large, an unchecked exception is thrown.
     * That shouldn't happen because the only values this is invoked on
     * are offsets into a ByteBuffer.
     *
     * @param  lvalue  long value
     * @return   integer with the same value as <code>lvalue</code>
     */
    private static int toInt( long lvalue ) {
        int ivalue = (int) lvalue;
        if ( ivalue != lvalue ) {
            throw new IllegalArgumentException( "Pointer out of range: "
                                              + lvalue + " >32 bits" );
        }
        return ivalue;
    }
}