-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathID3v2Frame.java
More file actions
205 lines (173 loc) · 6.49 KB
/
Copy pathID3v2Frame.java
File metadata and controls
205 lines (173 loc) · 6.49 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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
package Mp3File;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Objects;
public class ID3v2Frame {
private static final int HEADER_LENGTH = 10;
private static final int ID_OFFSET = 0;
private static final int ID_LENGTH = 4;
protected static final int DATA_LENGTH_OFFSET = 4;
private static final int FLAGS1_OFFSET = 8;
private static final int FLAGS2_OFFSET = 9;
private static final int PRESERVE_TAG_BIT = 6;
private static final int PRESERVE_FILE_BIT = 5;
private static final int READ_ONLY_BIT = 4;
private static final int GROUP_BIT = 6;
private static final int COMPRESSION_BIT = 3;
private static final int ENCRYPTION_BIT = 2;
private static final int UNSYNCHRONISATION_BIT = 1;
private static final int DATA_LENGTH_INDICATOR_BIT = 0;
protected String id;
protected int dataLength = 0;
protected byte[] data = null;
private boolean preserveTag = false;
private boolean preserveFile = false;
private boolean readOnly = false;
private boolean group = false;
private boolean compression = false;
private boolean encryption = false;
private boolean unsynchronisation = false;
private boolean dataLengthIndicator = false;
public ID3v2Frame(byte[] buffer, int offset) throws InvalidDataException {
unpackFrame(buffer, offset);
}
public ID3v2Frame(String id, byte[] data) {
this.id = id;
this.data = data;
dataLength = data.length;
}
protected final void unpackFrame(byte[] buffer, int offset) throws InvalidDataException {
int dataOffset = unpackHeader(buffer, offset);
sanityCheckUnpackedHeader();
data = BufferTools.copyBuffer(buffer, dataOffset, dataLength);
}
protected int unpackHeader(byte[] buffer, int offset) {
id = BufferTools.byteBufferToStringIgnoringEncodingIssues(buffer, offset + ID_OFFSET, ID_LENGTH);
unpackDataLength(buffer, offset);
unpackFlags(buffer, offset);
return offset + HEADER_LENGTH;
}
protected void unpackDataLength(byte[] buffer, int offset) {
dataLength = BufferTools.unpackInteger(buffer[offset + DATA_LENGTH_OFFSET], buffer[offset + DATA_LENGTH_OFFSET + 1], buffer[offset + DATA_LENGTH_OFFSET + 2], buffer[offset + DATA_LENGTH_OFFSET + 3]);
}
private void unpackFlags(byte[] buffer, int offset) {
preserveTag = BufferTools.checkBit(buffer[offset + FLAGS1_OFFSET], PRESERVE_TAG_BIT);
preserveFile = BufferTools.checkBit(buffer[offset + FLAGS1_OFFSET], PRESERVE_FILE_BIT);
readOnly = BufferTools.checkBit(buffer[offset + FLAGS1_OFFSET], READ_ONLY_BIT);
group = BufferTools.checkBit(buffer[offset + FLAGS2_OFFSET], GROUP_BIT);
compression = BufferTools.checkBit(buffer[offset + FLAGS2_OFFSET], COMPRESSION_BIT);
encryption = BufferTools.checkBit(buffer[offset + FLAGS2_OFFSET], ENCRYPTION_BIT);
unsynchronisation = BufferTools.checkBit(buffer[offset + FLAGS2_OFFSET], UNSYNCHRONISATION_BIT);
dataLengthIndicator = BufferTools.checkBit(buffer[offset + FLAGS2_OFFSET], DATA_LENGTH_INDICATOR_BIT);
}
protected void sanityCheckUnpackedHeader() throws InvalidDataException {
for (int i = 0; i < id.length(); i++) {
if (!((id.charAt(i) >= 'A' && id.charAt(i) <= 'Z') || (id.charAt(i) >= '0' && id.charAt(i) <= '9'))) {
throw new InvalidDataException("Not a valid frame - invalid tag " + id);
}
}
}
public byte[] toBytes() throws NotSupportedException {
byte[] bytes = new byte[getLength()];
packFrame(bytes, 0);
return bytes;
}
public void toBytes(byte[] bytes, int offset) throws NotSupportedException {
packFrame(bytes, offset);
}
public void packFrame(byte[] bytes, int offset) throws NotSupportedException {
packHeader(bytes, offset);
BufferTools.copyIntoByteBuffer(data, 0, data.length, bytes, offset + HEADER_LENGTH);
}
private void packHeader(byte[] bytes, int i) {
try {
BufferTools.stringIntoByteBuffer(id, 0, id.length(), bytes, 0);
} catch (UnsupportedEncodingException e) {
}
BufferTools.copyIntoByteBuffer(packDataLength(), 0, 4, bytes, 4);
BufferTools.copyIntoByteBuffer(packFlags(), 0, 2, bytes, 8);
}
protected byte[] packDataLength() {
return BufferTools.packInteger(dataLength);
}
private byte[] packFlags() {
byte[] bytes = new byte[2];
bytes[0] = BufferTools.setBit(bytes[0], PRESERVE_TAG_BIT, preserveTag);
bytes[0] = BufferTools.setBit(bytes[0], PRESERVE_FILE_BIT, preserveFile);
bytes[0] = BufferTools.setBit(bytes[0], READ_ONLY_BIT, readOnly);
bytes[1] = BufferTools.setBit(bytes[1], GROUP_BIT, group);
bytes[1] = BufferTools.setBit(bytes[1], COMPRESSION_BIT, compression);
bytes[1] = BufferTools.setBit(bytes[1], ENCRYPTION_BIT, encryption);
bytes[1] = BufferTools.setBit(bytes[1], UNSYNCHRONISATION_BIT, unsynchronisation);
bytes[1] = BufferTools.setBit(bytes[1], DATA_LENGTH_INDICATOR_BIT, dataLengthIndicator);
return bytes;
}
public String getId() {
return id;
}
public int getDataLength() {
return dataLength;
}
public int getLength() {
return dataLength + HEADER_LENGTH;
}
public byte[] getData() {
return data;
}
public void setData(byte[] data) {
this.data = data;
if (data == null) dataLength = 0;
else dataLength = data.length;
}
public boolean hasDataLengthIndicator() {
return dataLengthIndicator;
}
public boolean hasCompression() {
return compression;
}
public boolean hasEncryption() {
return encryption;
}
public boolean hasGroup() {
return group;
}
public boolean hasPreserveFile() {
return preserveFile;
}
public boolean hasPreserveTag() {
return preserveTag;
}
public boolean isReadOnly() {
return readOnly;
}
public boolean hasUnsynchronisation() {
return unsynchronisation;
}
@Override
public int hashCode() {
return 31 * Objects.hash(compression, dataLength, dataLengthIndicator, encryption, group,
id, preserveFile, preserveTag, readOnly, unsynchronisation) + Arrays.hashCode(data);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final ID3v2Frame other = (ID3v2Frame) obj;
return
Arrays.equals(data, other.data) &&
Objects.equals(compression, other.compression) &&
Objects.equals(dataLength, other.dataLength) &&
Objects.equals(dataLengthIndicator, other.dataLengthIndicator) &&
Objects.equals(encryption, other.encryption) &&
Objects.equals(group, other.group) &&
Objects.equals(id, other.id) &&
Objects.equals(preserveFile, other.preserveFile) &&
Objects.equals(preserveTag, other.preserveTag) &&
Objects.equals(readOnly, other.readOnly) &&
Objects.equals(unsynchronisation, other.unsynchronisation);
}
}