1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package entagged.audioformats.flac.util;
20
21 import entagged.audioformats.*;
22 import entagged.audioformats.exceptions.*;
23 import entagged.audioformats.ogg.OggTag;
24
25 import java.io.*;
26 import java.nio.channels.*;
27 import java.util.*;
28
29
30 public class FlacTagWriter {
31
32 private Vector metadataBlockPadding = new Vector(1);
33 private Vector metadataBlockApplication = new Vector(1);
34 private Vector metadataBlockSeekTable = new Vector(1);
35 private Vector metadataBlockCueSheet = new Vector(1);
36
37 private FlacTagCreator tc = new FlacTagCreator();
38 private FlacTagReader reader = new FlacTagReader();
39
40 public void delete(RandomAccessFile raf, RandomAccessFile tempRaf) throws IOException, CannotWriteException {
41 OggTag tag = null;
42 try {
43 tag = reader.read(raf);
44 } catch(CannotReadException e) {
45 write(new OggTag(), raf, tempRaf);
46 return;
47 }
48
49 OggTag emptyTag = new OggTag();
50 emptyTag.setVendor(tag.getVendor());
51
52 raf.seek(0);
53 tempRaf.seek(0);
54
55 write(emptyTag, raf, tempRaf);
56 }
57
58 public void write( Tag tag, RandomAccessFile raf, RandomAccessFile rafTemp ) throws CannotWriteException, IOException {
59
60 metadataBlockPadding.removeAllElements();
61 metadataBlockApplication.removeAllElements();
62 metadataBlockSeekTable.removeAllElements();
63 metadataBlockCueSheet.removeAllElements();
64
65 byte[] b = new byte[4];
66 raf.readFully(b);
67
68 String flac = new String(b);
69 if(!flac.equals("fLaC"))
70 throw new CannotWriteException("This is not a FLAC file");
71
72 boolean isLastBlock = false;
73 while(!isLastBlock) {
74 b = new byte[4];
75 raf.readFully(b);
76 MetadataBlockHeader mbh = new MetadataBlockHeader(b);
77
78
79 switch(mbh.getBlockType()) {
80 case MetadataBlockHeader.VORBIS_COMMENT : handlePadding(mbh, raf); break;
81 case MetadataBlockHeader.PADDING : handlePadding(mbh, raf); break;
82 case MetadataBlockHeader.APPLICATION : handleApplication(mbh, raf); break;
83 case MetadataBlockHeader.SEEKTABLE : handleSeekTable(mbh, raf); break;
84 case MetadataBlockHeader.CUESHEET : handleCueSheet(mbh, raf); break;
85 default : skipBlock(mbh, raf); break;
86 }
87
88 isLastBlock = mbh.isLastBlock();
89 }
90
91 int availableRoom = computeAvailableRoom();
92 int newTagSize = tc.getTagLength(tag);
93 int neededRoom = newTagSize + computeNeededRoom();
94
95 raf.seek(0);
96
97 if(availableRoom>=neededRoom) {
98
99 raf.seek(42);
100
101 for(int i = 0; i<metadataBlockApplication.size(); i++) {
102 raf.write( ((MetadataBlock) metadataBlockApplication.elementAt(i)).getHeader().getBytes());
103 raf.write( ((MetadataBlock) metadataBlockApplication.elementAt(i)).getData().getBytes());
104 }
105
106 for(int i = 0; i<metadataBlockSeekTable.size(); i++) {
107 raf.write( ((MetadataBlock) metadataBlockSeekTable.elementAt(i)).getHeader().getBytes());
108 raf.write( ((MetadataBlock) metadataBlockSeekTable.elementAt(i)).getData().getBytes());
109 }
110
111 for(int i = 0; i<metadataBlockCueSheet.size(); i++) {
112 raf.write( ((MetadataBlock) metadataBlockCueSheet.elementAt(i)).getHeader().getBytes());
113 raf.write( ((MetadataBlock) metadataBlockCueSheet.elementAt(i)).getData().getBytes());
114 }
115
116 raf.getChannel().write( tc.convert(tag, availableRoom-neededRoom ) );
117
118 } else {
119
120
121 FileChannel fc = raf.getChannel();
122 b = new byte[42];
123 raf.readFully(b);
124 raf.seek(availableRoom+42);
125
126 FileChannel tempFC = rafTemp.getChannel();
127
128 rafTemp.write( b );
129
130 for(int i = 0; i<metadataBlockApplication.size(); i++) {
131 rafTemp.write( ((MetadataBlock) metadataBlockApplication.elementAt(i)).getHeader().getBytes());
132 rafTemp.write( ((MetadataBlock) metadataBlockApplication.elementAt(i)).getData().getBytes());
133 }
134
135 for(int i = 0; i<metadataBlockSeekTable.size(); i++) {
136 rafTemp.write( ((MetadataBlock) metadataBlockSeekTable.elementAt(i)).getHeader().getBytes());
137 rafTemp.write( ((MetadataBlock) metadataBlockSeekTable.elementAt(i)).getData().getBytes());
138 }
139
140 for(int i = 0; i<metadataBlockCueSheet.size(); i++) {
141 rafTemp.write( ((MetadataBlock) metadataBlockCueSheet.elementAt(i)).getHeader().getBytes());
142 rafTemp.write( ((MetadataBlock) metadataBlockCueSheet.elementAt(i)).getData().getBytes());
143 }
144
145 rafTemp.write( tc.convert(tag, FlacTagCreator.DEFAULT_PADDING ).array());
146
147 tempFC.transferFrom( fc, tempFC.position(), fc.size() );
148 }
149 }
150
151 private int computeAvailableRoom() {
152 int length = 0;
153
154 for(int i = 0; i<metadataBlockApplication.size(); i++)
155 length += ((MetadataBlock) metadataBlockApplication.elementAt(i)).getLength();
156
157 for(int i = 0; i<metadataBlockSeekTable.size(); i++)
158 length += ((MetadataBlock) metadataBlockSeekTable.elementAt(i)).getLength();
159
160 for(int i = 0; i<metadataBlockCueSheet.size(); i++)
161 length += ((MetadataBlock) metadataBlockCueSheet.elementAt(i)).getLength();
162
163 for(int i = 0; i<metadataBlockPadding.size(); i++)
164 length += ((MetadataBlock) metadataBlockPadding.elementAt(i)).getLength();
165
166 return length;
167 }
168
169 private int computeNeededRoom() {
170 int length = 0;
171
172 for(int i = 0; i<metadataBlockApplication.size(); i++)
173 length += ((MetadataBlock) metadataBlockApplication.elementAt(i)).getLength();
174
175 for(int i = 0; i<metadataBlockSeekTable.size(); i++)
176 length += ((MetadataBlock) metadataBlockSeekTable.elementAt(i)).getLength();
177
178 for(int i = 0; i<metadataBlockCueSheet.size(); i++)
179 length += ((MetadataBlock) metadataBlockCueSheet.elementAt(i)).getLength();
180
181 return length;
182 }
183
184
185 private void skipBlock(MetadataBlockHeader mbh, RandomAccessFile raf) throws IOException {
186 raf.seek(raf.getFilePointer()+mbh.getDataLength());
187 }
188
189
190 private void handlePadding(MetadataBlockHeader mbh, RandomAccessFile raf) throws IOException {
191 raf.seek(raf.getFilePointer()+mbh.getDataLength());
192
193 MetadataBlockData mbd = new MetadataBlockDataPadding( mbh.getDataLength() );
194 metadataBlockPadding.add(new MetadataBlock(mbh, mbd));
195 }
196
197 private void handleApplication(MetadataBlockHeader mbh, RandomAccessFile raf) throws IOException {
198 byte[] b = new byte[mbh.getDataLength()];
199 raf.readFully(b);
200
201 MetadataBlockData mbd = new MetadataBlockDataApplication(b);
202 metadataBlockApplication.add(new MetadataBlock(mbh, mbd));
203 }
204
205 private void handleSeekTable(MetadataBlockHeader mbh, RandomAccessFile raf) throws IOException {
206 byte[] b = new byte[mbh.getDataLength()];
207 raf.readFully(b);
208
209 MetadataBlockData mbd = new MetadataBlockDataSeekTable(b);
210 metadataBlockSeekTable.add(new MetadataBlock(mbh, mbd));
211 }
212
213 private void handleCueSheet(MetadataBlockHeader mbh, RandomAccessFile raf) throws IOException {
214 byte[] b = new byte[mbh.getDataLength()];
215 raf.readFully(b);
216
217 MetadataBlockData mbd = new MetadataBlockDataCueSheet(b);
218 metadataBlockCueSheet.add(new MetadataBlock(mbh, mbd));
219 }
220
221 }
222