-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathUTF8Modified.java
More file actions
131 lines (124 loc) · 4.24 KB
/
UTF8Modified.java
File metadata and controls
131 lines (124 loc) · 4.24 KB
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
/*
* Copyright (C) 2010 Preston Lacey http://javaflacencoder.sourceforge.net/
* All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package javaFlacEncoder;
/**
* This is a utility class that provides methods to both encode to and decode
* from the extended version of UTF8 used by the FLAC format. All functions
* should work with standard UTF8 as well, since this only extends it to handle
* larger input values.
*
* @author Preston Lacey
*/
public class UTF8Modified {
static final long oneByteLimit = (long)Math.pow(2, 7);
static final long twoByteLimit = (long)Math.pow(2, 11);
static final long threeByteLimit = (long)Math.pow(2, 16);
static final long fourByteLimit = (long)Math.pow(2, 21);
static final long fiveByteLimit = (long)Math.pow(2, 26);
static final long sixByteLimit = (long)Math.pow(2, 31);
static final long sevenByteLimit = (long)Math.pow(2, 36);
static long[] limits = {
oneByteLimit,
twoByteLimit,
threeByteLimit,
fourByteLimit,
fiveByteLimit,
sixByteLimit,
sevenByteLimit
};
/** For debugging: Higher value equals more output, generally by increments
* of 10 */
public static int DEBUG_LEV = 0;
/**
* Constructor. This Class provides only static methods and static fields.
*/
public UTF8Modified() {
}
/**
* Decode an extended UTF8(as used in FLAC), to a long value.
* @param input extended UTF8 encoded value.
* @return value represented by the UTF8 input.
*/
public static long decodeFromExtendedUTF8(byte[] input) {
int leadOnes = 0;
int leadMask = 128;
int work = input[0];
while((work & leadMask) > 0) {
leadOnes++;
work = work << 1;
}
int valMask = 255 >>> (leadOnes+1);
long val = input[0] & valMask;
for(int i = 1; i < leadOnes; i++) {
int midMask = 0x3F;
val = val << 6;
val = (input[i] & midMask) | val;
}
return val;
}
/**
* Convert a value to an extended UTF8 format(as used in FLAC).
* @param value value to convert to extended UTF8(value must be positive
* and 36 bits or less in size)
* @return extended UTF8 encoded value(array size is equal to the number of
* usable bytes)
*/
public static byte[] convertToExtendedUTF8(long value) {
//calculate bytes needed
int bytesNeeded = 1;
for(int i = 0; i < 7; i++) {
if(value >= limits[i] ) {
bytesNeeded++;
}
}
//create space
byte [] result = new byte[bytesNeeded];
int byteIndex = 0;
int inputIndex = 0;
int bytesLeft = bytesNeeded;
while(bytesLeft > 1) {
int midByteMarker = 0x80;//10 in leftmost bits
int midByteMask = 0x3F;//00111111
int val = ((int)(value >>> inputIndex) & midByteMask) | midByteMarker;
result[byteIndex++] = (byte)val;
inputIndex += 6;
bytesLeft--;
}
int onesNeeded = inputIndex/6;
if(onesNeeded > 0)
onesNeeded++;
int startMask = 255 >>> (onesNeeded + 1);
int ones = 255 << (8-onesNeeded);
int val = ((int)(value >>> inputIndex) & startMask) | ones;
result[byteIndex++] = (byte)val;
byte[] finalResult = new byte[bytesNeeded];
for(int i = 0; i < bytesNeeded; i++) {
int sourceIndex = bytesNeeded-1-i;
int destIndex = i;
finalResult[destIndex] = result[sourceIndex];
}
if(DEBUG_LEV > 10) {
System.err.print("input:result_length:result :: " +value+":"+finalResult.length+"::");
for(int i = 0; i < finalResult.length; i++)
System.err.print(Integer.toHexString(finalResult[i])+":");
System.err.println();
}
return finalResult;
}
}