~ubuntu-branches/ubuntu/utopic/libjaudiotagger-java/utopic

« back to all changes in this revision

Viewing changes to src/org/jaudiotagger/audio/asf/io/AsfExtHeaderModifier.java

  • Committer: Bazaar Package Importer
  • Author(s): Varun Hiremath, Damien Raude-Morvan, Varun Hiremath
  • Date: 2009-04-01 19:17:56 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20090401191756-bygniim270guy7o1
Tags: 1.0.9-1
[ Damien Raude-Morvan ]
* New upstream release
* debian/watch: Use java.net repository (which contains new releases!)
* debian/control:
  - Build-Depends on default-jdk-builddep
  - Bump Standards-Version to 3.8.1 (no changes needed)
  - Change section to "java"
* debian/rules: use default-java as JAVA_HOME
* debina/orig-tar.{sh|excludes}: strip audio and others binary files from ZIP
* debian/build.xml:
  - compile with "nowarn" to keep build log readable
  - exclude LogFormatter from build (use com.sun classes)
* debian/ant.properties: new source directory is "src" in orig.tar.gz
* Add myself as Uploaders

[ Varun Hiremath ]
* Accept changes made by Damien Raude-Morvan (Closes: #522130)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package org.jaudiotagger.audio.asf.io;
 
2
 
 
3
import org.jaudiotagger.audio.asf.data.GUID;
 
4
import org.jaudiotagger.audio.asf.util.Utils;
 
5
 
 
6
import java.io.ByteArrayOutputStream;
 
7
import java.io.IOException;
 
8
import java.io.InputStream;
 
9
import java.io.OutputStream;
 
10
import java.math.BigInteger;
 
11
import java.util.ArrayList;
 
12
import java.util.HashSet;
 
13
import java.util.List;
 
14
import java.util.Set;
 
15
 
 
16
/**
 
17
 * This modifier manipulates an ASF header extension object. 
 
18
 * 
 
19
 * @author Christian Laireiter
 
20
 */
 
21
public class AsfExtHeaderModifier implements ChunkModifier
 
22
{
 
23
 
 
24
    /**
 
25
     * List of modifiers which are to be applied to contained chunks.
 
26
     */
 
27
    private final List<ChunkModifier> modifierList;
 
28
 
 
29
    /**
 
30
     * Creates an instance.<br>
 
31
     * 
 
32
     * @param modifiers modifiers to apply.
 
33
     */
 
34
    public AsfExtHeaderModifier(List<ChunkModifier> modifiers)
 
35
    {
 
36
        assert modifiers != null;
 
37
        this.modifierList = new ArrayList<ChunkModifier>(modifiers);
 
38
    }
 
39
 
 
40
    /**
 
41
     * Simply copies a chunk from <code>source</code> to <code>destination</code>.<br>
 
42
     * The method assumes, that the GUID has already been read and will write the provided one to
 
43
     * the destination.<br> 
 
44
     * The chunk length however will be read and used to determine the amount of bytes to copy.  
 
45
     * 
 
46
     * @param guid GUID of the current CHUNK.
 
47
     * @param source source of an ASF chunk, which is to be located at the chunk length field.
 
48
     * @param destination the destination to copy the chunk to.
 
49
     * @throws IOException on I/O errors.
 
50
     */
 
51
    private void copyChunk(GUID guid, InputStream source, OutputStream destination) throws IOException
 
52
    {
 
53
        long chunkSize = Utils.readUINT64(source);
 
54
        destination.write(guid.getBytes());
 
55
        Utils.writeUINT64(chunkSize, destination);
 
56
        Utils.copy(source, destination, chunkSize - 24);
 
57
    }
 
58
 
 
59
    /**
 
60
     * {@inheritDoc}
 
61
     */
 
62
    public boolean isApplicable(GUID guid)
 
63
    {
 
64
        return GUID.GUID_HEADER_EXTENSION.equals(guid);
 
65
    }
 
66
 
 
67
    /**
 
68
     * {@inheritDoc}
 
69
     */
 
70
    public ModificationResult modify(GUID guid, InputStream source, OutputStream destination) throws IOException
 
71
    {
 
72
        assert GUID.GUID_HEADER_EXTENSION.equals(guid);
 
73
 
 
74
        long difference = 0;
 
75
        final List<ChunkModifier> modders = new ArrayList<ChunkModifier>(this.modifierList);
 
76
        final Set<GUID> occuredGuids = new HashSet<GUID>();
 
77
        occuredGuids.add(guid);
 
78
 
 
79
        BigInteger chunkLen = Utils.readBig64(source);
 
80
        final GUID reserved1 = Utils.readGUID(source);
 
81
        final int reserved2 = Utils.readUINT16(source);
 
82
        final long dataSize = Utils.readUINT32(source);
 
83
 
 
84
        assert dataSize == 0 || dataSize >= 24;
 
85
        assert chunkLen.subtract(BigInteger.valueOf(46)).longValue() == dataSize;
 
86
 
 
87
        /*
 
88
         * Stream buffer for the chunk list
 
89
         */
 
90
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
 
91
        /*
 
92
         * Stream which counts read bytes. Dirty but quick way of implementing this.
 
93
         */
 
94
        final CountingInputStream cis = new CountingInputStream(source);
 
95
 
 
96
        while (cis.getReadCount() < dataSize)
 
97
        {
 
98
            // read GUID
 
99
            GUID curr = Utils.readGUID(cis);
 
100
            boolean handled = false;
 
101
            for (int i = 0; i < modders.size() && !handled; i++)
 
102
            {
 
103
                if (modders.get(i).isApplicable(curr))
 
104
                {
 
105
                    final ModificationResult modRes = modders.get(i).modify(curr, cis, bos);
 
106
                    difference += modRes.getByteDifference();
 
107
                    occuredGuids.addAll(modRes.getOccuredGUIDs());
 
108
                    modders.remove(i);
 
109
                    handled = true;
 
110
                }
 
111
            }
 
112
            if (!handled)
 
113
            {
 
114
                occuredGuids.add(curr);
 
115
                copyChunk(curr, cis, bos);
 
116
            }
 
117
        }
 
118
        // Now apply the left modifiers. 
 
119
        for (ChunkModifier curr : modders)
 
120
        {
 
121
            // chunks, which were not in the source file, will be added to the destination
 
122
            final ModificationResult result = curr.modify(null, null, bos);
 
123
            difference += result.getByteDifference();
 
124
            occuredGuids.addAll(result.getOccuredGUIDs());
 
125
        }
 
126
        destination.write(GUID.GUID_HEADER_EXTENSION.getBytes());
 
127
        Utils.writeUINT64(chunkLen.add(BigInteger.valueOf(difference)).longValue(), destination);
 
128
        destination.write(reserved1.getBytes());
 
129
        Utils.writeUINT16(reserved2, destination);
 
130
        Utils.writeUINT32(dataSize + difference, destination);
 
131
        destination.write(bos.toByteArray());
 
132
        return new ModificationResult(0, difference, occuredGuids);
 
133
    }
 
134
 
 
135
}