FileDocCategorySizeDatePackage
AsfFileWriter.javaAPI DocJaudiotagger 2.0.46171Wed Mar 30 16:11:52 BST 2011org.jaudiotagger.audio.asf

AsfFileWriter.java

/*
 * Entagged Audio Tag library
 * Copyright (c) 2004-2005 Christian Laireiter <liree@web.de>
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *  
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
package org.jaudiotagger.audio.asf;

import org.jaudiotagger.audio.asf.data.AsfHeader;
import org.jaudiotagger.audio.asf.data.ChunkContainer;
import org.jaudiotagger.audio.asf.data.MetadataContainer;
import org.jaudiotagger.audio.asf.io.*;
import org.jaudiotagger.tag.asf.AsfTag;
import org.jaudiotagger.audio.asf.util.TagConverter;
import org.jaudiotagger.audio.exceptions.CannotWriteException;
import org.jaudiotagger.audio.generic.AudioFileWriter;
import org.jaudiotagger.tag.Tag;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;

/**
 * This class writes given tags to ASF files containing WMA content. <br>
 * <br>
 * 
 * @author Christian Laireiter
 */
public class AsfFileWriter extends AudioFileWriter {

    /**
     * {@inheritDoc}
     */
    @Override
    protected void deleteTag(final RandomAccessFile raf,
            final RandomAccessFile tempRaf) throws CannotWriteException,
            IOException {
        writeTag(new AsfTag(true), raf, tempRaf);
    }

    private boolean[] searchExistence(final ChunkContainer container,
            final MetadataContainer[] metaContainers) {
        assert container != null;
        assert metaContainers != null;
        final boolean[] result = new boolean[metaContainers.length];
        for (int i = 0; i < result.length; i++) {
            result[i] = container.hasChunkByGUID(metaContainers[i]
                    .getContainerType().getContainerGUID());
        }
        return result;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void writeTag(final Tag tag, final RandomAccessFile raf,
            final RandomAccessFile rafTemp) throws CannotWriteException,
            IOException {
        /*
         * Since this implementation should not change the structure of the ASF
         * file (locations of content description chunks), we need to read the
         * content description chunk and the extended content description chunk
         * from the source file. In the second step we need to determine which
         * modifier (asf header or asf extended header) gets the appropriate
         * modifiers. The following policies are applied: if the source does not
         * contain any descriptor, the necessary descriptors are appended to the
         * header object.
         * 
         * if the source contains only one descriptor in the header extension
         * object, and the other type is needed as well, the other one will be
         * put into the header extension object.
         * 
         * for each descriptor type, if an object is found, an updater will be
         * configured.
         */
        final AsfHeader sourceHeader = AsfHeaderReader.readTagHeader(raf);
        raf.seek(0); // Reset for the streamer
        /*
         * Now createField modifiers for metadata descriptor and extended content
         * descriptor as implied by the given Tag.
         */
        // TODO not convinced that we need to copy fields here
        final AsfTag copy = new AsfTag(tag, true);
        final MetadataContainer[] distribution = TagConverter
                .distributeMetadata(copy);
        final boolean[] existHeader = searchExistence(sourceHeader,
                distribution);
        final boolean[] existExtHeader = searchExistence(sourceHeader
                .getExtendedHeader(), distribution);
        // Modifiers for the asf header object
        final List<ChunkModifier> headerModifier = new ArrayList<ChunkModifier>();
        // Modifiers for the asf header extension object
        final List<ChunkModifier> extHeaderModifier = new ArrayList<ChunkModifier>();
        for (int i = 0; i < distribution.length; i++) {
            final WriteableChunkModifer modifier = new WriteableChunkModifer(
                    distribution[i]);
            if (existHeader[i]) {
                // Will remove or modify chunks in ASF header
                headerModifier.add(modifier);
            } else if (existExtHeader[i]) {
                // Will remove or modify chunks in extended header
                extHeaderModifier.add(modifier);
            } else {
                // Objects (chunks) will be added here.
                if (i == 0 || i == 2 || i == 1) {
                    // Add content description and extended content description
                    // at header for maximum compatibility
                    headerModifier.add(modifier);
                } else {
                    // For now, the rest should be created at extended header
                    // since other positions aren't known.
                    extHeaderModifier.add(modifier);
                }
            }
        }
        // only addField an AsfExtHeaderModifier, if there is actually something to
        // change (performance)
        if (!extHeaderModifier.isEmpty()) {
            headerModifier.add(new AsfExtHeaderModifier(extHeaderModifier));
        }
        new AsfStreamer()
                .createModifiedCopy(new RandomAccessFileInputstream(raf),
                        new RandomAccessFileOutputStream(rafTemp),
                        headerModifier);
    }

}