summaryrefslogtreecommitdiff
path: root/src/fjbg/ch/epfl/lamp/util/ByteArray.java
blob: 59a3ac9a12f6f488b49e2721d8545e7415a6efa0 (plain) (blame)
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
/* FJBG -- Fast Java Bytecode Generator
 * Copyright 2002-2012 LAMP/EPFL
 * @author  Michel Schinz
 */

package ch.epfl.lamp.util;

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

/**
 * Array of bytes.
 *
 * @author Michel Schinz
 * @version 1.0
 */

public class ByteArray {
    protected final static int BYTE_BLOCK_BITS = 8;
    protected final static int BYTE_BLOCK_SIZE = 1 << BYTE_BLOCK_BITS;
    protected final static int BYTE_BLOCK_MASK = BYTE_BLOCK_SIZE - 1;

    protected byte[][] data = new byte[][] { new byte[BYTE_BLOCK_SIZE] };
    protected int pos = 0;  // The next free position.

    protected boolean frozen = false;

    public ByteArray() { }

    public ByteArray(InputStream stream, int size) throws IOException {
        pos = size;
        for (int i = 0; size > 0; ++i) {
            int sizeToRead = Math.min(BYTE_BLOCK_SIZE, size);
            stream.read(data[i], 0, sizeToRead);

            size -= sizeToRead;
            if (size > 0) addNewBlock();
        }
    }

    public void freeze() { frozen = true; }

    public int nextBytePosition() {
        return pos;
    }

    public int getSize() {
        return pos;
    }

    protected void addNewBlock() {
        int nextBlockPos = pos >>> BYTE_BLOCK_BITS;
        if (nextBlockPos == data.length) {
            byte[][] newData = new byte[data.length * 2][];
            System.arraycopy(data, 0, newData, 0, data.length);
            data = newData;
        }
        assert data[nextBlockPos] == null : pos + " " + nextBlockPos;
        data[nextBlockPos] = new byte[BYTE_BLOCK_SIZE];
    }

    protected void addByte(int b) {
        assert !frozen;

        if ((pos & BYTE_BLOCK_MASK) == 0 && pos > 0)
            addNewBlock();
        int currPos = pos++;
        data[currPos >>> BYTE_BLOCK_BITS][currPos & BYTE_BLOCK_MASK] = (byte)b;
    }

    public void addU1(int i) {
        assert i <= 0xFF : i;
        addByte(i);
    }

    public void addU2(int i) {
        assert i <= 0xFFFF : i;

        addByte(i >>> 8);
        addByte(i & 0xFF);
    }

    public void addU4(int i) {
        addByte(i >>> 24);
        addByte((i >>> 16) & 0xFF);
        addByte((i >>>  8) & 0xFF);
        addByte(i & 0xFF);
    }

    public void putByte(int targetPos, int b) {
        assert !frozen;
        assert targetPos < pos : targetPos + " >= " + pos;

        data[targetPos >>> BYTE_BLOCK_BITS][targetPos & BYTE_BLOCK_MASK] = (byte)b;
    }

    public void putU2(int targetPos, int i) {
        assert i < 0xFFFF : i;
        putByte(targetPos, i >>> 8);
        putByte(targetPos + 1, i & 0xFF);
    }

    public void putU4(int targetPos, int i) {
        putByte(targetPos, i >>> 24);
        putByte(targetPos + 1, (i >>> 16) & 0xFF);
        putByte(targetPos + 2, (i >>>  8) & 0xFF);
        putByte(targetPos + 3, i & 0xFF);
    }

    public int getU1(int sourcePos) {
        assert sourcePos < pos : sourcePos + " >= " + pos;
        return data[sourcePos >>> BYTE_BLOCK_BITS][sourcePos & BYTE_BLOCK_MASK] & 0xFF;
    }

    public int getU2(int sourcePos) {
        return (getU1(sourcePos) << 8) | getU1(sourcePos + 1);
    }

    public int getU4(int sourcePos) {
        return (getU2(sourcePos) << 16) | getU2(sourcePos + 2);
    }

    public int getS1(int sourcePos) {
        assert sourcePos < pos : sourcePos + " >= " + pos;
        return data[sourcePos >>> BYTE_BLOCK_BITS][sourcePos & BYTE_BLOCK_MASK];
    }

    public int getS2(int sourcePos) {
        return (getS1(sourcePos) << 8) | getU1(sourcePos + 1);
    }

    public int getS4(int sourcePos) {
        return (getS2(sourcePos) << 16) | getU2(sourcePos + 2);
    }

    public void writeTo(OutputStream stream) throws IOException {
        if (!frozen) freeze();

        for (int i = 0; i < data.length && data[i] != null; ++i) {
            int len = Math.min(BYTE_BLOCK_SIZE, pos - (i << BYTE_BLOCK_BITS));
            stream.write(data[i], 0, len);
        }
    }
}