5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package com.sun.media.sound; 26 27 import java.io.File; 28 import java.io.FileNotFoundException; 29 import java.io.IOException; 30 import java.io.OutputStream; 31 import java.io.RandomAccessFile; 32 33 /** 34 * Resource Interchange File Format (RIFF) stream encoder. 35 * 36 * @author Karl Helgason 37 */ 38 public final class RIFFWriter extends OutputStream { 39 40 private interface RandomAccessWriter { 41 42 public void seek(long chunksizepointer) throws IOException; 43 44 public long getPointer() throws IOException; 45 46 public void close() throws IOException; 47 48 public void write(int b) throws IOException; 49 50 public void write(byte[] b, int off, int len) throws IOException; 51 52 public void write(byte[] bytes) throws IOException; 53 54 public long length() throws IOException; 55 56 public void setLength(long i) throws IOException; 57 } 58 59 private static class RandomAccessFileWriter implements RandomAccessWriter { 60 61 RandomAccessFile raf; 62 63 RandomAccessFileWriter(File file) throws FileNotFoundException { 64 this.raf = new RandomAccessFile(file, "rw"); 65 } 66 67 RandomAccessFileWriter(String name) throws FileNotFoundException { 68 this.raf = new RandomAccessFile(name, "rw"); 69 } 70 71 public void seek(long chunksizepointer) throws IOException { 72 raf.seek(chunksizepointer); 73 } 74 75 public long getPointer() throws IOException { 76 return raf.getFilePointer(); 77 } 78 79 public void close() throws IOException { 80 raf.close(); 81 } 82 83 public void write(int b) throws IOException { 84 raf.write(b); 85 } 86 87 public void write(byte[] b, int off, int len) throws IOException { 88 raf.write(b, off, len); 89 } 90 91 public void write(byte[] bytes) throws IOException { 92 raf.write(bytes); 93 } 94 95 public long length() throws IOException { 96 return raf.length(); 97 } 98 99 public void setLength(long i) throws IOException { 100 raf.setLength(i); 101 } 102 } 103 104 private static class RandomAccessByteWriter implements RandomAccessWriter { 105 106 byte[] buff = new byte[32]; 107 int length = 0; 108 int pos = 0; 109 byte[] s; 110 final OutputStream stream; 111 112 RandomAccessByteWriter(OutputStream stream) { 113 this.stream = stream; 114 } 115 116 public void seek(long chunksizepointer) throws IOException { 117 pos = (int) chunksizepointer; 118 } 119 120 public long getPointer() throws IOException { 121 return pos; 122 } 123 124 public void close() throws IOException { 125 stream.write(buff, 0, length); 126 stream.close(); 127 } 128 129 public void write(int b) throws IOException { 130 if (s == null) 131 s = new byte[1]; 132 s[0] = (byte)b; 133 write(s, 0, 1); 134 } 135 136 public void write(byte[] b, int off, int len) throws IOException { 137 int newsize = pos + len; 138 if (newsize > length) 139 setLength(newsize); 140 int end = off + len; 141 for (int i = off; i < end; i++) { 142 buff[pos++] = b[i]; 143 } 144 } 145 146 public void write(byte[] bytes) throws IOException { 147 write(bytes, 0, bytes.length); 148 } 149 150 public long length() throws IOException { 151 return length; 152 } 153 154 public void setLength(long i) throws IOException { 155 length = (int) i; 156 if (length > buff.length) { 157 int newlen = Math.max(buff.length << 1, length); 158 byte[] newbuff = new byte[newlen]; 159 System.arraycopy(buff, 0, newbuff, 0, buff.length); 160 buff = newbuff; 161 } 162 } 163 } 164 private int chunktype = 0; // 0=RIFF, 1=LIST; 2=CHUNK 165 private RandomAccessWriter raf; 166 private final long chunksizepointer; 167 private final long startpointer; 168 private RIFFWriter childchunk = null; 169 private boolean open = true; 170 private boolean writeoverride = false; 171 172 public RIFFWriter(String name, String format) throws IOException { 173 this(new RandomAccessFileWriter(name), format, 0); 206 raf.write((format + " ").substring(0, 4).getBytes("ascii")); 207 208 } 209 210 public void seek(long pos) throws IOException { 211 raf.seek(pos); 212 } 213 214 public long getFilePointer() throws IOException { 215 return raf.getPointer(); 216 } 217 218 public void setWriteOverride(boolean writeoverride) { 219 this.writeoverride = writeoverride; 220 } 221 222 public boolean getWriteOverride() { 223 return writeoverride; 224 } 225 226 public void close() throws IOException { 227 if (!open) 228 return; 229 if (childchunk != null) { 230 childchunk.close(); 231 childchunk = null; 232 } 233 234 int bakchunktype = chunktype; 235 long fpointer = raf.getPointer(); 236 raf.seek(chunksizepointer); 237 chunktype = 2; 238 writeUnsignedInt(fpointer - startpointer); 239 240 if (bakchunktype == 0) 241 raf.close(); 242 else 243 raf.seek(fpointer); 244 open = false; 245 raf = null; 246 } 247 248 public void write(int b) throws IOException { 249 if (!writeoverride) { 250 if (chunktype != 2) { 251 throw new IllegalArgumentException( 252 "Only chunks can write bytes!"); 253 } 254 if (childchunk != null) { 255 childchunk.close(); 256 childchunk = null; 257 } 258 } 259 raf.write(b); 260 } 261 262 public void write(byte b[], int off, int len) throws IOException { 263 if (!writeoverride) { 264 if (chunktype != 2) { 265 throw new IllegalArgumentException( 266 "Only chunks can write bytes!"); 267 } 268 if (childchunk != null) { 269 childchunk.close(); 270 childchunk = null; 271 } 272 } 273 raf.write(b, off, len); 274 } 275 276 public RIFFWriter writeList(String format) throws IOException { 277 if (chunktype == 2) { 278 throw new IllegalArgumentException( 279 "Only LIST and RIFF can write lists!"); 280 } 281 if (childchunk != null) { | 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.media.sound; 27 28 import java.io.File; 29 import java.io.FileNotFoundException; 30 import java.io.IOException; 31 import java.io.OutputStream; 32 import java.io.RandomAccessFile; 33 34 /** 35 * Resource Interchange File Format (RIFF) stream encoder. 36 * 37 * @author Karl Helgason 38 */ 39 public final class RIFFWriter extends OutputStream { 40 41 private interface RandomAccessWriter { 42 43 void seek(long chunksizepointer) throws IOException; 44 45 long getPointer() throws IOException; 46 47 void close() throws IOException; 48 49 void write(int b) throws IOException; 50 51 void write(byte[] b, int off, int len) throws IOException; 52 53 void write(byte[] bytes) throws IOException; 54 55 long length() throws IOException; 56 57 void setLength(long i) throws IOException; 58 } 59 60 private static class RandomAccessFileWriter implements RandomAccessWriter { 61 62 RandomAccessFile raf; 63 64 RandomAccessFileWriter(File file) throws FileNotFoundException { 65 this.raf = new RandomAccessFile(file, "rw"); 66 } 67 68 RandomAccessFileWriter(String name) throws FileNotFoundException { 69 this.raf = new RandomAccessFile(name, "rw"); 70 } 71 72 @Override 73 public void seek(long chunksizepointer) throws IOException { 74 raf.seek(chunksizepointer); 75 } 76 77 @Override 78 public long getPointer() throws IOException { 79 return raf.getFilePointer(); 80 } 81 82 @Override 83 public void close() throws IOException { 84 raf.close(); 85 } 86 87 @Override 88 public void write(int b) throws IOException { 89 raf.write(b); 90 } 91 92 @Override 93 public void write(byte[] b, int off, int len) throws IOException { 94 raf.write(b, off, len); 95 } 96 97 @Override 98 public void write(byte[] bytes) throws IOException { 99 raf.write(bytes); 100 } 101 102 @Override 103 public long length() throws IOException { 104 return raf.length(); 105 } 106 107 @Override 108 public void setLength(long i) throws IOException { 109 raf.setLength(i); 110 } 111 } 112 113 private static class RandomAccessByteWriter implements RandomAccessWriter { 114 115 byte[] buff = new byte[32]; 116 int length = 0; 117 int pos = 0; 118 byte[] s; 119 final OutputStream stream; 120 121 RandomAccessByteWriter(OutputStream stream) { 122 this.stream = stream; 123 } 124 125 @Override 126 public void seek(long chunksizepointer) throws IOException { 127 pos = (int) chunksizepointer; 128 } 129 130 @Override 131 public long getPointer() throws IOException { 132 return pos; 133 } 134 135 @Override 136 public void close() throws IOException { 137 stream.write(buff, 0, length); 138 stream.close(); 139 } 140 141 @Override 142 public void write(int b) throws IOException { 143 if (s == null) 144 s = new byte[1]; 145 s[0] = (byte)b; 146 write(s, 0, 1); 147 } 148 149 @Override 150 public void write(byte[] b, int off, int len) throws IOException { 151 int newsize = pos + len; 152 if (newsize > length) 153 setLength(newsize); 154 int end = off + len; 155 for (int i = off; i < end; i++) { 156 buff[pos++] = b[i]; 157 } 158 } 159 160 @Override 161 public void write(byte[] bytes) throws IOException { 162 write(bytes, 0, bytes.length); 163 } 164 165 @Override 166 public long length() throws IOException { 167 return length; 168 } 169 170 @Override 171 public void setLength(long i) throws IOException { 172 length = (int) i; 173 if (length > buff.length) { 174 int newlen = Math.max(buff.length << 1, length); 175 byte[] newbuff = new byte[newlen]; 176 System.arraycopy(buff, 0, newbuff, 0, buff.length); 177 buff = newbuff; 178 } 179 } 180 } 181 private int chunktype = 0; // 0=RIFF, 1=LIST; 2=CHUNK 182 private RandomAccessWriter raf; 183 private final long chunksizepointer; 184 private final long startpointer; 185 private RIFFWriter childchunk = null; 186 private boolean open = true; 187 private boolean writeoverride = false; 188 189 public RIFFWriter(String name, String format) throws IOException { 190 this(new RandomAccessFileWriter(name), format, 0); 223 raf.write((format + " ").substring(0, 4).getBytes("ascii")); 224 225 } 226 227 public void seek(long pos) throws IOException { 228 raf.seek(pos); 229 } 230 231 public long getFilePointer() throws IOException { 232 return raf.getPointer(); 233 } 234 235 public void setWriteOverride(boolean writeoverride) { 236 this.writeoverride = writeoverride; 237 } 238 239 public boolean getWriteOverride() { 240 return writeoverride; 241 } 242 243 @Override 244 public void close() throws IOException { 245 if (!open) 246 return; 247 if (childchunk != null) { 248 childchunk.close(); 249 childchunk = null; 250 } 251 252 int bakchunktype = chunktype; 253 long fpointer = raf.getPointer(); 254 raf.seek(chunksizepointer); 255 chunktype = 2; 256 writeUnsignedInt(fpointer - startpointer); 257 258 if (bakchunktype == 0) 259 raf.close(); 260 else 261 raf.seek(fpointer); 262 open = false; 263 raf = null; 264 } 265 266 @Override 267 public void write(int b) throws IOException { 268 if (!writeoverride) { 269 if (chunktype != 2) { 270 throw new IllegalArgumentException( 271 "Only chunks can write bytes!"); 272 } 273 if (childchunk != null) { 274 childchunk.close(); 275 childchunk = null; 276 } 277 } 278 raf.write(b); 279 } 280 281 @Override 282 public void write(byte b[], int off, int len) throws IOException { 283 if (!writeoverride) { 284 if (chunktype != 2) { 285 throw new IllegalArgumentException( 286 "Only chunks can write bytes!"); 287 } 288 if (childchunk != null) { 289 childchunk.close(); 290 childchunk = null; 291 } 292 } 293 raf.write(b, off, len); 294 } 295 296 public RIFFWriter writeList(String format) throws IOException { 297 if (chunktype == 2) { 298 throw new IllegalArgumentException( 299 "Only LIST and RIFF can write lists!"); 300 } 301 if (childchunk != null) { |