FileDocCategorySizeDatePackage
AsfExtHeaderModifier.javaAPI DocJaudiotagger 2.0.45119Wed Mar 30 16:11:50 BST 2011org.jaudiotagger.audio.asf.io

AsfExtHeaderModifier

public class AsfExtHeaderModifier extends Object implements ChunkModifier
This modifier manipulates an ASF header extension object.
author
Christian Laireiter

Fields Summary
private final List
modifierList
List of modifiers which are to be applied to contained chunks.
Constructors Summary
public AsfExtHeaderModifier(List modifiers)
Creates an instance.

param
modifiers modifiers to apply.

        assert modifiers != null;
        this.modifierList = new ArrayList<ChunkModifier>(modifiers);
    
Methods Summary
private voidcopyChunk(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.

param
guid GUID of the current CHUNK.
param
source source of an ASF chunk, which is to be located at the chunk length field.
param
destination the destination to copy the chunk to.
throws
IOException on I/O errors.

        final long chunkSize = Utils.readUINT64(source);
        destination.write(guid.getBytes());
        Utils.writeUINT64(chunkSize, destination);
        Utils.copy(source, destination, chunkSize - 24);
    
public booleanisApplicable(org.jaudiotagger.audio.asf.data.GUID guid)
{@inheritDoc}

        return GUID.GUID_HEADER_EXTENSION.equals(guid);
    
public ModificationResultmodify(org.jaudiotagger.audio.asf.data.GUID guid, java.io.InputStream source, java.io.OutputStream destination)
{@inheritDoc}

        assert GUID.GUID_HEADER_EXTENSION.equals(guid);

        long difference = 0;
        final List<ChunkModifier> modders = new ArrayList<ChunkModifier>(
                this.modifierList);
        final Set<GUID> occuredGuids = new HashSet<GUID>();
        occuredGuids.add(guid);

        final BigInteger chunkLen = Utils.readBig64(source);
        final GUID reserved1 = Utils.readGUID(source);
        final int reserved2 = Utils.readUINT16(source);
        final long dataSize = Utils.readUINT32(source);

        assert dataSize == 0 || dataSize >= 24;
        assert chunkLen.subtract(BigInteger.valueOf(46)).longValue() == dataSize;

        /*
         * Stream buffer for the chunk list
         */
        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
        /*
         * Stream which counts read bytes. Dirty but quick way of implementing
         * this.
         */
        final CountingInputStream cis = new CountingInputStream(source);

        while (cis.getReadCount() < dataSize) {
            // read GUID
            final GUID curr = Utils.readGUID(cis);
            boolean handled = false;
            for (int i = 0; i < modders.size() && !handled; i++) {
                if (modders.get(i).isApplicable(curr)) {
                    final ModificationResult modRes = modders.get(i).modify(
                            curr, cis, bos);
                    difference += modRes.getByteDifference();
                    occuredGuids.addAll(modRes.getOccuredGUIDs());
                    modders.remove(i);
                    handled = true;
                }
            }
            if (!handled) {
                occuredGuids.add(curr);
                copyChunk(curr, cis, 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);
            difference += result.getByteDifference();
            occuredGuids.addAll(result.getOccuredGUIDs());
        }
        destination.write(GUID.GUID_HEADER_EXTENSION.getBytes());
        Utils.writeUINT64(chunkLen.add(BigInteger.valueOf(difference))
                .longValue(), destination);
        destination.write(reserved1.getBytes());
        Utils.writeUINT16(reserved2, destination);
        Utils.writeUINT32(dataSize + difference, destination);
        destination.write(bos.toByteArray());
        return new ModificationResult(0, difference, occuredGuids);