1/*
2 * Copyright 2012 Sebastian Annies, Hamburg
3 *
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.coremedia.iso;
17
18import java.io.ByteArrayOutputStream;
19import java.nio.ByteBuffer;
20
21public final class IsoTypeReader {
22
23
24    public static long readUInt32BE(ByteBuffer bb) {
25        long ch1 = readUInt8(bb);
26        long ch2 = readUInt8(bb);
27        long ch3 = readUInt8(bb);
28        long ch4 = readUInt8(bb);
29        return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0));
30
31    }
32
33
34    public static long readUInt32(ByteBuffer bb) {
35        long i = bb.getInt();
36        if (i < 0) {
37            i += 1l<<32;
38        }
39        return i;
40    }
41
42    public static int readUInt24(ByteBuffer bb) {
43        int result = 0;
44        result += readUInt16(bb) << 8;
45        result += byte2int(bb.get());
46        return result;
47    }
48
49
50    public static int readUInt16(ByteBuffer bb) {
51        int result = 0;
52        result += byte2int(bb.get()) << 8;
53        result += byte2int(bb.get());
54        return result;
55    }
56
57    public static int readUInt16BE(ByteBuffer bb) {
58        int result = 0;
59        result += byte2int(bb.get());
60        result += byte2int(bb.get()) << 8;
61        return result;
62    }
63
64    public static int readUInt8(ByteBuffer bb) {
65        return byte2int(bb.get());
66    }
67
68    public static int byte2int(byte b) {
69        return b < 0 ? b + 256 : b;
70    }
71
72
73    /**
74     * Reads a zero terminated UTF-8 string.
75     *
76     * @param byteBuffer the data source
77     * @return the string readByte
78     * @throws Error in case of an error in the underlying stream
79     */
80    public static String readString(ByteBuffer byteBuffer) {
81
82        ByteArrayOutputStream out = new ByteArrayOutputStream();
83        int read;
84        while ((read = byteBuffer.get()) != 0) {
85            out.write(read);
86        }
87        return Utf8.convert(out.toByteArray());
88    }
89
90    public static String readString(ByteBuffer byteBuffer, int length) {
91        byte[] buffer = new byte[length];
92        byteBuffer.get(buffer);
93        return Utf8.convert(buffer);
94
95    }
96
97    public static long readUInt64(ByteBuffer byteBuffer) {
98        long result = 0;
99        // thanks to Erik Nicolas for finding a bug! Cast to long is definitivly needed
100        result += readUInt32(byteBuffer) << 32;
101        if (result < 0) {
102            throw new RuntimeException("I don't know how to deal with UInt64! long is not sufficient and I don't want to use BigInt");
103        }
104        result += readUInt32(byteBuffer);
105
106        return result;
107    }
108
109    public static double readFixedPoint1616(ByteBuffer bb) {
110        byte[] bytes = new byte[4];
111        bb.get(bytes);
112
113        int result = 0;
114        result |= ((bytes[0] << 24) & 0xFF000000);
115        result |= ((bytes[1] << 16) & 0xFF0000);
116        result |= ((bytes[2] << 8) & 0xFF00);
117        result |= ((bytes[3]) & 0xFF);
118        return ((double) result) / 65536;
119
120    }
121
122    public static float readFixedPoint88(ByteBuffer bb) {
123        byte[] bytes = new byte[2];
124        bb.get(bytes);
125        short result = 0;
126        result |= ((bytes[0] << 8) & 0xFF00);
127        result |= ((bytes[1]) & 0xFF);
128        return ((float) result) / 256;
129    }
130
131    public static String readIso639(ByteBuffer bb) {
132        int bits = readUInt16(bb);
133        StringBuilder result = new StringBuilder();
134        for (int i = 0; i < 3; i++) {
135            int c = (bits >> (2 - i) * 5) & 0x1f;
136            result.append((char) (c + 0x60));
137        }
138        return result.toString();
139    }
140
141    public static String read4cc(ByteBuffer bb) {
142        byte[] b = new byte[4];
143        bb.get(b);
144        return IsoFile.bytesToFourCC(b);
145    }
146
147}
148