AsfStreamerpublic class AsfStreamer extends Object This class creates a modified copy of an ASF file.
|
Methods Summary |
---|
private void | copyChunk(org.jaudiotagger.audio.asf.data.GUID guid, java.io.InputStream source, java.io.OutputStream destination)Simply copies a chunk from source to
destination .
The method assumes, that the GUID has already been read and will write
the provided one to the destination.
The chunk length however will be read and used to determine the amount of
bytes to copy.
final long chunkSize = Utils.readUINT64(source);
destination.write(guid.getBytes());
Utils.writeUINT64(chunkSize, destination);
Utils.copy(source, destination, chunkSize - 24);
| public void | createModifiedCopy(java.io.InputStream source, java.io.OutputStream dest, java.util.List modifiers)Reads the source and applies the modifications provided by
the given modifiers , and puts it to dest .
Each {@linkplain ChunkModifier modifier} is used only once, so if one
should be used multiple times, it should be added multiple times into the
list.
final List<ChunkModifier> modders = new ArrayList<ChunkModifier>();
if (modifiers != null) {
modders.addAll(modifiers);
}
// Read and check ASF GUID
final GUID readGUID = Utils.readGUID(source);
if (GUID.GUID_HEADER.equals(readGUID)) {
// used to calculate differences
long totalDiff = 0;
long chunkDiff = 0;
// read header information
final long headerSize = Utils.readUINT64(source);
final long chunkCount = Utils.readUINT32(source);
final byte[] reserved = new byte[2];
reserved[0] = (byte) (source.read() & 0xFF);
reserved[1] = (byte) (source.read() & 0xFF);
/*
* bos will get all unmodified and modified header chunks. This is
* necessary, because the header chunk (and file properties chunk)
* need to be adjusted but are written in front of the others.
*/
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
// fileHeader will get the binary representation of the file
// properties chunk, without GUID
byte[] fileHeader = null;
// Iterate through all chunks
for (long i = 0; i < chunkCount; i++) {
// Read GUID
final GUID curr = Utils.readGUID(source);
// special case for file properties chunk
if (GUID.GUID_FILE.equals(curr)) {
final ByteArrayOutputStream tmp = new ByteArrayOutputStream();
final long size = Utils.readUINT64(source);
Utils.writeUINT64(size, tmp);
Utils.copy(source, tmp, size - 24);
fileHeader = tmp.toByteArray();
} else {
/*
* Now look for ChunkModifier objects which modify the
* current chunk
*/
boolean handled = false;
for (int j = 0; j < modders.size() && !handled; j++) {
if (modders.get(j).isApplicable(curr)) {
// alter current chunk
final ModificationResult result = modders.get(j)
.modify(curr, source, bos);
// remember size differences.
chunkDiff += result.getChunkCountDifference();
totalDiff += result.getByteDifference();
// remove current modifier from index.
modders.remove(j);
handled = true;
}
}
if (!handled) {
// copy chunks which are not modified.
copyChunk(curr, source, bos);
}
}
}
// Now apply the left modifiers.
for (final ChunkModifier curr : modders) {
// chunks, which were not in the source file, will be added to
// the destination
final ModificationResult result = curr.modify(null, null, bos);
chunkDiff += result.getChunkCountDifference();
totalDiff += result.getByteDifference();
}
/*
* Now all header objects have been read or manipulated and stored
* in the internal buffer (bos).
*/
// write ASF GUID
dest.write(readGUID.getBytes());
// write altered header object size
Utils.writeUINT64(headerSize + totalDiff, dest);
// write altered number of chunks
Utils.writeUINT32(chunkCount + chunkDiff, dest);
// write the reserved 2 bytes (0x01,0x02).
dest.write(reserved);
// write the new file header
modifyFileHeader(new ByteArrayInputStream(fileHeader), dest,
totalDiff);
// write the header objects (chunks)
dest.write(bos.toByteArray());
// copy the rest of the file (data and index)
Utils.flush(source, dest);
} else {
throw new IllegalArgumentException("No ASF header object.");
}
| private void | modifyFileHeader(java.io.InputStream source, java.io.OutputStream destination, long fileSizeDiff)This is a slight variation of
{@link #copyChunk(GUID, InputStream, OutputStream)}, it only handles file
property chunks correctly.
The copied chunk will have the file size field modified by the given
fileSizeDiff value.
destination.write(GUID.GUID_FILE.getBytes());
final long chunkSize = Utils.readUINT64(source);
Utils.writeUINT64(chunkSize, destination);
destination.write(Utils.readGUID(source).getBytes());
final long fileSize = Utils.readUINT64(source);
Utils.writeUINT64(fileSize + fileSizeDiff, destination);
Utils.copy(source, destination, chunkSize - 48);
|
|