diff --git a/buildSrc/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/buildSrc/src/main/kotlin/Versions.kt index c15ac7b7..cb42e0a8 100644 --- a/buildSrc/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/buildSrc/src/main/kotlin/Versions.kt @@ -140,6 +140,7 @@ object Extras { const val youtubeDownloader = "com.shabinder.downloader:youtube-api-dl:0.1" //Local Maven const val fuzzyWuzzy = "me.xdrop:fuzzywuzzy:1.3.1" const val mp3agic = "com.mpatric:mp3agic:0.9.0" + const val jaudioTagger = "com.github.Shabinder:JAudioTagger-Android:1.0" const val kermit = "co.touchlab:kermit:${Versions.kermit}" object Android { val razorpay = "com.razorpay:checkout:1.6.5" diff --git a/common/dependency-injection/build.gradle.kts b/common/dependency-injection/build.gradle.kts index dcd0922c..376b63d6 100644 --- a/common/dependency-injection/build.gradle.kts +++ b/common/dependency-injection/build.gradle.kts @@ -52,7 +52,7 @@ kotlin { implementation(Extras.Android.fetch) implementation(Extras.Android.razorpay) api(Extras.mp3agic) - api(project(":jaudiotagger")) + api(Extras.jaudioTagger) // api(files("$rootDir/libs/mobile-ffmpeg.aar")) } } @@ -62,7 +62,7 @@ kotlin { implementation(Ktor.clientApache) implementation(Ktor.slf4j) api(Extras.mp3agic) - api(project(":jaudiotagger")) + api(Extras.jaudioTagger) } } jsMain { diff --git a/jaudiotagger/.gitignore b/jaudiotagger/.gitignore deleted file mode 100644 index 42afabfd..00000000 --- a/jaudiotagger/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build \ No newline at end of file diff --git a/jaudiotagger/build.gradle.kts b/jaudiotagger/build.gradle.kts deleted file mode 100644 index 6b082805..00000000 --- a/jaudiotagger/build.gradle.kts +++ /dev/null @@ -1,8 +0,0 @@ -plugins { - id("java-library") -} - -java { - sourceCompatibility = JavaVersion.VERSION_1_7 - targetCompatibility = JavaVersion.VERSION_1_7 -} \ No newline at end of file diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/FileConstants.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/FileConstants.java deleted file mode 100644 index 38a4a3b8..00000000 --- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/FileConstants.java +++ /dev/null @@ -1,61 +0,0 @@ -/** - * @author : Paul Taylor - * - * Version @version:$Id$ - * - * Jaudiotagger Copyright (C)2004,2005 - * - * 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, - * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Description: - */ -package com.mp3.jaudiotagger; - -/** - * Definitions of the bit used when reading file format from file - */ -public interface FileConstants -{ - /** - * defined for convenience - */ - int BIT7 = 0x80; - /** - * defined for convenience - */ - int BIT6 = 0x40; - /** - * defined for convenience - */ - int BIT5 = 0x20; - /** - * defined for convenience - */ - int BIT4 = 0x10; - /** - * defined for convenience - */ - int BIT3 = 0x08; - /** - * defined for convenience - */ - int BIT2 = 0x04; - /** - * defined for convenience - */ - int BIT1 = 0x02; - /** - * defined for convenience - */ - int BIT0 = 0x01; -} diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/StandardCharsets.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/StandardCharsets.java deleted file mode 100644 index dec92b24..00000000 --- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/StandardCharsets.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.mp3.jaudiotagger; - -import java.nio.charset.Charset; - -/** - * Constant definitions for the standard {@link Charset Charsets}. These - * charsets are guaranteed to be available on every implementation of the Java - * platform. - * - * @see Standard Charsets - * @since 1.7 - */ -public final class StandardCharsets { - - private StandardCharsets() { - throw new AssertionError("No com.mp3.jaudiotagger.StandardCharsets instances for you!"); - } - /** - * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the - * Unicode character set - */ - public static final Charset US_ASCII = Charset.forName("US-ASCII"); - /** - * ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1 - */ - public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); - /** - * Eight-bit UCS Transformation Format - */ - public static final Charset UTF_8 = Charset.forName("UTF-8"); - /** - * Sixteen-bit UCS Transformation Format, big-endian byte order - */ - public static final Charset UTF_16BE = Charset.forName("UTF-16BE"); - /** - * Sixteen-bit UCS Transformation Format, little-endian byte order - */ - public static final Charset UTF_16LE = Charset.forName("UTF-16LE"); - /** - * Sixteen-bit UCS Transformation Format, byte order identified by an - * optional byte-order mark - */ - public static final Charset UTF_16 = Charset.forName("UTF-16"); -} diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/AudioFile.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/AudioFile.java deleted file mode 100644 index 749a586e..00000000 --- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/AudioFile.java +++ /dev/null @@ -1,476 +0,0 @@ -package com.mp3.jaudiotagger.audio; - -import com.mp3.jaudiotagger.audio.dsf.Dsf; -import com.mp3.jaudiotagger.audio.exceptions.*; -import com.mp3.jaudiotagger.audio.flac.metadatablock.MetadataBlockDataPicture; -import com.mp3.jaudiotagger.audio.real.RealTag; -import com.mp3.jaudiotagger.logging.ErrorMessage; -import com.mp3.jaudiotagger.tag.Tag; -import com.mp3.jaudiotagger.tag.TagOptionSingleton; -import com.mp3.jaudiotagger.tag.aiff.AiffTag; -import com.mp3.jaudiotagger.tag.asf.AsfTag; -import com.mp3.jaudiotagger.tag.flac.FlacTag; -import com.mp3.jaudiotagger.tag.id3.AbstractID3v2Tag; -import com.mp3.jaudiotagger.tag.id3.ID3v22Tag; -import com.mp3.jaudiotagger.tag.id3.ID3v23Tag; -import com.mp3.jaudiotagger.tag.id3.ID3v24Tag; -import com.mp3.jaudiotagger.tag.mp4.Mp4Tag; -import com.mp3.jaudiotagger.tag.reference.ID3V2Version; -import com.mp3.jaudiotagger.tag.vorbiscomment.VorbisCommentTag; -import com.mp3.jaudiotagger.tag.wav.WavTag; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.RandomAccessFile; -import java.util.ArrayList; -import java.util.logging.Logger; - -/** - *
This is the main object manipulated by the user representing an audiofile, its properties and its tag. - *
The preferred way to obtain an AudioFile
is to use the AudioFileIO.read(File)
method.
- *
The AudioHeader
contains every properties associated with the file itself (no meta-data), like the bitrate, the sampling rate, the encoding audioHeaders, etc.
- *
To get the meta-data contained in this file you have to get the Tag
of this AudioFile
- *
- * @author Raphael Slinckx
- * @version $Id$
- * @see AudioFileIO
- * @see Tag
- * @since v0.01
- */
-public class AudioFile
-{
- //Logger
- public static Logger logger = Logger.getLogger("com.mp3.jaudiotagger.audio");
-
- /**
- *
- * The physical file that this instance represents.
- */
- protected File file;
-
- /**
- * The Audio header info
- */
- protected AudioHeader audioHeader;
-
- /**
- * The tag
- */
- protected Tag tag;
-
- /**
- * The tag
- */
- protected String extension;
-
- public AudioFile()
- {
-
- }
-
- /**
- *
These constructors are used by the different readers, users should not use them, but use the AudioFileIO.read(File)
method instead !.
- *
Create the AudioFile representing file f, the encoding audio headers and containing the tag - * - * @param f The file of the audio file - * @param audioHeader the encoding audioHeaders over this file - * @param tag the tag contained in this file or null if no tag exists - */ - public AudioFile(File f, AudioHeader audioHeader, Tag tag) - { - this.file = f; - this.audioHeader = audioHeader; - this.tag = tag; - } - - - /** - *
These constructors are used by the different readers, users should not use them, but use the AudioFileIO.read(File)
method instead !.
- *
Create the AudioFile representing file denoted by pathnames, the encoding audio Headers and containing the tag - * - * @param s The pathname of the audio file - * @param audioHeader the encoding audioHeaders over this file - * @param tag the tag contained in this file - */ - public AudioFile(String s, AudioHeader audioHeader, Tag tag) - { - this.file = new File(s); - this.audioHeader = audioHeader; - this.tag = tag; - } - - /** - *
Write the tag contained in this AudioFile in the actual file on the disk, this is the same as calling the AudioFileIO.write(this)
method.
- *
- * @throws NoWritePermissionsException if the file could not be written to due to file permissions
- * @throws CannotWriteException If the file could not be written/accessed, the extension wasn't recognized, or other IO error occured.
- * @see AudioFileIO
- */
- public void commit() throws CannotWriteException
- {
- AudioFileIO.write(this);
- }
-
- /**
- *
Delete any tags that exist in the fie , this is the same as calling the AudioFileIO.delete(this)
method.
- *
- * @throws CannotWriteException If the file could not be written/accessed, the extension wasn't recognized, or other IO error occured.
- * @see AudioFileIO
- */
- public void delete() throws CannotReadException, CannotWriteException
- {
- AudioFileIO.delete(this);
- }
-
- /**
- * Set the file to store the info in
- *
- * @param file
- */
- public void setFile(File file)
- {
- this.file = file;
- }
-
- /**
- * Retrieve the physical file
- *
- * @return
- */
- public File getFile()
- {
- return file;
- }
-
- /**
- * Set the file extension
- *
- * @param ext
- */
- public void setExt(String ext)
- {
- this.extension = ext;
- }
-
- /**
- * Retrieve the file extension
- *
- * @return
- */
- public String getExt()
- {
- return extension;
- }
-
- /**
- * Assign a tag to this audio file
- *
- * @param tag Tag to be assigned
- */
- public void setTag(Tag tag)
- {
- this.tag = tag;
- }
-
- /**
- * Return audio header information
- * @return
- */
- public AudioHeader getAudioHeader()
- {
- return audioHeader;
- }
-
- /**
- *
Returns the tag contained in this AudioFile, the Tag
contains any useful meta-data, like
- * artist, album, title, etc. If the file does not contain any tag the null is returned. Some audio formats do
- * not allow there to be no tag so in this case the reader would return an empty tag whereas for others such
- * as mp3 it is purely optional.
- *
- * @return Returns the tag contained in this AudioFile, or null if no tag exists.
- */
- public Tag getTag()
- {
- return tag;
- }
-
- /**
- *
Returns a multi-line string with the file path, the encoding audioHeader, and the tag contents.
- *
- * @return A multi-line string with the file path, the encoding audioHeader, and the tag contents.
- * TODO Maybe this can be changed ?
- */
- public String toString()
- {
- return "AudioFile " + getFile().getAbsolutePath()
- + " --------\n" + audioHeader.toString() + "\n" + ((tag == null) ? "" : tag.toString()) + "\n-------------------";
- }
-
- /**
- * Check does file exist
- *
- * @param file
- * @throws FileNotFoundException if file not found
- */
- public void checkFileExists(File file)throws FileNotFoundException
- {
- logger.config("Reading file:" + "path" + file.getPath() + ":abs:" + file.getAbsolutePath());
- if (!file.exists())
- {
- logger.severe("Unable to find:" + file.getPath());
- throw new FileNotFoundException(ErrorMessage.UNABLE_TO_FIND_FILE.getMsg(file.getPath()));
- }
- }
-
- /**
- * Checks the file is accessible with the correct permissions, otherwise exception occurs
- *
- * @param file
- * @param readOnly
- * @throws ReadOnlyFileException
- * @throws FileNotFoundException
- * @return
- */
- protected RandomAccessFile checkFilePermissions(File file, boolean readOnly) throws ReadOnlyFileException, FileNotFoundException, CannotReadException
- {
- RandomAccessFile newFile;
- checkFileExists(file);
-
- // Unless opened as readonly the file must be writable
- if (readOnly)
- {
- //May not even be readable
- if(!file.canRead())
- {
- logger.severe("Unable to read file:" + file.getPath());
- throw new NoReadPermissionsException(ErrorMessage.GENERAL_READ_FAILED_DO_NOT_HAVE_PERMISSION_TO_READ_FILE.getMsg(file.getPath()));
- }
- newFile = new RandomAccessFile(file, "r");
- }
- else
- {
- if (TagOptionSingleton.getInstance().isCheckIsWritable() && !file.canWrite())
- {
- throw new ReadOnlyFileException(ErrorMessage.NO_PERMISSIONS_TO_WRITE_TO_FILE.getMsg(file.getPath()));
- }
- newFile = new RandomAccessFile(file, "rw");
- }
- return newFile;
- }
-
- /**
- * Optional debugging method. Must override to do anything interesting.
- *
- * @return Empty string.
- */
- public String displayStructureAsXML()
- {
- return "";
- }
-
- /**
- * Optional debugging method. Must override to do anything interesting.
- *
- * @return
- */
- public String displayStructureAsPlainText()
- {
- return "";
- }
-
-
- /** Create Default Tag
- *
- * @return
- */
- public Tag createDefaultTag()
- {
- String extension = getExt();
- if(extension == null)
- {
- String fileName = file.getName();
- extension = fileName.substring(fileName.lastIndexOf('.') + 1);
- setExt(extension);
- }
- if(SupportedFileFormat.FLAC.getFilesuffix().equals(extension))
- {
- return new FlacTag(VorbisCommentTag.createNewTag(), new ArrayList< MetadataBlockDataPicture >());
- }
- else if(SupportedFileFormat.OGG.getFilesuffix().equals(extension))
- {
- return VorbisCommentTag.createNewTag();
- }
- else if(SupportedFileFormat.MP4.getFilesuffix().equals(extension))
- {
- return new Mp4Tag();
- }
- else if(SupportedFileFormat.M4A.getFilesuffix().equals(extension))
- {
- return new Mp4Tag();
- }
- else if(SupportedFileFormat.M4P.getFilesuffix().equals(extension))
- {
- return new Mp4Tag();
- }
- else if(SupportedFileFormat.WMA.getFilesuffix().equals(extension))
- {
- return new AsfTag();
- }
- else if(SupportedFileFormat.WAV.getFilesuffix().equals(extension))
- {
- return new WavTag(TagOptionSingleton.getInstance().getWavOptions());
- }
- else if(SupportedFileFormat.RA.getFilesuffix().equals(extension))
- {
- return new RealTag();
- }
- else if(SupportedFileFormat.RM.getFilesuffix().equals(extension))
- {
- return new RealTag();
- }
- else if(SupportedFileFormat.AIF.getFilesuffix().equals(extension))
- {
- return new AiffTag();
- }
- else if(SupportedFileFormat.AIFC.getFilesuffix().equals(extension))
- {
- return new AiffTag();
- }
- else if(SupportedFileFormat.AIFF.getFilesuffix().equals(extension))
- {
- return new AiffTag();
- }
- else if(SupportedFileFormat.DSF.getFilesuffix().equals(extension))
- {
- return Dsf.createDefaultTag();
- }
- else
- {
- throw new RuntimeException("Unable to create default tag for this file format");
- }
-
- }
-
- /**
- * Get the tag or if the file doesn't have one at all, create a default tag and return
- *
- * @return
- */
- public Tag getTagOrCreateDefault()
- {
- Tag tag = getTag();
- if(tag==null)
- {
- return createDefaultTag();
- }
- return tag;
- }
-
- /**
- * Get the tag or if the file doesn't have one at all, create a default tag and set it
- * as the tag of this file
- *
- * @return
- */
- public Tag getTagOrCreateAndSetDefault()
- {
- Tag tag = getTagOrCreateDefault();
- setTag(tag);
- return tag;
- }
-
- /**
- * Get the tag and convert to the default tag version or if the file doesn't have one at all, create a default tag
- * set as tag for this file
- *
- * Conversions are currently only necessary/available for formats that support ID3
- *
- * @return
- */
- public Tag getTagAndConvertOrCreateAndSetDefault()
- {
- Tag tag = getTagOrCreateDefault();
-
- /* TODO Currently only works for Dsf We need additional check here for Wav and Aif because they wrap the ID3 tag so never return
- * null for getTag() and the wrapper stores the location of the existing tag, would that be broken if tag set to something else
- */
- if(tag instanceof AbstractID3v2Tag)
- {
- Tag convertedTag = convertID3Tag((AbstractID3v2Tag)tag, TagOptionSingleton.getInstance().getID3V2Version());
- if(convertedTag!=null)
- {
- setTag(convertedTag);
- }
- else
- {
- setTag(tag);
- }
- }
- else
- {
- setTag(tag);
- }
- return getTag();
- }
-
- /**
- *
- * @param file
- * @return filename with audioFormat separator stripped off.
- */
- public static String getBaseFilename(File file)
- {
- int index=file.getName().toLowerCase().lastIndexOf(".");
- if(index>0)
- {
- return file.getName().substring(0,index);
- }
- return file.getName();
- }
-
- /**
- * If using ID3 format convert tag from current version to another as specified by id3V2Version,
- *
- * @return null if no conversion necessary
- */
- public AbstractID3v2Tag convertID3Tag(AbstractID3v2Tag tag, ID3V2Version id3V2Version)
- {
- if(tag instanceof ID3v24Tag)
- {
- switch(id3V2Version)
- {
- case ID3_V22:
- return new ID3v22Tag((ID3v24Tag)tag);
- case ID3_V23:
- return new ID3v23Tag((ID3v24Tag)tag);
- case ID3_V24:
- return null;
- }
- }
- else if(tag instanceof ID3v23Tag)
- {
- switch(id3V2Version)
- {
- case ID3_V22:
- return new ID3v22Tag((ID3v23Tag)tag);
- case ID3_V23:
- return null;
- case ID3_V24:
- return new ID3v24Tag((ID3v23Tag)tag);
- }
- }
- else if(tag instanceof ID3v22Tag)
- {
- switch(id3V2Version)
- {
- case ID3_V22:
- return null;
- case ID3_V23:
- return new ID3v23Tag((ID3v22Tag)tag);
- case ID3_V24:
- return new ID3v24Tag((ID3v22Tag)tag);
- }
- }
- return null;
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/AudioFileFilter.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/AudioFileFilter.java
deleted file mode 100644
index 4ba6ae08..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/AudioFileFilter.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2003-2005 Raphaël Slinckx This is a simple FileFilter that will only allow the file supported by this library.
- * It will also accept directories. An additional condition is that file must be readable (read permission) and
- * are not hidden (dot files, or hidden files)
- *
- * @author Raphael Slinckx
- * @version $Id$
- * @since v0.01
- */
-public class AudioFileFilter implements FileFilter
-{
- /**
- * allows Directories
- */
- private final boolean allowDirectories;
-
- public AudioFileFilter( boolean allowDirectories)
- {
- this.allowDirectories=allowDirectories;
- }
-
- public AudioFileFilter()
- {
- this(true);
- }
-
- /**
- * Check whether the given file meet the required conditions (supported by the library OR directory).
- * The File must also be readable and not hidden.
- *
- * @param f The file to test
- * @return a boolean indicating if the file is accepted or not
- */
- public boolean accept(File f)
- {
- if (f.isHidden() || !f.canRead())
- {
- return false;
- }
-
- if (f.isDirectory())
- {
- return allowDirectories;
- }
-
- String ext = Utils.getExtension(f);
-
- try
- {
- if (SupportedFileFormat.valueOf(ext.toUpperCase()) != null)
- {
- return true;
- }
- }
- catch(IllegalArgumentException iae)
- {
- //Not known enum value
- return false;
- }
- return false;
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/AudioFileIO.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/AudioFileIO.java
deleted file mode 100644
index ad46867c..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/AudioFileIO.java
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2003-2005 Raphaël Slinckx Contains info about the Audio Header
- */
-public interface AudioHeader
-{
- /**
- * @return the audio file type
- */
- public abstract String getEncodingType();
-
- /**
- * @return the ByteRate of the Audio, this is the total average amount of bytes of data sampled per second
- */
- public Integer getByteRate();
-
-
-
- /**
- * @return the BitRate of the Audio, this is the amount of kilobits of data sampled per second
- */
- public String getBitRate();
-
- /**
- * @return bitRate as a number, this is the amount of kilobits of data sampled per second
- */
- public long getBitRateAsNumber();
-
-
- /**
- *
- * @return length of the audio data in bytes, exactly what this means depends on the audio format
- *
- * TODO currently only used by Wav/Aiff/Flac/Mp4
- */
- public Long getAudioDataLength();
-
-
- /**
- *
- * @return the location in the file where the audio samples start
- *
- * TODO currently only used by Wav/Aiff/Flac/Mp4
- */
- public Long getAudioDataStartPosition();
-
-
- /**
- *
- * @return the location in the file where the audio samples end
- *
- * TODO currently only used by Wav/Aiff/Flac/Mp4
- */
- public Long getAudioDataEndPosition();
-
-
- /**
- * @return the Sampling rate, the number of samples taken per second
- */
- public String getSampleRate();
-
- /**
- * @return he Sampling rate, the number of samples taken per second
- */
- public int getSampleRateAsNumber();
-
- /**
- * @return the format
- */
- public String getFormat();
-
- /**
- * @return the number of channels (i.e 1 = Mono, 2 = Stereo)
- */
- public String getChannels();
-
- /**
- * @return if the sampling bitRate is variable or constant
- */
- public boolean isVariableBitRate();
-
- /**
- * @return track length in seconds
- */
- public int getTrackLength();
-
- /**
- *
- * @return track length as float
- */
- public double getPreciseTrackLength();
-
- /**
- * @return the number of bits in each sample
- */
- public int getBitsPerSample();
-
- /**
- *
- * @return if the audio codec is lossless or lossy
- */
- public boolean isLossless();
-
- /**
- *
- * @return the total number of samples, this can usually be used in conjunction with the
- * sample rate to determine the track duration
- */
- public Long getNoOfSamples();
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/SupportedFileFormat.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/SupportedFileFormat.java
deleted file mode 100644
index fd138a92..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/SupportedFileFormat.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.mp3.jaudiotagger.audio;
-
-/**
- * Files formats currently supported by Library.
- * Each enum value is associated with a file suffix (extension).
- */
-public enum SupportedFileFormat
-{
- OGG("ogg"),
- MP3("mp3"),
- FLAC("flac"),
- MP4("mp4"),
- M4A("m4a"),
- M4P("m4p"),
- WMA("wma"),
- WAV("wav"),
- RA("ra"),
- RM("rm"),
- M4B("m4b"),
- AIF("aif"),
- AIFF("aiff"),
- AIFC("aifc"),
- DSF("dsf");
-
- private String filesuffix;
-
- /** Constructor for internal use by this enum.
- */
- SupportedFileFormat(String filesuffix)
- {
- this.filesuffix = filesuffix;
- }
-
- /**
- * Returns the file suffix (lower case without initial .) associated with the format.
- */
- public String getFilesuffix()
- {
- return filesuffix;
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/AiffAudioHeader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/AiffAudioHeader.java
deleted file mode 100644
index a1438c13..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/AiffAudioHeader.java
+++ /dev/null
@@ -1,233 +0,0 @@
-package com.mp3.jaudiotagger.audio.aiff;
-
-import com.mp3.jaudiotagger.audio.generic.GenericAudioHeader;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-/**
- * Non-"tag" metadata from the AIFF file. In general, read-only.
- */
-public class AiffAudioHeader extends GenericAudioHeader
-{
-
- public enum Endian
- {
- BIG_ENDIAN,
- LITTLE_ENDIAN
- }
-
- private AiffType fileType;
- private Date timestamp;
- private Endian endian;
- private String audioEncoding;
- private String name;
- private String author;
- private String copyright;
-
- private List
- * Aiff File Header always consists of
- * Deletes the given ID3-{@link Tag}/{@link Chunk} from the file by moving all following chunks up.
- * A comment consists of a time stamp, marker id, and a text count followed by text.
- *
- * {@code timeStamp} indicates when the comment was created. Units are the number of seconds
- * since January 1, 1904. (This time convention is the one used by the Macintosh. For procedures
- * that manipulate the time stamp, see The Operating System Utilities chapter in Inside Macintosh,
- * vol II). For a routine that will convert this to an Apple II GS/OS format time, please see
- * Apple II File Type Note for filetype 0xD8, aux type 0x0000.
- *
- * A comment can be linked to a marker. This allows applications to store long descriptions of
- * markers as a comment. If the comment is referring to a marker, then marker is the ID of that
- * marker. Otherwise, marker is zero, indicating that this comment is not linked to a marker.
- *
- * {@code count} is the length of the text that makes up the comment. This is a 16 bit quantity,
- * allowing much longer comments than would be available with a pstring.
- *
- * {@code text} contains the comment itself. This text must be padded with a byte at the end to
- * insure that it is an even number of bytes in length. This pad byte, if present, is not
- * included in count.
- *
- * The Copyright Chunk contains a copyright notice for the sound. text contains a date followed
- * by the copyright owner. The chunk ID '(c) ' serves as the copyright characters '©'. For example,
- * a Copyright Chunk containing the text "1988 Apple Computer, Inc." means "© 1988 Apple Computer, Inc."
- *
- * The Copyright Chunk is optional. No more than one Copyright Chunk may exist within a FORM AIFF.
- *
- * The Format Version Chunk contains a date field to indicate the format rules for an
- * AIFF-C specification. This will enable smoother future upgrades to this specification.
- *
- * ckID is always 'FVER'.
- *
- * {@code ckDataSize} is the size of the data portion of the chunk, in bytes. It does not
- * include the 8 bytes used by ckID and ckDataSize. For this Chunk, ckDataSize has a value of 4.
- *
- * {@code timeStamp} indicates when the format version for the AIFF-C file was created.
- * Units are the number of seconds since January 1, 1904. (This time convention is the one
- * used by the Macintosh. For procedures that manipulate the time stamp, see The Operating
- * System Utilities chapter in Inside Macintosh, vol II ). For a routine that will convert
- * this to an Apple II GS/OS format time, please see Apple II File Type Note for filetype
- * 0xD8, aux type 0x0000.
- *
- * The Format Version Chunk is required. One and only one Format Version Chunk must appear in a FORM AIFC.
- *
- * However this method requires a contiguous amount of memory equal to the size of the audio to be available and this
- * can cause a failure on low memory systems, so no longer used.
- *
- * @param tag
- * @param fc
- * @param blockInfo
- * @param flacStream
- * @param availableRoom
- * @throws IOException
- * @throws UnsupportedEncodingException
- */
- private void insertUsingDirectBuffer(File file, Tag tag, FileChannel fc, MetadataBlockInfo blockInfo, FlacStreamReader flacStream, int availableRoom) throws IOException {
- //Find end of metadata blocks (start of Audio), i.e start of Flac + 4 bytes for 'fLaC', 4 bytes for streaminfo header and
- //34 bytes for streaminfo and then size of all the other existing blocks
- fc.position(flacStream.getStartOfFlacInFile()
- + FlacStreamReader.FLAC_STREAM_IDENTIFIER_LENGTH
- + MetadataBlockHeader.HEADER_LENGTH
- + MetadataBlockDataStreamInfo.STREAM_INFO_DATA_LENGTH
- + availableRoom);
-
- //And copy into Buffer, because direct buffer doesnt use heap
- ByteBuffer audioData = ByteBuffer.allocateDirect((int) (fc.size() - fc.position()));
- fc.read(audioData);
- audioData.flip();
-
- //Jump over Id3 (if exists) Flac Header
- fc.position(flacStream.getStartOfFlacInFile() + FlacStreamReader.FLAC_STREAM_IDENTIFIER_LENGTH);
- writeOtherMetadataBlocks(fc, blockInfo);
-
- //Write tag (and add some default padding)
- fc.write(tc.convert(tag, FlacTagCreator.DEFAULT_PADDING));
-
- //Write Audio
- fc.write(audioData);
- }
-
-
- /**
- * Insert metadata into space that is not large enough
- *
- * We do this by reading/writing chunks of data allowing it to work on low memory systems
- *
- * Chunk size defined by TagOptionSingleton.getInstance().getWriteChunkSize()
- *
- * @param tag
- * @param fc
- * @param blockInfo
- * @param flacStream
- * @param neededRoom
- * @param availableRoom
- * @throws IOException
- * @throws UnsupportedEncodingException
- */
- private void insertUsingChunks(File file, Tag tag, FileChannel fc, MetadataBlockInfo blockInfo, FlacStreamReader flacStream, int neededRoom, int availableRoom) throws IOException, UnsupportedEncodingException {
- long originalFileSize = fc.size();
-
- //Find end of metadata blocks (start of Audio), i.e start of Flac + 4 bytes for 'fLaC', 4 bytes for streaminfo header and
- //34 bytes for streaminfo and then size of all the other existing blocks
- long audioStart = flacStream.getStartOfFlacInFile()
- + FlacStreamReader.FLAC_STREAM_IDENTIFIER_LENGTH
- + MetadataBlockHeader.HEADER_LENGTH
- + MetadataBlockDataStreamInfo.STREAM_INFO_DATA_LENGTH
- + availableRoom;
-
- //Extra Space Required for larger metadata block
- int extraSpaceRequired = neededRoom - availableRoom;
- logger.config(file + " Audio needs shifting:" + extraSpaceRequired);
-
- //ChunkSize must be at least as large as the extra space required to write the metadata
- int chunkSize = (int) TagOptionSingleton.getInstance().getWriteChunkSize();
- if (chunkSize < extraSpaceRequired) {
- chunkSize = extraSpaceRequired;
- }
-
- Queue
- * But this is problematic on 32bit systems for large flac files may not be able to map a contiguous address space large enough
- * for a large audio size , so no longer used since better to go straight to using chunks
- *
- * @param tag
- * @param fc
- * @param blockInfo
- * @param flacStream
- * @param neededRoom
- * @param availableRoom
- * @throws IOException
- * @throws UnsupportedEncodingException
- */
- private void insertTagAndShift(File file, Tag tag, FileChannel fc, MetadataBlockInfo blockInfo, FlacStreamReader flacStream, int neededRoom, int availableRoom) throws IOException, UnsupportedEncodingException {
- int headerLength = flacStream.getStartOfFlacInFile() + FlacStreamReader.FLAC_STREAM_IDENTIFIER_LENGTH + MetadataBlockHeader.HEADER_LENGTH // this should be the length of the block header for the stream info
- + MetadataBlockDataStreamInfo.STREAM_INFO_DATA_LENGTH;
- long targetSizeBeforeAudioData = headerLength + neededRoom + FlacTagCreator.DEFAULT_PADDING;
- long remainderTargetSize = fc.size() - (headerLength + availableRoom);
- long totalTargetSize = targetSizeBeforeAudioData + remainderTargetSize;
-
- MappedByteBuffer mappedFile = null;
- try {
- //Use ByteBuffer
- mappedFile = fc.map(MapMode.READ_WRITE, 0, totalTargetSize);
- insertTagAndShiftViaMappedByteBuffer(tag, mappedFile, fc, targetSizeBeforeAudioData, totalTargetSize, blockInfo, flacStream, neededRoom, availableRoom);
- } catch (IOException ioe) {
- //#175: Flac Map error on write
- if (mappedFile == null) {
- insertUsingChunks(file, tag, fc, blockInfo, flacStream, neededRoom + FlacTagCreator.DEFAULT_PADDING, availableRoom);
- } else {
- logger.log(Level.SEVERE, ioe.getMessage(), ioe);
- throw ioe;
- }
- }
- }
-
- /**
- * Insert new metadata into file by using memory mapped file
- *
- * But this is problematic on 32bit systems for large flac files may not be able to map a contiguous address space large enough
- * for a large audio size , so no longer used
- *
- * @param tag
- * @param mappedFile
- * @param fc
- * @param targetSizeBeforeAudioData
- * @param totalTargetSize
- * @param blockInfo
- * @param flacStream
- * @param neededRoom
- * @param availableRoom
- * @throws IOException
- * @throws UnsupportedEncodingException
- */
- private void insertTagAndShiftViaMappedByteBuffer(Tag tag, MappedByteBuffer mappedFile, FileChannel fc, long targetSizeBeforeAudioData, long totalTargetSize, MetadataBlockInfo blockInfo, FlacStreamReader flacStream, int neededRoom, int availableRoom) throws IOException, UnsupportedEncodingException {
- //Find end of metadata blacks (start of Audio)
- int currentEndOfFilePosition = safeLongToInt(fc.size());
- /*
- * First shift data to the 'right' of the tag to the end of the file, whose position is currentEndOfTagsPosition
- */
- int currentEndOfTagsPosition = safeLongToInt((targetSizeBeforeAudioData - FlacTagCreator.DEFAULT_PADDING) - neededRoom + availableRoom);
- int lengthDiff = safeLongToInt(totalTargetSize - currentEndOfFilePosition);
- final int BLOCK_SIZE = safeLongToInt(TagOptionSingleton.getInstance().getWriteChunkSize());
- int currentPos = currentEndOfFilePosition - BLOCK_SIZE;
- byte[] buffer = new byte[BLOCK_SIZE];
- for (; currentPos >= currentEndOfTagsPosition; currentPos -= BLOCK_SIZE) {
- mappedFile.position(currentPos);
- mappedFile.get(buffer, 0, BLOCK_SIZE);
- mappedFile.position(currentPos + lengthDiff);
- mappedFile.put(buffer, 0, BLOCK_SIZE);
- }
-
- /*
- * Final movement of start bytes. This also covers cases where BLOCK_SIZE is larger than the audio data
- */
- int remainder = (currentPos + BLOCK_SIZE) - currentEndOfTagsPosition;
- if (remainder > 0) {
- mappedFile.position(currentEndOfTagsPosition);
- mappedFile.get(buffer, 0, remainder);
- mappedFile.position(currentEndOfTagsPosition + lengthDiff);
- mappedFile.put(buffer, 0, remainder);
- }
-
- DirectByteBufferUtils.release(mappedFile);
-
- /* Now overwrite the tag */
- writeTags(tag, fc, blockInfo, flacStream);
- }
-
- private void writeTags(Tag tag, FileChannel fc, MetadataBlockInfo blockInfo, FlacStreamReader flacStream) throws IOException, UnsupportedEncodingException {
- //Jump over Id3 (if exists) Flac Header
- fc.position(flacStream.getStartOfFlacInFile() + FlacStreamReader.FLAC_STREAM_IDENTIFIER_LENGTH);
- writeOtherMetadataBlocks(fc, blockInfo);
-
- //Write tag (and add some default padding)
- fc.write(tc.convert(tag, FlacTagCreator.DEFAULT_PADDING));
- }
-
- /**
- * Write all metadata blocks except for the the actual tag metadata
- * A FLAC bitstream consists of the "fLaC" marker at the beginning of the stream,
- * followed by a mandatory metadata block (called the STREAMINFO block), any number of other metadata blocks,
- * then the audio frames.
- */
-public class MetadataBlock
-{
- private MetadataBlockHeader mbh;
- private MetadataBlockData mbd;
-
- public MetadataBlock(MetadataBlockHeader mbh, MetadataBlockData mbd)
- {
- this.mbh = mbh;
- this.mbd = mbd;
- }
-
- public MetadataBlockHeader getHeader()
- {
- return mbh;
- }
-
- public MetadataBlockData getData()
- {
- return mbd;
- }
-
- public int getLength()
- {
- return MetadataBlockHeader.HEADER_LENGTH + mbh.getDataLength();
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/flac/metadatablock/MetadataBlockData.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/flac/metadatablock/MetadataBlockData.java
deleted file mode 100644
index 3fb56768..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/flac/metadatablock/MetadataBlockData.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2003-2005 Raphaël Slinckx This block is for use by third-party applications. The only mandatory field is a 32-bit identifier.
- * This ID is granted upon request to an application by the FLAC maintainers. The remainder is of the block is defined
- * by the registered application.
- */
-public class MetadataBlockDataApplication implements MetadataBlockData
-{
- private ByteBuffer data;
-
- public MetadataBlockDataApplication(MetadataBlockHeader header, FileChannel fc) throws IOException
- {
- data = ByteBuffer.allocate(header.getDataLength());
- fc.read(data);
- data.flip();
- }
-
- public ByteBuffer getBytes()
- {
- return data;
- }
-
-
- public int getLength()
- {
- return data.limit();
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataCueSheet.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataCueSheet.java
deleted file mode 100644
index d0f91632..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataCueSheet.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2003-2005 Raphaël Slinckx This block is for storing various information that can be used in a cue sheet. It supports track and index points,
- * compatible with Red Book CD digital audio discs, as well as other CD-DA metadata such as media catalog number and
- * track ISRCs. The CUESHEET block is especially useful for backing up CD-DA discs, but it can be used as a general
- * purpose cueing mechanism for playback
- */
-public class MetadataBlockDataCueSheet implements MetadataBlockData
-{
- private ByteBuffer data;
-
- public MetadataBlockDataCueSheet(MetadataBlockHeader header, FileChannel fc) throws IOException
- {
- data = ByteBuffer.allocate(header.getDataLength());
- fc.read(data);
- data.flip();
- }
-
- public ByteBuffer getBytes()
- {
- return data;
- }
-
- public int getLength()
- {
- return data.limit();
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataPadding.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataPadding.java
deleted file mode 100644
index 13f7aa1f..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataPadding.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2003-2005 Raphaël Slinckx This is an optional block for storing seek points. It is possible to seek to any given sample in a FLAC stream
- * without a seek table, but the delay can be unpredictable since the bitrate may vary widely within a stream.
- * By adding seek points to a stream, this delay can be significantly reduced. Each seek point takes 18 bytes, so 1%
- * resolution within a stream adds less than 2k. There can be only one SEEKTABLE in a stream, but the table can have
- * any number of seek points. There is also a special 'placeholder' seekpoint which will be ignored by decoders but
- * which can be used to reserve space for future seek point insertion.
- */
-public class MetadataBlockDataSeekTable implements MetadataBlockData
-{
- private ByteBuffer data;
-
- public MetadataBlockDataSeekTable(MetadataBlockHeader header, FileChannel fc) throws IOException
- {
- data = ByteBuffer.allocate(header.getDataLength());
- fc.read(data);
- data.flip();
- }
-
- public ByteBuffer getBytes()
- {
- return data;
- }
-
-
- public int getLength()
- {
- return data.limit();
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataStreamInfo.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataStreamInfo.java
deleted file mode 100644
index 7e9e34f3..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataStreamInfo.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2003-2005 Raphaël Slinckx It will be notified on several occasions:
- * Transfers the content from {@code newFile} to a file named {@code originalFile}.
- * With regards to file identity (inode/fileIndex),
- * after execution, {@code originalFile} may be a completely new file or the same file as before execution, depending
- * on {@code reuseExistingOriginalFile}.
- *
- * Reusing the existing file may be slower, if both the temp file and the original file are located
- * in the same filesystem, because an actual copy is created instead of just a file rename.
- * If both files are on different filesystems, a copy is always needed — regardless of which method is used.
- *
- * Writes the contents of the given {@code newFile} to the given {@code originalFile},
- * overwriting the already existing content in {@code originalFile}.
- * This ensures that the file denoted by the abstract pathname {@code originalFile}
- * keeps the same Unix inode or Windows
- * fileIndex.
- *
- * If no errors occur, the method follows this approach:
- *
- * Replaces the original file with the new file in a way that changes the file identity.
- * In other words, the Unix inode or the Windows
- * fileIndex
- * of the resulting file with the name {@code originalFile} is not identical to the inode/fileIndex
- * of the file named {@code originalFile} before this method was called.
- *
- * If no errors occur, the method follows this approach:
- *
- * So if storing a number which only requires one byte it will be stored in the last
- * byte.
- *
- * Will fail if end - start >= 8, due to the limitations of the long type.
- */
- public static long getLongBE(final ByteBuffer b, final int start, final int end) {
- long number = 0;
- for (int i = 0; i < (end - start + 1); i++) {
- number += ((long) ((b.get(end - i) & 0xFF)) << i * 8);
- }
-
- return number;
- }
-
- /**
- * Computes a number whereby the 1st byte is the least significant and the last
- * byte is the most significant. This version doesn't take a length,
- * and it returns an int rather than a long.
- *
- * @param b The byte array. Maximum length for valid results is 4 bytes.
- */
- public static int getIntLE(final byte[] b) {
- return (int) getLongLE(ByteBuffer.wrap(b), 0, b.length - 1);
- }
-
- /**
- * Computes a number whereby the 1st byte is the least significant and the last
- * byte is the most significant. end - start must be no greater than 4.
- *
- * @param b The byte array
- * @param start The starting offset in b (b[offset]). The less
- * significant byte
- * @param end The end index (included) in b (b[end])
- * @return a int number represented by the byte sequence.
- */
- public static int getIntLE(final byte[] b, final int start, final int end) {
- return (int) getLongLE(ByteBuffer.wrap(b), start, end);
- }
-
- /**
- * Computes a number whereby the 1st byte is the most significant and the last
- * byte is the least significant.
- *
- * @param b The ByteBuffer
- * @param start The starting offset in b. The less
- * significant byte
- * @param end The end index (included) in b
- * @return an int number represented by the byte sequence.
- */
- public static int getIntBE(final ByteBuffer b, final int start, final int end) {
- return (int) getLongBE(b, start, end);
- }
-
- /**
- * Computes a number whereby the 1st byte is the most significant and the last
- * byte is the least significant.
- *
- * @param b The ByteBuffer
- * @param start The starting offset in b. The less
- * significant byte
- * @param end The end index (included) in b
- * @return a short number represented by the byte sequence.
- */
- public static short getShortBE(final ByteBuffer b, final int start, final int end) {
- return (short) getIntBE(b, start, end);
- }
-
- /**
- * Convert int to byte representation - Big Endian (as used by mp4).
- *
- * @param size
- * @return byte representation
- */
- public static byte[] getSizeBEInt32(final int size) {
- final byte[] b = new byte[4];
- b[0] = (byte) ((size >> 24) & 0xFF);
- b[1] = (byte) ((size >> 16) & 0xFF);
- b[2] = (byte) ((size >> 8) & 0xFF);
- b[3] = (byte) (size & 0xFF);
- return b;
- }
-
- /**
- * Convert short to byte representation - Big Endian (as used by mp4).
- *
- * @param size number to convert
- * @return byte representation
- */
- public static byte[] getSizeBEInt16(final short size) {
- final byte[] b = new byte[2];
- b[0] = (byte) ((size >> 8) & 0xFF);
- b[1] = (byte) (size & 0xFF);
- return b;
- }
-
- /**
- * Convert int to byte representation - Little Endian (as used by ogg vorbis).
- *
- * @param size number to convert
- * @return byte representation
- */
- public static byte[] getSizeLEInt32(final int size) {
- final byte[] b = new byte[4];
- b[0] = (byte) (size & 0xff);
- b[1] = (byte) ((size >>> 8) & 0xffL);
- b[2] = (byte) ((size >>> 16) & 0xffL);
- b[3] = (byte) ((size >>> 24) & 0xffL);
- return b;
- }
-
- /**
- * Convert a byte array to a Pascal string. The first byte is the byte count,
- * followed by that many active characters.
- *
- * @param bb
- * @return
- * @throws IOException
- */
- public static String readPascalString(final ByteBuffer bb) throws IOException {
- final int len = Utils.u(bb.get()); //Read as unsigned value
- final byte[] buf = new byte[len];
- bb.get(buf);
- return new String(buf, 0, len, ISO_8859_1);
- }
-
- /**
- * Reads bytes from a ByteBuffer as if they were encoded in the specified CharSet.
- *
- * @param buffer
- * @param offset offset from current position
- * @param length size of data to process
- * @param encoding
- * @return
- */
- public static String getString(final ByteBuffer buffer, final int offset, final int length, final Charset encoding) {
- final byte[] b = new byte[length];
- buffer.position(buffer.position() + offset);
- buffer.get(b);
- return new String(b, 0, length, encoding);
- }
-
- /**
- * Reads bytes from a ByteBuffer as if they were encoded in the specified CharSet.
- *
- * @param buffer
- * @param encoding
- * @return
- */
- public static String getString(final ByteBuffer buffer, final Charset encoding) {
- final byte[] b = new byte[buffer.remaining()];
- buffer.get(b);
- return new String(b, 0, b.length, encoding);
- }
-
- /**
- * Read a 32-bit big-endian unsigned integer using a DataInput.
- *
- * Reads 4 bytes but returns as long
- */
- public static long readUint32(final DataInput di) throws IOException {
- final byte[] buf8 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- di.readFully(buf8, 4, 4);
- return ByteBuffer.wrap(buf8).getLong();
- }
-
- /**
- * Read a 16-bit big-endian unsigned integer.
- *
- * Reads 2 bytes but returns as an integer
- */
- public static int readUint16(final DataInput di) throws IOException {
- final byte[] buf = {0x00, 0x00, 0x00, 0x00};
- di.readFully(buf, 2, 2);
- return ByteBuffer.wrap(buf).getInt();
- }
-
-
- /**
- * Read a string of a specified number of ASCII bytes.
- */
- public static String readString(final DataInput di, final int charsToRead) throws IOException {
- final byte[] buf = new byte[charsToRead];
- di.readFully(buf);
- return new String(buf, US_ASCII);
- }
-
- /**
- * Get a base for temp file, this should be long enough so that it easy to work out later what file the temp file
- * was created for if it is left lying round, but not ridiculously long as this can cause problems with max filename
- * limits and is not very useful.
- *
- * @param file
- * @return
- */
- public static String getBaseFilenameForTempFile(final File file) {
- final String filename = getMinBaseFilenameAllowedForTempFile(file);
- if (filename.length() <= MAX_BASE_TEMP_FILENAME_LENGTH) {
- return filename;
- }
- return filename.substring(0, MAX_BASE_TEMP_FILENAME_LENGTH);
- }
-
- /**
- * @param file
- * @return filename with audioformat separator stripped of, lengthened to ensure not too small for valid tempfile
- * creation.
- */
- public static String getMinBaseFilenameAllowedForTempFile(final File file) {
- final String s = AudioFile.getBaseFilename(file);
- if (s.length() >= 3) {
- return s;
- }
- if (s.length() == 1) {
- return s + "000";
- } else if (s.length() == 1) {
- return s + "00";
- } else if (s.length() == 2) {
- return s + "0";
- }
- return s;
- }
-
- /**
- * Rename file, and if normal rename fails, try copy and delete instead.
- *
- * @param fromFile
- * @param toFile
- * @return
- */
- public static boolean rename(final File fromFile, final File toFile) {
- logger.log(Level.CONFIG, "Renaming From:" + fromFile.getAbsolutePath() + " to " + toFile.getAbsolutePath());
-
- if (toFile.exists()) {
- logger.log(Level.SEVERE, "Destination File:" + toFile + " already exists");
- return false;
- }
-
- //Rename File, could fail because being used or because trying to rename over filesystems
- final boolean result = fromFile.renameTo(toFile);
- if (!result) {
- // Might be trying to rename over filesystem, so try copy and delete instead
- if (copy(fromFile, toFile)) {
- //If copy works but deletion of original file fails then it is because the file is being used
- //so we need to delete the file we have just created
- boolean deleteResult = fromFile.delete();
- if (!deleteResult) {
- logger.log(Level.SEVERE, "Unable to delete File:" + fromFile);
- toFile.delete();
- return false;
- }
- return true;
- } else {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Copy a File.
- *
- * ToDo refactor AbstractTestCase to use this method as it contains an exact duplicate.
- *
- * @param fromFile The existing File
- * @param toFile The new File
- * @return This useful to the library because it allows the encoder to be identified, full specification
- * can be found at http://gabriel.mp3-tech.org/mp3infotag.html
- *
- * Summarized here:
- * 4 bytes:LAME
- * 5 bytes:LAME Encoder Version
- * 1 bytes:VNR Method
- * 1 bytes:Lowpass filter value
- * 8 bytes:Replay Gain
- * 1 byte:Encoding Flags
- * 1 byte:minimal byte rate
- * 3 bytes:extra samples
- * 1 byte:Stereo Mode
- * 1 byte:MP3 Gain
- * 2 bytes:Surround Dound
- * 4 bytes:MusicLength
- * 2 bytes:Music CRC
- * 2 bytes:CRC Tag
- */
-public class LameFrame
-{
- public static final int LAME_HEADER_BUFFER_SIZE = 36;
- public static final int ENCODER_SIZE = 9; //Includes LAME ID
- public static final int LAME_ID_SIZE = 4;
- public static final String LAME_ID = "LAME";
- private String encoder;
-
- /**
- * Initilise a Lame Mpeg Frame
- * @param lameHeader
- */
- private LameFrame(ByteBuffer lameHeader)
- {
- encoder = Utils.getString(lameHeader, 0, ENCODER_SIZE, StandardCharsets.ISO_8859_1);
- }
-
- /**
- * Parse frame
- *
- * @param bb
- * @return frame or null if not exists
- */
- public static LameFrame parseLameFrame(ByteBuffer bb)
- {
- ByteBuffer lameHeader = bb.slice();
- String id = Utils.getString(lameHeader, 0, LAME_ID_SIZE, StandardCharsets.ISO_8859_1);
- lameHeader.rewind();
- if (id.equals(LAME_ID))
- {
- LameFrame lameFrame = new LameFrame(lameHeader);
- return lameFrame;
- }
- return null;
- }
-
- /**
- * @return encoder
- */
- public String getEncoder()
- {
- return encoder;
- }
-}
-
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/mp3/MP3AudioHeader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/mp3/MP3AudioHeader.java
deleted file mode 100644
index e10ed765..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/mp3/MP3AudioHeader.java
+++ /dev/null
@@ -1,871 +0,0 @@
-/**
- * @author : Paul Taylor
- *
- * Version @version:$Id$
- *
- * MusicTag Copyright (C)2003,2004
- *
- * 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,
- * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-package com.mp3.jaudiotagger.audio.mp3;
-
-import com.mp3.jaudiotagger.audio.AudioHeader;
-import com.mp3.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
-import com.mp3.jaudiotagger.logging.ErrorMessage;
-import com.mp3.jaudiotagger.logging.Hex;
-
-import java.io.EOFException;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * Represents the audio header of an MP3 File
- *
- * The audio header consists of a number of
- * audio frames. Because we are not trying to play the audio but only extract some information
- * regarding the audio we only need to read the first audio frames to ensure that we have correctly
- * identified them as audio frames and extracted the metadata we reuire.
- *
- * Start of Audio id 0xFF (11111111) and then second byte anded with 0xE0(11100000).
- * For example 2nd byte doesnt have to be 0xE0 is just has to have the top 3 signicant
- * bits set. For example 0xFB (11111011) is a common occurence of the second match. The 2nd byte
- * defines flags to indicate various mp3 values.
- *
- * Having found these two values we then read the header which comprises these two bytes plus a further
- * two to ensure this really is a MP3Header, sometimes the first frame is actually a dummy frame with summary information
- * held within about the whole file, typically using a Xing Header or LAme Header. This is most useful when the file
- * is variable bit rate, if the file is variable bit rate but does not use a summary header it will not be correctly
- * identified as a VBR frame and the track length will be incorrectly calculated. Strictly speaking MP3 means
- * Layer III file but MP2 Layer II), MP1 Layer I) and MPEG-2 files are sometimes used and named with
- * the .mp3 suffix so this library attempts to supports all these formats.
- */
-public class MP3AudioHeader implements AudioHeader
-{
- protected MPEGFrameHeader mp3FrameHeader;
- protected XingFrame mp3XingFrame;
- protected VbriFrame mp3VbriFrame;
-
- private Long audioDataStartPosition;
- private Long audioDataEndPosition;
-
- private long fileSize;
- private long startByte;
- private double timePerFrame;
- private double trackLength;
- private long numberOfFrames;
- private long numberOfFramesEstimate;
- private long bitrate;
- private String encoder = "";
-
- private static final SimpleDateFormat timeInFormat = new SimpleDateFormat("ss", Locale.UK);
- private static final SimpleDateFormat timeOutFormat = new SimpleDateFormat("mm:ss",Locale.UK);
- private static final SimpleDateFormat timeOutOverAnHourFormat = new SimpleDateFormat("kk:mm:ss",Locale.UK);
- private static final char isVbrIdentifier = '~';
- private static final int CONVERT_TO_KILOBITS = 1000;
- private static final String TYPE_MP3 = "mp3";
- private static final int CONVERTS_BYTE_TO_BITS = 8;
-
- //Logger
- public static Logger logger = Logger.getLogger("com.mp3.jaudiotagger.audio.mp3");
-
- /**
- * After testing the average location of the first MP3Header bit was at 5000 bytes so this is
- * why chosen as a default.
- */
- private final static int FILE_BUFFER_SIZE = 5000;
- private final static int MIN_BUFFER_REMAINING_REQUIRED = MPEGFrameHeader.HEADER_SIZE + XingFrame.MAX_BUFFER_SIZE_NEEDED_TO_READ_XING;
- private static final int NO_SECONDS_IN_HOUR = 3600;
-
- public MP3AudioHeader()
- {
- }
-
- /**
- * Search for the first MP3Header in the file
- *
- * The search starts from the start of the file, it is usually safer to use the alternative constructor that
- * allows you to provide the length of the tag header as a parameter so the tag can be skipped over.
- *
- * @param seekFile
- * @throws IOException
- * @throws InvalidAudioFrameException
- */
- public MP3AudioHeader(final File seekFile) throws IOException, InvalidAudioFrameException
- {
- if (!seek(seekFile, 0))
- {
- throw new InvalidAudioFrameException("No audio header found within" + seekFile.getName());
- }
- }
-
- /**
- * Search for the first MP3Header in the file
- *
- * Starts searching from location startByte, this is because there is likely to be an ID3TagHeader
- * before the start of the audio. If this tagHeader contains unsynchronized information there is a
- * possibility that it might be inaccurately identified as the start of the Audio data. Various checks
- * are done in this code to prevent this happening but it cannot be guaranteed.
- *
- * Of course if the startByte provided overstates the length of the tag header, this could mean the
- * start of the MP3AudioHeader is missed, further checks are done within the MP3 class to recognize
- * if this has occurred and take appropriate action.
- *
- * @param seekFile
- * @param startByte
- * @throws IOException
- * @throws InvalidAudioFrameException
- */
- public MP3AudioHeader(final File seekFile, long startByte) throws IOException, InvalidAudioFrameException
- {
- if (!seek(seekFile, startByte))
- {
- throw new InvalidAudioFrameException(ErrorMessage.NO_AUDIO_HEADER_FOUND.getMsg(seekFile.getName()));
- }
- }
-
- /**
- * Returns true if the first MP3 frame can be found for the MP3 file
- *
- * This is the first byte of music data and not the ID3 Tag Frame. *
- *
- * @param seekFile MP3 file to seek
- * @param startByte if there is an ID3v2tag we dont want to start reading from the start of the tag
- * @return true if the first MP3 frame can be found
- * @throws IOException on any I/O error
- */
- public boolean seek(final File seekFile, long startByte) throws IOException
- {
- //References to Xing/VRbi Header
- ByteBuffer header;
-
- //This is substantially faster than updating the filechannels position
- long filePointerCount;
-
- final FileInputStream fis = new FileInputStream(seekFile);
- final FileChannel fc = fis.getChannel();
-
- //Read into Byte Buffer in Chunks
- ByteBuffer bb = ByteBuffer.allocateDirect(FILE_BUFFER_SIZE);
-
- //Move FileChannel to the starting position (skipping over tag if any)
- fc.position(startByte);
-
- //Update filePointerCount
- filePointerCount = startByte;
-
- //Read from here into the byte buffer , doesn't move location of filepointer
- fc.read(bb, startByte);
- bb.flip();
-
- boolean syncFound = false;
- try
- {
- do
- {
- //TODO remaining() is quite an expensive operation, isn't there a way we can work this out without
- //interrogating the bytebuffer. Also this is rarely going to be true, and could be made less true
- //by increasing FILE_BUFFER_SIZE
- if (bb.remaining() <= MIN_BUFFER_REMAINING_REQUIRED)
- {
- bb.clear();
- fc.position(filePointerCount);
- fc.read(bb, fc.position());
- bb.flip();
- if (bb.limit() <= MIN_BUFFER_REMAINING_REQUIRED)
- {
- //No mp3 exists
- return false;
- }
- }
- //MP3File.logger.finest("fc:"+fc.position() + "bb"+bb.position());
- if (MPEGFrameHeader.isMPEGFrame(bb))
- {
- try
- {
- if (MP3AudioHeader.logger.isLoggable(Level.FINEST))
- {
- MP3AudioHeader.logger.finest("Found Possible header at:" + filePointerCount);
- }
-
- mp3FrameHeader = MPEGFrameHeader.parseMPEGHeader(bb);
- syncFound = true;
- //if(2==1) use this line when you want to test getting the next frame without using xing
-
- if ((header = XingFrame.isXingFrame(bb, mp3FrameHeader))!=null)
- {
- if (MP3AudioHeader.logger.isLoggable(Level.FINEST))
- {
- MP3AudioHeader.logger.finest("Found Possible XingHeader");
- }
- try
- {
- //Parses Xing frame without modifying position of main buffer
- mp3XingFrame = XingFrame.parseXingFrame(header);
- }
- catch (InvalidAudioFrameException ex)
- {
- // We Ignore because even if Xing Header is corrupted
- //doesn't mean file is corrupted
- }
- break;
- }
- else if ((header = VbriFrame.isVbriFrame(bb, mp3FrameHeader))!=null)
- {
- if (MP3AudioHeader.logger.isLoggable(Level.FINEST))
- {
- MP3AudioHeader.logger.finest("Found Possible VbriHeader");
- }
- try
- {
- //Parses Vbri frame without modifying position of main buffer
- mp3VbriFrame = VbriFrame.parseVBRIFrame(header);
- }
- catch (InvalidAudioFrameException ex)
- {
- // We Ignore because even if Vbri Header is corrupted
- //doesn't mean file is corrupted
- }
- break;
- }
- // There is a small but real chance that an unsynchronised ID3 Frame could fool the MPEG
- // Parser into thinking it was an MPEG Header. If this happens the chances of the next bytes
- // forming a Xing frame header are very remote. On the basis that most files these days have
- // Xing headers we do an additional check for when an apparent frame header has been found
- // but is not followed by a Xing Header:We check the next header this wont impose a large
- // overhead because wont apply to most Mpegs anyway ( Most likely to occur if audio
- // has an APIC frame which should have been unsynchronised but has not been) , or if the frame
- // has been encoded with as Unicode LE because these have a BOM of 0xFF 0xFE
- else
- {
- syncFound = isNextFrameValid(seekFile, filePointerCount, bb, fc);
- if (syncFound)
- {
- break;
- }
- }
-
- }
- catch (InvalidAudioFrameException ex)
- {
- // We Ignore because likely to be incorrect sync bits ,
- // will just continue in loop
- }
- }
-
- //TODO position() is quite an expensive operation, isn't there a way we can work this out without
- //interrogating the bytebuffer
- bb.position(bb.position() + 1);
- filePointerCount++;
-
-
- }
- while (!syncFound);
- }
- catch (EOFException ex)
- {
- MP3AudioHeader.logger.log(Level.WARNING, "Reached end of file without finding sync match", ex);
- syncFound = false;
- }
- catch (IOException iox)
- {
- MP3AudioHeader.logger.log(Level.SEVERE, "IOException occurred whilst trying to find sync", iox);
- syncFound = false;
- throw iox;
- }
- finally
- {
- if (fc != null)
- {
- fc.close();
- }
-
- if (fis != null)
- {
- fis.close();
- }
- }
-
- //Return to start of audio header
- if (MP3AudioHeader.logger.isLoggable(Level.FINEST))
- {
- MP3AudioHeader.logger.finer("Return found matching mp3 header starting at" + filePointerCount);
- }
- setFileSize(seekFile.length());
- setMp3StartByte(filePointerCount);
- setTimePerFrame();
- setNumberOfFrames();
- setTrackLength();
- setBitRate();
- setEncoder();
- /*if((filePointerCount - startByte )>0)
- {
- logger.severe(seekFile.getName()+"length:"+startByte+"Difference:"+(filePointerCount - startByte));
- }
- */
- return syncFound;
- }
-
- /**
- * Called in some circumstances to check the next frame to ensure we have the correct audio header
- *
- * @param seekFile
- * @param filePointerCount
- * @param bb
- * @param fc
- * @return true if frame is valid
- * @throws IOException
- */
- private boolean isNextFrameValid(File seekFile, long filePointerCount, ByteBuffer bb, FileChannel fc) throws IOException
- {
- if (MP3AudioHeader.logger.isLoggable(Level.FINEST))
- {
- MP3AudioHeader.logger.finer("Checking next frame" + seekFile.getName() + ":fpc:" + filePointerCount + "skipping to:" + (filePointerCount + mp3FrameHeader.getFrameLength()));
- }
- boolean result = false;
-
- int currentPosition = bb.position();
-
- //Our buffer is not large enough to fit in the whole of this frame, something must
- //have gone wrong because frames are not this large, so just return false
- //bad frame header
- if (mp3FrameHeader.getFrameLength() > (FILE_BUFFER_SIZE - MIN_BUFFER_REMAINING_REQUIRED))
- {
- MP3AudioHeader.logger.finer("Frame size is too large to be a frame:" + mp3FrameHeader.getFrameLength());
- return false;
- }
-
- //Check for end of buffer if not enough room get some more
- if (bb.remaining() <= MIN_BUFFER_REMAINING_REQUIRED + mp3FrameHeader.getFrameLength())
- {
- MP3AudioHeader.logger.finer("Buffer too small, need to reload, buffer size:" + bb.remaining());
- bb.clear();
- fc.position(filePointerCount);
- fc.read(bb, fc.position());
- bb.flip();
- //So now original buffer has been replaced, so set current position to start of buffer
- currentPosition = 0;
- //Not enough left
- if (bb.limit() <= MIN_BUFFER_REMAINING_REQUIRED)
- {
- //No mp3 exists
- MP3AudioHeader.logger.finer("Nearly at end of file, no header found:");
- return false;
- }
-
- //Still Not enough left for next alleged frame size so giving up
- if (bb.limit() <= MIN_BUFFER_REMAINING_REQUIRED + mp3FrameHeader.getFrameLength())
- {
- //No mp3 exists
- MP3AudioHeader.logger.finer("Nearly at end of file, no room for next frame, no header found:");
- return false;
- }
- }
-
- //Position bb to the start of the alleged next frame
- bb.position(bb.position() + mp3FrameHeader.getFrameLength());
- if (MPEGFrameHeader.isMPEGFrame(bb))
- {
- try
- {
- MPEGFrameHeader.parseMPEGHeader(bb);
- MP3AudioHeader.logger.finer("Check next frame confirms is an audio header ");
- result = true;
- }
- catch (InvalidAudioFrameException ex)
- {
- MP3AudioHeader.logger.finer("Check next frame has identified this is not an audio header");
- result = false;
- }
- }
- else
- {
- MP3AudioHeader.logger.finer("isMPEGFrame has identified this is not an audio header");
- }
- //Set back to the start of the previous frame
- bb.position(currentPosition);
- return result;
- }
-
- /**
- * Set the location of where the Audio file begins in the file
- *
- * @param startByte
- */
- protected void setMp3StartByte(final long startByte)
- {
- this.startByte = startByte;
- }
-
-
- /**
- * Returns the byte position of the first MP3 Frame that the
- *
- * AudioFile audioFile = AudioFileIO.read(new File("audiofile.mp3")); //Reads the given file.
- * int bitrate = audioFile.getBitrate(); //Retreives the bitrate of the file.
- * String artist = audioFile.getTag().getFirst(TagFieldKey.ARTIST); //Retreive the artist name.
- * audioFile.getTag().setGenre("Progressive Rock"); //Sets the genre to Prog. Rock, note the file on disk is still unmodified.
- * AudioFileIO.write(audioFile); //Write the modifications in the file on disk.
- *
- *
- *
- * You can also use the commit()
method defined for
- * AudioFile
s to achieve the same goal as
- * AudioFileIO.write(File)
, like this:
- *
- *
- *
- * AudioFile audioFile = AudioFileIO.read(new File("audiofile.mp3"));
- * audioFile.getTag().setGenre("Progressive Rock");
- * audioFile.commit(); //Write the modifications in the file on disk.
- *
- *
- *
- * @author Raphael Slinckx
- * @version $Id$
- * @see AudioFile
- * @see com.mp3.jaudiotagger.tag.Tag
- * @since v0.01
- */
-public class AudioFileIO
-{
-
- //Logger
- public static Logger logger = Logger.getLogger("com.mp3.jaudiotagger.audio");
-
- // !! Do not forget to also add new supported extensions to AudioFileFilter
- // !!
-
- /**
- * This field contains the default instance for static use.
- */
- private static AudioFileIO defaultInstance;
-
- /**
- *
- * Delete the tag, if any, contained in the given file.
- *
- *
- * @param f The file where the tag will be deleted
- * @throws CannotWriteException If the file could not be written/accessed, the extension
- * wasn't recognized, or other IO error occurred.
- * @throws CannotReadException
- */
- public static void delete(AudioFile f) throws CannotReadException, CannotWriteException
- {
- getDefaultAudioFileIO().deleteTag(f);
- }
-
- /**
- * This method returns the default instance for static use.
- *
- * @return The default instance.
- */
- public static AudioFileIO getDefaultAudioFileIO()
- {
- if (defaultInstance == null)
- {
- defaultInstance = new AudioFileIO();
- }
- return defaultInstance;
- }
-
- /**
- *
- * Read the tag contained in the given file.
- *
- *
- * @param f The file to read.
- * @param ext The extension to be used.
- * @return The AudioFile with the file tag and the file encoding info.
- * @throws CannotReadException If the file could not be read, the extension wasn't
- * recognized, or an IO error occurred during the read.
- * @throws TagException
- * @throws ReadOnlyFileException
- * @throws IOException
- * @throws InvalidAudioFrameException
- */
- public static AudioFile readAs(File f,String ext)
- throws CannotReadException, IOException, TagException, ReadOnlyFileException, InvalidAudioFrameException
- {
- return getDefaultAudioFileIO().readFileAs(f,ext);
- }
-
- /**
- *
- * Read the tag contained in the given file.
- *
- *
- * @param f The file to read.
- * @return The AudioFile with the file tag and the file encoding info.
- * @throws CannotReadException If the file could not be read, the extension wasn't
- * recognized, or an IO error occurred during the read.
- * @throws TagException
- * @throws ReadOnlyFileException
- * @throws IOException
- * @throws InvalidAudioFrameException
- */
- public static AudioFile readMagic(File f)
- throws CannotReadException, IOException, TagException, ReadOnlyFileException, InvalidAudioFrameException
- {
- return getDefaultAudioFileIO().readFileMagic(f);
- }
-
- /**
- *
- * Read the tag contained in the given file.
- *
- *
- * @param f The file to read.
- * @return The AudioFile with the file tag and the file encoding info.
- * @throws CannotReadException If the file could not be read, the extension wasn't
- * recognized, or an IO error occurred during the read.
- * @throws TagException
- * @throws ReadOnlyFileException
- * @throws IOException
- * @throws InvalidAudioFrameException
- */
- public static AudioFile read(File f)
- throws CannotReadException, IOException, TagException, ReadOnlyFileException, InvalidAudioFrameException
- {
- return getDefaultAudioFileIO().readFile(f);
- }
-
- /**
- *
- * Write the tag contained in the audioFile in the actual file on the disk.
- *
- *
- * @param f The AudioFile to be written
- * @throws NoWritePermissionsException if the file could not be written to due to file permissions
- * @throws CannotWriteException If the file could not be written/accessed, the extension
- * wasn't recognized, or other IO error occurred.
- */
- public static void write(AudioFile f) throws CannotWriteException
- {
- getDefaultAudioFileIO().writeFile(f,null);
- }
-
- /**
- *
- * Write the tag contained in the audioFile in the actual file on the disk.
- *
- *
- * @param f The AudioFile to be written
- * @param targetPath The AudioFile path to which to be written without the extension. Cannot be null
- * @throws NoWritePermissionsException if the file could not be written to due to file permissions
- * @throws CannotWriteException If the file could not be written/accessed, the extension
- * wasn't recognized, or other IO error occurred.
- */
- public static void writeAs(AudioFile f, String targetPath) throws CannotWriteException
- {
- if (targetPath == null || targetPath.isEmpty()) {
- throw new CannotWriteException("Not a valid target path: " + targetPath);
- }
- getDefaultAudioFileIO().writeFile(f,targetPath);
- }
-
- /**
- * This member is used to broadcast modification events to registered
- */
- private final ModificationHandler modificationHandler;
-
- // These tables contains all the readers/writers associated with extension
- // as a key
- public Map
- *
- */
-public class AiffFileHeader
-{
- private static final String FORM = "FORM";
- private static Logger logger = Logger.getLogger("com.mp3.jaudiotagger.audio.aiff.AudioFileHeader");
-
- /**
- * Reads the file header and registers the data (file type) with the given header.
- *
- * @param fc random access file
- * @param aiffAudioHeader the {@link com.mp3.jaudiotagger.audio.AudioHeader} we set the read data to
- * @param fileName
- * @return the number of bytes in the FORM chunk, i.e. the size of the payload
- * @throws IOException
- * @throws CannotReadException if the file is not a valid AIFF file
- */
- public long readHeader(FileChannel fc, final AiffAudioHeader aiffAudioHeader, String fileName) throws IOException, CannotReadException
- {
- final ByteBuffer headerData = ByteBuffer.allocateDirect(HEADER_LENGTH);
- headerData.order(BIG_ENDIAN);
- final int bytesRead = fc.read(headerData);
- headerData.position(0);
-
- if (bytesRead < HEADER_LENGTH)
- {
- throw new IOException(fileName + " AIFF:Unable to read required number of databytes read:" + bytesRead + ":required:" + HEADER_LENGTH);
- }
-
- final String signature = Utils.readFourBytesAsChars(headerData);
- if(FORM.equals(signature))
- {
- // read chunk size
- final long chunkSize = headerData.getInt();
- logger.severe(fileName + " Reading AIFF header size:" + Hex.asDecAndHex(chunkSize));
-
- readFileType(headerData, aiffAudioHeader);
- // subtract the file type length from the chunk size to get remaining number of bytes
- return chunkSize - TYPE_LENGTH;
- }
- else
- {
- throw new CannotReadException(fileName + "Not an AIFF file: incorrect signature " + signature);
- }
- }
-
- /**
- * Reads the file type ({@link AiffType}).
- *
- * @throws CannotReadException if the file type is not supported
- */
- private void readFileType(final ByteBuffer bytes, final AiffAudioHeader aiffAudioHeader) throws IOException, CannotReadException {
- final String type = Utils.readFourBytesAsChars(bytes);
- if (AIFF.getCode().equals(type))
- {
- aiffAudioHeader.setFileType(AIFF);
- }
- else if (AIFC.getCode().equals(type))
- {
- aiffAudioHeader.setFileType(AIFC);
- }
- else
- {
- throw new CannotReadException("Invalid AIFF file: Incorrect file type info " + type);
- }
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/AiffFileReader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/AiffFileReader.java
deleted file mode 100644
index a8e9b6a2..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/AiffFileReader.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.mp3.jaudiotagger.audio.aiff;
-
-import com.mp3.jaudiotagger.audio.exceptions.CannotReadException;
-import com.mp3.jaudiotagger.audio.generic.AudioFileReader2;
-import com.mp3.jaudiotagger.audio.generic.GenericAudioHeader;
-import com.mp3.jaudiotagger.tag.Tag;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * Reads Audio and Metadata information contained in Aiff file.
- */
-public class AiffFileReader extends AudioFileReader2 {
- private AiffInfoReader ir = new AiffInfoReader();
- private AiffTagReader im = new AiffTagReader();
-
- @Override
- protected GenericAudioHeader getEncodingInfo(File file) throws CannotReadException, IOException {
- return ir.read(file);
- }
-
- @Override
- protected Tag getTag(File file) throws CannotReadException, IOException {
- return im.read(file);
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/AiffFileWriter.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/AiffFileWriter.java
deleted file mode 100644
index 0ccfcb42..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/AiffFileWriter.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2003-2005 Raphaël Slinckx
- * [chunk][-id3-][chunk][chunk]
- * [chunk] <<--- [chunk][chunk]
- * [chunk][chunk][chunk]
- *
- *
- * @param fc, filechannel
- * @param existingTag existing tag
- * @param tagChunkHeader existing chunk header for the tag
- * @throws IOException if something goes wrong
- */
- private void deleteTagChunk(FileChannel fc, final AiffTag existingTag, final ChunkHeader tagChunkHeader, String fileName) throws IOException {
- int lengthTagChunk = (int) tagChunkHeader.getSize() + ChunkHeader.CHUNK_HEADER_SIZE;
- if (Utils.isOddLength(lengthTagChunk)) {
- if (existingTag.getStartLocationInFileOfId3Chunk() + lengthTagChunk < fc.size()) {
- lengthTagChunk++;
- }
- }
- final long newLength = fc.size() - lengthTagChunk;
- logger.severe(fileName + " Size of id3 chunk to delete is:" + lengthTagChunk + ":Location:" + existingTag.getStartLocationInFileOfId3Chunk());
-
- // position for reading after the id3 tag
- fc.position(existingTag.getStartLocationInFileOfId3Chunk() + lengthTagChunk);
-
- deleteTagChunkUsingSmallByteBufferSegments(existingTag, fc, newLength, lengthTagChunk);
- // truncate the file after the last chunk
- logger.severe(fileName + " Setting new length to:" + newLength);
- fc.truncate(newLength);
- }
-
- /**
- * If Metadata tags are corrupted and no other tags later in the file then just truncate ID3 tags and start again
- *
- * @param fc
- * @param existingTag
- * @throws IOException
- */
- private void deleteRemainderOfFile(FileChannel fc, final AiffTag existingTag, String fileName) throws IOException {
- ChunkSummary precedingChunk = AiffChunkSummary.getChunkBeforeStartingMetadataTag(existingTag);
- if (!Utils.isOddLength(precedingChunk.getEndLocation())) {
- logger.severe(fileName + " Truncating corrupted ID3 tags from:" + (existingTag.getStartLocationInFileOfId3Chunk() - 1));
- fc.truncate(existingTag.getStartLocationInFileOfId3Chunk() - 1);
- } else {
- logger.severe(fileName + " Truncating corrupted ID3 tags from:" + (existingTag.getStartLocationInFileOfId3Chunk()));
- fc.truncate(existingTag.getStartLocationInFileOfId3Chunk());
- }
- }
-
- /**
- * The following seems to work on Windows but hangs on OSX!
- * Bug is filed here.
- *
- * @param existingTag existing tag
- * @param channel channel
- * @param newLength new length
- * @throws IOException if something goes wrong
- */
- private void deleteTagChunkUsingChannelTransfer(final AiffTag existingTag, final FileChannel channel, final long newLength)
- throws IOException {
- long read;
- //Read from just after the ID3Chunk into the channel at where the ID3 chunk started, should usually only require one transfer
- //but put into loop in case multiple calls are required
- for (long position = existingTag.getStartLocationInFileOfId3Chunk();
- (read = channel.transferFrom(channel, position, newLength - position)) < newLength - position;
- position += read)
- ;//is this problem if loop called more than once do we need to update position of channel to modify
- //where write to ?
- }
-
- /**
- * Use ByteBuffers to copy a 4mb chunk, write the chunk and repeat until the rest of the file after the ID3 tag
- * is rewritten
- *
- * @param existingTag existing tag
- * @param channel channel
- * @param newLength new length
- * @param lengthTagChunk length tag chunk
- * @throws IOException if something goes wrong
- */
- // TODO: arguments are not used, position is implicit
- private void deleteTagChunkUsingSmallByteBufferSegments(final AiffTag existingTag, final FileChannel channel, final long newLength, final long lengthTagChunk)
- throws IOException {
- final ByteBuffer buffer = ByteBuffer.allocateDirect((int) TagOptionSingleton.getInstance().getWriteChunkSize());
- while (channel.read(buffer) >= 0 || buffer.position() != 0) {
- buffer.flip();
- final long readPosition = channel.position();
- channel.position(readPosition - lengthTagChunk - buffer.limit());
- channel.write(buffer);
- channel.position(readPosition);
- buffer.compact();
- }
- }
-
- /**
- * @param tag
- * @param file
- * @throws CannotWriteException
- * @throws IOException
- */
- public void write(final Tag tag, File file) throws CannotWriteException {
- logger.severe(file + " Writing Aiff tag to file");
- AiffTag existingTag = null;
- try {
- existingTag = getExistingMetadata(file);
- } catch (IOException ioe) {
- throw new CannotWriteException(file + ":" + ioe.getMessage());
- }
-
- RandomAccessFile raf = null;
- try {
- raf = new RandomAccessFile(file, "rw");
- FileChannel fc = raf.getChannel();
- long existingFileLength = fc.size();
-
- final AiffTag aiffTag = (AiffTag) tag;
- final ByteBuffer bb = convert(aiffTag, existingTag);
-
- //Replacing ID3 tag
- if (existingTag.isExistingId3Tag() && existingTag.getID3Tag().getStartLocationInFile() != null) {
- //Usual case
- if (!existingTag.isIncorrectlyAlignedTag()) {
- final ChunkHeader chunkHeader = seekToStartOfMetadata(fc, existingTag, file.toString());
- logger.info(file + "Current Space allocated:" + existingTag.getSizeOfID3TagOnly() + ":NewTagRequires:" + bb.limit());
-
- //Usual case ID3 is last chunk
- if (isAtEndOfFileAllowingForPaddingByte(existingTag, fc)) {
- writeDataToFile(fc, bb);
- }
- //Unusual Case where ID3 is not last chunk
- else {
- deleteTagChunk(fc, existingTag, chunkHeader, file.toString());
- fc.position(fc.size());
- writeExtraByteIfChunkOddSize(fc, fc.size());
- writeDataToFile(fc, bb);
- }
- }
- //Existing ID3 tag is incorrectly aligned so if we can lets delete it and any subsequentially added
- //ID3 tags as we only want one ID3 tag.
- else if (AiffChunkSummary.isOnlyMetadataTagsAfterStartingMetadataTag(existingTag)) {
- deleteRemainderOfFile(fc, existingTag, file.toString());
- fc.position(fc.size());
- writeExtraByteIfChunkOddSize(fc, fc.size());
- writeDataToFile(fc, bb);
- } else {
- throw new CannotWriteException(file + " Metadata tags are corrupted and not at end of file so cannot be fixed");
- }
- }
- //New Tag
- else {
- fc.position(fc.size());
- if (Utils.isOddLength(fc.size())) {
- fc.write(ByteBuffer.allocateDirect(1));
- }
- writeDataToFile(fc, bb);
- }
-
- if (existingFileLength != fc.size()) {
- rewriteRiffHeaderSize(fc);
- }
- } catch (IOException ioe) {
- throw new CannotWriteException(file + ":" + ioe.getMessage());
- } finally {
- AudioFileIO.closeQuietly(raf);
- }
- }
-
- /**
- * Rewrite RAF header to reflect new file length
- *
- * @param fc
- * @throws IOException
- */
- private void rewriteRiffHeaderSize(FileChannel fc) throws IOException {
-
- fc.position(IffHeaderChunk.SIGNATURE_LENGTH);
- ByteBuffer bb = ByteBuffer.allocateDirect(IffHeaderChunk.SIZE_LENGTH);
- bb.order(ByteOrder.BIG_ENDIAN);
- int size = ((int) fc.size()) - SIGNATURE_LENGTH - SIZE_LENGTH;
- bb.putInt(size);
- bb.flip();
- fc.write(bb);
- }
-
- /**
- * Writes data as a {@link AiffChunkType#TAG} chunk to the file.
- *
- * @param fc filechannel
- * @param bb data to write
- * @throws IOException
- */
- private void writeDataToFile(FileChannel fc, final ByteBuffer bb)
- throws IOException {
- final ChunkHeader ch = new ChunkHeader(ByteOrder.BIG_ENDIAN);
- ch.setID(AiffChunkType.TAG.getCode());
- ch.setSize(bb.limit());
- fc.write(ch.writeHeader());
- fc.write(bb);
- writeExtraByteIfChunkOddSize(fc, bb.limit());
- }
-
- /**
- * Chunk must also start on an even byte so if our chunksize is odd we need
- * to write another byte. This should never happen as ID3Tag is now amended
- * to ensure always write padding byte if needed to stop it being odd sized
- * but we keep check in just incase.
- *
- * @param fc
- * @param size
- * @throws IOException
- */
- private void writeExtraByteIfChunkOddSize(FileChannel fc, long size)
- throws IOException {
- if (Utils.isOddLength(size)) {
- fc.write(ByteBuffer.allocateDirect(1));
- }
- }
-
- /**
- * Converts tag to {@link ByteBuffer}.
- *
- * @param tag tag
- * @param existingTag
- * @return byte buffer containing the tag data
- * @throws UnsupportedEncodingException
- */
- public ByteBuffer convert(final AiffTag tag, AiffTag existingTag) throws UnsupportedEncodingException {
- try {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- long existingTagSize = existingTag.getSizeOfID3TagOnly();
-
- //If existingTag is uneven size lets make it even
- if (existingTagSize > 0) {
- if ((existingTagSize & 1) != 0) {
- existingTagSize++;
- }
- }
-
- //Write Tag to buffer
- tag.getID3Tag().write(baos, (int) existingTagSize);
-
- //If the tag is now odd because we needed to increase size and the data made it odd sized
- //we redo adding a padding byte to make it even
- if ((baos.toByteArray().length & 1) != 0) {
- int newSize = baos.toByteArray().length + 1;
- baos = new ByteArrayOutputStream();
- tag.getID3Tag().write(baos, newSize);
- }
- final ByteBuffer buf = ByteBuffer.wrap(baos.toByteArray());
- buf.rewind();
- return buf;
- } catch (IOException ioe) {
- //Should never happen as not writing to file at this point
- throw new RuntimeException(ioe);
- }
- }
-}
-
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/AiffType.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/AiffType.java
deleted file mode 100644
index 073f3e16..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/AiffType.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.mp3.jaudiotagger.audio.aiff;
-
-/**
- * AIFF types, refers to BigEndian or LittleEndian
- */
-public enum AiffType
-{
- AIFF("AIFF"), //Original non-compressed format on Mac pre-intel hardware
- AIFC("AIFC"), //Originally Compressed AIFF but also used for Uncompressed in LE rather than BE order
- ;
-
- String code;
-
- AiffType(String code)
- {
- this.code=code;
- }
-
- public String getCode()
- {
- return code;
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/AiffUtil.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/AiffUtil.java
deleted file mode 100644
index 7731bb85..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/AiffUtil.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.mp3.jaudiotagger.audio.aiff;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Date;
-
-/**
- * Utility methods only of use for Aiff datatypes
- */
-public class AiffUtil
-{
-
- private final static SimpleDateFormat dateFmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
-
-
- public static double read80BitDouble(ByteBuffer chunkData) throws IOException
- {
- byte[] buf = new byte[10];
- chunkData.get(buf);
- ExtDouble xd = new ExtDouble(buf);
- return xd.toDouble();
- }
-
- /**
- * Converts a Macintosh-style timestamp (seconds since
- * January 1, 1904) into a Java date. The timestamp is
- * treated as a time in the default localization.
- * Depending on that localization,
- * there may be some variation in the exact hour of the date
- * returned, e.g., due to daylight savings time.
- */
- public static Date timestampToDate(long timestamp)
- {
- Calendar cal = Calendar.getInstance();
- cal.set(1904, 0, 1, 0, 0, 0);
-
- // If we add the seconds directly, we'll truncate the long
- // value when converting to int. So convert to hours plus
- // residual seconds.
- int hours = (int) (timestamp / 3600);
- int seconds = (int) (timestamp - (long) hours * 3600L);
- cal.add(Calendar.HOUR_OF_DAY, hours);
- cal.add(Calendar.SECOND, seconds);
- Date dat = cal.getTime();
- return dat;
- }
-
- /**
- * Format a date as text
- */
- public static String formatDate(Date dat)
- {
- return dateFmt.format(dat);
- }
-
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/ExtDouble.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/ExtDouble.java
deleted file mode 100644
index 4bab0315..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/ExtDouble.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package com.mp3.jaudiotagger.audio.aiff;
-
-/**
- * Code to deal with the 80-bit floating point (extended double)
- * numbers which occur in AIFF files. Should also be applicable
- * in general.
- *
- * Java has no built-in support for IEEE 754 extended double numbers.
- * Thus, we have to unpack the number and convert it to a double by
- * hand. There is, of course, loss of precision.
- *
- * This isn't designed for high-precision work; as the standard
- * disclaimer says, don't use it for life support systems or nuclear
- * power plants.
- *
- * Lifted bodily from JHOVE.
- *
- * @author Gary McGath
- */
-public class ExtDouble
-{
-
- byte[] _rawData;
-
- /**
- * Constructor.
- *
- * @param rawData A 10-byte array representing the number
- * in the sequence in which it was stored.
- */
- public ExtDouble(byte[] rawData)
- {
- _rawData = rawData;
- }
-
-
- /**
- * Convert the value to a Java double. This results in
- * loss of precision. If the number is out of range,
- * results aren't guaranteed.
- */
- public double toDouble()
- {
- int sign;
- int exponent;
- long mantissa = 0;
-
- // Extract the sign bit.
- sign = _rawData[0] >> 7;
-
- // Extract the exponent. It's stored with a
- // bias of 16383, so subtract that off.
- // Also, the mantissa is between 1 and 2 (i.e.,
- // all but 1 digits are to the right of the binary point, so
- // we take 62 (not 63: see below) off the exponent for that.
- exponent = (_rawData[0] << 8) | _rawData[1];
- exponent &= 0X7FFF; // strip off sign bit
- exponent -= (16383 + 62); // 1 is added to the "real" exponent
-
- // Extract the mantissa. It's 64 bits of unsigned
- // data, but a long is a signed number, so we have to
- // discard the LSB. We'll lose more than that converting
- // to double anyway. This division by 2 is the reason for
- // adding an extra 1 to the exponent above.
- int shifter = 55;
- for (int i = 2; i < 9; i++)
- {
- mantissa |= ((long) _rawData[i] & 0XFFL) << shifter;
- shifter -= 8;
- }
- mantissa |= _rawData[9] >>> 1;
-
- // Now put it together in a floating point number.
- double val = Math.pow(2, exponent);
- val *= mantissa;
- if (sign != 0)
- {
- val = -val;
- }
- return val;
- }
-}
-
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/AiffChunkReader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/AiffChunkReader.java
deleted file mode 100644
index f73f272c..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/AiffChunkReader.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.mp3.jaudiotagger.audio.aiff.chunk;
-
-import com.mp3.jaudiotagger.audio.iff.ChunkHeader;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.channels.FileChannel;
-
-/**
- * Abstract class For reading Aiff Chunks used by both Audio and Tag Reader
- */
-public abstract class AiffChunkReader
-{
- /**
- * Read the next chunk into ByteBuffer as specified by ChunkHeader and moves raf file pointer
- * to start of next chunk/end of file.
- *
- * @param fc
- * @param chunkHeader
- * @return
- * @throws IOException
- */
- protected ByteBuffer readChunkDataIntoBuffer(FileChannel fc, final ChunkHeader chunkHeader) throws IOException
- {
- final ByteBuffer chunkData = ByteBuffer.allocateDirect((int)chunkHeader.getSize());
- chunkData.order(ByteOrder.BIG_ENDIAN);
- fc.read(chunkData);
- chunkData.position(0);
- return chunkData;
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/AiffChunkSummary.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/AiffChunkSummary.java
deleted file mode 100644
index 41b744dd..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/AiffChunkSummary.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.mp3.jaudiotagger.audio.aiff.chunk;
-
-import com.mp3.jaudiotagger.audio.iff.ChunkSummary;
-import com.mp3.jaudiotagger.tag.aiff.AiffTag;
-
-/**
- * AIFF Specific methods for ChunkSummarys
- */
-public class AiffChunkSummary
-{
- /**
- * Checks that there are only id3 tags after the currently selected id3tag because this means its safe to truncate
- * the remainder of the file.
- *
- * @param tag
- * @return
- */
- public static boolean isOnlyMetadataTagsAfterStartingMetadataTag(AiffTag tag)
- {
- boolean firstId3Tag = false;
- for(ChunkSummary cs:tag.getChunkSummaryList())
- {
- if(firstId3Tag)
- {
- if(!cs.getChunkId().equals(AiffChunkType.TAG.getCode()))
- {
- return false;
- }
- }
- else
- {
- if (cs.getFileStartLocation() == tag.getStartLocationInFileOfId3Chunk())
- {
- //Found starting point
- firstId3Tag = true;
- }
- }
- }
-
- //Should always be true but this is to protect against something gone wrong
- if(firstId3Tag==true)
- {
- return true;
- }
- return false;
-
- }
-
- /**
- * Get chunk before starting metadata tag
- *
- * @param tag
- * @return
- */
- public static ChunkSummary getChunkBeforeStartingMetadataTag(AiffTag tag)
- {
- for(int i=0;i < tag.getChunkSummaryList().size(); i++)
- {
- ChunkSummary cs = tag.getChunkSummaryList().get(i);
- if (cs.getFileStartLocation() == tag.getStartLocationInFileOfId3Chunk())
- {
- return tag.getChunkSummaryList().get(i - 1);
- }
- }
- return null;
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/AiffChunkType.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/AiffChunkType.java
deleted file mode 100644
index 1e0e5101..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/AiffChunkType.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.mp3.jaudiotagger.audio.aiff.chunk;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Chunk types mark each {@link com.mp3.jaudiotagger.audio.iff.ChunkHeader}. They are always 4 ASCII chars long.
- *
- * @see com.mp3.jaudiotagger.audio.iff.Chunk
- */
-public enum AiffChunkType
-{
- FORMAT_VERSION("FVER"),
- APPLICATION("APPL"),
- SOUND("SSND"),
- COMMON("COMM"),
- COMMENTS("COMT"),
- NAME("NAME"),
- AUTHOR("AUTH"),
- COPYRIGHT("(c) "),
- ANNOTATION("ANNO"),
- TAG("ID3 "),
- CORRUPT_TAG_LATE("D3 \u0000"),
- CORRUPT_TAG_EARLY("\u0000ID3");
-
- private static final Mapfalse
if the chunk is structurally
- * invalid, otherwise true
- */
- public boolean readChunk() throws IOException
- {
- final String applicationSignature = Utils.readFourBytesAsChars(chunkData);
- String applicationName = null;
-
- /* If the application signature is 'pdos' or 'stoc',
- * then the beginning of the data area is a Pascal
- * string naming the application. Otherwise, we
- * ignore the data. ('pdos' is for Apple II
- * applications, 'stoc' for the entire non-Apple world.)
- */
- if (SIGNATURE_STOC.equals(applicationSignature) || SIGNATURE_PDOS.equals(applicationSignature))
- {
- applicationName = Utils.readPascalString(chunkData);
- }
- aiffHeader.addApplicationIdentifier(applicationSignature + ": " + applicationName);
-
- return true;
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/AuthorChunk.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/AuthorChunk.java
deleted file mode 100644
index 99e84e88..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/AuthorChunk.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.mp3.jaudiotagger.audio.aiff.chunk;
-
-import com.mp3.jaudiotagger.audio.aiff.AiffAudioHeader;
-import com.mp3.jaudiotagger.audio.iff.ChunkHeader;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-/**
- * Contains one or more author names. An author in this case is the creator of a sampled sound.
- * The Author Chunk is optional. No more than one Author Chunk may exist within a FORM AIFF.
- */
-public class AuthorChunk extends TextChunk
-{
-
- /**
- * @param chunkHeader The header for this chunk
- * @param chunkData The buffer from which the AIFF data are being read
- * @param aiffAudioHeader The AiffAudioHeader into which information is stored
- */
- public AuthorChunk(final ChunkHeader chunkHeader, final ByteBuffer chunkData, final AiffAudioHeader aiffAudioHeader)
- {
- super(chunkHeader, chunkData, aiffAudioHeader);
- }
-
- @Override
- public boolean readChunk() throws IOException
- {
- aiffAudioHeader.setAuthor(readChunkText());
- return true;
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/CommentsChunk.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/CommentsChunk.java
deleted file mode 100644
index 02f9507e..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/CommentsChunk.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package com.mp3.jaudiotagger.audio.aiff.chunk;
-
-import com.mp3.jaudiotagger.StandardCharsets;
-import com.mp3.jaudiotagger.audio.aiff.AiffAudioHeader;
-import com.mp3.jaudiotagger.audio.aiff.AiffUtil;
-import com.mp3.jaudiotagger.audio.generic.Utils;
-import com.mp3.jaudiotagger.audio.iff.Chunk;
-import com.mp3.jaudiotagger.audio.iff.ChunkHeader;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.Date;
-
-/**
- *
- * typedef struct {
- * unsigned long timeStamp;
- * MarkerID marker;
- * unsigned short count;
- * char text[];
- * } Comment;
- *
- * false
if the chunk is structurally
- * invalid, otherwise true
- */
- public boolean readChunk() throws IOException
- {
- final int numComments = Utils.u(chunkData.getShort());
-
- //For each comment
- for (int i = 0; i < numComments; i++)
- {
- final long timestamp = Utils.u(chunkData.getInt());
- final Date jTimestamp = AiffUtil.timestampToDate(timestamp);
- final int marker = Utils.u(chunkData.getShort());
- final int count = Utils.u(chunkData.getShort());
- // Append a timestamp to the comment
- final String text = Utils.getString(chunkData, 0, count, StandardCharsets.ISO_8859_1) + " " + AiffUtil.formatDate(jTimestamp);
- if (count % 2 != 0) {
- // if count is odd, text is padded with an extra byte that we need to consume
- chunkData.get();
- }
- aiffHeader.addComment(text);
- }
- return true;
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/CommonChunk.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/CommonChunk.java
deleted file mode 100644
index 3731e4c2..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/CommonChunk.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package com.mp3.jaudiotagger.audio.aiff.chunk;
-
-import com.mp3.jaudiotagger.audio.aiff.AiffAudioHeader;
-import com.mp3.jaudiotagger.audio.aiff.AiffType;
-import com.mp3.jaudiotagger.audio.aiff.AiffUtil;
-import com.mp3.jaudiotagger.audio.generic.Utils;
-import com.mp3.jaudiotagger.audio.iff.Chunk;
-import com.mp3.jaudiotagger.audio.iff.ChunkHeader;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-/**
- The Common Chunk describes fundamental parameters of the waveform data such as sample rate,
- bit resolution, and how many channels of digital audio are stored in the FORM AIFF.
- */
-public class CommonChunk extends Chunk
-{
- private AiffAudioHeader aiffHeader;
-
- /**
- *
- * @param hdr
- * @param chunkData
- * @param aiffAudioHeader
- */
- public CommonChunk(ChunkHeader hdr, ByteBuffer chunkData, AiffAudioHeader aiffAudioHeader)
- {
- super(chunkData, hdr);
- aiffHeader = aiffAudioHeader;
- }
-
-
- @Override
- public boolean readChunk() throws IOException
- {
-
- int numChannels = Utils.u(chunkData.getShort());
- long numSamples = chunkData.getInt();
- int bitsPerSample = Utils.u(chunkData.getShort());
- double sampleRate = AiffUtil.read80BitDouble(chunkData);
- //Compression format, but not necessarily compressed
- String compressionType;
- String compressionName;
- if (aiffHeader.getFileType() == AiffType.AIFC)
- {
- // This is a rather special case, but testing did turn up
- // a file that misbehaved in this way.
- if (chunkData.remaining()==0)
- {
- return false;
- }
- compressionType = Utils.readFourBytesAsChars(chunkData);
- if (compressionType.equals(AiffCompressionType.SOWT.getCode()))
- {
- aiffHeader.setEndian(AiffAudioHeader.Endian.LITTLE_ENDIAN);
- }
- compressionName = Utils.readPascalString(chunkData);
- // Proper handling of compression type should depend
- // on whether raw output is set
- if (compressionType != null)
- {
- //Is it a known compression type
- AiffCompressionType act = AiffCompressionType.getByCode(compressionType);
- if (act != null)
- {
- compressionName = act.getCompression();
- aiffHeader.setLossless(act.isLossless());
- // we assume that the bitrate is not variable, if there is no compression
- if (act == AiffCompressionType.NONE) {
- aiffHeader.setVariableBitRate(false);
- }
- }
- else
- {
- // We don't know compression type, so we have to assume lossy compression as we know we are using AIFC format
- aiffHeader.setLossless(false);
- }
-
- if (compressionName.isEmpty())
- {
- aiffHeader.setEncodingType(compressionType);
- }
- else
- {
- aiffHeader.setEncodingType(compressionName);
- }
- }
- }
- //Must be lossless
- else
- {
- aiffHeader.setLossless(true);
- aiffHeader.setEncodingType(AiffCompressionType.NONE.getCompression());
- // regular AIFF has no variable bit rate AFAIK
- aiffHeader.setVariableBitRate(false);
- }
-
- aiffHeader.setBitsPerSample(bitsPerSample);
- aiffHeader.setSamplingRate((int) sampleRate);
- aiffHeader.setChannelNumber(numChannels);
- aiffHeader.setPreciseLength((numSamples / sampleRate));
- aiffHeader.setNoOfSamples(numSamples);
- return true;
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/CopyrightChunk.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/CopyrightChunk.java
deleted file mode 100644
index c0bac4cb..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/CopyrightChunk.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.mp3.jaudiotagger.audio.aiff.chunk;
-
-import com.mp3.jaudiotagger.audio.aiff.AiffAudioHeader;
-import com.mp3.jaudiotagger.audio.iff.ChunkHeader;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-/**
- * false
if the chunk is structurally
- * invalid, otherwise true
- */
- public boolean readChunk() throws IOException
- {
- final long rawTimestamp = chunkData.getInt();
- // The timestamp is in seconds since January 1, 1904.
- // We must convert to Java time.
- final Date timestamp = AiffUtil.timestampToDate(rawTimestamp);
- aiffHeader.setTimestamp(timestamp);
- return true;
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/ID3Chunk.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/ID3Chunk.java
deleted file mode 100644
index 4d2e1807..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/ID3Chunk.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package com.mp3.jaudiotagger.audio.aiff.chunk;
-
-import com.mp3.jaudiotagger.audio.AudioFile;
-import com.mp3.jaudiotagger.audio.iff.Chunk;
-import com.mp3.jaudiotagger.audio.iff.ChunkHeader;
-import com.mp3.jaudiotagger.tag.TagException;
-import com.mp3.jaudiotagger.tag.aiff.AiffTag;
-import com.mp3.jaudiotagger.tag.id3.AbstractID3v2Tag;
-import com.mp3.jaudiotagger.tag.id3.ID3v22Tag;
-import com.mp3.jaudiotagger.tag.id3.ID3v23Tag;
-import com.mp3.jaudiotagger.tag.id3.ID3v24Tag;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.logging.Logger;
-
-/**
- * Contains the ID3 tags.
- */
-public class ID3Chunk extends Chunk
-{
- public static Logger logger = Logger.getLogger("com.mp3.jaudiotagger.audio.aiff.chunk");
- private AiffTag aiffTag;
-
- /**
- * Constructor.
- *
- * @param chunkHeader The header for this chunk
- * @param chunkData The content of this chunk
- * @param tag The AiffTag into which information is stored
- */
- public ID3Chunk(final ChunkHeader chunkHeader, final ByteBuffer chunkData, final AiffTag tag)
- {
- super(chunkData, chunkHeader);
- aiffTag = tag;
- }
-
- @Override
- public boolean readChunk() throws IOException
- {
- AudioFile.logger.severe("Reading chunk");
- if (!isId3v2Tag(chunkData))
- {
- logger.severe("Invalid ID3 header for ID3 chunk");
- return false;
- }
-
- final int version = chunkData.get();
- final AbstractID3v2Tag id3Tag;
- switch (version)
- {
- case ID3v22Tag.MAJOR_VERSION:
- id3Tag = new ID3v22Tag();
- AudioFile.logger.severe("Reading ID3V2.2 tag");
- break;
- case ID3v23Tag.MAJOR_VERSION:
- id3Tag = new ID3v23Tag();
- AudioFile.logger.severe("Reading ID3V2.3 tag");
- break;
- case ID3v24Tag.MAJOR_VERSION:
- id3Tag = new ID3v24Tag();
- AudioFile.logger.severe("Reading ID3V2.4 tag");
- break;
- default:
- return false; // bad or unknown version
- }
-
- aiffTag.setID3Tag(id3Tag);
- chunkData.position(0);
- try
- {
- id3Tag.read(chunkData);
- }
- catch (TagException e)
- {
- AudioFile.logger.info("Exception reading ID3 tag: " + e.getClass().getName() + ": " + e.getMessage());
- return false;
- }
- return true;
- }
-
- /**
- * Reads 3 bytes to determine if the tag really looks like ID3 data.
- */
- private boolean isId3v2Tag(final ByteBuffer headerData) throws IOException
- {
- for (int i = 0; i < AbstractID3v2Tag.FIELD_TAGID_LENGTH; i++)
- {
- if (headerData.get() != AbstractID3v2Tag.TAG_ID[i])
- {
- return false;
- }
- }
- return true;
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/NameChunk.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/NameChunk.java
deleted file mode 100644
index eb83030d..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/NameChunk.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.mp3.jaudiotagger.audio.aiff.chunk;
-
-import com.mp3.jaudiotagger.audio.aiff.AiffAudioHeader;
-import com.mp3.jaudiotagger.audio.iff.ChunkHeader;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-/**
- * Contains the name of the sampled sound. The Name Chunk is optional.
- * No more than one Name Chunk may exist within a FORM AIFF.
- */
-public class NameChunk extends TextChunk
-{
-
- /**
- * @param chunkHeader The header for this chunk
- * @param chunkData The buffer from which the AIFF data are being read
- * @param aiffAudioHeader The AiffAudioHeader into which information is stored
- */
- public NameChunk(final ChunkHeader chunkHeader, final ByteBuffer chunkData, final AiffAudioHeader aiffAudioHeader)
- {
- super(chunkHeader, chunkData, aiffAudioHeader);
- }
-
- @Override
- public boolean readChunk() throws IOException
- {
- aiffAudioHeader.setName(readChunkText());
- return true;
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/SoundChunk.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/SoundChunk.java
deleted file mode 100644
index ab2263ba..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/SoundChunk.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.mp3.jaudiotagger.audio.aiff.chunk;
-
-import com.mp3.jaudiotagger.audio.iff.Chunk;
-import com.mp3.jaudiotagger.audio.iff.ChunkHeader;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-/**
- * Sound chunk.
- * Doesn't actually read the content, but skips it.
- */
-public class SoundChunk extends Chunk
-{
-
- /**
- * @param chunkHeader The header for this chunk
- * @param chunkData The file from which the AIFF data are being read
- */
- public SoundChunk(final ChunkHeader chunkHeader, final ByteBuffer chunkData)
- {
- super(chunkData, chunkHeader);
- }
-
- /**
- * Reads a chunk and extracts information.
- *
- * @return false
if the chunk is structurally
- * invalid, otherwise true
- */
- public boolean readChunk() throws IOException
- {
- return true;
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/TextChunk.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/TextChunk.java
deleted file mode 100644
index 0ca582eb..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/aiff/chunk/TextChunk.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.mp3.jaudiotagger.audio.aiff.chunk;
-
-import com.mp3.jaudiotagger.StandardCharsets;
-import com.mp3.jaudiotagger.audio.aiff.AiffAudioHeader;
-import com.mp3.jaudiotagger.audio.generic.Utils;
-import com.mp3.jaudiotagger.audio.iff.Chunk;
-import com.mp3.jaudiotagger.audio.iff.ChunkHeader;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-/**
- * Provides common functionality for textual chunks like {@link NameChunk}, {@link AuthorChunk},
- * {@link CopyrightChunk} and {@link AnnotationChunk}.
- */
-public abstract class TextChunk extends Chunk
-{
- protected final AiffAudioHeader aiffAudioHeader;
-
- /**
- * Constructor.
- *
- * @param chunkHeader The header for this chunk
- * @param chunkData The buffer from which the AIFF data are being read
- * @param aiffAudioHeader aiff header
- */
- public TextChunk(final ChunkHeader chunkHeader, final ByteBuffer chunkData, final AiffAudioHeader aiffAudioHeader)
- {
- super(chunkData, chunkHeader);
- this.aiffAudioHeader = aiffAudioHeader;
- }
-
- /**
- * Reads the chunk and transforms it to a {@link String}.
- *
- * @return text string
- * @throws IOException if the read fails
- */
- protected String readChunkText() throws IOException {
- // the spec actually only defines ASCII, not ISO_8859_1, but it probably does not hurt to be lenient
- return Utils.getString(chunkData, 0, chunkData.remaining(), StandardCharsets.ISO_8859_1);
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/AsfFileReader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/AsfFileReader.java
deleted file mode 100644
index 11c39598..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/AsfFileReader.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2004-2005 Christian Laireiter
- *
- * @author Christian Laireiter
- */
-public class AsfFileReader extends AudioFileReader
-{
-
- /**
- * Logger instance
- */
- private final static Logger LOGGER = Logger.getLogger("com.mp3.jaudiotagger.audio.asf");
-
- /**
- * This reader will be configured to read tag and audio header information.
- */
- private final static AsfHeaderReader HEADER_READER;
-
- static
- {
- final List
- *
- * @param header the header to look up.
- * @return true
if "isVbr" is present with a
- * true
value.
- */
- private boolean determineVariableBitrate(final AsfHeader header)
- {
- assert header != null;
- boolean result = false;
- final MetadataContainer extDesc = header.findExtendedContentDescription();
- if (extDesc != null)
- {
- final List
- *
- *
- * @author Christian Laireiter
- */
-public class AsfFileWriter extends AudioFileWriter
-{
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected void deleteTag(Tag tag, final RandomAccessFile raf, final RandomAccessFile tempRaf) throws CannotWriteException, IOException
- {
- writeTag(null, 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(AudioFile audioFile, 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
- * Like {@link AsfHeader} it contains multiple other ASF objects (chunks).
- *
- * @author Christian Laireiter
- */
-public final class AsfExtendedHeader extends ChunkContainer
-{
-
- /**
- * Creates an instance.
- *
- * @param pos Position within the stream.
- * @param length the length of the extended header object.
- */
- public AsfExtendedHeader(final long pos, final BigInteger length)
- {
- super(GUID.GUID_HEADER_EXTENSION, pos, length);
- }
-
- /**
- * @return Returns the contentDescription.
- */
- public ContentDescription getContentDescription()
- {
- return (ContentDescription) getFirst(GUID.GUID_CONTENTDESCRIPTION, ContentDescription.class);
- }
-
- /**
- * @return Returns the tagHeader.
- */
- public MetadataContainer getExtendedContentDescription()
- {
- return (MetadataContainer) getFirst(GUID.GUID_EXTENDED_CONTENT_DESCRIPTION, MetadataContainer.class);
- }
-
- /**
- * Returns a language list object if present.
- *
- * @return a language list object.
- */
- public LanguageList getLanguageList()
- {
- return (LanguageList) getFirst(GUID.GUID_LANGUAGE_LIST, LanguageList.class);
- }
-
- /**
- * Returns a metadata library object if present.
- *
- * @return metadata library objet
- */
- public MetadataContainer getMetadataLibraryObject()
- {
- return (MetadataContainer) getFirst(GUID.GUID_METADATA_LIBRARY, MetadataContainer.class);
- }
-
- /**
- * Returns a metadata object if present.
- *
- * @return metadata object
- */
- public MetadataContainer getMetadataObject()
- {
- return (MetadataContainer) getFirst(GUID.GUID_METADATA, MetadataContainer.class);
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/AsfHeader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/AsfHeader.java
deleted file mode 100644
index 07238c50..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/AsfHeader.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2004-2005 Christian Laireiter
- * This header contains other chunks. Each chunk starts with a 16 byte GUID
- * followed by the length (in bytes) of the chunk (including GUID). The length
- * number takes 8 bytes and is unsigned. Finally the chunk's data appears.
- *
- * @author Christian Laireiter
- */
-public final class AsfHeader extends ChunkContainer
-{
- /**
- * The charset "UTF-16LE" is mandatory for ASF handling.
- */
- public final static Charset ASF_CHARSET = Charset.forName("UTF-16LE"); //$NON-NLS-1$
-
- /**
- * Byte sequence representing the zero term character.
- */
- public final static byte[] ZERO_TERM = {0, 0};
-
- static
- {
- Set
- * The count of those is stored here.
- */
- private final long chunkCount;
-
- /**
- * Creates an instance.
- *
- * @param pos see {@link Chunk#position}
- * @param chunkLen see {@link Chunk#chunkLength}
- * @param chunkCnt
- */
- public AsfHeader(final long pos, final BigInteger chunkLen, final long chunkCnt)
- {
- super(GUID.GUID_HEADER, pos, chunkLen);
- this.chunkCount = chunkCnt;
- }
-
- /**
- * This method looks for an content description object in this header
- * instance, if not found there, it tries to get one from a contained ASF
- * header extension object.
- *
- * @return content description if found, null
otherwise.
- */
- public ContentDescription findContentDescription()
- {
- ContentDescription result = getContentDescription();
- if (result == null && getExtendedHeader() != null)
- {
- result = getExtendedHeader().getContentDescription();
- }
- return result;
- }
-
- /**
- * This method looks for an extended content description object in this
- * header instance, if not found there, it tries to get one from a contained
- * ASF header extension object.
- *
- * @return extended content description if found, null
- * otherwise.
- */
- public MetadataContainer findExtendedContentDescription()
- {
- MetadataContainer result = getExtendedContentDescription();
- if (result == null && getExtendedHeader() != null)
- {
- result = getExtendedHeader().getExtendedContentDescription();
- }
- return result;
- }
-
- /**
- * This method searches for a metadata container of the given type.
- *
- * @param type the type of the container to look up.
- * @return a container of specified type, of null
if not
- * contained.
- */
- public MetadataContainer findMetadataContainer(final ContainerType type)
- {
- MetadataContainer result = (MetadataContainer) getFirst(type.getContainerGUID(), MetadataContainer.class);
- if (result == null)
- {
- result = (MetadataContainer) getExtendedHeader().getFirst(type.getContainerGUID(), MetadataContainer.class);
- }
- return result;
- }
-
- /**
- * This method returns the first audio stream chunk found in the asf file or
- * stream.
- *
- * @return Returns the audioStreamChunk.
- */
- public AudioStreamChunk getAudioStreamChunk()
- {
- AudioStreamChunk result = null;
- final List
- * If chunks have been added, this won't be reflected with this call.
- * For that use {@link #getChunks()}.
- *
- * @return Chunkcount at instance creation.
- */
- public long getChunkCount()
- {
- return this.chunkCount;
- }
-
- /**
- * @return Returns the contentDescription.
- */
- public ContentDescription getContentDescription()
- {
- return (ContentDescription) getFirst(GUID.GUID_CONTENTDESCRIPTION, ContentDescription.class);
- }
-
- /**
- * @return Returns the encodingChunk.
- */
- public EncodingChunk getEncodingChunk()
- {
- return (EncodingChunk) getFirst(GUID.GUID_ENCODING, EncodingChunk.class);
- }
-
- /**
- * @return Returns the encodingChunk.
- */
- public EncryptionChunk getEncryptionChunk()
- {
- return (EncryptionChunk) getFirst(GUID.GUID_CONTENT_ENCRYPTION, EncryptionChunk.class);
- }
-
- /**
- * @return Returns the tagHeader.
- */
- public MetadataContainer getExtendedContentDescription()
- {
- return (MetadataContainer) getFirst(GUID.GUID_EXTENDED_CONTENT_DESCRIPTION, MetadataContainer.class);
- }
-
- /**
- * @return Returns the extended header.
- */
- public AsfExtendedHeader getExtendedHeader()
- {
- return (AsfExtendedHeader) getFirst(GUID.GUID_HEADER_EXTENSION, AsfExtendedHeader.class);
- }
-
- /**
- * @return Returns the fileHeader.
- */
- public FileHeader getFileHeader()
- {
- return (FileHeader) getFirst(GUID.GUID_FILE, FileHeader.class);
- }
-
- /**
- * @return Returns the streamBitratePropertiesChunk.
- */
- public StreamBitratePropertiesChunk getStreamBitratePropertiesChunk()
- {
- return (StreamBitratePropertiesChunk) getFirst(GUID.GUID_STREAM_BITRATE_PROPERTIES, StreamBitratePropertiesChunk.class);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String prettyPrint(final String prefix)
- {
- final StringBuilder result = new StringBuilder(super.prettyPrint(prefix, prefix + " | : Contains: \"" + getChunkCount() + "\" chunks" + Utils.LINE_SEPARATOR));
- return result.toString();
- }
-}
\ No newline at end of file
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/AudioStreamChunk.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/AudioStreamChunk.java
deleted file mode 100644
index 35e354cd..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/AudioStreamChunk.java
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2004-2005 Christian Laireiter
- *
- * @author Christian Laireiter
- */
-public final class AudioStreamChunk extends StreamChunk
-{
- /**
- * Stores the hex values of codec identifiers to their descriptions.
- */
- public final static String[][] CODEC_DESCRIPTIONS = {{"161", " (Windows Media Audio (ver 7,8,9))"}, {"162", " (Windows Media Audio 9 series (Professional))"}, {"163", "(Windows Media Audio 9 series (Lossless))"}, {"7A21", " (GSM-AMR (CBR))"}, {"7A22", " (GSM-AMR (VBR))"}};
- /**
- * Stores the audio codec number for WMA
- */
- public final static long WMA = 0x161;
- /**
- * Stores the audio codec number for WMA (CBR)
- */
- public final static long WMA_CBR = 0x7A21;
- /**
- * Stores the audio codec number for WMA_LOSSLESS
- */
- public final static long WMA_LOSSLESS = 0x163;
- /**
- * Stores the audio codec number for WMA_PRO
- */
- public final static long WMA_PRO = 0x162;
-
- /**
- * Stores the audio codec number for WMA (VBR)
- */
- public final static long WMA_VBR = 0x7A22;
-
- /**
- * Stores the average amount of bytes used by audio stream.
- * This value is a field within type specific data of audio stream. Maybe it
- * could be used to calculate the KBPs.
- */
- private long averageBytesPerSec;
-
- /**
- * Amount of bits used per sample.
- */
- private int bitsPerSample;
-
- /**
- * The block alignment of the audio data.
- */
- private long blockAlignment;
-
- /**
- * Number of channels.
- */
- private long channelCount;
-
- /**
- * Some data which needs to be interpreted if the codec is handled.
- */
- private byte[] codecData = new byte[0];
-
- /**
- * The audio compression format code.
- */
- private long compressionFormat;
-
- /**
- * this field stores the error concealment type.
- */
- private GUID errorConcealment;
-
- /**
- * Sampling rate of audio stream.
- */
- private long samplingRate;
-
- /**
- * Creates an instance.
- *
- * @param chunkLen Length of the entire chunk (including guid and size)
- */
- public AudioStreamChunk(final BigInteger chunkLen)
- {
- super(GUID.GUID_AUDIOSTREAM, chunkLen);
- }
-
- /**
- * @return Returns the averageBytesPerSec.
- */
- public long getAverageBytesPerSec()
- {
- return this.averageBytesPerSec;
- }
-
- /**
- * @return Returns the bitsPerSample.
- */
- public int getBitsPerSample()
- {
- return this.bitsPerSample;
- }
-
- /**
- * @return Returns the blockAlignment.
- */
- public long getBlockAlignment()
- {
- return this.blockAlignment;
- }
-
- /**
- * @return Returns the channelCount.
- */
- public long getChannelCount()
- {
- return this.channelCount;
- }
-
- /**
- * @return Returns the codecData.
- */
- public byte[] getCodecData()
- {
- return this.codecData.clone();
- }
-
- /**
- * This method will take a look at {@link #compressionFormat}and returns a
- * String with its hex value and if known a textual note on what coded it
- * represents.
- *
- * @return A description for the used codec.
- */
- public String getCodecDescription()
- {
- final StringBuilder result = new StringBuilder(Long.toHexString(getCompressionFormat()));
- String furtherDesc = " (Unknown)";
- for (final String[] aCODEC_DESCRIPTIONS : CODEC_DESCRIPTIONS)
- {
- if (aCODEC_DESCRIPTIONS[0].equalsIgnoreCase(result.toString()))
- {
- furtherDesc = aCODEC_DESCRIPTIONS[1];
- break;
- }
- }
- if (result.length() % 2 == 0)
- {
- result.insert(0, "0x");
- }
- else
- {
- result.insert(0, "0x0");
- }
- result.append(furtherDesc);
- return result.toString();
- }
-
- /**
- * @return Returns the compressionFormat.
- */
- public long getCompressionFormat()
- {
- return this.compressionFormat;
- }
-
- /**
- * @return Returns the errorConcealment.
- */
- public GUID getErrorConcealment()
- {
- return this.errorConcealment;
- }
-
- /**
- * This method takes the value of {@link #getAverageBytesPerSec()}and
- * calculates the kbps out of it, by simply multiplying by 8 and dividing by
- * 1000.
- *
- * @return amount of bits per second in kilo bits.
- */
- public int getKbps()
- {
- return (int) getAverageBytesPerSec() * 8 / 1000;
- }
-
- /**
- * @return Returns the samplingRate.
- */
- public long getSamplingRate()
- {
- return this.samplingRate;
- }
-
- /**
- * This mehtod returns whether the audio stream data is error concealed.
- * For now only interleaved concealment is known.
- *
- * @return true
if error concealment is used.
- */
- public boolean isErrorConcealed()
- {
- return getErrorConcealment().equals(GUID.GUID_AUDIO_ERROR_CONCEALEMENT_INTERLEAVED);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String prettyPrint(final String prefix)
- {
- final StringBuilder result = new StringBuilder(super.prettyPrint(prefix));
- result.append(prefix).append(" |-> Audio info:").append(Utils.LINE_SEPARATOR);
- result.append(prefix).append(" | : Bitrate : ").append(getKbps()).append(Utils.LINE_SEPARATOR);
- result.append(prefix).append(" | : Channels : ").append(getChannelCount()).append(" at ").append(getSamplingRate()).append(" Hz").append(Utils.LINE_SEPARATOR);
- result.append(prefix).append(" | : Bits per Sample: ").append(getBitsPerSample()).append(Utils.LINE_SEPARATOR);
- result.append(prefix).append(" | : Formatcode: ").append(getCodecDescription()).append(Utils.LINE_SEPARATOR);
- return result.toString();
- }
-
- /**
- * @param avgeBytesPerSec The averageBytesPerSec to set.
- */
- public void setAverageBytesPerSec(final long avgeBytesPerSec)
- {
- this.averageBytesPerSec = avgeBytesPerSec;
- }
-
- /**
- * Sets the bitsPerSample
- *
- * @param bps
- */
- public void setBitsPerSample(final int bps)
- {
- this.bitsPerSample = bps;
- }
-
- /**
- * Sets the blockAlignment.
- *
- * @param align
- */
- public void setBlockAlignment(final long align)
- {
- this.blockAlignment = align;
- }
-
- /**
- * @param channels The channelCount to set.
- */
- public void setChannelCount(final long channels)
- {
- this.channelCount = channels;
- }
-
- /**
- * Sets the codecData
- *
- * @param codecSpecificData
- */
- public void setCodecData(final byte[] codecSpecificData)
- {
- if (codecSpecificData == null)
- {
- throw new IllegalArgumentException();
- }
- this.codecData = codecSpecificData.clone();
- }
-
- /**
- * @param cFormatCode The compressionFormat to set.
- */
- public void setCompressionFormat(final long cFormatCode)
- {
- this.compressionFormat = cFormatCode;
- }
-
- /**
- * This method sets the error concealment type which is given by two GUIDs.
- *
- * @param errConc the type of error concealment the audio stream is stored as.
- */
- public void setErrorConcealment(final GUID errConc)
- {
- this.errorConcealment = errConc;
- }
-
- /**
- * @param sampRate The samplingRate to set.
- */
- public void setSamplingRate(final long sampRate)
- {
- this.samplingRate = sampRate;
- }
-}
\ No newline at end of file
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/Chunk.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/Chunk.java
deleted file mode 100644
index 6f909f32..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/Chunk.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2004-2005 Christian Laireiter
- * Each chunk starts with a 16byte {@linkplain GUID GUID} identifying the type.
- * After that a number (represented by 8 bytes) follows which shows the size in
- * bytes of the chunk. Finally there is the data of the chunk.
- *
- * @author Christian Laireiter
- */
-public class Chunk
-{
-
- /**
- * The length of current chunk.
- */
- protected final BigInteger chunkLength;
-
- /**
- * The GUID of represented chunk header.
- */
- protected final GUID guid;
-
- /**
- * The position of current header object within file or stream.
- */
- protected long position;
-
- /**
- * Creates an instance
- *
- * @param headerGuid The GUID of header object.
- * @param chunkLen Length of current chunk.
- */
- public Chunk(final GUID headerGuid, final BigInteger chunkLen)
- {
- if (headerGuid == null)
- {
- throw new IllegalArgumentException("GUID must not be null.");
- }
- if (chunkLen == null || chunkLen.compareTo(BigInteger.ZERO) < 0)
- {
- throw new IllegalArgumentException("chunkLen must not be null nor negative.");
- }
- this.guid = headerGuid;
- this.chunkLength = chunkLen;
- }
-
- /**
- * Creates an instance
- *
- * @param headerGuid The GUID of header object.
- * @param pos Position of header object within stream or file.
- * @param chunkLen Length of current chunk.
- */
- public Chunk(final GUID headerGuid, final long pos, final BigInteger chunkLen)
- {
- if (headerGuid == null)
- {
- throw new IllegalArgumentException("GUID must not be null");
- }
- if (pos < 0)
- {
- throw new IllegalArgumentException("Position of header can't be negative.");
- }
- if (chunkLen == null || chunkLen.compareTo(BigInteger.ZERO) < 0)
- {
- throw new IllegalArgumentException("chunkLen must not be null nor negative.");
- }
- this.guid = headerGuid;
- this.position = pos;
- this.chunkLength = chunkLen;
- }
-
- /**
- * This method returns the End of the current chunk introduced by current
- * header object.
- *
- * @return Position after current chunk.
- * @deprecated typo, use {@link #getChunkEnd()} instead.
- */
- @Deprecated
- public long getChunckEnd()
- {
- return this.position + this.chunkLength.longValue();
- }
-
- /**
- * This method returns the End of the current chunk introduced by current
- * header object.
- *
- * @return Position after current chunk.
- */
- public long getChunkEnd()
- {
- return this.position + this.chunkLength.longValue();
- }
-
- /**
- * @return Returns the chunkLength.
- */
- public BigInteger getChunkLength()
- {
- return this.chunkLength;
- }
-
- /**
- * @return Returns the guid.
- */
- public GUID getGuid()
- {
- return this.guid;
- }
-
- /**
- * @return Returns the position.
- */
- public long getPosition()
- {
- return this.position;
- }
-
- /**
- * This method creates a String containing useful information prepared to be
- * printed on STD-OUT.
- * This method is intended to be overwritten by inheriting classes.
- *
- * @param prefix each line gets this string prepended.
- * @return Information of current Chunk Object.
- */
- public String prettyPrint(final String prefix)
- {
- final StringBuilder result = new StringBuilder();
- result.append(prefix).append("-> GUID: ").append(GUID.getGuidDescription(this.guid)).append(Utils.LINE_SEPARATOR);
- result.append(prefix).append(" | : Starts at position: ").append(getPosition()).append(Utils.LINE_SEPARATOR);
- result.append(prefix).append(" | : Last byte at: ").append(getChunkEnd() - 1).append(Utils.LINE_SEPARATOR);
- return result.toString();
- }
-
- /**
- * Sets the position.
- *
- * @param pos position to set.
- */
- public void setPosition(final long pos)
- {
- this.position = pos;
- }
-
- /**
- * (overridden)
- *
- * @see Object#toString()
- */
- @Override
- public String toString()
- {
- return prettyPrint("");
- }
-
-}
\ No newline at end of file
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/ChunkContainer.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/ChunkContainer.java
deleted file mode 100644
index f6bb13b1..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/ChunkContainer.java
+++ /dev/null
@@ -1,191 +0,0 @@
-package com.mp3.jaudiotagger.audio.asf.data;
-
-import com.mp3.jaudiotagger.audio.asf.util.ChunkPositionComparator;
-import com.mp3.jaudiotagger.audio.asf.util.Utils;
-
-import java.math.BigInteger;
-import java.util.*;
-
-/**
- * Stores multiple ASF objects (chunks) in form of {@link Chunk} objects, and is
- * itself an ASF object (chunk).
- *
- * Because current implementation is solely used for ASF metadata, all chunks
- * (except for {@link StreamChunk}) may only be {@linkplain #addChunk(Chunk)
- * inserted} once.
- *
- * @author Christian Laireiter
- */
-public class ChunkContainer extends Chunk
-{
-
- /**
- * Stores the {@link GUID} instances, which are allowed multiple times
- * within an ASF header.
- */
- private final static Settrue
if all chunks are located at an unique
- * position. However, no intersection is tested.
- */
- protected static boolean chunkstartsUnique(final ChunkContainer container)
- {
- boolean result = true;
- final Set
- *
- * @param toAdd The chunk which is to be added.
- * @throws IllegalArgumentException If a chunk of same type is already added, except for
- * {@link StreamChunk}.
- */
- public void addChunk(final Chunk toAdd)
- {
- final List
- *
- * @param lookFor The GUID to get list for.
- * @return an already existing, or newly created list.
- */
- protected List
- *
- * @return all contained chunks
- */
- public Collectionnull
if no chunk was found, or the stored instance
- * doesn't match.
- */
- protected Chunk getFirst(final GUID lookFor, final Class extends Chunk> instanceOf)
- {
- Chunk result = null;
- final List
- *
- * @param lookFor GUID to look up.
- * @return true
if chunk with specified GUID has been added.
- */
- public boolean hasChunkByGUID(final GUID lookFor)
- {
- return this.chunkTable.containsKey(lookFor);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String prettyPrint(final String prefix)
- {
- return prettyPrint(prefix, "");
- }
-
- /**
- * Nearly the same as {@link #prettyPrint(String)} however, additional
- * information can be injected below the {@link Chunk#prettyPrint(String)}
- * output and the listing of the contained chunks.
- *
- * @param prefix The prefix to prepend.
- * @param containerInfo Information to inject.
- * @return Information of current Chunk Object.
- */
- public String prettyPrint(final String prefix, final String containerInfo)
- {
- final StringBuilder result = new StringBuilder(super.prettyPrint(prefix));
- result.append(containerInfo);
- result.append(prefix).append(" |").append(Utils.LINE_SEPARATOR);
- final ArrayList
- *
- * The {@link #METADATA_LIBRARY_OBJECT} allows the most variations of data, as
- * well as no size limitation (if it can be stored within a DWORD amount of
- * bytes).
- *
- * @author Christian Laireiter
- */
-public enum ContainerType
-{
-
- /**
- * The descriptor is used in the content branding object (chunk)
- */
- CONTENT_BRANDING(GUID.GUID_CONTENT_BRANDING, 32, false, false, false, false),
-
- /**
- * The descriptor is used in the content description object (chunk), so
- * {@linkplain MetadataDescriptor#DWORD_MAXVALUE maximum data length}
- * applies, no language index and stream number are allowed, as well as no
- * multiple values.
- */
- CONTENT_DESCRIPTION(GUID.GUID_CONTENTDESCRIPTION, 16, false, false, false, false),
- /**
- * The descriptor is used in an extended content description object, so the
- * {@linkplain MetadataDescriptor#DWORD_MAXVALUE maximum data size} applies,
- * and no language index and stream number other than "0" is
- * allowed. Additionally no multiple values are permitted.
- */
- EXTENDED_CONTENT(GUID.GUID_EXTENDED_CONTENT_DESCRIPTION, 16, false, false, false, false),
- /**
- * The descriptor is used in a metadata library object. No real size limit
- * (except DWORD range) applies. Stream numbers and language indexes can be
- * specified.
- */
- METADATA_LIBRARY_OBJECT(GUID.GUID_METADATA_LIBRARY, 32, true, true, true, true),
- /**
- * The descriptor is used in a metadata object. The
- * {@linkplain MetadataDescriptor#DWORD_MAXVALUE maximum data size} applies.
- * Stream numbers can be specified. But no language index (always
- * "0").
- */
- METADATA_OBJECT(GUID.GUID_METADATA, 16, false, true, false, true);
-
- /**
- * Determines if low has index as high, in respect to
- * {@link #getOrdered()}
- *
- * @param low
- * @param high
- * @return true
if in correct order.
- */
- public static boolean areInCorrectOrder(final ContainerType low, final ContainerType high)
- {
- final List
- *
- * @return capability ordered types
- */
- public static ContainerType[] getOrdered()
- {
- return new ContainerType[]{CONTENT_DESCRIPTION, CONTENT_BRANDING, EXTENDED_CONTENT, METADATA_OBJECT, METADATA_LIBRARY_OBJECT};
- }
-
- /**
- * Stores the guid that identifies ASF chunks which store metadata of the
- * current type.
- */
- private final GUID containerGUID;
-
- /**
- * true
if the descriptor field can store {@link GUID} values.
- */
- private final boolean guidEnabled;
-
- /**
- * true
if descriptor field can refer to a language.
- */
- private final boolean languageEnabled;
-
- /**
- * The maximum amount of bytes the descriptor data may consume.
- */
- private final BigInteger maximumDataLength;
-
- /**
- * true
if the container may store multiple values of the same
- * metadata descriptor specification (equality on name, language, and
- * stream).
- * WindowsMedia players advanced tag editor for example stores the
- * WM/Picture attribute once in the extended content description, and all
- * others in the metadata library object.
- */
- private final boolean multiValued;
-
- /**
- * if -1
a size value has to be compared against
- * {@link #maximumDataLength} because {@link Long#MAX_VALUE} is exceeded.
- * Otherwise this is the {@link BigInteger#longValue()} representation.
- */
- private final long perfMaxDataLen;
-
- /**
- * true
if descriptor field can refer to specific streams.
- */
- private final boolean streamEnabled;
-
- /**
- * Creates an instance
- *
- * @param guid see {@link #containerGUID}
- * @param maxDataLenBits The amount of bits that is used to represent an unsigned value
- * for the containers size descriptors. Will create a maximum
- * value for {@link #maximumDataLength}. (2 ^ maxDataLenBits -1)
- * @param guidAllowed see {@link #guidEnabled}
- * @param stream see {@link #streamEnabled}
- * @param language see {@link #languageEnabled}
- * @param multiValue see {@link #multiValued}
- */
- private ContainerType(final GUID guid, final int maxDataLenBits, final boolean guidAllowed, final boolean stream, final boolean language, final boolean multiValue)
- {
- this.containerGUID = guid;
- this.maximumDataLength = BigInteger.valueOf(2).pow(maxDataLenBits).subtract(BigInteger.ONE);
- if (this.maximumDataLength.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) <= 0)
- {
- this.perfMaxDataLen = this.maximumDataLength.longValue();
- }
- else
- {
- this.perfMaxDataLen = -1;
- }
- this.guidEnabled = guidAllowed;
- this.streamEnabled = stream;
- this.languageEnabled = language;
- this.multiValued = multiValue;
- }
-
- /**
- * Calls {@link #checkConstraints(String, byte[], int, int, int)} and
- * actually throws the exception if there is one.
- *
- * @param name name of the descriptor
- * @param data content
- * @param type data type
- * @param stream stream number
- * @param language language index
- */
- public void assertConstraints(final String name, final byte[] data, final int type, final int stream, final int language)
- {
- final RuntimeException result = checkConstraints(name, data, type, stream, language);
- if (result != null)
- {
- throw result;
- }
- }
-
- /**
- * Checks if the values for a {@linkplain MetadataDescriptor content
- * descriptor} match the contraints of the container type, and returns a
- * {@link RuntimeException} if the requirements aren't met.
- *
- * @param name name of the descriptor
- * @param data content
- * @param type data type
- * @param stream stream number
- * @param language language index
- * @return null
if everything is fine.
- */
- public RuntimeException checkConstraints(final String name, final byte[] data, final int type, final int stream, final int language)
- {
- RuntimeException result = null;
- // TODO generate tests
- if (name == null || data == null)
- {
- result = new IllegalArgumentException("Arguments must not be null.");
- }
- else
- {
- if (!Utils.isStringLengthValidNullSafe(name))
- {
- result = new IllegalArgumentException(ErrorMessage.WMA_LENGTH_OF_STRING_IS_TOO_LARGE.getMsg(name.length()));
- }
- }
- if (result == null && !isWithinValueRange(data.length))
- {
- result = new IllegalArgumentException(ErrorMessage.WMA_LENGTH_OF_DATA_IS_TOO_LARGE.getMsg(data.length, getMaximumDataLength(), getContainerGUID().getDescription()));
- }
- if (result == null && (stream < 0 || stream > MetadataDescriptor.MAX_STREAM_NUMBER || (!isStreamNumberEnabled() && stream != 0)))
- {
- final String streamAllowed = isStreamNumberEnabled() ? "0 to 127" : "0";
- result = new IllegalArgumentException(ErrorMessage.WMA_INVALID_STREAM_REFERNCE.getMsg(stream, streamAllowed, getContainerGUID().getDescription()));
- }
- if (result == null && type == MetadataDescriptor.TYPE_GUID && !isGuidEnabled())
- {
- result = new IllegalArgumentException(ErrorMessage.WMA_INVALID_GUID_USE.getMsg(getContainerGUID().getDescription()));
- }
- if (result == null && ((language != 0 && !isLanguageEnabled()) || (language < 0 || language >= MetadataDescriptor.MAX_LANG_INDEX)))
- {
- final String langAllowed = isStreamNumberEnabled() ? "0 to 126" : "0";
- result = new IllegalArgumentException(ErrorMessage.WMA_INVALID_LANGUAGE_USE.getMsg(language, getContainerGUID().getDescription(), langAllowed));
- }
- if (result == null && this == CONTENT_DESCRIPTION && type != MetadataDescriptor.TYPE_STRING)
- {
- result = new IllegalArgumentException(ErrorMessage.WMA_ONLY_STRING_IN_CD.getMsg());
- }
- return result;
- }
-
- /**
- * @return the containerGUID
- */
- public GUID getContainerGUID()
- {
- return this.containerGUID;
- }
-
- /**
- * @return the maximumDataLength
- */
- public BigInteger getMaximumDataLength()
- {
- return this.maximumDataLength;
- }
-
- /**
- * @return the guidEnabled
- */
- public boolean isGuidEnabled()
- {
- return this.guidEnabled;
- }
-
- /**
- * @return the languageEnabled
- */
- public boolean isLanguageEnabled()
- {
- return this.languageEnabled;
- }
-
- /**
- * Tests if the given value is less than or equal to
- * {@link #getMaximumDataLength()}, and greater or equal to zero.
- *
- * @param value The value to test
- * @return true
if size restrictions for binary data are met
- * with this container type.
- */
- public boolean isWithinValueRange(final long value)
- {
- return (this.perfMaxDataLen == -1 || this.perfMaxDataLen >= value) && value >= 0;
- }
-
- /**
- * @return the multiValued
- */
- public boolean isMultiValued()
- {
- return this.multiValued;
- }
-
- /**
- * @return the streamEnabled
- */
- public boolean isStreamNumberEnabled()
- {
- return this.streamEnabled;
- }
-}
\ No newline at end of file
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/ContentBranding.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/ContentBranding.java
deleted file mode 100644
index 5a1e2f9b..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/ContentBranding.java
+++ /dev/null
@@ -1,224 +0,0 @@
-package com.mp3.jaudiotagger.audio.asf.data;
-
-import com.mp3.jaudiotagger.StandardCharsets;
-import com.mp3.jaudiotagger.audio.asf.util.Utils;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.math.BigInteger;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * This structure represents the value of the content branding object, which
- * stores the banner image, the banner image URL and the copyright URL.
- *
- * @author Christian Laireiter
- */
-public final class ContentBranding extends MetadataContainer
-{
-
- /**
- * Stores the allowed {@linkplain MetadataDescriptor#getName() descriptor
- * keys}.
- */
- public final static Set
- *
- * Known/valid values are:
- *
- *
- */
- public final static String KEY_BANNER_TYPE = "BANNER_IMAGE_TYPE";
-
- /**
- * Descriptor key representing the banner image URL.
- */
- public final static String KEY_BANNER_URL = "BANNER_IMAGE_URL";
-
- /**
- * Descriptor key representing the copyright URL.
- */
- public final static String KEY_COPYRIGHT_URL = "COPYRIGHT_URL";
-
- static
- {
- ALLOWED = new HashSet
- *
- * @return image type
- * @see #KEY_BANNER_TYPE for known/valid values.
- */
- public long getImageType()
- {
- if (!hasDescriptor(KEY_BANNER_TYPE))
- {
- final MetadataDescriptor descriptor = new MetadataDescriptor(ContainerType.CONTENT_BRANDING, KEY_BANNER_TYPE, MetadataDescriptor.TYPE_DWORD);
- descriptor.setDWordValue(0);
- addDescriptor(descriptor);
- }
- return assertDescriptor(KEY_BANNER_TYPE).getNumber();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean isAddSupported(final MetadataDescriptor descriptor)
- {
- return ALLOWED.contains(descriptor.getName()) && super.isAddSupported(descriptor);
- }
-
- /**
- * This method sets the banner image URL, if imageURL
is not
- * blank.
- *
- * @param imageURL image URL to set.
- */
- public void setBannerImageURL(final String imageURL)
- {
- if (Utils.isBlank(imageURL))
- {
- removeDescriptorsByName(KEY_BANNER_URL);
- }
- else
- {
- assertDescriptor(KEY_BANNER_URL).setStringValue(imageURL);
- }
- }
-
- /**
- * This method sets the copyright URL, if copyRight
is not
- * blank.
- *
- * @param copyRight copyright URL to set.
- */
- public void setCopyRightURL(final String copyRight)
- {
- if (Utils.isBlank(copyRight))
- {
- removeDescriptorsByName(KEY_COPYRIGHT_URL);
- }
- else
- {
- assertDescriptor(KEY_COPYRIGHT_URL).setStringValue(copyRight);
- }
- }
-
- /**
- * @param imageType
- * @param imageData
- */
- public void setImage(final long imageType, final byte[] imageData)
- {
- assert imageType >= 0 && imageType <= 3;
- assert imageType > 0 || imageData.length == 0;
- assertDescriptor(KEY_BANNER_TYPE, MetadataDescriptor.TYPE_DWORD).setDWordValue(imageType);
- assertDescriptor(KEY_BANNER_IMAGE, MetadataDescriptor.TYPE_BINARY).setBinaryValue(imageData);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public long writeInto(final OutputStream out) throws IOException
- {
- final long chunkSize = getCurrentAsfChunkSize();
- out.write(getGuid().getBytes());
- Utils.writeUINT64(chunkSize, out);
- Utils.writeUINT32(getImageType(), out);
- assert getImageType() >= 0 && getImageType() <= 3;
- final byte[] imageData = getImageData();
- assert getImageType() > 0 || imageData.length == 0;
- Utils.writeUINT32(imageData.length, out);
- out.write(imageData);
- Utils.writeUINT32(getBannerImageURL().length(), out);
- out.write(getBannerImageURL().getBytes(StandardCharsets.US_ASCII));
- Utils.writeUINT32(getCopyRightURL().length(), out);
- out.write(getCopyRightURL().getBytes(StandardCharsets.US_ASCII));
- return chunkSize;
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/ContentDescription.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/ContentDescription.java
deleted file mode 100644
index d7ae6143..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/ContentDescription.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2004-2005 Christian Laireiter
- * It is optional within ASF files. But if, exists only once.
- *
- * @author Christian Laireiter
- */
-public final class ContentDescription extends MetadataContainer
-{
- /**
- * Stores the only allowed keys of this metadata container.
- */
- public final static Set
- */
- public ContentDescription()
- {
- this(0, BigInteger.ZERO);
- }
-
- /**
- * Creates an instance.
- *
- * @param pos Position of content description within file or stream
- * @param chunkLen Length of content description.
- */
- public ContentDescription(final long pos, final BigInteger chunkLen)
- {
- super(ContainerType.CONTENT_DESCRIPTION, pos, chunkLen);
- }
-
- /**
- * @return Returns the author.
- */
- public String getAuthor()
- {
- return getValueFor(KEY_AUTHOR);
- }
-
- /**
- * @return Returns the comment.
- */
- public String getComment()
- {
- return getValueFor(KEY_DESCRIPTION);
- }
-
- /**
- * @return Returns the copyRight.
- */
- public String getCopyRight()
- {
- return getValueFor(KEY_COPYRIGHT);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public long getCurrentAsfChunkSize()
- {
- long result = 44; // GUID + UINT64 for size + 5 times string length
- // (each
- // 2 bytes) + 5 times zero term char (2 bytes each).
- result += getAuthor().length() * 2; // UTF-16LE
- result += getComment().length() * 2;
- result += getRating().length() * 2;
- result += getTitle().length() * 2;
- result += getCopyRight().length() * 2;
- return result;
- }
-
- /**
- * @return returns the rating.
- */
- public String getRating()
- {
- return getValueFor(KEY_RATING);
- }
-
- /**
- * @return Returns the title.
- */
- public String getTitle()
- {
- return getValueFor(KEY_TITLE);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean isAddSupported(final MetadataDescriptor descriptor)
- {
- return ALLOWED.contains(descriptor.getName()) && super.isAddSupported(descriptor);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String prettyPrint(final String prefix)
- {
- final StringBuilder result = new StringBuilder(super.prettyPrint(prefix));
- result.append(prefix).append(" |->Title : ").append(getTitle()).append(Utils.LINE_SEPARATOR);
- result.append(prefix).append(" |->Author : ").append(getAuthor()).append(Utils.LINE_SEPARATOR);
- result.append(prefix).append(" |->Copyright : ").append(getCopyRight()).append(Utils.LINE_SEPARATOR);
- result.append(prefix).append(" |->Description: ").append(getComment()).append(Utils.LINE_SEPARATOR);
- result.append(prefix).append(" |->Rating :").append(getRating()).append(Utils.LINE_SEPARATOR);
- return result.toString();
- }
-
- /**
- * @param fileAuthor The author to set.
- * @throws IllegalArgumentException If "UTF-16LE"-byte-representation would take more than 65535
- * bytes.
- */
- public void setAuthor(final String fileAuthor) throws IllegalArgumentException
- {
- setStringValue(KEY_AUTHOR, fileAuthor);
- }
-
- /**
- * @param tagComment The comment to set.
- * @throws IllegalArgumentException If "UTF-16LE"-byte-representation would take more than 65535
- * bytes.
- */
- public void setComment(final String tagComment) throws IllegalArgumentException
- {
- setStringValue(KEY_DESCRIPTION, tagComment);
- }
-
- /**
- * @param cpright The copyRight to set.
- * @throws IllegalArgumentException If "UTF-16LE"-byte-representation would take more than 65535
- * bytes.
- */
- public void setCopyright(final String cpright) throws IllegalArgumentException
- {
- setStringValue(KEY_COPYRIGHT, cpright);
- }
-
- /**
- * @param ratingText The rating to be set.
- * @throws IllegalArgumentException If "UTF-16LE"-byte-representation would take more than 65535
- * bytes.
- */
- public void setRating(final String ratingText) throws IllegalArgumentException
- {
- setStringValue(KEY_RATING, ratingText);
- }
-
- /**
- * @param songTitle The title to set.
- * @throws IllegalArgumentException If "UTF-16LE"-byte-representation would take more than 65535
- * bytes.
- */
- public void setTitle(final String songTitle) throws IllegalArgumentException
- {
- setStringValue(KEY_TITLE, songTitle);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public long writeInto(final OutputStream out) throws IOException
- {
- final long chunkSize = getCurrentAsfChunkSize();
-
- out.write(this.getGuid().getBytes());
- Utils.writeUINT64(getCurrentAsfChunkSize(), out);
- // write the sizes of the string representations plus 2 bytes zero term
- // character
- Utils.writeUINT16(getTitle().length() * 2 + 2, out);
- Utils.writeUINT16(getAuthor().length() * 2 + 2, out);
- Utils.writeUINT16(getCopyRight().length() * 2 + 2, out);
- Utils.writeUINT16(getComment().length() * 2 + 2, out);
- Utils.writeUINT16(getRating().length() * 2 + 2, out);
- // write the Strings
- out.write(Utils.getBytes(getTitle(), AsfHeader.ASF_CHARSET));
- out.write(AsfHeader.ZERO_TERM);
- out.write(Utils.getBytes(getAuthor(), AsfHeader.ASF_CHARSET));
- out.write(AsfHeader.ZERO_TERM);
- out.write(Utils.getBytes(getCopyRight(), AsfHeader.ASF_CHARSET));
- out.write(AsfHeader.ZERO_TERM);
- out.write(Utils.getBytes(getComment(), AsfHeader.ASF_CHARSET));
- out.write(AsfHeader.ZERO_TERM);
- out.write(Utils.getBytes(getRating(), AsfHeader.ASF_CHARSET));
- out.write(AsfHeader.ZERO_TERM);
- return chunkSize;
- }
-}
\ No newline at end of file
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/EncodingChunk.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/EncodingChunk.java
deleted file mode 100644
index 6cd9b218..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/EncodingChunk.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2004-2005 Christian Laireiter
- * Since the needed parameters were found in other chunks the implementation of
- * this class was paused.
- * TODO complete analysis.
- *
- * @author Christian Laireiter
- */
-public class EncodingChunk extends Chunk
-{
-
- /**
- * The read strings.
- */
- private final List
- *
- * @author Christian Laireiter
- */
-public class FileHeader extends Chunk
-{
-
- /**
- * Duration of the media content in 100ns steps.
- */
- private final BigInteger duration;
-
- /**
- * The time the file was created.
- */
- private final Date fileCreationTime;
-
- /**
- * Size of the file or stream.
- */
- private final BigInteger fileSize;
-
- /**
- * Usually contains value of 2.
- */
- private final long flags;
-
- /**
- * Maximum size of stream packages.
- * Warning: must be same size as {@link #minPackageSize}. Its not
- * known how to handle deviating values.
- */
- private final long maxPackageSize;
-
- /**
- * Minimun size of stream packages.
- * Warning: must be same size as {@link #maxPackageSize}. Its not
- * known how to handle deviating values.
- */
- private final long minPackageSize;
-
- /**
- * Number of stream packages within the File.
- */
- private final BigInteger packageCount;
-
- /**
- * No Idea of the Meaning, but stored anyway.
- * Source documentation says it is: "Timestamp of end position"
- */
- private final BigInteger timeEndPos;
-
- /**
- * Like {@link #timeEndPos}no Idea.
- */
- private final BigInteger timeStartPos;
-
- /**
- * Size of an uncompressed video frame.
- */
- private final long uncompressedFrameSize;
-
- /**
- * Creates an instance.
- *
- * @param chunckLen Length of the file header (chunk)
- * @param size Size of file or stream
- * @param fileTime Time file or stream was created. Time is calculated since 1st
- * january of 1601 in 100ns steps.
- * @param pkgCount Number of stream packages.
- * @param dur Duration of media clip in 100ns steps
- * @param timestampStart Timestamp of start {@link #timeStartPos}
- * @param timestampEnd Timestamp of end {@link #timeEndPos}
- * @param headerFlags some stream related flags.
- * @param minPkgSize minimum size of packages
- * @param maxPkgSize maximum size of packages
- * @param uncmpVideoFrameSize Size of an uncompressed Video Frame.
- */
- public FileHeader(final BigInteger chunckLen, final BigInteger size, final BigInteger fileTime, final BigInteger pkgCount, final BigInteger dur, final BigInteger timestampStart, final BigInteger timestampEnd, final long headerFlags, final long minPkgSize, final long maxPkgSize, final long uncmpVideoFrameSize)
- {
- super(GUID.GUID_FILE, chunckLen);
- this.fileSize = size;
- this.packageCount = pkgCount;
- this.duration = dur;
- this.timeStartPos = timestampStart;
- this.timeEndPos = timestampEnd;
- this.flags = headerFlags;
- this.minPackageSize = minPkgSize;
- this.maxPackageSize = maxPkgSize;
- this.uncompressedFrameSize = uncmpVideoFrameSize;
- this.fileCreationTime = Utils.getDateOf(fileTime).getTime();
- }
-
- /**
- * @return Returns the duration.
- */
- public BigInteger getDuration()
- {
- return this.duration;
- }
-
- /**
- * This method converts {@link #getDuration()}from 100ns steps to normal
- * seconds.
- *
- * @return Duration of the media in seconds.
- */
- public int getDurationInSeconds()
- {
- return this.duration.divide(new BigInteger("10000000")).intValue();
- }
-
- /**
- * @return Returns the fileCreationTime.
- */
- public Date getFileCreationTime()
- {
- return new Date(this.fileCreationTime.getTime());
- }
-
- /**
- * @return Returns the fileSize.
- */
- public BigInteger getFileSize()
- {
- return this.fileSize;
- }
-
- /**
- * @return Returns the flags.
- */
- public long getFlags()
- {
- return this.flags;
- }
-
- /**
- * @return Returns the maxPackageSize.
- */
- public long getMaxPackageSize()
- {
- return this.maxPackageSize;
- }
-
- /**
- * @return Returns the minPackageSize.
- */
- public long getMinPackageSize()
- {
- return this.minPackageSize;
- }
-
- /**
- * @return Returns the packageCount.
- */
- public BigInteger getPackageCount()
- {
- return this.packageCount;
- }
-
- /**
- * This method converts {@link #getDuration()} from 100ns steps to normal
- * seconds with a fractional part taking milliseconds.
- *
- * @return The duration of the media in seconds (with a precision of
- * milliseconds)
- */
- public float getPreciseDuration()
- {
- return (float) (getDuration().doubleValue() / 10000000d);
- }
-
- /**
- * @return Returns the timeEndPos.
- */
- public BigInteger getTimeEndPos()
- {
- return this.timeEndPos;
- }
-
- /**
- * @return Returns the timeStartPos.
- */
- public BigInteger getTimeStartPos()
- {
- return this.timeStartPos;
- }
-
- /**
- * @return Returns the uncompressedFrameSize.
- */
- public long getUncompressedFrameSize()
- {
- return this.uncompressedFrameSize;
- }
-
- /**
- * (overridden)
- *
- * @see Chunk#prettyPrint(String)
- */
- @Override
- public String prettyPrint(final String prefix)
- {
- final StringBuilder result = new StringBuilder(super.prettyPrint(prefix));
- result.append(prefix).append(" |-> Filesize = ").append(getFileSize().toString()).append(" Bytes").append(Utils.LINE_SEPARATOR);
- result.append(prefix).append(" |-> Media duration= ").append(getDuration().divide(new BigInteger("10000")).toString()).append(" ms").append(Utils.LINE_SEPARATOR);
- result.append(prefix).append(" |-> Created at = ").append(getFileCreationTime()).append(Utils.LINE_SEPARATOR);
- return result.toString();
- }
-}
\ No newline at end of file
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/GUID.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/GUID.java
deleted file mode 100644
index 510339a4..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/GUID.java
+++ /dev/null
@@ -1,520 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2004-2005 Christian Laireiter
- *
- * @author Christian Laireiter
- */
-public final class GUID
-{
-
- /**
- * This constant defines the GUID for stream chunks describing audio
- * streams, indicating the the audio stream has no error concealment.
- */
- public final static GUID GUID_AUDIO_ERROR_CONCEALEMENT_ABSENT = new GUID(new int[]{0x40, 0xA4, 0xF1, 0x49, 0xCE, 0x4E, 0xD0, 0x11, 0xA3, 0xAC, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6}, "Audio error concealment absent.");
-
- /**
- * This constant defines the GUID for stream chunks describing audio
- * streams, indicating the the audio stream has interleaved error
- * concealment.
- */
- public final static GUID GUID_AUDIO_ERROR_CONCEALEMENT_INTERLEAVED = new GUID(new int[]{0x40, 0xA4, 0xF1, 0x49, 0xCE, 0x4E, 0xD0, 0x11, 0xA3, 0xAC, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6}, "Interleaved audio error concealment.");
-
- /**
- * This constant stores the GUID indicating that stream type is audio.
- */
- public final static GUID GUID_AUDIOSTREAM = new GUID(new int[]{0x40, 0x9E, 0x69, 0xF8, 0x4D, 0x5B, 0xCF, 0x11, 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}, " Audio stream");
-
- /**
- * This constant stores the GUID indicating a content branding object.
- */
- public final static GUID GUID_CONTENT_BRANDING = new GUID(new int[]{0xFA, 0xB3, 0x11, 0x22, 0x23, 0xBD, 0xD2, 0x11, 0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E}, "Content Branding");
-
- /**
- * This is for the Content Encryption Object
- * 2211B3FB-BD23-11D2-B4B7-00A0C955FC6E, needs to be little-endian.
- */
- public final static GUID GUID_CONTENT_ENCRYPTION = new GUID(new int[]{0xfb, 0xb3, 0x11, 0x22, 0x23, 0xbd, 0xd2, 0x11, 0xb4, 0xb7, 0x00, 0xa0, 0xc9, 0x55, 0xfc, 0x6e}, "Content Encryption Object");
-
- /**
- * This constant represents the guidData for a chunk which contains Title,
- * author, copyright, description and rating.
- */
- public final static GUID GUID_CONTENTDESCRIPTION = new GUID(new int[]{0x33, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF, 0x11, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}, "Content Description");
-
- /**
- * This constant stores the GUID for Encoding-Info chunks.
- */
- public final static GUID GUID_ENCODING = new GUID(new int[]{0x40, 0x52, 0xD1, 0x86, 0x1D, 0x31, 0xD0, 0x11, 0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6}, "Encoding description");
-
- /**
- * This constant defines the GUID for a WMA "Extended Content Description"
- * chunk.
- */
- public final static GUID GUID_EXTENDED_CONTENT_DESCRIPTION = new GUID(new int[]{0x40, 0xA4, 0xD0, 0xD2, 0x07, 0xE3, 0xD2, 0x11, 0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50}, "Extended Content Description");
-
- /**
- * GUID of ASF file header.
- */
- public final static GUID GUID_FILE = new GUID(new int[]{0xA1, 0xDC, 0xAB, 0x8C, 0x47, 0xA9, 0xCF, 0x11, 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}, "File header");
-
- /**
- * This constant defines the GUID of a asf header chunk.
- */
- public final static GUID GUID_HEADER = new GUID(new int[]{0x30, 0x26, 0xb2, 0x75, 0x8e, 0x66, 0xcf, 0x11, 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c}, "Asf header");
-
- /**
- * This constant stores a GUID whose functionality is unknown.
- */
- public final static GUID GUID_HEADER_EXTENSION = new GUID(new int[]{0xB5, 0x03, 0xBF, 0x5F, 0x2E, 0xA9, 0xCF, 0x11, 0x8E, 0xE3, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}, "Header Extension");
-
- /**
- * This constant stores the GUID indicating the asf language list object.
- */
- public final static GUID GUID_LANGUAGE_LIST = new GUID(new int[]{0xa9, 0x46, 0x43, 0x7c, 0xe0, 0xef, 0xfc, 0x4b, 0xb2, 0x29, 0x39, 0x3e, 0xde, 0x41, 0x5c, 0x85}, "Language List");
-
- /**
- * This constant stores the length of GUIDs used with ASF streams.
- */
- public final static int GUID_LENGTH = 16;
-
- /**
- * This constant stores the GUID indicating the asf metadata object.
- */
- public final static GUID GUID_METADATA = new GUID(new int[]{0xea, 0xcb, 0xf8, 0xc5, 0xaf, 0x5b, 0x77, 0x48, 0x84, 0x67, 0xaa, 0x8c, 0x44, 0xfa, 0x4c, 0xca}, "Metadata");
-
- /**
- * This constant stores the GUID indicating the asf metadata library object.
- */
- public final static GUID GUID_METADATA_LIBRARY = new GUID(new int[]{0x94, 0x1c, 0x23, 0x44, 0x98, 0x94, 0xd1, 0x49, 0xa1, 0x41, 0x1d, 0x13, 0x4e, 0x45, 0x70, 0x54}, "Metadata Library");
-
- /**
- * The GUID String values format.
- */
- private final static Pattern GUID_PATTERN = Pattern.compile("[a-f0-9]{8}\\-[a-f0-9]{4}\\-[a-f0-9]{4}\\-[a-f0-9]{4}\\-[a-f0-9]{12}", Pattern.CASE_INSENSITIVE);
-
- /**
- * This constant stores the GUID indicating a stream object.
- */
- public final static GUID GUID_STREAM = new GUID(new int[]{0x91, 0x07, 0xDC, 0xB7, 0xB7, 0xA9, 0xCF, 0x11, 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}, "Stream");
-
- /**
- * This constant stores a GUID indicating a "stream bitrate properties"
- * chunk.
- */
- public final static GUID GUID_STREAM_BITRATE_PROPERTIES = new GUID(new int[]{0xCE, 0x75, 0xF8, 0x7B, 0x8D, 0x46, 0xD1, 0x11, 0x8D, 0x82, 0x00, 0x60, 0x97, 0xC9, 0xA2, 0xB2}, "Stream bitrate properties");
-
- /**
- * This map is used, to get the description of a GUID instance, which has
- * been created by reading.
- * The map comparison is done against the {@link GUID#guidData} field. But
- * only the {@link #KNOWN_GUIDS} have a description set.
- */
- private final static Map
- */
- public final static GUID SCRIPT_COMMAND_OBJECT = new GUID(new int[]{0x30, 0x1a, 0xfb, 0x1e, 0x62, 0x0b, 0xd0, 0x11, 0xa3, 0x9b, 0x00, 0xa0, 0xc9, 0x03, 0x48, 0xf6}, "Script Command Object");
-
- static
- {
- KNOWN_GUIDS = new GUID[]{GUID_AUDIO_ERROR_CONCEALEMENT_ABSENT, GUID_CONTENTDESCRIPTION, GUID_AUDIOSTREAM, GUID_ENCODING, GUID_FILE, GUID_HEADER, GUID_STREAM, GUID_EXTENDED_CONTENT_DESCRIPTION, GUID_VIDEOSTREAM, GUID_HEADER_EXTENSION, GUID_STREAM_BITRATE_PROPERTIES, SCRIPT_COMMAND_OBJECT, GUID_CONTENT_ENCRYPTION, GUID_CONTENT_BRANDING, GUID_UNSPECIFIED, GUID_METADATA_LIBRARY, GUID_METADATA, GUID_LANGUAGE_LIST};
- GUID_TO_CONFIGURED = new HashMapvalue
is matching the GUID
- * specification of ASF streams.
- *
- * @param value possible GUID.
- * @return true
if value
matches the specification
- * of a GUID.
- */
- public static boolean assertGUID(final int[] value)
- {
- return value != null && value.length == GUID.GUID_LENGTH;
- }
-
- /**
- * This method looks up a GUID instance from {@link #KNOWN_GUIDS} which
- * matches the value of the given GUID.
- *
- * @param orig GUID to look up.
- * @return a GUID instance from {@link #KNOWN_GUIDS} if available.
- * null
else.
- */
- public static GUID getConfigured(final GUID orig)
- {
- // safe against null
- return GUID_TO_CONFIGURED.get(orig);
- }
-
- /**
- * This method searches a GUID in {@link #KNOWN_GUIDS}which is equal to the
- * given guidData
and returns its description.
- * This method is useful if a GUID was read out of a file and no
- * identification has been done yet.
- *
- * @param guid GUID, which description is needed.
- * @return description of the GUID if found. Else null
- */
- public static String getGuidDescription(final GUID guid)
- {
- String result = null;
- if (guid == null)
- {
- throw new IllegalArgumentException("Argument must not be null.");
- }
- if (getConfigured(guid) != null)
- {
- result = getConfigured(guid).getDescription();
- }
- return result;
- }
-
- /**
- * This method parses a String as GUID.
- * The format is like the one in the ASF specification.
- * An Example: C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA
- *
- * @param guid the string to parse.
- * @return the GUID.
- * @throws GUIDFormatException If the GUID has an invalid format.
- */
- public static GUID parseGUID(final String guid) throws GUIDFormatException
- {
- if (guid == null)
- {
- throw new GUIDFormatException("null");
- }
- if (!GUID_PATTERN.matcher(guid).matches())
- {
- throw new GUIDFormatException("Invalid guidData format.");
- }
- final int[] bytes = new int[GUID_LENGTH];
- /*
- * Don't laugh, but did not really come up with a nicer solution today
- */
- final int[] arrayIndices = {3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15};
- int arrayPointer = 0;
- for (int i = 0; i < guid.length(); i++)
- {
- if (guid.charAt(i) == '-')
- {
- continue;
- }
- bytes[arrayIndices[arrayPointer++]] = Integer.parseInt(guid.substring(i, i + 2), 16);
- i++;
- }
- return new GUID(bytes);
- }
-
- /**
- * Stores an optionally description of the GUID.
- */
- private String description = "";
-
- /**
- * An instance of this class stores the value of the wrapped GUID in this
- * field.
- */
- private int[] guidData = null;
-
- /**
- * Stores the hash code of the object.
- * "-1"
if not determined yet.
- */
- private int hash;
-
- /**
- * Creates an instance and assigns given value
.
- *
- * @param value GUID, which should be assigned. (will be converted to int[])
- */
- public GUID(final byte[] value)
- {
- assert value != null;
- final int[] tmp = new int[value.length];
- for (int i = 0; i < value.length; i++)
- {
- tmp[i] = (0xFF & value[i]);
- }
- setGUID(tmp);
- }
-
- /**
- * Creates an instance and assigns given value
.
- *
- * @param value GUID, which should be assigned.
- */
- public GUID(final int[] value)
- {
- setGUID(value);
- }
-
- /**
- * Creates an instance like {@link #GUID(int[])}and sets the optional
- * description.
- *
- * @param value GUID, which should be assigned.
- * @param desc Description for the GUID.
- */
- public GUID(final int[] value, final String desc)
- {
- this(value);
- if (desc == null)
- {
- throw new IllegalArgumentException("Argument must not be null.");
- }
- this.description = desc;
- }
-
- /**
- * Creates an instance like {@link #GUID(int[])} and sets the optional
- * description. (the int[] is obtained by {@link GUID#parseGUID(String)})
- *
- * @param guidString GUID, which should be assigned.
- * @param desc Description for the GUID.
- */
- public GUID(final String guidString, final String desc)
- {
- this(parseGUID(guidString).getGUID());
- if (desc == null)
- {
- throw new IllegalArgumentException("Argument must not be null.");
- }
- this.description = desc;
- }
-
- /**
- * This method compares two objects. If the given Object is a {@link GUID},
- * the stored GUID values are compared.
- *
- * @see Object#equals(Object)
- */
- @Override
- public boolean equals(final Object obj)
- {
- boolean result = false;
- if (obj instanceof GUID)
- {
- final GUID other = (GUID) obj;
- result = Arrays.equals(this.getGUID(), other.getGUID());
- }
- return result;
- }
-
- /**
- * This method returns the GUID as an array of bytes.
- *
- * @return The GUID as a byte array.
- * @see #getGUID()
- */
- public byte[] getBytes()
- {
- final byte[] result = new byte[this.guidData.length];
- for (int i = 0; i < result.length; i++)
- {
- result[i] = (byte) (this.guidData[i] & 0xFF);
- }
- return result;
- }
-
- /**
- * @return Returns the description.
- */
- public String getDescription()
- {
- return this.description;
- }
-
- /**
- * This method returns the GUID of this object.
- *
- * @return stored GUID.
- */
- public int[] getGUID()
- {
- final int[] copy = new int[this.guidData.length];
- System.arraycopy(this.guidData, 0, copy, 0, this.guidData.length);
- return copy;
- }
-
- /**
- * Convenience method to get 2digit hex values of each byte.
- *
- * @param bytes bytes to convert.
- * @return each byte as 2 digit hex.
- */
- private String[] getHex(final byte[] bytes)
- {
- final String[] result = new String[bytes.length];
- final StringBuilder tmp = new StringBuilder();
- for (int i = 0; i < bytes.length; i++)
- {
- tmp.delete(0, tmp.length());
- tmp.append(Integer.toHexString(0xFF & bytes[i]));
- if (tmp.length() == 1)
- {
- tmp.insert(0, "0");
- }
- result[i] = tmp.toString();
- }
- return result;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode()
- {
- if (this.hash == -1)
- {
- int tmp = 0;
- for (final int curr : getGUID())
- {
- tmp = tmp * 31 + curr;
- }
- this.hash = tmp;
- }
- return this.hash;
- }
-
- /**
- * This method checks if the currently stored GUID ({@link #guidData}) is
- * correctly filled.
- *
- * @return true
if it is.
- */
- public boolean isValid()
- {
- return assertGUID(getGUID());
- }
-
- /**
- * This method gives a hex formatted representation of {@link #getGUID()}
- *
- * @return hex formatted representation.
- */
- public String prettyPrint()
- {
- final StringBuilder result = new StringBuilder();
- String descr = getDescription();
- if (Utils.isBlank(descr))
- {
- descr = getGuidDescription(this);
- }
- if (!Utils.isBlank(descr))
- {
- result.append("Description: ").append(descr).append(Utils.LINE_SEPARATOR).append(" ");
- }
- result.append(this.toString());
- return result.toString();
- }
-
- /**
- * This method saves a copy of the given value
as the
- * represented value of this object.
- * The given value is checked with {@link #assertGUID(int[])}.
- *
- * @param value GUID to assign.
- */
- private void setGUID(final int[] value)
- {
- if (assertGUID(value))
- {
- this.guidData = new int[GUID_LENGTH];
- System.arraycopy(value, 0, this.guidData, 0, GUID_LENGTH);
- }
- else
- {
- throw new IllegalArgumentException("The given guidData doesn't match the GUID specification.");
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString()
- {
- // C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA
- // 0xea, 0xcb,0xf8, 0xc5, 0xaf, 0x5b, 0x77, 0x48, 0x84, 0x67, 0xaa,
- // 0x8c, 0x44,0xfa, 0x4c, 0xca
- final StringBuilder result = new StringBuilder();
- final String[] bytes = getHex(getBytes());
- result.append(bytes[3]);
- result.append(bytes[2]);
- result.append(bytes[1]);
- result.append(bytes[0]);
- result.append('-');
- result.append(bytes[5]);
- result.append(bytes[4]);
- result.append('-');
- result.append(bytes[7]);
- result.append(bytes[6]);
- result.append('-');
- result.append(bytes[8]);
- result.append(bytes[9]);
- result.append('-');
- result.append(bytes[10]);
- result.append(bytes[11]);
- result.append(bytes[12]);
- result.append(bytes[13]);
- result.append(bytes[14]);
- result.append(bytes[15]);
- return result.toString();
- }
-
-}
\ No newline at end of file
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/GUIDFormatException.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/GUIDFormatException.java
deleted file mode 100644
index 74b8a7b6..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/GUIDFormatException.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.mp3.jaudiotagger.audio.asf.data;
-
-/**
- * This exception is used when a string was about to be interpreted as a GUID,
- * but did not match the format.
- *
- * @author Christian Laireiter
- */
-public class GUIDFormatException extends IllegalArgumentException
-{
-
- /**
- *
- */
- private static final long serialVersionUID = 6035645678612384953L;
-
- /**
- * Creates an instance.
- *
- * @param detail detail message.
- */
- public GUIDFormatException(final String detail)
- {
- super(detail);
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/LanguageList.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/LanguageList.java
deleted file mode 100644
index eb96d985..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/LanguageList.java
+++ /dev/null
@@ -1,125 +0,0 @@
-package com.mp3.jaudiotagger.audio.asf.data;
-
-import com.mp3.jaudiotagger.audio.asf.util.Utils;
-import com.mp3.jaudiotagger.logging.ErrorMessage;
-
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * This structure represents the data of the ASF language object.
- * The language list is simply a listing of language codes which should comply
- * to RFC-1766.
- * Consider: the index of a language is used by other entries in the ASF
- * metadata.
- *
- * @author Christian Laireiter
- */
-public class LanguageList extends Chunk
-{
-
- /**
- * List of language codes, complying RFC-1766
- */
- private final List
- */
- public LanguageList()
- {
- super(GUID.GUID_LANGUAGE_LIST, 0, BigInteger.ZERO);
- }
-
- /**
- * Creates an instance.
- *
- * @param pos position within the ASF file.
- * @param size size of the chunk
- */
- public LanguageList(final long pos, final BigInteger size)
- {
- super(GUID.GUID_LANGUAGE_LIST, pos, size);
- }
-
- /**
- * This method adds a language.
- *
- * @param language language code
- */
- public void addLanguage(final String language)
- {
- if (language.length() < MetadataDescriptor.MAX_LANG_INDEX)
- {
- if (!this.languages.contains(language))
- {
- this.languages.add(language);
- }
- }
- else
- {
- throw new IllegalArgumentException(ErrorMessage.WMA_LENGTH_OF_LANGUAGE_IS_TOO_LARGE.getMsg(language.length() * 2 + 2));
- }
- }
-
- /**
- * Returns the language code at the specified index.
- *
- * @param index the index of the language code to get.
- * @return the language code at given index.
- */
- public String getLanguage(final int index)
- {
- return this.languages.get(index);
- }
-
- /**
- * Returns the amount of stored language codes.
- *
- * @return number of stored language codes.
- */
- public int getLanguageCount()
- {
- return this.languages.size();
- }
-
- /**
- * Returns all language codes in list.
- *
- * @return list of language codes.
- */
- public List
- *
- * @author Christian Laireiter
- */
-public class MetadataContainer extends Chunk implements WriteableChunk
-{
-
- /**
- * This class is used to uniquely identify an enclosed descriptor by its
- * name, language index and stream number.
- * The type of the descriptor is ignored, since it just specifies the data
- * content.
- *
- * @author Christian Laireiter
- */
- private final static class DescriptorPointer
- {
-
- /**
- * The represented descriptor.
- */
- private MetadataDescriptor desc;
-
- /**
- * Creates an instance.
- *
- * @param descriptor the metadata descriptor to identify.
- */
- public DescriptorPointer(final MetadataDescriptor descriptor)
- {
- setDescriptor(descriptor);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals(final Object obj)
- {
- boolean result = obj == this;
- if (obj instanceof DescriptorPointer && !result)
- {
- final MetadataDescriptor other = ((DescriptorPointer) obj).desc;
- result = this.desc.getName().equals(other.getName());
- result &= this.desc.getLanguageIndex() == other.getLanguageIndex();
- result &= this.desc.getStreamNumber() == other.getStreamNumber();
- }
- return result;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode()
- {
- int hashCode;
- hashCode = this.desc.getName().hashCode();
- hashCode = hashCode * 31 + this.desc.getLanguageIndex();
- hashCode = hashCode * 31 + this.desc.getStreamNumber();
- return hashCode;
- }
-
- /**
- * Sets the descriptor to identify.
- *
- * @param descriptor the descriptor to identify.
- * @return this instance.
- */
- protected DescriptorPointer setDescriptor(final MetadataDescriptor descriptor)
- {
- assert descriptor != null;
- this.desc = descriptor;
- return this;
- }
- }
-
- /**
- * Looks up all {@linkplain ContainerType#getContainerGUID() guids} and
- * returns the matching type.
- *
- * @param guid GUID to look up
- * @return matching container type.
- * @throws IllegalArgumentException if no container type matches
- */
- private static ContainerType determineType(final GUID guid) throws IllegalArgumentException
- {
- assert guid != null;
- ContainerType result = null;
- for (final ContainerType curr : ContainerType.values())
- {
- if (curr.getContainerGUID().equals(guid))
- {
- result = curr;
- break;
- }
- }
- if (result == null)
- {
- throw new IllegalArgumentException("Unknown metadata container specified by GUID (" + guid.toString() + ")");
- }
- return result;
- }
-
- /**
- * stores the represented container type.
- */
- private final ContainerType containerType;
-
- /**
- * Stores the descriptors.
- */
- private final Map
- */
- private final DescriptorPointer perfPoint = new DescriptorPointer(new MetadataDescriptor(""));
-
- /**
- * Creates an instance.
- *
- * @param type determines the type of the container
- */
- public MetadataContainer(final ContainerType type)
- {
- this(type, 0, BigInteger.ZERO);
- }
-
- /**
- * Creates an instance.
- *
- * @param type determines the type of the container
- * @param pos location in the ASF file
- * @param size size of the chunk.
- */
- public MetadataContainer(final ContainerType type, final long pos, final BigInteger size)
- {
- super(type.getContainerGUID(), pos, size);
- this.containerType = type;
- }
-
- /**
- * Creates an instance.
- *
- * @param containerGUID the containers GUID
- * @param pos location in the ASF file
- * @param size size of the chunk.
- */
- public MetadataContainer(final GUID containerGUID, final long pos, final BigInteger size)
- {
- this(determineType(containerGUID), pos, size);
- }
-
- /**
- * Adds a metadata descriptor.
- *
- * @param toAdd the descriptor to add.
- * @throws IllegalArgumentException if descriptor does not meet container requirements, or
- * already exist.
- */
- public final void addDescriptor(final MetadataDescriptor toAdd) throws IllegalArgumentException
- {
- // check with throwing exceptions
- this.containerType.assertConstraints(toAdd.getName(), toAdd.getRawData(), toAdd.getType(), toAdd.getStreamNumber(), toAdd.getLanguageIndex());
- // validate containers capabilities
- if (!isAddSupported(toAdd))
- {
- throw new IllegalArgumentException("Descriptor cannot be added, see isAddSupported(...)");
- }
- /*
- * Check for containers types capabilities.
- */
- // Search for descriptor list by name, language and stream.
- List
- * Name, stream number and language index are compared. Data and data type
- * are ignored.
- *
- * @param lookup descriptor to look up.
- * @return true
if such a descriptor already exists.
- */
- public final boolean containsDescriptor(final MetadataDescriptor lookup)
- {
- assert lookup != null;
- return this.descriptors.containsKey(this.perfPoint.setDescriptor(lookup));
- }
-
- /**
- * Returns the type of container this instance represents.
- *
- * @return represented container type.
- */
- public final ContainerType getContainerType()
- {
- return this.containerType;
- }
-
- /**
- * {@inheritDoc}
- */
- public long getCurrentAsfChunkSize()
- {
- /*
- * 16 bytes GUID, 8 bytes chunk size, 2 bytes descriptor count
- */
- long result = 26;
- for (final MetadataDescriptor curr : getDescriptors())
- {
- result += curr.getCurrentAsfSize(this.containerType);
- }
- return result;
- }
-
- /**
- * Returns the number of contained descriptors.
- *
- * @return number of descriptors.
- */
- public final int getDescriptorCount()
- {
- return this.getDescriptors().size();
- }
-
- /**
- * Returns all stored descriptors.
- *
- * @return stored descriptors.
- */
- public final List
- *
- * @param name name of the descriptors to return
- * @return list of descriptors with given name.
- */
- public final List> values = this.descriptors.values();
- for (final List
- *
- * @param name the name of the descriptor to look up.
- * @return the string representation of a found descriptors value. Even an
- * empty string if no descriptor has been found.
- */
- protected final String getValueFor(final String name)
- {
- String result = "";
- final List
- *
- * @param name Name of the descriptor to look for.
- * @return true
if descriptor has been found.
- */
- public final boolean hasDescriptor(final String name)
- {
- return !getDescriptorsByName(name).isEmpty();
- }
-
- /**
- * Determines/checks if the given descriptor may be added to the container.
- * This implies a check for the capabilities of the container specified by
- * its {@linkplain #getContainerType() container type}.
- *
- * @param descriptor the descriptor to test.
- * @return true
if {@link #addDescriptor(MetadataDescriptor)}
- * can be called with given descriptor.
- */
- public boolean isAddSupported(final MetadataDescriptor descriptor)
- {
- boolean result = getContainerType().checkConstraints(descriptor.getName(), descriptor.getRawData(), descriptor.getType(), descriptor.getStreamNumber(), descriptor.getLanguageIndex()) == null;
- // Now check if there is already a value contained.
- if (result && !getContainerType().isMultiValued())
- {
- synchronized (this.perfPoint)
- {
- final List
- *
- * @param name the name to remove.
- */
- public final void removeDescriptorsByName(final String name)
- {
- assert name != null;
- final Iterator> iterator = this.descriptors.values().iterator();
- while (iterator.hasNext())
- {
- final List
name
and
- * {@linkplain MetadataDescriptor#setStringValue(String) assings} the string
- * value.
- *
- * @param name the name of the descriptor to set the value for.
- * @param value the string value.
- */
- protected final void setStringValue(final String name, final String value)
- {
- assertDescriptor(name).setStringValue(value);
- }
-
- /**
- * {@inheritDoc}
- */
- public long writeInto(final OutputStream out) throws IOException
- {
- final long chunkSize = getCurrentAsfChunkSize();
- final List
- *
- * @author Christian Laireiter
- */
-public final class MetadataContainerFactory
-{
-
- /**
- * Factory instance.
- */
- private final static MetadataContainerFactory INSTANCE = new MetadataContainerFactory();
-
- /**
- * Returns an instance.
- *
- * @return an instance.
- */
- public static MetadataContainerFactory getInstance()
- {
- return INSTANCE;
- }
-
- /**
- * Hidden utility class constructor.
- */
- private MetadataContainerFactory()
- {
- // Hidden
- }
-
- /**
- * Creates an appropriate {@linkplain MetadataContainer container
- * implementation} for the given container type.
- *
- * @param type the type of container to get a container instance for.
- * @return appropriate container implementation.
- */
- public MetadataContainer createContainer(final ContainerType type)
- {
- return createContainer(type, 0, BigInteger.ZERO);
- }
-
- /**
- * Convenience Method for I/O. Same as
- * {@link #createContainer(ContainerType)}, but additionally assigns
- * position and size. (since a {@link MetadataContainer} is actually a
- * {@link Chunk}).
- *
- * @param type The containers type.
- * @param pos the position within the stream.
- * @param chunkSize the size of the container.
- * @return an appropriate container implementation with assigned size and
- * position.
- */
- public MetadataContainer createContainer(final ContainerType type, final long pos, final BigInteger chunkSize)
- {
- MetadataContainer result;
- if (type == ContainerType.CONTENT_DESCRIPTION)
- {
- result = new ContentDescription(pos, chunkSize);
- }
- else if (type == ContainerType.CONTENT_BRANDING)
- {
- result = new ContentBranding(pos, chunkSize);
- }
- else
- {
- result = new MetadataContainer(type, pos, chunkSize);
- }
- return result;
- }
-
- /**
- * Convenience method which calls {@link #createContainer(ContainerType)}
- * for each given container type.
- *
- * @param types types of the container which are to be created.
- * @return appropriate container implementations.
- */
- public MetadataContainer[] createContainers(final ContainerType[] types)
- {
- assert types != null;
- final MetadataContainer[] result = new MetadataContainer[types.length];
- for (int i = 0; i < result.length; i++)
- {
- result[i] = createContainer(types[i]);
- }
- return result;
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/MetadataDescriptor.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/MetadataDescriptor.java
deleted file mode 100644
index 3399599e..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/MetadataDescriptor.java
+++ /dev/null
@@ -1,940 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2004-2005 Christian Laireiter
- * The values are
- * {@linkplain ContainerType#assertConstraints(String, byte[], int, int, int)
- * checked} against the capability introduced by the given
- * {@link ContainerType} at construction.
- *
- * Limitation: Even though some container types do not restrict the data
- * size to {@link Integer#MAX_VALUE}, this implementation does it (due to java
- * nature).
- * 2 GiB of data should suffice, and even be to large for normal java heap.
- *
- * @author Christian Laireiter
- */
-public class MetadataDescriptor implements Comparable
- */
- public static final BigInteger QWORD_MAXVALUE = new BigInteger("FFFFFFFFFFFFFFFF", 16);
-
- /**
- * Constant for the metadata descriptor-type for binary data.
- */
- public final static int TYPE_BINARY = 1;
-
- /**
- * Constant for the metadata descriptor-type for booleans.
- */
- public final static int TYPE_BOOLEAN = 2;
-
- /**
- * Constant for the metadata descriptor-type for DWORD (32-bit unsigned).
- */
- public final static int TYPE_DWORD = 3;
-
- /**
- * Constant for the metadata descriptor-type for GUIDs (128-bit).
- */
- public final static int TYPE_GUID = 6;
-
- /**
- * Constant for the metadata descriptor-type for QWORD (64-bit unsinged).
- */
- public final static int TYPE_QWORD = 4;
-
- /**
- * Constant for the metadata descriptor-type for Strings.
- */
- public final static int TYPE_STRING = 0;
-
- /**
- * Constant for the metadata descriptor-type for WORD (16-bit unsigned).
- */
- public final static int TYPE_WORD = 5;
-
- /**
- * Maximum value for WORD.
- */
- public static final int WORD_MAXVALUE = 65535;
-
- /**
- * Stores the containerType of the descriptor.
- */
- private final ContainerType containerType;
-
- /**
- * The binary representation of the value.
- */
- /*
- * Note: The maximum data length could be up to a 64-Bit number (unsigned),
- * but java for now handles just int sized byte[]. Since this class stores
- * all data in primitive byte[] this size restriction is cascaded to all
- * dependent implementations.
- */
- private byte[] content = new byte[0];
-
- /**
- * This field shows the type of the metadata descriptor.
- *
- * @see #TYPE_BINARY
- * @see #TYPE_BOOLEAN
- * @see #TYPE_DWORD
- * @see #TYPE_GUID
- * @see #TYPE_QWORD
- * @see #TYPE_STRING
- * @see #TYPE_WORD
- */
- private int descriptorType;
-
- /**
- * the index of the language in the {@linkplain LanguageList language list}
- * this descriptor applies to.
- */
- private int languageIndex = 0;
-
- /**
- * The name of the metadata descriptor.
- */
- private final String name;
-
- /**
- * The number of the stream, this descriptor applies to.
- */
- private int streamNumber = 0;
-
- /**
- * Creates an Instance.
- *
- * @param type the container type, this descriptor is resctricted to.
- * @param propName Name of the MetadataDescriptor.
- * @param propType Type of the metadata descriptor. See {@link #descriptorType}
- */
- public MetadataDescriptor(final ContainerType type, final String propName, final int propType)
- {
- this(type, propName, propType, 0, 0);
- }
-
- /**
- * Creates an Instance.
- *
- * @param type The container type the values (the whole descriptor) is
- * restricted to.
- * @param propName Name of the MetadataDescriptor.
- * @param propType Type of the metadata descriptor. See {@link #descriptorType}
- * @param stream the number of the stream the descriptor refers to.
- * @param language the index of the language entry in a {@link LanguageList} this
- * descriptor refers to.
- * Consider: No checks performed if language entry exists.
- */
- public MetadataDescriptor(final ContainerType type, final String propName, final int propType, final int stream, final int language)
- {
- assert type != null;
- type.assertConstraints(propName, new byte[0], propType, stream, language);
- this.containerType = type;
- this.name = propName;
- this.descriptorType = propType;
- this.streamNumber = stream;
- this.languageIndex = language;
- }
-
- /**
- * Creates an instance.
- * Capabilities are set to {@link ContainerType#METADATA_LIBRARY_OBJECT}.
- *
- * @param propName name of the metadata descriptor.
- */
- public MetadataDescriptor(final String propName)
- {
- this(propName, TYPE_STRING);
- }
-
- /**
- * Creates an Instance.
- * Capabilities are set to {@link ContainerType#METADATA_LIBRARY_OBJECT}.
- *
- * @param propName Name of the MetadataDescriptor.
- * @param propType Type of the metadata descriptor. See {@link #descriptorType}
- */
- public MetadataDescriptor(final String propName, final int propType)
- {
- this(ContainerType.METADATA_LIBRARY_OBJECT, propName, propType, 0, 0);
- }
-
- /**
- * Converts the descriptors value into a number if possible.
- * A boolean will be converted to "1" if true
,
- * otherwise "0".
- * String will be interpreted as number with radix "10".
- * Binary data will be interpreted as the default WORD,DWORD or QWORD binary
- * representation, but only if the data does not exceed 8 bytes. This
- * precaution is done to prevent creating a number of a multi kilobyte
- * image.
- * A GUID cannot be converted in any case.
- *
- * @return number representation.
- * @throws NumberFormatException If no conversion is supported.
- */
- public BigInteger asNumber()
- {
- BigInteger result = null;
- switch (this.descriptorType)
- {
- case TYPE_BOOLEAN:
- case TYPE_WORD:
- case TYPE_DWORD:
- case TYPE_QWORD:
- case TYPE_BINARY:
- if (this.content.length > 8)
- {
- throw new NumberFormatException("Binary data would exceed QWORD");
- }
- break;
- case TYPE_GUID:
- throw new NumberFormatException("GUID cannot be converted to a number.");
- case TYPE_STRING:
- result = new BigInteger(getString(), 10);
- break;
- default:
- throw new IllegalStateException();
- }
- if (result == null)
- {
- final byte[] copy = new byte[this.content.length];
- for (int i = 0; i < copy.length; i++)
- {
- copy[i] = this.content[this.content.length - (i + 1)];
- }
- result = new BigInteger(1, copy);
- }
- return result;
- }
-
- /**
- * (overridden)
- *
- * @see Object#clone()
- */
- @Override
- public Object clone() throws CloneNotSupportedException
- {
- return super.clone();
- }
-
- /**
- * {@inheritDoc}
- */
- public int compareTo(final MetadataDescriptor other)
- {
- return getName().compareTo(other.getName());
- }
-
- /**
- * This method creates a copy of the current object.
- * All data will be copied, too.
- *
- * @return A new metadata descriptor containing the same values as the
- * current one.
- */
- public MetadataDescriptor createCopy()
- {
- final MetadataDescriptor result = new MetadataDescriptor(this.containerType, this.name, this.descriptorType, this.streamNumber, this.languageIndex);
- result.content = getRawData();
- return result;
- }
-
- /**
- * (overridden)
- *
- * @see Object#equals(Object)
- */
- @Override
- public boolean equals(final Object obj)
- {
- boolean result = false;
- if (obj instanceof MetadataDescriptor)
- {
- if (obj == this)
- {
- result = true;
- }
- else
- {
- final MetadataDescriptor other = (MetadataDescriptor) obj;
- result = other.getName().equals(getName()) && other.descriptorType == this.descriptorType && other.languageIndex == this.languageIndex && other.streamNumber == this.streamNumber && Arrays.equals(this.content, other.content);
- }
- }
- return result;
- }
-
- /**
- * Returns the value of the MetadataDescriptor as a Boolean.
- * If no Conversion is Possible false is returned.
- * true
if first byte of {@link #content}is not zero.
- *
- * @return boolean representation of the current value.
- */
- public boolean getBoolean()
- {
- return this.content.length > 0 && this.content[0] != 0;
- }
-
- /**
- * This method will return a byte array, which can directly be written into
- * an "Extended Content Description"-chunk.
- *
- * @return byte[] with the data, that occurs in ASF files.
- * @deprecated {@link #writeInto(OutputStream, ContainerType)} is used
- */
- @Deprecated
- public byte[] getBytes()
- {
- final ByteArrayOutputStream result = new ByteArrayOutputStream();
- try
- {
- writeInto(result, this.containerType);
- }
- catch (final IOException e)
- {
- LOGGER.warning(e.getMessage());
- }
- return result.toByteArray();
- }
-
- /**
- * Returns the container type this descriptor ist restricted to.
- *
- * @return the container type
- */
- public ContainerType getContainerType()
- {
- return this.containerType;
- }
-
- /**
- * Returns the size (in bytes) this descriptor will take when written to an
- * ASF file.
- *
- * @param type the container type for which the size is calculated.
- * @return size of the descriptor in an ASF file.
- */
- public int getCurrentAsfSize(final ContainerType type)
- {
- /*
- * 2 bytes name length, 2 bytes name zero term, 2 bytes type, 2 bytes
- * content length
- */
- int result = 8;
-
- if (type != ContainerType.EXTENDED_CONTENT)
- {
- // Stream number and language index (respectively reserved field).
- // And +2 bytes, because data type is 32 bit, not 16
- result += 6;
- }
- result += getName().length() * 2;
-
- if (this.getType() == TYPE_BOOLEAN)
- {
- result += 2;
- if (type == ContainerType.EXTENDED_CONTENT)
- {
- // Extended content description boolean values are stored with
- // 32-bit
- result += 2;
- }
- }
- else
- {
-
- result += this.content.length;
- if (TYPE_STRING == this.getType())
- {
- result += 2; // zero term of content string.
- }
- }
- return result;
- }
-
- /**
- * Returns the GUID value, if content could represent one.
- *
- * @return GUID value
- */
- public GUID getGuid()
- {
- GUID result = null;
- if (getType() == TYPE_GUID && this.content.length == GUID.GUID_LENGTH)
- {
- result = new GUID(this.content);
- }
- return result;
- }
-
- /**
- * Returns the index of the language that is referred (see
- * {@link LanguageList}):
- *
- * @return the language index
- */
- public int getLanguageIndex()
- {
- return this.languageIndex;
- }
-
- /**
- * This method returns the name of the metadata descriptor.
- *
- * @return Name.
- */
- public String getName()
- {
- return this.name;
- }
-
- /**
- * This method returns the value of the metadata descriptor as a long.
- * Converts the needed amount of byte out of {@link #content}to a number.
- * Only possible if {@link #getType()}equals on of the following:
- *
- * @return integer value.
- * @see #TYPE_BOOLEAN
- * @see #TYPE_DWORD
- * @see #TYPE_QWORD
- * @see #TYPE_WORD
- */
- public long getNumber()
- {
- int bytesNeeded;
- switch (getType())
- {
- case TYPE_BOOLEAN:
- bytesNeeded = 1;
- break;
- case TYPE_DWORD:
- bytesNeeded = 4;
- break;
- case TYPE_QWORD:
- bytesNeeded = 8;
- break;
- case TYPE_WORD:
- bytesNeeded = 2;
- break;
- default:
- throw new UnsupportedOperationException("The current type doesn't allow an interpretation as a number. (" + getType() + ")");
- }
- if (bytesNeeded > this.content.length)
- {
- throw new IllegalStateException("The stored data cannot represent the type of current object.");
- }
- long result = 0;
- for (int i = 0; i < bytesNeeded; i++)
- {
- result |= (((long) this.content[i] & 0xFF) << (i * 8));
- }
- return result;
- }
-
- /**
- * This method returns a copy of the content of the descriptor.
- *
- * @return The content in binary representation, as it would be written to
- * asf file.
- */
- public byte[] getRawData()
- {
- final byte[] copy = new byte[this.content.length];
- System.arraycopy(this.content, 0, copy, 0, this.content.length);
- return copy;
- }
-
- /**
- * Returns the size (in bytes) the binary representation of the content
- * uses. (length of {@link #getRawData()})
- *
- * @return size of binary representation of the content.
- */
- public int getRawDataSize()
- {
- return this.content.length;
- }
-
- /**
- * Returns the stream number this descriptor applies to.
- *
- * @return the stream number.
- */
- public int getStreamNumber()
- {
- return this.streamNumber;
- }
-
- /**
- * Returns the value of the MetadataDescriptor as a String.
- *
- * @return String - Representation Value
- */
- public String getString()
- {
- String result = null;
- switch (getType())
- {
- case TYPE_BINARY:
- result = "binary data";
- break;
- case TYPE_BOOLEAN:
- result = String.valueOf(getBoolean());
- break;
- case TYPE_GUID:
- result = getGuid() == null ? "Invalid GUID" : getGuid().toString();
- break;
- case TYPE_QWORD:
- case TYPE_DWORD:
- case TYPE_WORD:
- result = String.valueOf(getNumber());
- break;
- case TYPE_STRING:
- try
- {
- result = new String(this.content, "UTF-16LE");
- }
- catch (final UnsupportedEncodingException e)
- {
- LOGGER.warning(e.getMessage());
- }
- break;
- default:
- throw new IllegalStateException("Current type is not known.");
- }
- return result;
- }
-
- /**
- * Returns the type of the metadata descriptor.
- *
- * @return the value of {@link #descriptorType}
- * @see #TYPE_BINARY
- * @see #TYPE_BOOLEAN
- * @see #TYPE_DWORD
- * @see #TYPE_GUID
- * @see #TYPE_QWORD
- * @see #TYPE_STRING
- * @see #TYPE_WORD
- */
- public int getType()
- {
- return this.descriptorType;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode()
- {
- return this.name.hashCode();
- }
-
- /**
- * This method checks if the binary data is empty.
- * Disregarding the type of the descriptor its content is stored as a byte
- * array.
- *
- * @return true
if no value is set.
- */
- public boolean isEmpty()
- {
- return this.content.length == 0;
- }
-
- /**
- * Sets the Value of the current metadata descriptor.
- * Using this method will change {@link #descriptorType}to
- * {@link #TYPE_BINARY}.
- *
- * @param data Value to set.
- * @throws IllegalArgumentException if data is invalid for {@linkplain #getContainerType()
- * container}.
- */
- public void setBinaryValue(final byte[] data) throws IllegalArgumentException
- {
- this.containerType.assertConstraints(this.name, data, this.descriptorType, this.streamNumber, this.languageIndex);
- this.content = data.clone();
- this.descriptorType = TYPE_BINARY;
- }
-
- /**
- * Sets the Value of the current metadata descriptor.
- * Using this method will change {@link #descriptorType}to
- * {@link #TYPE_BOOLEAN}.
- *
- * @param value Value to set.
- */
- public void setBooleanValue(final boolean value)
- {
- this.content = new byte[]{value ? (byte) 1 : 0};
- this.descriptorType = TYPE_BOOLEAN;
- }
-
- /**
- * Sets the Value of the current metadata descriptor.
- * Using this method will change {@link #descriptorType}to
- * {@link #TYPE_DWORD}.
- *
- * @param value Value to set.
- */
- public void setDWordValue(final long value)
- {
- if (value < 0 || value > DWORD_MAXVALUE)
- {
- throw new IllegalArgumentException("value out of range (0-" + DWORD_MAXVALUE + ")");
- }
- this.content = Utils.getBytes(value, 4);
- this.descriptorType = TYPE_DWORD;
- }
-
- /**
- * Sets the value of the metadata descriptor.
- * Using this method will change {@link #descriptorType} to
- * {@link #TYPE_GUID}
- *
- * @param value value to set.
- */
- public void setGUIDValue(final GUID value)
- {
- this.containerType.assertConstraints(this.name, value.getBytes(), TYPE_GUID, this.streamNumber, this.languageIndex);
- this.content = value.getBytes();
- this.descriptorType = TYPE_GUID;
- }
-
- /**
- * Sets the index of the referred language (see {@link LanguageList}).
- * Consider: The {@linkplain #containerType requirements} must be
- * held.
- *
- * @param language the language index to set
- */
- public void setLanguageIndex(final int language)
- {
- this.containerType.assertConstraints(this.name, this.content, this.descriptorType, this.streamNumber, language);
- this.languageIndex = language;
- }
-
- /**
- * Sets the Value of the current metadata descriptor.
- * Using this method will change {@link #descriptorType}to
- * {@link #TYPE_QWORD}
- *
- * @param value Value to set.
- * @throws NumberFormatException on null
values.
- * @throws IllegalArgumentException on illegal values or values exceeding range.
- */
- public void setQWordValue(final BigInteger value) throws IllegalArgumentException
- {
- if (value == null)
- {
- throw new NumberFormatException("null");
- }
- if (BigInteger.ZERO.compareTo(value) > 0)
- {
- throw new IllegalArgumentException("Only unsigned values allowed (no negative)");
- }
- if (MetadataDescriptor.QWORD_MAXVALUE.compareTo(value) < 0)
- {
- throw new IllegalArgumentException("Value exceeds QWORD (64 bit unsigned)");
- }
- this.content = new byte[8];
- final byte[] valuesBytes = value.toByteArray();
- if (valuesBytes.length <= 8)
- {
- for (int i = valuesBytes.length - 1; i >= 0; i--)
- {
- this.content[valuesBytes.length - (i + 1)] = valuesBytes[i];
- }
- }
- else
- {
- /*
- * In case of 64-Bit set
- */
- Arrays.fill(this.content, (byte) 0xFF);
- }
- this.descriptorType = TYPE_QWORD;
- }
-
- /**
- * Sets the Value of the current metadata descriptor.
- * Using this method will change {@link #descriptorType}to
- * {@link #TYPE_QWORD}
- *
- * @param value Value to set.
- */
- public void setQWordValue(final long value)
- {
- if (value < 0)
- {
- throw new IllegalArgumentException("value out of range (0-" + MetadataDescriptor.QWORD_MAXVALUE.toString() + ")");
- }
- this.content = Utils.getBytes(value, 8);
- this.descriptorType = TYPE_QWORD;
- }
-
- /**
- * Sets the stream number the descriptor applies to.
- * Consider: The {@linkplain #containerType requirements} must be
- * held.
- *
- * @param stream the stream number to set
- */
- public void setStreamNumber(final int stream)
- {
- this.containerType.assertConstraints(this.name, this.content, this.descriptorType, stream, this.languageIndex);
- this.streamNumber = stream;
- }
-
- /**
- * This method converts the given string value into the current
- * {@linkplain #getType() data type}.
- *
- * @param value value to set.
- * @throws IllegalArgumentException If conversion was impossible.
- */
- public void setString(final String value) throws IllegalArgumentException
- {
- try
- {
- switch (getType())
- {
- case TYPE_BINARY:
- throw new IllegalArgumentException("Cannot interpret binary as string.");
- case TYPE_BOOLEAN:
- setBooleanValue(Boolean.parseBoolean(value));
- break;
- case TYPE_DWORD:
- setDWordValue(Long.parseLong(value));
- break;
- case TYPE_QWORD:
- setQWordValue(new BigInteger(value, 10));
- break;
- case TYPE_WORD:
- setWordValue(Integer.parseInt(value));
- break;
- case TYPE_GUID:
- setGUIDValue(GUID.parseGUID(value));
- break;
- case TYPE_STRING:
- setStringValue(value);
- break;
- default:
- // new Type added but not handled.
- throw new IllegalStateException();
- }
- }
- catch (final NumberFormatException nfe)
- {
- throw new IllegalArgumentException("Value cannot be parsed as Number or is out of range (\"" + value + "\")", nfe);
- }
- }
-
- /**
- * Sets the Value of the current metadata descriptor.
- * Using this method will change {@link #descriptorType}to
- * {@link #TYPE_STRING}.
- *
- * @param value Value to set.
- * @throws IllegalArgumentException If byte representation would take more than 65535 Bytes.
- */
- // TODO Test
- public void setStringValue(final String value) throws IllegalArgumentException
- {
- if (value == null)
- {
- this.content = new byte[0];
- }
- else
- {
- final byte[] tmp = Utils.getBytes(value, AsfHeader.ASF_CHARSET);
- if (getContainerType().isWithinValueRange(tmp.length))
- {
- // Everything is fine here, data can be stored.
- this.content = tmp;
- }
- else
- {
- // Normally a size violation, check if JAudiotagger my truncate
- // the string
- if (TagOptionSingleton.getInstance().isTruncateTextWithoutErrors())
- {
- // truncate the string
- final int copyBytes = (int) getContainerType().getMaximumDataLength().longValue();
- this.content = new byte[copyBytes % 2 == 0 ? copyBytes : copyBytes - 1];
- System.arraycopy(tmp, 0, this.content, 0, this.content.length);
- }
- else
- {
- // We may not truncate, so its an error
- throw new IllegalArgumentException(ErrorMessage.WMA_LENGTH_OF_DATA_IS_TOO_LARGE.getMsg(tmp.length, getContainerType().getMaximumDataLength(), getContainerType().getContainerGUID().getDescription())
- );
- }
- }
- }
- this.descriptorType = TYPE_STRING;
- }
-
- /**
- * Sets the Value of the current metadata descriptor.
- * Using this method will change {@link #descriptorType}to
- * {@link #TYPE_WORD}
- *
- * @param value Value to set.
- * @throws IllegalArgumentException on negative values. ASF just supports unsigned values.
- */
- public void setWordValue(final int value) throws IllegalArgumentException
- {
- if (value < 0 || value > WORD_MAXVALUE)
- {
- throw new IllegalArgumentException("value out of range (0-" + WORD_MAXVALUE + ")");
- }
- this.content = Utils.getBytes(value, 2);
- this.descriptorType = TYPE_WORD;
- }
-
- /**
- * (overridden)
- *
- * @see Object#toString()
- */
- @Override
- public String toString()
- {
- return getName() + " : " + new String[]{"String: ", "Binary: ", "Boolean: ", "DWORD: ", "QWORD:", "WORD:", "GUID:"}[this.descriptorType] + getString() + " (language: " + this.languageIndex + " / stream: " + this.streamNumber + ")";
- }
-
- /**
- * Writes this descriptor into the specified output stream.
- *
- * @param out stream to write into.
- * @param contType the container type this descriptor is written to.
- * @return amount of bytes written.
- * @throws IOException on I/O Errors
- */
- public int writeInto(final OutputStream out, final ContainerType contType) throws IOException
- {
- final int size = getCurrentAsfSize(contType);
- /*
- * Booleans are stored as one byte, if a boolean is written, the data
- * must be converted according to the container type.
- */
- byte[] binaryData;
- if (this.descriptorType == TYPE_BOOLEAN)
- {
- binaryData = new byte[contType == ContainerType.EXTENDED_CONTENT ? 4 : 2];
- binaryData[0] = (byte) (getBoolean() ? 1 : 0);
- }
- else
- {
- binaryData = this.content;
- }
- // for Metadata objects the stream number and language index
- if (contType != ContainerType.EXTENDED_CONTENT)
- {
- Utils.writeUINT16(getLanguageIndex(), out);
- Utils.writeUINT16(getStreamNumber(), out);
- }
- Utils.writeUINT16(getName().length() * 2 + 2, out);
-
- // The name for the metadata objects come later
- if (contType == ContainerType.EXTENDED_CONTENT)
- {
- out.write(Utils.getBytes(getName(), AsfHeader.ASF_CHARSET));
- out.write(AsfHeader.ZERO_TERM);
- }
-
- // type and content len follow up are identical
- final int type = getType();
- Utils.writeUINT16(type, out);
- int contentLen = binaryData.length;
- if (TYPE_STRING == type)
- {
- contentLen += 2; // Zero Term
- }
-
- if (contType == ContainerType.EXTENDED_CONTENT)
- {
- Utils.writeUINT16(contentLen, out);
- }
- else
- {
- Utils.writeUINT32(contentLen, out);
- }
-
- // Metadata objects now write their descriptor name
- if (contType != ContainerType.EXTENDED_CONTENT)
- {
- out.write(Utils.getBytes(getName(), AsfHeader.ASF_CHARSET));
- out.write(AsfHeader.ZERO_TERM);
- }
-
- // The content.
- out.write(binaryData);
- if (TYPE_STRING == type)
- {
- out.write(AsfHeader.ZERO_TERM);
- }
- return size;
- }
-}
\ No newline at end of file
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/StreamBitratePropertiesChunk.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/StreamBitratePropertiesChunk.java
deleted file mode 100644
index 9695b011..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/StreamBitratePropertiesChunk.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2004-2005 Christian Laireiter
- * It is optional, but contains useful information about the streams bitrate.
- *
- * @author Christian Laireiter
- */
-public class StreamBitratePropertiesChunk extends Chunk
-{
-
- /**
- * For each call of {@link #addBitrateRecord(int, long)} an {@link Long}
- * object is appended, which represents the average bitrate.
- */
- private final List
- *
- * @param streamNumber Number of the stream whose bitrate to determine.
- * @return The average bitrate of the numbered stream. -1
if no
- * information was given.
- */
- public long getAvgBitrate(final int streamNumber)
- {
- final Integer seach = streamNumber;
- final int index = this.streamNumbers.indexOf(seach);
- long result;
- if (index == -1)
- {
- result = -1;
- }
- else
- {
- result = this.bitRates.get(index);
- }
- return result;
- }
-
- /**
- * (overridden)
- *
- * @see Chunk#prettyPrint(String)
- */
- @Override
- public String prettyPrint(final String prefix)
- {
- final StringBuilder result = new StringBuilder(super.prettyPrint(prefix));
- for (int i = 0; i < this.bitRates.size(); i++)
- {
- result.append(prefix).append(" |-> Stream no. \"").append(this.streamNumbers.get(i)).append("\" has an average bitrate of \"").append(this.bitRates.get(i)).append('"').append(Utils.LINE_SEPARATOR);
- }
- return result.toString();
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/StreamChunk.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/StreamChunk.java
deleted file mode 100644
index e32dd617..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/StreamChunk.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2004-2005 Christian Laireiter
- * A Stream chunk delivers information about a audio or video stream. Because of
- * this the stream chunk identifies in one field what type of stream it is
- * describing and so other data is provided. However some information is common
- * to all stream chunks which are stored in this hierarchy of the class tree.
- *
- * @author Christian Laireiter
- */
-public abstract class StreamChunk extends Chunk
-{
-
- /**
- * If true
, the stream data is encrypted.
- */
- private boolean contentEncrypted;
-
- /**
- * This field stores the number of the current stream.
- */
- private int streamNumber;
-
- /**
- * @see #typeSpecificDataSize
- */
- private long streamSpecificDataSize;
-
- /**
- * Something technical.
- * Format time in 100-ns steps.
- */
- private long timeOffset;
-
- /**
- * Stores the stream type.
- *
- * @see GUID#GUID_AUDIOSTREAM
- * @see GUID#GUID_VIDEOSTREAM
- */
- private final GUID type;
-
- /**
- * Stores the size of type specific data structure within chunk.
- */
- private long typeSpecificDataSize;
-
- /**
- * Creates an instance
- *
- * @param streamType The GUID which tells the stream type represented (
- * {@link GUID#GUID_AUDIOSTREAM} or {@link GUID#GUID_VIDEOSTREAM}
- * ):
- * @param chunkLen length of chunk
- */
- public StreamChunk(final GUID streamType, final BigInteger chunkLen)
- {
- super(GUID.GUID_STREAM, chunkLen);
- assert GUID.GUID_AUDIOSTREAM.equals(streamType) || GUID.GUID_VIDEOSTREAM.equals(streamType);
- this.type = streamType;
- }
-
- /**
- * @return Returns the streamNumber.
- */
- public int getStreamNumber()
- {
- return this.streamNumber;
- }
-
- /**
- * @return Returns the streamSpecificDataSize.
- */
- public long getStreamSpecificDataSize()
- {
- return this.streamSpecificDataSize;
- }
-
- /**
- * Returns the stream type of the stream chunk.
- *
- * @return {@link GUID#GUID_AUDIOSTREAM} or {@link GUID#GUID_VIDEOSTREAM}.
- */
- public GUID getStreamType()
- {
- return this.type;
- }
-
- /**
- * @return Returns the timeOffset.
- */
- public long getTimeOffset()
- {
- return this.timeOffset;
- }
-
- /**
- * @return Returns the typeSpecificDataSize.
- */
- public long getTypeSpecificDataSize()
- {
- return this.typeSpecificDataSize;
- }
-
- /**
- * @return Returns the contentEncrypted.
- */
- public boolean isContentEncrypted()
- {
- return this.contentEncrypted;
- }
-
- /**
- * (overridden)
- *
- * @see Chunk#prettyPrint(String)
- */
- @Override
- public String prettyPrint(final String prefix)
- {
- final StringBuilder result = new StringBuilder(super.prettyPrint(prefix));
- result.append(prefix).append(" |-> Stream number: ").append(getStreamNumber()).append(Utils.LINE_SEPARATOR);
- result.append(prefix).append(" |-> Type specific data size : ").append(getTypeSpecificDataSize()).append(Utils.LINE_SEPARATOR);
- result.append(prefix).append(" |-> Stream specific data size: ").append(getStreamSpecificDataSize()).append(Utils.LINE_SEPARATOR);
- result.append(prefix).append(" |-> Time Offset : ").append(getTimeOffset()).append(Utils.LINE_SEPARATOR);
- result.append(prefix).append(" |-> Content Encryption : ").append(isContentEncrypted()).append(Utils.LINE_SEPARATOR);
- return result.toString();
- }
-
- /**
- * @param cntEnc The contentEncrypted to set.
- */
- public void setContentEncrypted(final boolean cntEnc)
- {
- this.contentEncrypted = cntEnc;
- }
-
- /**
- * @param streamNum The streamNumber to set.
- */
- public void setStreamNumber(final int streamNum)
- {
- this.streamNumber = streamNum;
- }
-
- /**
- * @param strSpecDataSize The streamSpecificDataSize to set.
- */
- public void setStreamSpecificDataSize(final long strSpecDataSize)
- {
- this.streamSpecificDataSize = strSpecDataSize;
- }
-
- /**
- * @param timeOffs sets the time offset
- */
- public void setTimeOffset(final long timeOffs)
- {
- this.timeOffset = timeOffs;
- }
-
- /**
- * @param typeSpecDataSize The typeSpecificDataSize to set.
- */
- public void setTypeSpecificDataSize(final long typeSpecDataSize)
- {
- this.typeSpecificDataSize = typeSpecDataSize;
- }
-}
\ No newline at end of file
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/VideoStreamChunk.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/VideoStreamChunk.java
deleted file mode 100644
index ae4c874f..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/data/VideoStreamChunk.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2004-2005 Christian Laireiter char
.
- *
- * @return Codec Id as String.
- */
- public String getCodecIdAsString()
- {
- String result;
- if (this.codecId == null)
- {
- result = "Unknown";
- }
- else
- {
- result = new String(getCodecId());
- }
- return result;
- }
-
- /**
- * @return Returns the pictureHeight.
- */
- public long getPictureHeight()
- {
- return this.pictureHeight;
- }
-
- /**
- * @return Returns the pictureWidth.
- */
- public long getPictureWidth()
- {
- return this.pictureWidth;
- }
-
- /**
- * (overridden)
- *
- * @see StreamChunk#prettyPrint(String)
- */
- @Override
- public String prettyPrint(final String prefix)
- {
- final StringBuilder result = new StringBuilder(super.prettyPrint(prefix));
- result.insert(0, Utils.LINE_SEPARATOR + prefix + "|->VideoStream");
- result.append(prefix).append("Video info:").append(Utils.LINE_SEPARATOR);
- result.append(prefix).append(" |->Width : ").append(getPictureWidth()).append(Utils.LINE_SEPARATOR);
- result.append(prefix).append(" |->Heigth : ").append(getPictureHeight()).append(Utils.LINE_SEPARATOR);
- result.append(prefix).append(" |->Codec : ").append(getCodecIdAsString()).append(Utils.LINE_SEPARATOR);
- return result.toString();
- }
-
- /**
- * @param codecIdentifier The codecId to set.
- */
- public void setCodecId(final byte[] codecIdentifier)
- {
- this.codecId = codecIdentifier.clone();
- }
-
- /**
- * @param picHeight
- */
- public void setPictureHeight(final long picHeight)
- {
- this.pictureHeight = picHeight;
- }
-
- /**
- * @param picWidth
- */
- public void setPictureWidth(final long picWidth)
- {
- this.pictureWidth = picWidth;
- }
-}
\ No newline at end of file
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/AsfExtHeaderModifier.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/AsfExtHeaderModifier.java
deleted file mode 100644
index 14084524..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/AsfExtHeaderModifier.java
+++ /dev/null
@@ -1,140 +0,0 @@
-package com.mp3.jaudiotagger.audio.asf.io;
-
-import com.mp3.jaudiotagger.audio.asf.data.GUID;
-import com.mp3.jaudiotagger.audio.asf.util.Utils;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * This modifier manipulates an ASF header extension object.
- *
- * @author Christian Laireiter
- */
-public class AsfExtHeaderModifier implements ChunkModifier
-{
-
- /**
- * List of modifiers which are to be applied to contained chunks.
- */
- private final List
- *
- * @param modifiers modifiers to apply.
- */
- public AsfExtHeaderModifier(final Listsource
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.
- */
- private void copyChunk(final GUID guid, final InputStream source, final OutputStream destination) throws IOException
- {
- final long chunkSize = Utils.readUINT64(source);
- destination.write(guid.getBytes());
- Utils.writeUINT64(chunkSize, destination);
- Utils.copy(source, destination, chunkSize - 24);
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean isApplicable(final GUID guid)
- {
- return GUID.GUID_HEADER_EXTENSION.equals(guid);
- }
-
- /**
- * {@inheritDoc}
- */
- public ModificationResult modify(final GUID guid, final InputStream source, final OutputStream destination) throws IOException
- {
- assert GUID.GUID_HEADER_EXTENSION.equals(guid);
-
- long difference = 0;
- final List
- *
- * @author Christian Laireiter
- */
-public class AsfExtHeaderReader extends ChunkContainerReader
- *
- * @param toRegister List of {@link ChunkReader} class instances, which are to be
- * utilized by the instance.
- * @param readChunkOnce if true
, each chunk type (identified by chunk
- * GUID) will handled only once, if a reader is available, other
- * chunks will be discarded.
- */
- public AsfExtHeaderReader(final List
- * For now only ASF ver 1.0 is supported, because ver 2.0 seems not to be used
- * anywhere.
- * ASF headers contains other chunks. As of this other readers of current
- * package are called from within.
- *
- * @author Christian Laireiter
- */
-public class AsfHeaderReader extends ChunkContainerReader
- * If the ASF file only contains one audio stream it works fine.
- */
- private final static AsfHeaderReader INFO_READER;
-
- /**
- * ASF reader configured to just extract metadata information.
- */
- private final static AsfHeaderReader TAG_READER;
-
- static
- {
- final List
- *
- * @param raf data source to read from.
- * @return a stream which accesses the source.
- */
- private static InputStream createStream(final RandomAccessFile raf)
- {
- return new FullRequestInputStream(new BufferedInputStream(new RandomAccessFileInputstream(raf)));
- }
-
- /**
- * This method extracts the full ASF-Header from the given file.
- * If no header could be extracted null
is returned.
- *
- * @param file the ASF file to read.
- * @return AsfHeader-Wrapper, or null
if no supported ASF
- * header was found.
- * @throws IOException on I/O Errors.
- */
- public static AsfHeader readHeader(final File file) throws IOException
- {
- final InputStream stream = new FileInputStream(file);
- final AsfHeader result = FULL_READER.read(Utils.readGUID(stream), stream, 0);
- stream.close();
- return result;
- }
-
- /**
- * This method tries to extract a full ASF-header out of the given stream.
- * If no header could be extracted null
is returned.
- *
- * @param file File which contains the ASF header.
- * @return AsfHeader-Wrapper, or null
if no supported ASF
- * header was found.
- * @throws IOException Read errors
- */
- public static AsfHeader readHeader(final RandomAccessFile file) throws IOException
- {
- final InputStream stream = createStream(file);
- return FULL_READER.read(Utils.readGUID(stream), stream, 0);
- }
-
- /**
- * This method tries to extract an ASF-header out of the given stream, which
- * only contains information about the audio stream.
- * If no header could be extracted null
is returned.
- *
- * @param file File which contains the ASF header.
- * @return AsfHeader-Wrapper, or null
if no supported ASF
- * header was found.
- * @throws IOException Read errors
- */
- public static AsfHeader readInfoHeader(final RandomAccessFile file) throws IOException
- {
- final InputStream stream = createStream(file);
- return INFO_READER.read(Utils.readGUID(stream), stream, 0);
- }
-
- /**
- * This method tries to extract an ASF-header out of the given stream, which
- * only contains metadata.
- * If no header could be extracted null
is returned.
- *
- * @param file File which contains the ASF header.
- * @return AsfHeader-Wrapper, or null
if no supported ASF
- * header was found.
- * @throws IOException Read errors
- */
- public static AsfHeader readTagHeader(final RandomAccessFile file) throws IOException
- {
- final InputStream stream = createStream(file);
- return TAG_READER.read(Utils.readGUID(stream), stream, 0);
- }
-
- /**
- * Creates an instance of this reader.
- *
- * @param toRegister The chunk readers to utilize.
- * @param readChunkOnce if true
, each chunk type (identified by chunk
- * GUID) will handled only once, if a reader is available, other
- * chunks will be discarded.
- */
- public AsfHeaderReader(final List
- *
- * @author Christian Laireiter
- */
-public class AsfStreamer
-{
-
- /**
- * 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.
- */
- private void copyChunk(final GUID guid, final InputStream source, final OutputStream destination) throws IOException
- {
- final long chunkSize = Utils.readUINT64(source);
- destination.write(guid.getBytes());
- Utils.writeUINT64(chunkSize, destination);
- Utils.copy(source, destination, chunkSize - 24);
- }
-
- /**
- * 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.
- *
- * @param source the source ASF file
- * @param dest the destination to write the modified version to.
- * @param modifiers list of chunk modifiers to apply.
- * @throws IOException on I/O errors.
- */
- public void createModifiedCopy(final InputStream source, final OutputStream dest, final List
- * The copied chunk will have the file size field modified by the given
- * fileSizeDiff
value.
- *
- * @param source source of file properties chunk, located at its chunk length
- * field.
- * @param destination the destination to copy the chunk to.
- * @param fileSizeDiff the difference which should be applied. (negative values would
- * subtract the stored file size)
- * @throws IOException on I/O errors.
- */
- private void modifyFileHeader(final InputStream source, final OutputStream destination, final long fileSizeDiff) throws IOException
- {
- 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);
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/ChunkContainerReader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/ChunkContainerReader.java
deleted file mode 100644
index 65b58669..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/ChunkContainerReader.java
+++ /dev/null
@@ -1,231 +0,0 @@
-package com.mp3.jaudiotagger.audio.asf.io;
-
-import com.mp3.jaudiotagger.audio.asf.data.Chunk;
-import com.mp3.jaudiotagger.audio.asf.data.ChunkContainer;
-import com.mp3.jaudiotagger.audio.asf.data.GUID;
-import com.mp3.jaudiotagger.audio.asf.util.Utils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.math.BigInteger;
-import java.util.*;
-import java.util.logging.Logger;
-
-/**
- * This class represents a reader implementation, which is able to read ASF
- * objects (chunks) which store other objects (chunks) within them.
- *
- * @param true
each chunk type will only be read once.
- */
- protected final boolean eachChunkOnce;
-
- /**
- * If true
due to a {@linkplain #register(Class) registered}
- * chunk reader, all {@link InputStream} objects passed to
- * {@link #read(GUID, InputStream, long)} must support mark/reset.
- */
- protected boolean hasFailingReaders = false;
-
- /**
- * Registers GUIDs to their reader classes.
- */
- protected final Map
- *
- * @param toRegister List of {@link ChunkReader} class instances, which are to be
- * utilized by the instance.
- * @param readChunkOnce if true
, each chunk type (identified by chunk
- * GUID) will handled only once, if a reader is available, other
- * chunks will be discarded.
- */
- protected ChunkContainerReader(final List
- *
- * @param streamPosition position of the stream, the chunk starts.
- * @param chunkLength the length of the chunk (from chunk header)
- * @param stream to read the implementation specific information.
- * @return instance of the implementations result.
- * @throws IOException On I/O Errors and Invalid data.
- */
- abstract protected ChunkType createContainer(long streamPosition, BigInteger chunkLength, InputStream stream) throws IOException;
-
- /**
- * Gets a configured {@linkplain ChunkReader reader} instance for ASF
- * objects (chunks) with the specified guid
.
- *
- * @param guid GUID which identifies the chunk to be read.
- * @return an appropriate reader implementation, null
if not
- * {@linkplain #register(Class) registered}.
- */
- protected ChunkReader getReader(final GUID guid)
- {
- return this.readerMap.get(guid);
- }
-
- /**
- * Tests whether {@link #getReader(GUID)} won't return null
.
- *
- * @param guid GUID which identifies the chunk to be read.
- * @return true
if a reader is available.
- */
- protected boolean isReaderAvailable(final GUID guid)
- {
- return this.readerMap.containsKey(guid);
- }
-
- /**
- * This Method implements the reading of a chunk container.
- *
- * @param guid GUID of the currently read container.
- * @param stream Stream which contains the chunk container.
- * @param chunkStart The start of the chunk container from stream start.
- * For direct file streams one can assume 0
here.
- * @return null
if no valid data found, else a Wrapper
- * containing all supported data.
- * @throws IOException Read errors.
- * @throws IllegalArgumentException If one used {@link ChunkReader} could
- * {@linkplain ChunkReader#canFail() fail} and the stream source
- * doesn't support mark/reset.
- */
- public ChunkType read(final GUID guid, final InputStream stream, final long chunkStart) throws IOException, IllegalArgumentException
- {
- checkStream(stream);
- final CountingInputStream cis = new CountingInputStream(stream);
- if (!Arrays.asList(getApplyingIds()).contains(guid))
- {
- throw new IllegalArgumentException("provided GUID is not supported by this reader.");
- }
- // For Know the file pointer pointed to an ASF header chunk.
- final BigInteger chunkLen = Utils.readBig64(cis);
- /*
- * now read implementation specific information until the chunk
- * collection starts and create the resulting object.
- */
- final ChunkType result = createContainer(chunkStart, chunkLen, cis);
- // 16 bytes have already been for providing the GUID
- long currentPosition = chunkStart + cis.getReadCount() + 16;
-
- final HashSet
- *
- * @param
- *
- * @author Christian Laireiter
- */
-public interface ChunkModifier
-{
-
- /**
- * Determines, whether the modifier handles chunks identified by given
- * guid
.
- *
- * @param guid GUID to test.
- * @return true
, if this modifier can be used to modify the
- * chunk.
- */
- boolean isApplicable(GUID guid);
-
- /**
- * Writes a modified copy of the chunk into the destination.
.
- *
- * @param guid GUID of the chunk to modify.
- * @param source a stream providing the chunk, starting at the chunks length
- * field.
- * @param destination destination for the modified chunk.
- * @return the differences between source and destination.
- * @throws IOException on I/O errors.
- */
- ModificationResult modify(GUID guid, InputStream source, OutputStream destination) throws IOException;
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/ChunkReader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/ChunkReader.java
deleted file mode 100644
index c644e500..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/ChunkReader.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.mp3.jaudiotagger.audio.asf.io;
-
-import com.mp3.jaudiotagger.audio.asf.data.Chunk;
-import com.mp3.jaudiotagger.audio.asf.data.GUID;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * A ChunkReader provides methods for reading an ASF chunk.
- *
- * @author Christian Laireiter
- */
-public interface ChunkReader
-{
-
- /**
- * Tells whether the reader can fail to return a valid chunk.
- * The current Use would be a modified version of {@link StreamChunkReader},
- * which is configured to only manage audio streams. However, the primary
- * GUID for audio and video streams is the same. So if a stream shows itself
- * to be a video stream, the reader would return null
.
- *
- * @return true
, if further analysis of the chunk can show,
- * that the reader is not applicable, despite the header GUID
- * {@linkplain #getApplyingIds() identification} told it can handle
- * the chunk.
- */
- boolean canFail();
-
- /**
- * Returns the GUIDs identifying the types of chunk, this reader will parse.
- *
- * @return the GUIDs identifying the types of chunk, this reader will parse.
- */
- GUID[] getApplyingIds();
-
- /**
- * Parses the chunk.
- *
- * @param guid the GUID of the chunks header, which is about to be read.
- * @param stream source to read chunk from.
- * No {@link GUID} is expected at the currents stream position.
- * The length of the chunk is about to follow.
- * @param streamPosition the position in stream, the chunk starts.
- * @return the read chunk. (Mostly a subclass of {@link Chunk}).
- * @throws IOException On I/O Errors.
- */
- Chunk read(GUID guid, InputStream stream, long streamPosition) throws IOException;
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/ChunkRemover.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/ChunkRemover.java
deleted file mode 100644
index c87f99a7..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/ChunkRemover.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package com.mp3.jaudiotagger.audio.asf.io;
-
-import com.mp3.jaudiotagger.audio.asf.data.GUID;
-import com.mp3.jaudiotagger.audio.asf.util.Utils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * This {@link ChunkModifier} implementation is meant to remove selected chunks.
- *
- * @author Christian Laireiter
- */
-@SuppressWarnings({"ManualArrayToCollectionCopy"})
-public class ChunkRemover implements ChunkModifier
-{
-
- /**
- * Stores the GUIDs, which are about to be removed by this modifier.
- */
- private final Set
- *
- * @param guids the GUIDs which are about to be removed by this modifier.
- */
- public ChunkRemover(final GUID... guids)
- {
- this.toRemove = new HashSet
- *
- * @author Christian Laireiter
- * @see com.mp3.jaudiotagger.audio.asf.data.ContainerType#CONTENT_BRANDING
- * @see ContentBranding
- */
-public class ContentBrandingReader implements ChunkReader
-{
- /**
- * The GUID this reader {@linkplain #getApplyingIds() applies to}
- */
- private final static GUID[] APPLYING = {GUID.GUID_CONTENT_BRANDING};
-
- /**
- * Should not be used for now.
- */
- protected ContentBrandingReader()
- {
- // NOTHING toDo
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean canFail()
- {
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- public GUID[] getApplyingIds()
- {
- return APPLYING.clone();
- }
-
- /**
- * {@inheritDoc}
- */
- public Chunk read(final GUID guid, final InputStream stream, final long streamPosition) throws IOException
- {
- assert GUID.GUID_CONTENT_BRANDING.equals(guid);
- final BigInteger chunkSize = Utils.readBig64(stream);
- final long imageType = Utils.readUINT32(stream);
- assert imageType >= 0 && imageType <= 3 : imageType;
- final long imageDataSize = Utils.readUINT32(stream);
- assert imageType > 0 || imageDataSize == 0 : imageDataSize;
- assert imageDataSize < Integer.MAX_VALUE;
- final byte[] imageData = Utils.readBinary(stream, imageDataSize);
- final long copyRightUrlLen = Utils.readUINT32(stream);
- final String copyRight = new String(Utils.readBinary(stream, copyRightUrlLen));
- final long imageUrlLen = Utils.readUINT32(stream);
- final String imageUrl = new String(Utils.readBinary(stream, imageUrlLen));
- final ContentBranding result = new ContentBranding(streamPosition, chunkSize);
- result.setImage(imageType, imageData);
- result.setCopyRightURL(copyRight);
- result.setBannerImageURL(imageUrl);
- return result;
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/ContentDescriptionReader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/ContentDescriptionReader.java
deleted file mode 100644
index 9dfa3eeb..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/ContentDescriptionReader.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2004-2005 Christian Laireiter
- *
- * @author Christian Laireiter
- * @see com.mp3.jaudiotagger.audio.asf.data.ContentDescription
- */
-public class ContentDescriptionReader implements ChunkReader
-{
-
- /**
- * The GUID this reader {@linkplain #getApplyingIds() applies to}
- */
- private final static GUID[] APPLYING = {GUID.GUID_CONTENTDESCRIPTION};
-
- /**
- * Should not be used for now.
- */
- protected ContentDescriptionReader()
- {
- // NOTHING toDo
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean canFail()
- {
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- public GUID[] getApplyingIds()
- {
- return APPLYING.clone();
- }
-
- /**
- * Returns the next 5 UINT16 values as an array.
- *
- * @param stream stream to read from
- * @return 5 int values read from stream.
- * @throws IOException on I/O Errors.
- */
- private int[] getStringSizes(final InputStream stream) throws IOException
- {
- final int[] result = new int[5];
- for (int i = 0; i < result.length; i++)
- {
- result[i] = Utils.readUINT16(stream);
- }
- return result;
- }
-
- /**
- * {@inheritDoc}
- */
- public Chunk read(final GUID guid, final InputStream stream, final long chunkStart) throws IOException
- {
- final BigInteger chunkSize = Utils.readBig64(stream);
- /*
- * Now comes 16-Bit values representing the length of the Strings which
- * follows.
- */
- final int[] stringSizes = getStringSizes(stream);
-
- /*
- * Now we know the String length of each occuring String.
- */
- final String[] strings = new String[stringSizes.length];
- for (int i = 0; i < strings.length; i++)
- {
- if (stringSizes[i] > 0)
- {
- strings[i] = Utils.readFixedSizeUTF16Str(stream, stringSizes[i]);
- }
- }
- /*
- * Now create the result
- */
- final ContentDescription result = new ContentDescription(chunkStart, chunkSize);
- if (stringSizes[0] > 0)
- {
- result.setTitle(strings[0]);
- }
- if (stringSizes[1] > 0)
- {
- result.setAuthor(strings[1]);
- }
- if (stringSizes[2] > 0)
- {
- result.setCopyright(strings[2]);
- }
- if (stringSizes[3] > 0)
- {
- result.setComment(strings[3]);
- }
- if (stringSizes[4] > 0)
- {
- result.setRating(strings[4]);
- }
- return result;
- }
-}
\ No newline at end of file
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/CountingInputStream.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/CountingInputStream.java
deleted file mode 100644
index e721ad0d..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/CountingInputStream.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package com.mp3.jaudiotagger.audio.asf.io;
-
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * This implementation of {@link FilterInputStream} counts each read byte.
- * So at each time, with {@link #getReadCount()} one can determine how many
- * bytes have been read, by this classes read and skip methods (mark and reset
- * are also taken into account).
- *
- * @author Christian Laireiter
- */
-class CountingInputStream extends FilterInputStream
-{
-
- /**
- * If {@link #mark(int)} has been called, the current value of
- * {@link #readCount} is stored, in order to reset it upon {@link #reset()}.
- */
- private long markPos;
-
- /**
- * The amount of read or skipped bytes.
- */
- private long readCount;
-
- /**
- * Creates an instance, which delegates the commands to the given stream.
- *
- * @param stream stream to actually work with.
- */
- public CountingInputStream(final InputStream stream)
- {
- super(stream);
- this.markPos = 0;
- this.readCount = 0;
- }
-
- /**
- * Counts the given amount of bytes.
- *
- * @param amountRead number of bytes to increase.
- */
- private synchronized void bytesRead(final long amountRead)
- {
- if (amountRead >= 0)
- {
- this.readCount += amountRead;
- }
- }
-
- /**
- * @return the readCount
- */
- public synchronized long getReadCount()
- {
- return this.readCount;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public synchronized void mark(final int readlimit)
- {
- super.mark(readlimit);
- this.markPos = this.readCount;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int read() throws IOException
- {
- final int result = super.read();
- bytesRead(1);
- return result;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int read(final byte[] destination, final int off, final int len) throws IOException
- {
- final int result = super.read(destination, off, len);
- bytesRead(result);
- return result;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public synchronized void reset() throws IOException
- {
- super.reset();
- synchronized (this)
- {
- this.readCount = this.markPos;
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public long skip(final long amount) throws IOException
- {
- final long skipped = super.skip(amount);
- bytesRead(skipped);
- return skipped;
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/CountingOutputstream.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/CountingOutputstream.java
deleted file mode 100644
index ba93dc04..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/CountingOutputstream.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.mp3.jaudiotagger.audio.asf.io;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * This output stream wraps around another {@link OutputStream} and delegates
- * the write calls.
- * Additionally all written bytes are counted and available by
- * {@link #getCount()}.
- *
- * @author Christian Laireiter
- */
-public class CountingOutputstream extends OutputStream
-{
-
- /**
- * Stores the amount of bytes written.
- */
- private long count = 0;
-
- /**
- * The stream to forward the write calls.
- */
- private final OutputStream wrapped;
-
- /**
- * Creates an instance which will delegate the write calls to the given
- * output stream.
- *
- * @param outputStream stream to wrap.
- */
- public CountingOutputstream(final OutputStream outputStream)
- {
- super();
- assert outputStream != null;
- this.wrapped = outputStream;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void close() throws IOException
- {
- this.wrapped.close();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void flush() throws IOException
- {
- this.wrapped.flush();
- }
-
- /**
- * @return the count
- */
- public long getCount()
- {
- return this.count;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void write(final byte[] bytes) throws IOException
- {
- this.wrapped.write(bytes);
- this.count += bytes.length;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void write(final byte[] bytes, final int off, final int len) throws IOException
- {
- this.wrapped.write(bytes, off, len);
- this.count += len;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void write(final int toWrite) throws IOException
- {
- this.wrapped.write(toWrite);
- this.count++;
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/EncodingChunkReader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/EncodingChunkReader.java
deleted file mode 100644
index 6604ff43..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/EncodingChunkReader.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2004-2005 Christian Laireiter
- * Warning:
- * Implementation is not completed. More analysis of this chunk is needed.
- *
- * @author Christian Laireiter
- */
-class EncodingChunkReader implements ChunkReader
-{
- /**
- * The GUID this reader {@linkplain #getApplyingIds() applies to}
- */
- private final static GUID[] APPLYING = {GUID.GUID_ENCODING};
-
- /**
- * Should not be used for now.
- */
- protected EncodingChunkReader()
- {
- // NOTHING toDo
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean canFail()
- {
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- public GUID[] getApplyingIds()
- {
- return APPLYING.clone();
- }
-
- /**
- * {@inheritDoc}
- */
- public Chunk read(final GUID guid, final InputStream stream, final long chunkStart) throws IOException
- {
- final BigInteger chunkLen = Utils.readBig64(stream);
- final EncodingChunk result = new EncodingChunk(chunkLen);
- int readBytes = 24;
- // Can't be interpreted
- /*
- * What do I think of this data, well it seems to be another GUID. Then
- * followed by a UINT16 indicating a length of data following (by half).
- * My test files just had the length of one and a two bytes zero.
- */
- stream.skip(20);
- readBytes += 20;
-
- /*
- * Read the number of strings which will follow
- */
- final int stringCount = Utils.readUINT16(stream);
- readBytes += 2;
-
- /*
- * Now reading the specified amount of strings.
- */
- for (int i = 0; i < stringCount; i++)
- {
- final String curr = Utils.readCharacterSizedString(stream);
- result.addString(curr);
- readBytes += 4 + 2 * curr.length();
- }
- stream.skip(chunkLen.longValue() - readBytes);
- result.setPosition(chunkStart);
- return result;
- }
-
-}
\ No newline at end of file
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/EncryptionChunkReader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/EncryptionChunkReader.java
deleted file mode 100644
index 10152237..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/EncryptionChunkReader.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2004-2005 Christian Laireiter
- * Warning:
- * Implementation is not completed. More analysis of this chunk is needed.
- *
- * @author Christian Laireiter
- */
-class EncryptionChunkReader implements ChunkReader
-{
-
- /**
- * The GUID this reader {@linkplain #getApplyingIds() applies to}
- */
- private final static GUID[] APPLYING = {GUID.GUID_CONTENT_ENCRYPTION};
-
- /**
- * Should not be used for now.
- */
- protected EncryptionChunkReader()
- {
- // NOTHING toDo
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean canFail()
- {
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- public GUID[] getApplyingIds()
- {
- return APPLYING.clone();
- }
-
- /**
- * {@inheritDoc}
- */
- public Chunk read(final GUID guid, final InputStream stream, final long chunkStart) throws IOException
- {
- EncryptionChunk result;
- final BigInteger chunkLen = Utils.readBig64(stream);
- result = new EncryptionChunk(chunkLen);
-
- // Can't be interpreted
- /*
- * Object ID GUID 128 Object Size QWORD 64 Secret Data Length DWORD 32
- * Secret Data INTEGER varies Protection Type Length DWORD 32 Protection
- * Type char varies Key ID Length DWORD 32 Key ID char varies License
- * URL Length DWORD 32 License URL char varies * Read the
- */
- byte[] secretData;
- byte[] protectionType;
- byte[] keyID;
- byte[] licenseURL;
-
- // Secret Data length
- int fieldLength;
- fieldLength = (int) Utils.readUINT32(stream);
- // Secret Data
- secretData = new byte[fieldLength + 1];
- stream.read(secretData, 0, fieldLength);
- secretData[fieldLength] = 0;
-
- // Protection type Length
- fieldLength = 0;
- fieldLength = (int) Utils.readUINT32(stream);
- // Protection Data Length
- protectionType = new byte[fieldLength + 1];
- stream.read(protectionType, 0, fieldLength);
- protectionType[fieldLength] = 0;
-
- // Key ID length
- fieldLength = 0;
- fieldLength = (int) Utils.readUINT32(stream);
- // Key ID
- keyID = new byte[fieldLength + 1];
- stream.read(keyID, 0, fieldLength);
- keyID[fieldLength] = 0;
-
- // License URL length
- fieldLength = 0;
- fieldLength = (int) Utils.readUINT32(stream);
- // License URL
- licenseURL = new byte[fieldLength + 1];
- stream.read(licenseURL, 0, fieldLength);
- licenseURL[fieldLength] = 0;
-
- result.setSecretData(new String(secretData));
- result.setProtectionType(new String(protectionType));
- result.setKeyID(new String(keyID));
- result.setLicenseURL(new String(licenseURL));
-
- result.setPosition(chunkStart);
-
- return result;
- }
-
-}
\ No newline at end of file
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/FileHeaderReader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/FileHeaderReader.java
deleted file mode 100644
index 1162a75d..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/FileHeaderReader.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2004-2005 Christian Laireiter
- *
- * @author Christian Laireiter
- */
-public class FileHeaderReader implements ChunkReader
-{
-
- /**
- * The GUID this reader {@linkplain #getApplyingIds() applies to}
- */
- private final static GUID[] APPLYING = {GUID.GUID_FILE};
-
- /**
- * Should not be used for now.
- */
- protected FileHeaderReader()
- {
- // NOTHING toDo
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean canFail()
- {
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- public GUID[] getApplyingIds()
- {
- return APPLYING.clone();
- }
-
- /**
- * {@inheritDoc}
- */
- public Chunk read(final GUID guid, final InputStream stream, final long chunkStart) throws IOException
- {
- final BigInteger chunkLen = Utils.readBig64(stream);
- // Skip client GUID.
- stream.skip(16);
- final BigInteger fileSize = Utils.readBig64(stream);
- // fileTime in 100 ns since midnight of 1st january 1601 GMT
- final BigInteger fileTime = Utils.readBig64(stream);
-
- final BigInteger packageCount = Utils.readBig64(stream);
-
- final BigInteger timeEndPos = Utils.readBig64(stream);
- final BigInteger duration = Utils.readBig64(stream);
- final BigInteger timeStartPos = Utils.readBig64(stream);
-
- final long flags = Utils.readUINT32(stream);
-
- final long minPkgSize = Utils.readUINT32(stream);
- final long maxPkgSize = Utils.readUINT32(stream);
- final long uncompressedFrameSize = Utils.readUINT32(stream);
-
- final FileHeader result = new FileHeader(chunkLen, fileSize, fileTime, packageCount, duration, timeStartPos, timeEndPos, flags, minPkgSize, maxPkgSize, uncompressedFrameSize);
- result.setPosition(chunkStart);
- return result;
- }
-
-}
\ No newline at end of file
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/FullRequestInputStream.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/FullRequestInputStream.java
deleted file mode 100644
index 1434580f..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/FullRequestInputStream.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package com.mp3.jaudiotagger.audio.asf.io;
-
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * This implementation repeatedly reads from the wrapped input stream until the
- * requested amount of bytes are read.
- *
- * @author Christian Laireiter
- */
-public class FullRequestInputStream extends FilterInputStream
-{
-
- /**
- * Creates an instance.
- *
- * @param source stream to read from.
- */
- public FullRequestInputStream(final InputStream source)
- {
- super(source);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int read(final byte[] buffer) throws IOException
- {
- return read(buffer, 0, buffer.length);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int read(final byte[] buffer, final int off, final int len) throws IOException
- {
- int totalRead = 0;
- int read;
- while (totalRead < len)
- {
- read = super.read(buffer, off + totalRead, len - totalRead);
- if (read >= 0)
- {
- totalRead += read;
- }
- if (read == -1)
- {
- throw new IOException((len - totalRead) + " more bytes expected.");
- }
- }
- return totalRead;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public long skip(final long amount) throws IOException
- {
- long skipped = 0;
- int zeroSkipCnt = 0;
- long currSkipped;
- while (skipped < amount)
- {
- currSkipped = super.skip(amount - skipped);
- if (currSkipped == 0)
- {
- zeroSkipCnt++;
- if (zeroSkipCnt == 2)
- {
- // If the skip value exceeds streams size, this and the
- // number is extremely large, this can lead to a very long
- // running loop.
- break;
- }
- }
- skipped += currSkipped;
- }
- return skipped;
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/LanguageListReader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/LanguageListReader.java
deleted file mode 100644
index 33bcb32c..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/LanguageListReader.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.mp3.jaudiotagger.audio.asf.io;
-
-import com.mp3.jaudiotagger.audio.asf.data.Chunk;
-import com.mp3.jaudiotagger.audio.asf.data.GUID;
-import com.mp3.jaudiotagger.audio.asf.data.LanguageList;
-import com.mp3.jaudiotagger.audio.asf.util.Utils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.math.BigInteger;
-
-/**
- * Reads and interprets the "Language List Object" of ASF files.
- *
- * @author Christian Laireiter
- */
-public class LanguageListReader implements ChunkReader
-{
-
- /**
- * The GUID this reader {@linkplain #getApplyingIds() applies to}
- */
- private final static GUID[] APPLYING = {GUID.GUID_LANGUAGE_LIST};
-
- /**
- * {@inheritDoc}
- */
- public boolean canFail()
- {
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- public GUID[] getApplyingIds()
- {
- return APPLYING.clone();
- }
-
- /**
- * {@inheritDoc}
- */
- public Chunk read(final GUID guid, final InputStream stream, final long streamPosition) throws IOException
- {
- assert GUID.GUID_LANGUAGE_LIST.equals(guid);
- final BigInteger chunkLen = Utils.readBig64(stream);
-
- final int readUINT16 = Utils.readUINT16(stream);
-
- final LanguageList result = new LanguageList(streamPosition, chunkLen);
- for (int i = 0; i < readUINT16; i++)
- {
- final int langIdLen = (stream.read() & 0xFF);
- final String langId = Utils.readFixedSizeUTF16Str(stream, langIdLen);
- // langIdLen = 2 bytes for each char and optionally one zero
- // termination character
- assert langId.length() == langIdLen / 2 - 1 || langId.length() == langIdLen / 2;
- result.addLanguage(langId);
- }
-
- return result;
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/MetadataReader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/MetadataReader.java
deleted file mode 100644
index be127d96..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/MetadataReader.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package com.mp3.jaudiotagger.audio.asf.io;
-
-import com.mp3.jaudiotagger.audio.asf.data.*;
-import com.mp3.jaudiotagger.audio.asf.util.Utils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.math.BigInteger;
-
-/**
- * Reads an interprets "Metadata Object", "Metadata Library
- * Object" and "Extended Content Description" of ASF files.
- *
- * @author Christian Laireiter
- */
-public class MetadataReader implements ChunkReader
-{
-
- /**
- * The GUID this reader {@linkplain #getApplyingIds() applies to}
- */
- private final static GUID[] APPLYING = {ContainerType.EXTENDED_CONTENT.getContainerGUID(), ContainerType.METADATA_OBJECT.getContainerGUID(), ContainerType.METADATA_LIBRARY_OBJECT.getContainerGUID()};
-
- /**
- * {@inheritDoc}
- */
- public boolean canFail()
- {
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- public GUID[] getApplyingIds()
- {
- return APPLYING.clone();
- }
-
- /**
- * {@inheritDoc}
- */
- public Chunk read(final GUID guid, final InputStream stream, final long streamPosition) throws IOException
- {
- final BigInteger chunkLen = Utils.readBig64(stream);
-
- final MetadataContainer result = new MetadataContainer(guid, streamPosition, chunkLen);
- // isExtDesc will be set to true, if a extended content description
- // chunk is read
- // otherwise it is a metadata object, there are only slight differences
- final boolean isExtDesc = result.getContainerType() == ContainerType.EXTENDED_CONTENT;
- final int recordCount = Utils.readUINT16(stream);
- for (int i = 0; i < recordCount; i++)
- {
- int languageIndex = 0;
- int streamNumber = 0;
- if (!isExtDesc)
- {
- /*
- * Metadata objects have a language index and a stream number
- */
- languageIndex = Utils.readUINT16(stream);
- assert languageIndex >= 0 && languageIndex < MetadataDescriptor.MAX_LANG_INDEX;
- assert result.getContainerType() == ContainerType.METADATA_LIBRARY_OBJECT || languageIndex == 0;
- streamNumber = Utils.readUINT16(stream);
- assert streamNumber >= 0 && streamNumber <= MetadataDescriptor.MAX_STREAM_NUMBER;
- }
- final int nameLen = Utils.readUINT16(stream);
- String recordName = null;
- if (isExtDesc)
- {
- recordName = Utils.readFixedSizeUTF16Str(stream, nameLen);
- }
- final int dataType = Utils.readUINT16(stream);
- assert dataType >= 0 && dataType <= 6;
- final long dataLen = isExtDesc ? Utils.readUINT16(stream) : Utils.readUINT32(stream);
- assert dataLen >= 0;
- assert result.getContainerType() == ContainerType.METADATA_LIBRARY_OBJECT || dataLen <= MetadataDescriptor.DWORD_MAXVALUE;
- if (!isExtDesc)
- {
- recordName = Utils.readFixedSizeUTF16Str(stream, nameLen);
- }
- final MetadataDescriptor descriptor = new MetadataDescriptor(result.getContainerType(), recordName, dataType, streamNumber, languageIndex
- );
- switch (dataType)
- {
- case MetadataDescriptor.TYPE_STRING:
- descriptor.setStringValue(Utils.readFixedSizeUTF16Str(stream, (int) dataLen));
- break;
- case MetadataDescriptor.TYPE_BINARY:
- descriptor.setBinaryValue(Utils.readBinary(stream, dataLen));
- break;
- case MetadataDescriptor.TYPE_BOOLEAN:
- assert isExtDesc && dataLen == 4 || !isExtDesc && dataLen == 2;
- descriptor.setBooleanValue(readBoolean(stream, (int) dataLen));
- break;
- case MetadataDescriptor.TYPE_DWORD:
- assert dataLen == 4;
- descriptor.setDWordValue(Utils.readUINT32(stream));
- break;
- case MetadataDescriptor.TYPE_WORD:
- assert dataLen == 2;
- descriptor.setWordValue(Utils.readUINT16(stream));
- break;
- case MetadataDescriptor.TYPE_QWORD:
- assert dataLen == 8;
- descriptor.setQWordValue(Utils.readUINT64(stream));
- break;
- case MetadataDescriptor.TYPE_GUID:
- assert dataLen == GUID.GUID_LENGTH;
- descriptor.setGUIDValue(Utils.readGUID(stream));
- break;
- default:
- // Unknown, hopefully the convention for the size of the
- // value
- // is given, so we could read it binary
- descriptor.setStringValue("Invalid datatype: " + new String(Utils.readBinary(stream, dataLen)));
- }
- result.addDescriptor(descriptor);
- }
- return result;
- }
-
- /**
- * Reads the given amount of bytes and checks the last byte, if its equal to
- * one or zero (true / false).
- * All other bytes must be zero. (if assertions enabled).
- *
- * @param stream stream to read from.
- * @param bytes amount of bytes
- * @return true
or false
.
- * @throws IOException on I/O Errors
- */
- private boolean readBoolean(final InputStream stream, final int bytes) throws IOException
- {
- final byte[] tmp = new byte[bytes];
- stream.read(tmp);
- boolean result = false;
- for (int i = 0; i < bytes; i++)
- {
- if (i == bytes - 1)
- {
- result = tmp[i] == 1;
- assert tmp[i] == 0 || tmp[i] == 1;
- }
- else
- {
- assert tmp[i] == 0;
- }
- }
- return result;
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/ModificationResult.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/ModificationResult.java
deleted file mode 100644
index 5feeb4ab..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/ModificationResult.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package com.mp3.jaudiotagger.audio.asf.io;
-
-import com.mp3.jaudiotagger.audio.asf.data.GUID;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Structure to tell the differences occurred by altering a chunk.
- *
- * @author Christian Laireiter
- */
-final class ModificationResult
-{
-
- /**
- * Stores the difference of bytes.
- */
- private final long byteDifference;
-
- /**
- * Stores the difference of the amount of chunks.
- * "-1" if the chunk disappeared upon modification.
- * "0" if the chunk was just modified.
- * "1" if a chunk has been created.
- */
- private final int chunkDifference;
-
- /**
- * Stores all GUIDs, which have been read.
- */
- private final Set
- *
- * @param chunkCountDiff amount of chunks appeared, disappeared
- * @param bytesDiffer amount of bytes added or removed.
- * @param occurred all GUIDs which have been occurred, during processing
- */
- public ModificationResult(final int chunkCountDiff, final long bytesDiffer, final GUID... occurred)
- {
- assert occurred != null && occurred.length > 0;
- this.chunkDifference = chunkCountDiff;
- this.byteDifference = bytesDiffer;
- this.occuredGUIDs.addAll(Arrays.asList(occurred));
- }
-
- /**
- * Creates an instance.
- *
- * @param chunkCountDiff amount of chunks appeared, disappeared
- * @param bytesDiffer amount of bytes added or removed.
- * @param occurred all GUIDs which have been occurred, during processing
- */
- public ModificationResult(final int chunkCountDiff, final long bytesDiffer, final Set
- *
- * @author Christian Laireiter
- */
-public final class RandomAccessFileInputstream extends InputStream
-{
-
- /**
- * The file access to read from.
- */
- private final RandomAccessFile source;
-
- /**
- * Creates an instance that will provide {@link InputStream} functionality
- * on the given {@link RandomAccessFile} by delegating calls.
- *
- * @param file The file to read.
- */
- public RandomAccessFileInputstream(final RandomAccessFile file)
- {
- super();
- if (file == null)
- {
- throw new IllegalArgumentException("null");
- }
- this.source = file;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int read() throws IOException
- {
- return this.source.read();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int read(final byte[] buffer, final int off, final int len) throws IOException
- {
- return this.source.read(buffer, off, len);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public long skip(final long amount) throws IOException
- {
- if (amount < 0)
- {
- throw new IllegalArgumentException("invalid negative value");
- }
- long left = amount;
- while (left > Integer.MAX_VALUE)
- {
- this.source.skipBytes(Integer.MAX_VALUE);
- left -= Integer.MAX_VALUE;
- }
- return this.source.skipBytes((int) left);
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/RandomAccessFileOutputStream.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/RandomAccessFileOutputStream.java
deleted file mode 100644
index 448af6b4..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/RandomAccessFileOutputStream.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.mp3.jaudiotagger.audio.asf.io;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.RandomAccessFile;
-
-/**
- * Wraps a {@link RandomAccessFile} into an {@link OutputStream}.
- *
- * @author Christian Laireiter
- */
-public final class RandomAccessFileOutputStream extends OutputStream
-{
-
- /**
- * the file to write to.
- */
- private final RandomAccessFile targetFile;
-
- /**
- * Creates an instance.
- *
- * @param target file to write to.
- */
- public RandomAccessFileOutputStream(final RandomAccessFile target)
- {
- super();
- this.targetFile = target;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void write(final byte[] bytes, final int off, final int len) throws IOException
- {
- this.targetFile.write(bytes, off, len);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void write(final int toWrite) throws IOException
- {
- this.targetFile.write(toWrite);
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/StreamBitratePropertiesReader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/StreamBitratePropertiesReader.java
deleted file mode 100644
index 02056055..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/StreamBitratePropertiesReader.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2004-2005 Christian Laireiter
- *
- * @author Christian Laireiter
- */
-public class StreamBitratePropertiesReader implements ChunkReader
-{
-
- /**
- * The GUID this reader {@linkplain #getApplyingIds() applies to}
- */
- private final static GUID[] APPLYING = {GUID.GUID_STREAM_BITRATE_PROPERTIES};
-
- /**
- * Should not be used for now.
- */
- protected StreamBitratePropertiesReader()
- {
- // NOTHING toDo
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean canFail()
- {
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- public GUID[] getApplyingIds()
- {
- return APPLYING.clone();
- }
-
- /**
- * {@inheritDoc}
- */
- public Chunk read(final GUID guid, final InputStream stream, final long chunkStart) throws IOException
- {
- final BigInteger chunkLen = Utils.readBig64(stream);
- final StreamBitratePropertiesChunk result = new StreamBitratePropertiesChunk(chunkLen);
-
- /*
- * Read the amount of bitrate records
- */
- final long recordCount = Utils.readUINT16(stream);
- for (int i = 0; i < recordCount; i++)
- {
- final int flags = Utils.readUINT16(stream);
- final long avgBitrate = Utils.readUINT32(stream);
- result.addBitrateRecord(flags & 0x00FF, avgBitrate);
- }
-
- result.setPosition(chunkStart);
-
- return result;
- }
-
-}
\ No newline at end of file
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/StreamChunkReader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/StreamChunkReader.java
deleted file mode 100644
index df8cb432..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/StreamChunkReader.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2004-2005 Christian Laireiter
- *
- * @author Christian Laireiter
- */
-public class StreamChunkReader implements ChunkReader
-{
-
- /**
- * The GUID this reader {@linkplain #getApplyingIds() applies to}
- */
- private final static GUID[] APPLYING = {GUID.GUID_STREAM};
-
- /**
- * Shouldn't be used for now.
- */
- protected StreamChunkReader()
- {
- // Nothing to do
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean canFail()
- {
- return true;
- }
-
- /**
- * {@inheritDoc}
- */
- public GUID[] getApplyingIds()
- {
- return APPLYING.clone();
- }
-
- /**
- * {@inheritDoc}
- */
- public Chunk read(final GUID guid, final InputStream stream, final long chunkStart) throws IOException
- {
- StreamChunk result = null;
- final BigInteger chunkLength = Utils.readBig64(stream);
- // Now comes GUID indicating whether stream content type is audio or
- // video
- final GUID streamTypeGUID = Utils.readGUID(stream);
- if (GUID.GUID_AUDIOSTREAM.equals(streamTypeGUID) || GUID.GUID_VIDEOSTREAM.equals(streamTypeGUID))
- {
-
- // A GUID is indicating whether the stream is error
- // concealed
- final GUID errorConcealment = Utils.readGUID(stream);
- /*
- * Read the Time Offset
- */
- final long timeOffset = Utils.readUINT64(stream);
-
- final long typeSpecificDataSize = Utils.readUINT32(stream);
- final long streamSpecificDataSize = Utils.readUINT32(stream);
-
- /*
- * Read a bit field. (Contains stream number, and whether the stream
- * content is encrypted.)
- */
- final int mask = Utils.readUINT16(stream);
- final int streamNumber = mask & 127;
- final boolean contentEncrypted = (mask & 0x8000) != 0;
-
- /*
- * Skip a reserved field
- */
- stream.skip(4);
-
- /*
- * very important to set for every stream type. The size of bytes
- * read by the specific stream type, in order to skip the remaining
- * unread bytes of the stream chunk.
- */
- long streamSpecificBytes;
-
- if (GUID.GUID_AUDIOSTREAM.equals(streamTypeGUID))
- {
- /*
- * Reading audio specific information
- */
- final AudioStreamChunk audioStreamChunk = new AudioStreamChunk(chunkLength);
- result = audioStreamChunk;
-
- /*
- * read WAVEFORMATEX and format extension.
- */
- final long compressionFormat = Utils.readUINT16(stream);
- final long channelCount = Utils.readUINT16(stream);
- final long samplingRate = Utils.readUINT32(stream);
- final long avgBytesPerSec = Utils.readUINT32(stream);
- final long blockAlignment = Utils.readUINT16(stream);
- final int bitsPerSample = Utils.readUINT16(stream);
- final int codecSpecificDataSize = Utils.readUINT16(stream);
- final byte[] codecSpecificData = new byte[codecSpecificDataSize];
- stream.read(codecSpecificData);
-
- audioStreamChunk.setCompressionFormat(compressionFormat);
- audioStreamChunk.setChannelCount(channelCount);
- audioStreamChunk.setSamplingRate(samplingRate);
- audioStreamChunk.setAverageBytesPerSec(avgBytesPerSec);
- audioStreamChunk.setErrorConcealment(errorConcealment);
- audioStreamChunk.setBlockAlignment(blockAlignment);
- audioStreamChunk.setBitsPerSample(bitsPerSample);
- audioStreamChunk.setCodecData(codecSpecificData);
-
- streamSpecificBytes = 18 + codecSpecificData.length;
- }
- else
- {
- /*
- * Reading video specific information
- */
- final VideoStreamChunk videoStreamChunk = new VideoStreamChunk(chunkLength);
- result = videoStreamChunk;
-
- final long pictureWidth = Utils.readUINT32(stream);
- final long pictureHeight = Utils.readUINT32(stream);
-
- // Skip unknown field
- stream.skip(1);
-
- /*
- * Now read the format specific data
- */
- // Size of the data section (formatDataSize)
- stream.skip(2);
-
- stream.skip(16);
- final byte[] fourCC = new byte[4];
- stream.read(fourCC);
-
- videoStreamChunk.setPictureWidth(pictureWidth);
- videoStreamChunk.setPictureHeight(pictureHeight);
- videoStreamChunk.setCodecId(fourCC);
-
- streamSpecificBytes = 31;
- }
-
- /*
- * Setting common values for audio and video
- */
- result.setStreamNumber(streamNumber);
- result.setStreamSpecificDataSize(streamSpecificDataSize);
- result.setTypeSpecificDataSize(typeSpecificDataSize);
- result.setTimeOffset(timeOffset);
- result.setContentEncrypted(contentEncrypted);
- result.setPosition(chunkStart);
- /*
- * Now skip remainder of chunks bytes. chunk-length - 24 (size of
- * GUID and chunklen) - streamSpecificBytes(stream type specific
- * data) - 54 (common data)
- */
- stream.skip(chunkLength.longValue() - 24 - streamSpecificBytes - 54);
- }
- return result;
- }
-
-}
\ No newline at end of file
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/WriteableChunk.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/WriteableChunk.java
deleted file mode 100644
index a30b0125..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/WriteableChunk.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.mp3.jaudiotagger.audio.asf.io;
-
-import com.mp3.jaudiotagger.audio.asf.data.GUID;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * Implementors can write themselves directly to an output stream, and have the
- * ability to tell the size they would need, as well as determine if they are
- * empty.
- *
- * @author Christian Laireiter
- */
-public interface WriteableChunk
-{
-
- /**
- * This method calculates the total amount of bytes, the chunk would consume
- * in an ASF file.
- *
- * @return amount of bytes the chunk would currently need in an ASF file.
- */
- long getCurrentAsfChunkSize();
-
- /**
- * Returns the GUID of the chunk.
- *
- * @return GUID of the chunk.
- */
- GUID getGuid();
-
- /**
- * true
if it is not necessary to write the chunk into an ASF
- * file, since it contains no information.
- *
- * @return true
if no useful data will be preserved.
- */
- boolean isEmpty();
-
- /**
- * Writes the chunk into the specified output stream, as ASF stream chunk.
- *
- * @param out stream to write into.
- * @return amount of bytes written.
- * @throws IOException on I/O errors
- */
- long writeInto(OutputStream out) throws IOException;
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/WriteableChunkModifer.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/WriteableChunkModifer.java
deleted file mode 100644
index b6860e4b..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/io/WriteableChunkModifer.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.mp3.jaudiotagger.audio.asf.io;
-
-import com.mp3.jaudiotagger.audio.asf.data.GUID;
-import com.mp3.jaudiotagger.audio.asf.util.Utils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * A chunk modifier which works with information provided by
- * {@link WriteableChunk} objects.
- *
- * @author Christian Laireiter
- */
-public class WriteableChunkModifer implements ChunkModifier
-{
-
- /**
- * The chunk to write.
- */
- private final WriteableChunk writableChunk;
-
- /**
- * Creates an instance.
- *
- * @param chunk chunk to write
- */
- public WriteableChunkModifer(final WriteableChunk chunk)
- {
- this.writableChunk = chunk;
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean isApplicable(final GUID guid)
- {
- return guid.equals(this.writableChunk.getGuid());
- }
-
- /**
- * {@inheritDoc}
- */
- public ModificationResult modify(final GUID guid, final InputStream chunk, OutputStream destination) throws IOException
- { // NOPMD by Christian Laireiter on 5/9/09 5:03 PM
- int chunkDiff = 0;
- long newSize = 0;
- long oldSize = 0;
- /*
- * Replace the outputstream with the counting one, only if assert's are
- * evaluated.
- */
- assert (destination = new CountingOutputstream(destination)) != null;
- if (!this.writableChunk.isEmpty())
- {
- newSize = this.writableChunk.writeInto(destination);
- assert newSize == this.writableChunk.getCurrentAsfChunkSize();
- /*
- * If assert's are evaluated, we have replaced destination by a
- * CountingOutpustream and can now verify if
- * getCurrentAsfChunkSize() really works correctly.
- */
- assert ((CountingOutputstream) destination).getCount() == newSize;
- if (guid == null)
- {
- chunkDiff++;
- }
-
- }
- if (guid != null)
- {
- assert isApplicable(guid);
- if (this.writableChunk.isEmpty())
- {
- chunkDiff--;
- }
- oldSize = Utils.readUINT64(chunk);
- chunk.skip(oldSize - 24);
- }
- return new ModificationResult(chunkDiff, (newSize - oldSize), guid);
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/util/ChunkPositionComparator.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/util/ChunkPositionComparator.java
deleted file mode 100644
index 9de68289..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/asf/util/ChunkPositionComparator.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2004-2005 Christian Laireiter
- *
- * @author Christian Laireiter
- */
-public final class ChunkPositionComparator implements Comparator
- *
- * @author Christian Laireiter (liree)
- */
-public final class TagConverter
-{
-
- /**
- * This method assigns those tags of tag
which are defined to
- * be common by jaudiotagger.
- *
- * @param tag The tag from which the values are gathered.
- * Assigned values are:
- * @param description The extended content description which should receive the
- * values.
- * Warning: the common values will be replaced.
- */
- public static void assignCommonTagValues(Tag tag, MetadataContainer description)
- {
- assert description.getContainerType() == ContainerType.EXTENDED_CONTENT;
- MetadataDescriptor tmp;
- if (!Utils.isBlank(tag.getFirst(FieldKey.ALBUM)))
- {
- tmp = new MetadataDescriptor(description.getContainerType(), AsfFieldKey.ALBUM.getFieldName(), MetadataDescriptor.TYPE_STRING);
- tmp.setStringValue(tag.getFirst(FieldKey.ALBUM));
- description.removeDescriptorsByName(tmp.getName());
- description.addDescriptor(tmp);
- }
- else
- {
- description.removeDescriptorsByName(AsfFieldKey.ALBUM.getFieldName());
- }
- if (!Utils.isBlank(tag.getFirst(FieldKey.TRACK)))
- {
- tmp = new MetadataDescriptor(description.getContainerType(), AsfFieldKey.TRACK.getFieldName(), MetadataDescriptor.TYPE_STRING);
- tmp.setStringValue(tag.getFirst(FieldKey.TRACK));
- description.removeDescriptorsByName(tmp.getName());
- description.addDescriptor(tmp);
- }
- else
- {
- description.removeDescriptorsByName(AsfFieldKey.TRACK.getFieldName());
- }
- if (!Utils.isBlank(tag.getFirst(FieldKey.YEAR)))
- {
- tmp = new MetadataDescriptor(description.getContainerType(), AsfFieldKey.YEAR.getFieldName(), MetadataDescriptor.TYPE_STRING);
- tmp.setStringValue(tag.getFirst(FieldKey.YEAR));
- description.removeDescriptorsByName(tmp.getName());
- description.addDescriptor(tmp);
- }
- else
- {
- description.removeDescriptorsByName(AsfFieldKey.YEAR.getFieldName());
- }
- if (!Utils.isBlank(tag.getFirst(FieldKey.GENRE)))
- {
- // Write Genre String value
- tmp = new MetadataDescriptor(description.getContainerType(), AsfFieldKey.GENRE.getFieldName(), MetadataDescriptor.TYPE_STRING);
- tmp.setStringValue(tag.getFirst(FieldKey.GENRE));
- description.removeDescriptorsByName(tmp.getName());
- description.addDescriptor(tmp);
- Integer genreNum = GenreTypes.getInstanceOf().getIdForName(tag.getFirst(FieldKey.GENRE));
- // ..and if it is one of the standard genre types used the id as
- // well
- if (genreNum != null)
- {
- tmp = new MetadataDescriptor(description.getContainerType(), AsfFieldKey.GENRE_ID.getFieldName(), MetadataDescriptor.TYPE_STRING);
- tmp.setStringValue("(" + genreNum + ")");
- description.removeDescriptorsByName(tmp.getName());
- description.addDescriptor(tmp);
- }
- else
- {
- description.removeDescriptorsByName(AsfFieldKey.GENRE_ID.getFieldName());
- }
- }
- else
- {
- description.removeDescriptorsByName(AsfFieldKey.GENRE.getFieldName());
- description.removeDescriptorsByName(AsfFieldKey.GENRE_ID.getFieldName());
- }
- }
-
- /**
- * This method creates a {@link Tag}and fills it with the contents of the
- * given {@link AsfHeader}.
- *
- * @param source The ASF header which contains the information.
- * @return A Tag with all its values.
- */
- public static AsfTag createTagOf(AsfHeader source)
- {
- // TODO do we need to copy here.
- AsfTag result = new AsfTag(true);
- for (int i = 0; i < ContainerType.values().length; i++)
- {
- MetadataContainer current = source.findMetadataContainer(ContainerType.values()[i]);
- if (current != null)
- {
- List
- *
- * @author Christian Laireiter
- */
-public class Utils
-{
-
- public static final long DIFF_BETWEEN_ASF_DATE_AND_JAVA_DATE = 11644470000000l;
- /**
- * Stores the default line separator of the current underlying system.
- */
- public final static String LINE_SEPARATOR = System.getProperty("line.separator"); //$NON-NLS-1$
- /**
- *
- */
- private static final int MAXIMUM_STRING_LENGTH_ALLOWED = 32766;
-
- /**
- * This method checks given string will not exceed limit in bytes[] when
- * converted UTF-16LE encoding (2 bytes per character) and checks whether
- * the length doesn't exceed 65535 bytes.
- *
- * @param value The string to check.
- * @throws IllegalArgumentException If byte representation takes more than 65535 bytes.
- */
- public static void checkStringLengthNullSafe(String value) throws IllegalArgumentException
- {
- if (value != null)
- {
- if (value.length() > MAXIMUM_STRING_LENGTH_ALLOWED)
- {
- throw new IllegalArgumentException(ErrorMessage.WMA_LENGTH_OF_STRING_IS_TOO_LARGE.getMsg((value.length() * 2))
- );
- }
- }
- }
-
- /**
- * @param value String to check for null
- * @return true unless string is too long
- */
- public static boolean isStringLengthValidNullSafe(String value)
- {
- if (value != null)
- {
- if (value.length() > MAXIMUM_STRING_LENGTH_ALLOWED)
- {
- return false;
- }
- }
- return true;
- }
-
- /**
- * effectively copies a specified amount of bytes from one stream to
- * another.
- *
- * @param source stream to read from
- * @param dest stream to write to
- * @param amount amount of bytes to copy
- * @throws IOException on I/O errors, and if the source stream depletes before all
- * bytes have been copied.
- */
- public static void copy(InputStream source, OutputStream dest, long amount) throws IOException
- {
- byte[] buf = new byte[8192];
- long copied = 0;
- while (copied < amount)
- {
- int toRead = 8192;
- if ((amount - copied) < 8192)
- {
- toRead = (int) (amount - copied);
- }
- int read = source.read(buf, 0, toRead);
- if (read == -1)
- {
- throw new IOException("Inputstream has to continue for another " + (amount - copied) + " bytes."
- );
- }
- dest.write(buf, 0, read);
- copied += read;
- }
- }
-
- /**
- * Copies all of the source to the destination.
- *
- * @param source source to read from
- * @param dest stream to write to
- * @throws IOException on I/O errors.
- */
- public static void flush(final InputStream source, final OutputStream dest) throws IOException
- {
- final byte[] buf = new byte[8192];
- int read;
- while ((read = source.read(buf)) != -1)
- {
- dest.write(buf, 0, read);
- }
- }
-
- /**
- * This method will create a byte[] at the size of byteCount
- * and insert the bytes of value
(starting from lowset byte)
- * into it.
- * You can easily create a Word (16-bit), DWORD (32-bit), QWORD (64 bit) out
- * of the value, ignoring the original type of value, since java
- * automatically performs transformations.
- * Warning: This method works with unsigned numbers only.
- *
- * @param value The value to be written into the result.
- * @param byteCount The number of bytes the array has got.
- * @return A byte[] with the size of byteCount
containing the
- * lower byte values of value
.
- */
- public static byte[] getBytes(final long value, final int byteCount)
- {
- byte[] result = new byte[byteCount];
- for (int i = 0; i < result.length; i++)
- {
- result[i] = (byte) ((value >>> (i * 8)) & 0xFF);
- }
- return result;
- }
-
- /**
- * Convenience method to convert the given string into a byte sequence which
- * has the format of the charset given.
- *
- * @param source string to convert.
- * @param charset charset to apply
- * @return the source's binary representation according to the charset.
- */
- public static byte[] getBytes(final String source, final Charset charset)
- {
- assert charset != null;
- assert source != null;
- final ByteBuffer encoded = charset.encode(source);
- final byte[] result = new byte[encoded.limit()];
- encoded.rewind();
- encoded.get(result);
- return result;
- }
-
- /**
- * Since date values in ASF files are given in 100 ns steps since first
- * january of 1601 a little conversion must be done.
- * This method converts a date given in described manner to a calendar.
- *
- * @param fileTime
- * Time in 100ns since 1 jan 1601
- * @return Calendar holding the date representation.
- */
- /* Old method that ran very slowely and doesnt logical correct, how does dividing something
- at 10-4 by 10,000 convert it to 10 -3
- public static GregorianCalendar getDateOf(final BigInteger fileTime) {
- final GregorianCalendar result = new GregorianCalendar(1601, 0, 1);
- // lose anything beyond milliseconds, because calendar can't handle
- // less value
- BigInteger time = fileTime.divide(new BigInteger("10000")); //$NON-NLS-1$
- final BigInteger maxInt = new BigInteger(String
- .valueOf(Integer.MAX_VALUE));
- while (time.compareTo(maxInt) > 0) {
- result.add(Calendar.MILLISECOND, Integer.MAX_VALUE);
- time = time.subtract(maxInt);
- }
- result.add(Calendar.MILLISECOND, time.intValue());
- return result;
- }
- */
-
- /**
- * Date values in ASF files are given in 100 ns (10 exp -4) steps since first
- *
- * @param fileTime Time in 100ns since 1 jan 1601
- * @return Calendar holding the date representation.
- */
- public static GregorianCalendar getDateOf(final BigInteger fileTime)
- {
- final GregorianCalendar result = new GregorianCalendar();
-
- // Divide by 10 to convert from -4 to -3 (millisecs)
- BigInteger time = fileTime.divide(new BigInteger("10"));
- // Construct Date taking into the diff between 1601 and 1970
- Date date = new Date(time.longValue() - DIFF_BETWEEN_ASF_DATE_AND_JAVA_DATE);
- result.setTime(date);
- return result;
- }
-
- /**
- * Tests if the given string is null
or just contains
- * whitespace characters.
- *
- * @param toTest String to test.
- * @return see description.
- */
- public static boolean isBlank(String toTest)
- {
- if (toTest == null)
- {
- return true;
- }
-
- for (int i = 0; i < toTest.length(); i++)
- {
- if (!Character.isWhitespace(toTest.charAt(i)))
- {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Reads 8 bytes from stream and interprets them as a UINT64 which is
- * returned as {@link BigInteger}.
- *
- * @param stream stream to readm from.
- * @return a BigInteger which represents the read 8 bytes value.
- * @throws IOException if problem reading bytes
- */
- public static BigInteger readBig64(InputStream stream) throws IOException
- {
- byte[] bytes = new byte[8];
- byte[] oa = new byte[8];
- int read = stream.read(bytes);
- if (read != 8)
- {
- // 8 bytes mandatory.
- throw new EOFException();
- }
- for (int i = 0; i < bytes.length; i++)
- {
- oa[7 - i] = bytes[i];
- }
- return new BigInteger(oa);
- }
-
- /**
- * Reads size
bytes from the stream.
- *
- * @param stream stream to read from.
- * @param size amount of bytes to read.
- * @return the read bytes.
- * @throws IOException on I/O errors.
- */
- public static byte[] readBinary(InputStream stream, long size) throws IOException
- {
- byte[] result = new byte[(int) size];
- stream.read(result);
- return result;
- }
-
- /**
- * This method reads a UTF-16 String, which length is given on the number of
- * characters it consists of.
- * The stream must be at the number of characters. This number contains the
- * terminating zero character (UINT16).
- *
- * @param stream Input source
- * @return String
- * @throws IOException read errors
- */
- public static String readCharacterSizedString(InputStream stream) throws IOException
- {
- StringBuilder result = new StringBuilder();
- int strLen = readUINT16(stream);
- int character = stream.read();
- character |= stream.read() << 8;
- do
- {
- if (character != 0)
- {
- result.append((char) character);
- character = stream.read();
- character |= stream.read() << 8;
- }
- }
- while (character != 0 || (result.length() + 1) > strLen);
- if (strLen != (result.length() + 1))
- {
- throw new IllegalStateException("Invalid Data for current interpretation"); //$NON-NLS-1$
- }
- return result.toString();
- }
-
- /**
- * This method reads a UTF-16 encoded String.
- * For the use this method the number of bytes used by current string must
- * be known.
- * The ASF specification recommends that those strings end with a
- * terminating zero. However it also says that it is not always the case.
- *
- * @param stream Input source
- * @param strLen Number of bytes the String may take.
- * @return read String.
- * @throws IOException read errors.
- */
- public static String readFixedSizeUTF16Str(InputStream stream, int strLen) throws IOException
- {
- byte[] strBytes = new byte[strLen];
- int read = stream.read(strBytes);
- if (read == strBytes.length)
- {
- if (strBytes.length >= 2)
- {
- /*
- * Zero termination is recommended but optional. So check and
- * if, remove.
- */
- if (strBytes[strBytes.length - 1] == 0 && strBytes[strBytes.length - 2] == 0)
- {
- byte[] copy = new byte[strBytes.length - 2];
- System.arraycopy(strBytes, 0, copy, 0, strBytes.length - 2);
- strBytes = copy;
- }
- }
- return new String(strBytes, "UTF-16LE");
- }
- throw new IllegalStateException("Couldn't read the necessary amount of bytes.");
- }
-
- /**
- * This Method reads a GUID (which is a 16 byte long sequence) from the
- * given raf
and creates a wrapper.
- * Warning :
- * There is no way of telling if a byte sequence is a guid or not. The next
- * 16 bytes will be interpreted as a guid, whether it is or not.
- *
- * @param stream Input source.
- * @return A class wrapping the guid.
- * @throws IOException happens when the file ends before guid could be extracted.
- */
- public static GUID readGUID(InputStream stream) throws IOException
- {
- if (stream == null)
- {
- throw new IllegalArgumentException("Argument must not be null"); //$NON-NLS-1$
- }
- int[] binaryGuid = new int[GUID.GUID_LENGTH];
- for (int i = 0; i < binaryGuid.length; i++)
- {
- binaryGuid[i] = stream.read();
- }
- return new GUID(binaryGuid);
- }
-
- /**
- * Reads 2 bytes from stream and interprets them as UINT16.
- *
- * @param stream stream to read from.
- * @return UINT16 value
- * @throws IOException on I/O Errors.
- */
- public static int readUINT16(InputStream stream) throws IOException
- {
- int result = stream.read();
- result |= stream.read() << 8;
- return result;
- }
-
- /**
- * Reads 4 bytes from stream and interprets them as UINT32.
- *
- * @param stream stream to read from.
- * @return UINT32 value
- * @throws IOException on I/O Errors.
- */
- public static long readUINT32(InputStream stream) throws IOException
- {
- long result = 0;
- for (int i = 0; i <= 24; i += 8)
- {
- // Warning, always cast to long here. Otherwise it will be
- // shifted as int, which may produce a negative value, which will
- // then be extended to long and assign the long variable a negative
- // value.
- result |= (long) stream.read() << i;
- }
- return result;
- }
-
- /**
- * Reads long as little endian.
- *
- * @param stream Data source
- * @return long value
- * @throws IOException read error, or eof is reached before long is completed
- */
- public static long readUINT64(InputStream stream) throws IOException
- {
- long result = 0;
- for (int i = 0; i <= 56; i += 8)
- {
- // Warning, always cast to long here. Otherwise it will be
- // shifted as int, which may produce a negative value, which will
- // then be extended to long and assign the long variable a negative
- // value.
- result |= (long) stream.read() << i;
- }
- return result;
- }
-
- /**
- * This method reads a UTF-16 encoded String, beginning with a 16-bit value
- * representing the number of bytes needed. The String is terminated with as
- * 16-bit ZERO.
- *
- * @param stream Input source
- * @return read String.
- * @throws IOException read errors.
- */
- public static String readUTF16LEStr(InputStream stream) throws IOException
- {
- int strLen = readUINT16(stream);
- byte[] buf = new byte[strLen];
- int read = stream.read(buf);
- if (read == strLen || (strLen == 0 && read == -1))
- {
- /*
- * Check on zero termination
- */
- if (buf.length >= 2)
- {
- if (buf[buf.length - 1] == 0 && buf[buf.length - 2] == 0)
- {
- byte[] copy = new byte[buf.length - 2];
- System.arraycopy(buf, 0, copy, 0, buf.length - 2);
- buf = copy;
- }
- }
- return new String(buf, AsfHeader.ASF_CHARSET.name());
- }
- throw new IllegalStateException("Invalid Data for current interpretation"); //$NON-NLS-1$
- }
-
- /**
- * Writes the given value as UINT16 into the stream.
- *
- * @param number value to write.
- * @param out stream to write into.
- * @throws IOException On I/O errors
- */
- public static void writeUINT16(int number, OutputStream out) throws IOException
- {
- if (number < 0)
- {
- throw new IllegalArgumentException("positive value expected."); //$NON-NLS-1$
- }
- byte[] toWrite = new byte[2];
- for (int i = 0; i <= 8; i += 8)
- {
- toWrite[i / 8] = (byte) ((number >> i) & 0xFF);
- }
- out.write(toWrite);
- }
-
- /**
- * Writes the given value as UINT32 into the stream.
- *
- * @param number value to write.
- * @param out stream to write into.
- * @throws IOException On I/O errors
- */
- public static void writeUINT32(long number, OutputStream out) throws IOException
- {
- if (number < 0)
- {
- throw new IllegalArgumentException("positive value expected."); //$NON-NLS-1$
- }
- byte[] toWrite = new byte[4];
- for (int i = 0; i <= 24; i += 8)
- {
- toWrite[i / 8] = (byte) ((number >> i) & 0xFF);
- }
- out.write(toWrite);
- }
-
- /**
- * Writes the given value as UINT64 into the stream.
- *
- * @param number value to write.
- * @param out stream to write into.
- * @throws IOException On I/O errors
- */
- public static void writeUINT64(long number, OutputStream out) throws IOException
- {
- if (number < 0)
- {
- throw new IllegalArgumentException("positive value expected."); //$NON-NLS-1$
- }
- byte[] toWrite = new byte[8];
- for (int i = 0; i <= 56; i += 8)
- {
- toWrite[i / 8] = (byte) ((number >> i) & 0xFF);
- }
- out.write(toWrite);
- }
-
-}
\ No newline at end of file
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/dsf/DsdChunk.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/dsf/DsdChunk.java
deleted file mode 100644
index edbe8e04..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/dsf/DsdChunk.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package com.mp3.jaudiotagger.audio.dsf;
-
-import com.mp3.jaudiotagger.StandardCharsets;
-import com.mp3.jaudiotagger.audio.generic.Utils;
-import com.mp3.jaudiotagger.audio.iff.IffHeaderChunk;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-/**
- * DSD Chunk
- */
-public class DsdChunk
-{
- private long chunkSizeLength;
- private long fileLength;
- private long metadataOffset;
-
- public static final int CHUNKSIZE_LENGTH = 8;
- public static final int FILESIZE_LENGTH = 8;
- public static final int METADATA_OFFSET_LENGTH = 8;
- public static final int FMT_CHUNK_MIN_DATA_SIZE_ = 40;
-
- public static final int DSD_HEADER_LENGTH = IffHeaderChunk.SIGNATURE_LENGTH + CHUNKSIZE_LENGTH + FILESIZE_LENGTH + METADATA_OFFSET_LENGTH;
-
- public static DsdChunk readChunk(ByteBuffer dataBuffer)
- {
- String type = Utils.readFourBytesAsChars(dataBuffer);
- if (DsfChunkType.DSD.getCode().equals(type))
- {
- return new DsdChunk(dataBuffer);
- }
- return null;
- }
-
- private DsdChunk(ByteBuffer dataBuffer)
- {
- chunkSizeLength = dataBuffer.getLong();
- fileLength = dataBuffer.getLong();
- metadataOffset = dataBuffer.getLong();
- }
-
- public String toString()
- {
-
- return "ChunkSize:"+chunkSizeLength
- + ":fileLength:"+fileLength
- + ":metadata:"+metadataOffset;
-
- }
-
- public long getChunkSizeLength()
- {
- return chunkSizeLength;
- }
-
- public void setChunkSizeLength(long chunkSizeLength)
- {
- this.chunkSizeLength = chunkSizeLength;
- }
-
- public long getFileLength()
- {
- return fileLength;
- }
-
- public void setFileLength(long fileLength)
- {
- this.fileLength = fileLength;
- }
-
- public long getMetadataOffset()
- {
- return metadataOffset;
- }
-
- public void setMetadataOffset(long metadataOffset)
- {
- this.metadataOffset = metadataOffset;
- }
-
- /**
- * Write new DSDchunk to buffer
- *
- * @return
- */
- public ByteBuffer write()
- {
- ByteBuffer buffer = ByteBuffer.allocateDirect(DSD_HEADER_LENGTH);
- buffer.order(ByteOrder.LITTLE_ENDIAN);
- buffer.put(DsfChunkType.DSD.getCode().getBytes(StandardCharsets.US_ASCII));
- buffer.putLong(chunkSizeLength);
- buffer.putLong(fileLength);
- buffer.putLong(metadataOffset);
- buffer.flip();
- return buffer;
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/dsf/Dsf.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/dsf/Dsf.java
deleted file mode 100644
index 4aade677..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/dsf/Dsf.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.mp3.jaudiotagger.audio.dsf;
-
-import com.mp3.jaudiotagger.tag.Tag;
-import com.mp3.jaudiotagger.tag.TagOptionSingleton;
-import com.mp3.jaudiotagger.tag.id3.ID3v22Tag;
-import com.mp3.jaudiotagger.tag.id3.ID3v23Tag;
-import com.mp3.jaudiotagger.tag.id3.ID3v24Tag;
-import com.mp3.jaudiotagger.tag.reference.ID3V2Version;
-
-/**
- * Created by Paul on 28/01/2016.
- */
-public class Dsf
-{
- public static Tag createDefaultTag()
- {
- if(TagOptionSingleton.getInstance().getID3V2Version()== ID3V2Version.ID3_V24)
- {
- return new ID3v24Tag();
- }
- else if(TagOptionSingleton.getInstance().getID3V2Version()==ID3V2Version.ID3_V23)
- {
- return new ID3v23Tag();
- }
- else if(TagOptionSingleton.getInstance().getID3V2Version()==ID3V2Version.ID3_V22)
- {
- return new ID3v22Tag();
- }
- //Default in case not set somehow
- return new ID3v24Tag();
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/dsf/DsfChunkType.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/dsf/DsfChunkType.java
deleted file mode 100644
index 80bbf7f1..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/dsf/DsfChunkType.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.mp3.jaudiotagger.audio.dsf;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Chunk types mark each {@link com.mp3.jaudiotagger.audio.iff.ChunkHeader}. They are always 4 ASCII chars long.
- *
- * @see com.mp3.jaudiotagger.audio.iff.Chunk
- */
-public enum DsfChunkType
-{
- DSD("DSD "),
- FORMAT("fmt "),
- DATA("data"),
- ID3("ID3"),
- ;
-
- private static final Mapnull
.
- * @throws IOException if cannot read file.
- */
- private Tag readTag(FileChannel fc, DsdChunk dsd, String fileName) throws CannotReadException, IOException {
- if (dsd.getMetadataOffset() > 0) {
- fc.position(dsd.getMetadataOffset());
- ID3Chunk id3Chunk = ID3Chunk.readChunk(Utils.readFileDataIntoBufferLE(fc, (int) (fc.size() - fc.position())));
- if (id3Chunk != null) {
- int version = id3Chunk.getDataBuffer().get(AbstractID3v2Tag.FIELD_TAG_MAJOR_VERSION_POS);
- try {
- switch (version) {
- case ID3v22Tag.MAJOR_VERSION:
- return new ID3v22Tag(id3Chunk.getDataBuffer(), "");
- case ID3v23Tag.MAJOR_VERSION:
- return new ID3v23Tag(id3Chunk.getDataBuffer(), "");
- case ID3v24Tag.MAJOR_VERSION:
- return new ID3v24Tag(id3Chunk.getDataBuffer(), "");
- default:
- logger.log(Level.WARNING, fileName + " Unknown ID3v2 version " + version + ". Returning an empty ID3v2 Tag.");
- return null;
- }
- } catch (TagException e) {
- throw new CannotReadException(fileName + " Could not read ID3v2 tag:corruption");
- }
- } else {
- logger.log(Level.WARNING, fileName + " No existing ID3 tag(1)");
- return null;
- }
- } else {
- logger.log(Level.WARNING, fileName + " No existing ID3 tag(2)");
- return null;
- }
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/dsf/DsfFileWriter.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/dsf/DsfFileWriter.java
deleted file mode 100644
index c48956df..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/dsf/DsfFileWriter.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2003-2005 Raphaël Slinckx null
.
- */
- @SuppressWarnings("unused")
- private GenericAudioHeader readAudioInfo(DsdChunk dsd, ByteBuffer audioInfoChunk)
- {
- GenericAudioHeader audioHeader = new GenericAudioHeader();
- if (audioInfoChunk.limit() < FMT_CHUNK_MIN_DATA_SIZE_)
- {
- logger.log(Level.WARNING, "Not enough bytes supplied for Generic audio header. Returning an empty one.");
- return audioHeader;
- }
-
- audioInfoChunk.order(ByteOrder.LITTLE_ENDIAN);
- int version = audioInfoChunk.getInt();
- int formatId =audioInfoChunk.getInt();
- int channelType =audioInfoChunk.getInt();
- int channelNumber = audioInfoChunk.getInt();
- int samplingFreqency = audioInfoChunk.getInt();
- int bitsPerSample =audioInfoChunk.getInt();
- long sampleCount = audioInfoChunk.getLong();
- int blocksPerSample = audioInfoChunk.getInt();
-
- audioHeader.setEncodingType("DSF");
- audioHeader.setBitRate(bitsPerSample * samplingFreqency * channelNumber);
- audioHeader.setBitsPerSample(bitsPerSample);
- audioHeader.setChannelNumber(channelNumber);
- audioHeader.setSamplingRate(samplingFreqency);
- audioHeader.setNoOfSamples(sampleCount);
- audioHeader.setPreciseLength((float) sampleCount / samplingFreqency);
- audioHeader.setVariableBitRate(false);
- logger.log(Level.FINE, "Created audio header: " + audioHeader);
- return audioHeader;
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/dsf/ID3Chunk.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/dsf/ID3Chunk.java
deleted file mode 100644
index ba70c716..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/dsf/ID3Chunk.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.mp3.jaudiotagger.audio.dsf;
-
-import com.mp3.jaudiotagger.audio.generic.Utils;
-
-import java.nio.ByteBuffer;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * Created by Paul on 28/01/2016.
- */
-public class ID3Chunk
-{
- public static Logger logger = Logger.getLogger("com.mp3.jaudiotagger.audio.generic.ID3Chunk");
-
- private ByteBuffer dataBuffer;
- public static ID3Chunk readChunk(ByteBuffer dataBuffer)
- {
- String type = Utils.readThreeBytesAsChars(dataBuffer);
- if (DsfChunkType.ID3.getCode().equals(type))
- {
- return new ID3Chunk(dataBuffer);
- }
- logger.log(Level.WARNING,"Invalid type:"+type+" where expected ID3 tag");
- return null;
- }
-
- public ID3Chunk(ByteBuffer dataBuffer)
- {
- this.dataBuffer = dataBuffer;
- }
-
- public ByteBuffer getDataBuffer()
- {
- return dataBuffer;
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/exceptions/CannotReadException.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/exceptions/CannotReadException.java
deleted file mode 100644
index 4524a594..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/exceptions/CannotReadException.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2003-2005 Raphaël Slinckx
- * Causes may be invalid data or IO errors.
- *
- * @author Raphaël Slinckx
- */
-public class CannotReadException extends Exception
-{
- /**
- * Creates an instance.
- */
- public CannotReadException()
- {
- super();
- }
-
- public CannotReadException(Throwable ex)
- {
- super(ex);
- }
-
- /**
- * Creates an instance.
- *
- * @param message The message.
- */
- public CannotReadException(String message)
- {
- super(message);
- }
-
- /**
- * Creates an instance.
- *
- * @param message The error message.
- * @param cause The throwable causing this exception.
- */
- public CannotReadException(String message, Throwable cause)
- {
- super(message, cause);
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/exceptions/CannotReadVideoException.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/exceptions/CannotReadVideoException.java
deleted file mode 100644
index b22f5aed..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/exceptions/CannotReadVideoException.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.mp3.jaudiotagger.audio.exceptions;
-
-/**
- * This exception should be thrown idf it appears the file is a video file, jaudiotagger only supports audio
- * files.
- */
-public class CannotReadVideoException extends CannotReadException
-{
- /**
- * Creates an instance.
- */
- public CannotReadVideoException()
- {
- super();
- }
-
- public CannotReadVideoException(Throwable ex)
- {
- super(ex);
- }
-
- /**
- * Creates an instance.
- *
- * @param message The message.
- */
- public CannotReadVideoException(String message)
- {
- super(message);
- }
-
- /**
- * Creates an instance.
- *
- * @param message The error message.
- * @param cause The throwable causing this exception.
- */
- public CannotReadVideoException(String message, Throwable cause)
- {
- super(message, cause);
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/exceptions/CannotWriteException.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/exceptions/CannotWriteException.java
deleted file mode 100644
index f66e5609..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/exceptions/CannotWriteException.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2003-2005 Raphaël Slinckx
- * This exception can be used in all methods but
- * {@link com.mp3.jaudiotagger.audio.generic.AudioFileModificationListener#fileOperationFinished(java.io.File)}.
- *
- * @author Christian Laireiter
- */
-public class ModifyVetoException extends Exception
-{
-
- /**
- * (overridden)
- */
- public ModifyVetoException()
- {
- super();
- }
-
- /**
- * (overridden)
- *
- * @param message
- * @see Exception#Exception(String)
- */
- public ModifyVetoException(String message)
- {
- super(message);
- }
-
- /**
- * (overridden)
- *
- * @param message
- * @param cause
- * @see Exception#Exception(String,Throwable)
- */
- public ModifyVetoException(String message, Throwable cause)
- {
- super(message, cause);
- }
-
- /**
- * (overridden)
- *
- * @param cause
- * @see Exception#Exception(Throwable)
- */
- public ModifyVetoException(Throwable cause)
- {
- super(cause);
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/exceptions/NoReadPermissionsException.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/exceptions/NoReadPermissionsException.java
deleted file mode 100644
index a04930a2..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/exceptions/NoReadPermissionsException.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2003-2005 Raphaël Slinckx
- *
- * @param field The field containing the data to be taken.
- */
- public void copyContent(TagField field)
- {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Returns the Id of the represented tag field.
- * This value should uniquely identify a kind of tag data, like title.
- * {@link com.mp3.jaudiotagger.audio.generic.AbstractTag} will use the "id" to summarize multiple
- * fields.
- *
- * @return Unique identifier for the fields type. (title, artist...)
- */
- public String getId()
- {
- return FieldKey.COVER_ART.name();
- }
-
- /**
- * This method delivers the binary representation of the fields data in
- * order to be directly written to the file.
- *
- * @return Binary data representing the current tag field.
- * @throws UnsupportedEncodingException
- * Most tag data represents text. In some cases the underlying
- * implementation will need to convert the text data in java to
- * a specific charset encoding. In these cases an
- * {@link UnsupportedEncodingException} may occur.
- */
- public byte[] getRawContent() throws UnsupportedEncodingException
- {
- return getBytes().array();
- }
-
- /**
- * Determines whether the represented field contains (is made up of) binary
- * data, instead of text data.
- * Software can identify fields to be displayed because they are human
- * readable if this method returns false
.
- *
- * @return true
if field represents binary data (not human
- * readable).
- */
- public boolean isBinary()
- {
- return true;
- }
-
- /**
- * This method will set the field to represent binary data.
- *
- * Some implementations may support conversions.
- * As of now (Octobre 2005) there is no implementation really using this
- * method to perform useful operations.
- *
- * @param b true
, if the field contains binary data.
- * @deprecated As for now is of no use. Implementations should use another
- * way of setting this property.
- */
- public void isBinary(boolean b)
- {
- //Do nothing, always true
- }
-
- /**
- * Identifies a field to be of common use.
- *
- * Some software may differ between common and not common fields. A common
- * one is for sure the title field. A web link may not be of common use for
- * tagging. However some file formats, or future development of users
- * expectations will make more fields common than now can be known.
- *
- * @return true
if the field is of common use.
- */
- public boolean isCommon()
- {
- return true;
- }
-
- /**
- * Determines whether the content of the field is empty.
- *
- * @return true
if no data is stored (or empty String).
- */
- public boolean isEmpty()
- {
- return false;
- }
-
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataSeekTable.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataSeekTable.java
deleted file mode 100644
index ec59c5b2..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/flac/metadatablock/MetadataBlockDataSeekTable.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2003-2005 Raphaël Slinckx
- *
- * @author Raphaël Slinckx
- */
-public abstract class AbstractTag implements Tag
-{
- /**
- * Stores the amount of {@link TagField} with {@link TagField#isCommon()}
- * true
.
- */
- protected int commonNumber = 0;
-
- /**
- * This map stores the {@linkplain TagField#getId() ids} of the stored
- * fields to the {@linkplain TagField fields} themselves. Because a linked hashMap is used the order
- * that they are added in is preserved, the only exception to this rule is when two fields of the same id
- * exist, both will be returned according to when the first item was added to the file.
- */
- protected Maptrue
if the given encoding can be used.
- */
- protected abstract boolean isAllowedEncoding(Charset enc);
-
- /**
- * Is this tag empty
- *
- * @see Tag#isEmpty()
- */
- @Override
- public boolean isEmpty()
- {
- return fields.size() == 0;
- }
-
- /**
- * Create new field and set it in the tag
- *
- * @param genericKey
- * @param value
- * @throws KeyNotFoundException
- * @throws FieldDataInvalidException
- */
- @Override
- public void setField(FieldKey genericKey, String... value) throws KeyNotFoundException, FieldDataInvalidException
- {
- TagField tagfield = createField(genericKey,value);
- setField(tagfield);
- }
-
- /**
- * Create new field and add it to the tag
- *
- * @param genericKey
- * @param value
- * @throws KeyNotFoundException
- * @throws FieldDataInvalidException
- */
- @Override
- public void addField(FieldKey genericKey, String... value) throws KeyNotFoundException, FieldDataInvalidException
- {
- TagField tagfield = createField(genericKey,value);
- addField(tagfield);
- }
-
- /**
- * Set field
- *
- * Changed:Just because field is empty it doesn't mean it should be deleted. That should be the choice
- * of the developer. (Or does this break things)
- *
- * @see Tag#setField(TagField)
- */
- @Override
- public void setField(TagField field)
- {
- if (field == null)
- {
- return;
- }
-
- // If there is already an existing field with same id
- // and both are TextFields, we replace the first element
- List
- *
- *
- *
- *
- *
- * @author Christian Laireiter
- * Here one can modify the tag data because of global settings.original
has been processed.
- * Because the audiolibrary allows format implementors to either change the
- * original file or create a copy, it is possible that the real result is
- * located in the original and temporary
is of zero size
- * or the original will be deleted and replaced by temporary.
- *
- * @param original The original file on which the operation was started.
- * @param temporary The modified copy. (It may be of zero size if the original was
- * modified)
- * @throws ModifyVetoException If the Results doesn't fit the expectations of the listener,
- * it can prevent the replacement of the original by temporary.
- * If the original is already modified, this exception results
- * in nothing.
- */
- public void fileModified(AudioFile original, File temporary) throws ModifyVetoException;
-
- /**
- * Informs the listener that the process has been finished.
- * The given file is either the original file or the modified copy.
- *
- * @param result The remaining file. It's not of {@link AudioFile} since it may
- * be possible that a new file was created. In that case the
- * audiolibs would need to parse the file again, which leads to
- * long and unnecessary operation time, if the tag data is not
- * needed any more.
- */
- public void fileOperationFinished(File result);
-
- /**
- * Notifies that the file
is about to be modified.
- *
- * @param file The file that will be modified.
- * @param delete true
if the deletion of tag data will be
- * performed.
- * @throws ModifyVetoException Thrown if the listener wants to prevent the process.
- */
- public void fileWillBeModified(AudioFile file, boolean delete) throws ModifyVetoException;
-
- /**
- * This method notifies about a veto exception that has been thrown by
- * another listener.
- *
- * @param cause The instance which caused the veto.
- * @param original The original file, that was about to be modified.
- * @param veto The thrown exception.
- */
- public void vetoThrown(AudioFileModificationListener cause, AudioFile original, ModifyVetoException veto);
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/generic/AudioFileReader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/generic/AudioFileReader.java
deleted file mode 100644
index e50d17fd..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/generic/AudioFileReader.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2003-2005 Raphaël Slinckx null
, this listener is used to notify the listener
- * about modification events.
- */
- private AudioFileModificationListener modificationListener = null;
-
- /**
- * Delete the tag (if any) present in the given file
- *
- * @param af The file to process
- * @throws CannotWriteException if anything went wrong
- * @throws com.mp3.jaudiotagger.audio.exceptions.CannotReadException
- */
- public void delete(AudioFile af) throws CannotReadException, CannotWriteException {
- File file = af.getFile();
- if (TagOptionSingleton.getInstance().isCheckIsWritable() && !file.canWrite()) {
- throw new CannotWriteException(ErrorMessage.GENERAL_DELETE_FAILED.getMsg(file.getPath()));
- }
-
- if (af.getFile().length() <= MINIMUM_FILESIZE) {
- throw new CannotWriteException(ErrorMessage.GENERAL_DELETE_FAILED_BECAUSE_FILE_IS_TOO_SMALL.getMsg(file.getPath()));
- }
-
- RandomAccessFile raf = null;
- RandomAccessFile rafTemp = null;
- File tempF = null;
-
- // Will be set to true on VetoException, causing the finally block to
- // discard the tempfile.
- boolean revert = false;
-
- try {
-
- tempF = File.createTempFile(af.getFile().getName().replace('.', '_'), TEMP_FILENAME_SUFFIX, af.getFile().getParentFile());
- rafTemp = new RandomAccessFile(tempF, WRITE_MODE);
- raf = new RandomAccessFile(af.getFile(), WRITE_MODE);
- raf.seek(0);
- rafTemp.seek(0);
-
- try {
- if (this.modificationListener != null) {
- this.modificationListener.fileWillBeModified(af, true);
- }
- deleteTag(af.getTag(), raf, rafTemp);
- if (this.modificationListener != null) {
- this.modificationListener.fileModified(af, tempF);
- }
- } catch (ModifyVetoException veto) {
- throw new CannotWriteException(veto);
- }
-
- } catch (Exception e) {
- revert = true;
- throw new CannotWriteException("\"" + af.getFile().getAbsolutePath() + "\" :" + e, e);
- } finally {
- // will be set to the remaining file.
- File result = af.getFile();
- try {
- if (raf != null) {
- raf.close();
- }
- if (rafTemp != null) {
- rafTemp.close();
- }
-
- if (tempF.length() > 0 && !revert) {
- boolean deleteResult = af.getFile().delete();
- if (!deleteResult) {
- logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_ORIGINAL_FILE.getMsg(af.getFile().getPath(), tempF.getPath()));
- throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_ORIGINAL_FILE.getMsg(af.getFile().getPath(), tempF.getPath()));
- }
- boolean renameResult = tempF.renameTo(af.getFile());
- if (!renameResult) {
- logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_TO_ORIGINAL_FILE.getMsg(af.getFile().getPath(), tempF.getPath()));
- throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_TO_ORIGINAL_FILE.getMsg(af.getFile().getPath(), tempF.getPath()));
- }
- result = tempF;
-
- // If still exists we can now delete
- if (tempF.exists()) {
- if (!tempF.delete()) {
- // Non critical failed deletion
- logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_TEMPORARY_FILE.getMsg(tempF.getPath()));
- }
- }
- } else {
- // It was created but never used
- if (!tempF.delete()) {
- // Non critical failed deletion
- logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_TEMPORARY_FILE.getMsg(tempF.getPath()));
- }
- }
- } catch (Exception ex) {
- logger.severe("AudioFileWriter exception cleaning up delete:" + af.getFile().getPath() + " or" + tempF.getAbsolutePath() + ":" + ex);
- }
- // Notify listener
- if (this.modificationListener != null) {
- this.modificationListener.fileOperationFinished(result);
- }
- }
- }
-
- /**
- * Delete the tag (if any) present in the given randomaccessfile, and do not
- * close it at the end.
- *
- * @param tag
- * @param raf The source file, already opened in r-write mode
- * @param tempRaf The temporary file opened in r-write mode
- * @throws CannotWriteException if anything went wrong
- * @throws com.mp3.jaudiotagger.audio.exceptions.CannotReadException
- * @throws IOException
- */
- public void delete(Tag tag, RandomAccessFile raf, RandomAccessFile tempRaf) throws CannotReadException, CannotWriteException, IOException {
- raf.seek(0);
- tempRaf.seek(0);
- deleteTag(tag, raf, tempRaf);
- }
-
- /**
- * Same as above, but delete tag in the file.
- *
- * @param tag
- * @param raf
- * @param tempRaf
- * @throws IOException is thrown when the RandomAccessFile operations throw it (you
- * should never throw them manually)
- * @throws CannotWriteException when an error occured during the deletion of the tag
- * @throws com.mp3.jaudiotagger.audio.exceptions.CannotReadException
- */
- protected abstract void deleteTag(Tag tag, RandomAccessFile raf, RandomAccessFile tempRaf) throws CannotReadException, CannotWriteException, IOException;
-
- /**
- * This method sets the {@link AudioFileModificationListener}.
- * There is only one listener allowed, if you want more instances to be
- * supported, use the {@link ModificationHandler} to broadcast those events.
- *
- * @param listener The listener. null
allowed to deregister.
- */
- public void setAudioFileModificationListener(AudioFileModificationListener listener) {
- this.modificationListener = listener;
- }
-
- /**
- * Prechecks before normal write
- *
- *
- *
- *
- * @param af
- * @throws CannotWriteException
- */
- private void precheckWrite(AudioFile af) throws CannotWriteException {
- // Preliminary checks
- try {
- if (af.getTag().isEmpty()) {
- delete(af);
- return;
- }
- } catch (CannotReadException re) {
- throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED.getMsg(af.getFile().getPath()));
- }
-
- File file = af.getFile();
- if (TagOptionSingleton.getInstance().isCheckIsWritable() && !file.canWrite()) {
- logger.severe(ErrorMessage.GENERAL_WRITE_FAILED.getMsg(af.getFile().getPath()));
- throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_TO_OPEN_FILE_FOR_EDITING.getMsg(file.getPath()));
- }
-
- if (af.getFile().length() <= MINIMUM_FILESIZE) {
- logger.severe(ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_IS_TOO_SMALL.getMsg(file.getPath()));
- throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_IS_TOO_SMALL.getMsg(file.getPath()));
- }
- }
-
- /**
- * Write the tag (if not empty) present in the AudioFile in the associated
- * File
- *
- * @param af The file we want to process
- * @throws CannotWriteException if anything went wrong
- */
- // TODO Creates temp file in same folder as the original file, this is safe
- // but would impose a performance overhead if the original file is on a networked drive
- public void write(AudioFile af) throws CannotWriteException {
- logger.config("Started writing tag data for file:" + af.getFile().getName());
-
- // Prechecks
- precheckWrite(af);
-
- //mp3's use a different mechanism to the other formats
- if (af instanceof MP3File) {
- af.commit();
- return;
- }
-
- RandomAccessFile raf = null;
- RandomAccessFile rafTemp = null;
- File newFile;
- File result;
-
- // Create temporary File
- try {
- newFile = File.createTempFile(af.getFile().getName().replace('.', '_'), TEMP_FILENAME_SUFFIX, af.getFile().getParentFile());
- }
- // Unable to create temporary file, can happen in Vista if have Create
- // Files/Write Data set to Deny
- catch (IOException ioe) {
- if (ioe.getMessage().equals(FILE_NAME_TOO_LONG) && (af.getFile().getName().length() > FILE_NAME_TOO_LONG_SAFE_LIMIT)) {
- try {
-
- newFile = File.createTempFile(af.getFile().getName().substring(0, FILE_NAME_TOO_LONG_SAFE_LIMIT).replace('.', '_'), TEMP_FILENAME_SUFFIX, af.getFile().getParentFile());
-
- } catch (IOException ioe2) {
- logger.log(Level.SEVERE, ErrorMessage.GENERAL_WRITE_FAILED_TO_CREATE_TEMPORARY_FILE_IN_FOLDER.getMsg(af.getFile().getName(), af.getFile().getParentFile().getAbsolutePath()), ioe2);
- throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_TO_CREATE_TEMPORARY_FILE_IN_FOLDER.getMsg(af.getFile().getName(), af.getFile().getParentFile().getAbsolutePath()));
- }
- } else {
- logger.log(Level.SEVERE, ErrorMessage.GENERAL_WRITE_FAILED_TO_CREATE_TEMPORARY_FILE_IN_FOLDER.getMsg(af.getFile().getName(), af.getFile().getParentFile().getAbsolutePath()), ioe);
- throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_TO_CREATE_TEMPORARY_FILE_IN_FOLDER.getMsg(af.getFile().getName(), af.getFile().getParentFile().getAbsolutePath()));
- }
- }
-
- // Open temporary file and actual file for editing
- try {
- rafTemp = new RandomAccessFile(newFile, WRITE_MODE);
- raf = new RandomAccessFile(af.getFile(), WRITE_MODE);
-
- }
- // Unable to write to writable file, can happen in Vista if have Create
- // Folders/Append Data set to Deny
- catch (IOException ioe) {
- logger.log(Level.SEVERE, ErrorMessage.GENERAL_WRITE_FAILED_TO_OPEN_FILE_FOR_EDITING.getMsg(af.getFile().getAbsolutePath()), ioe);
-
- // If we managed to open either file, delete it.
- try {
- if (raf != null) {
- raf.close();
- }
- if (rafTemp != null) {
- rafTemp.close();
- }
- } catch (IOException ioe2) {
- // Warn but assume has worked okay
- logger.log(Level.WARNING, ErrorMessage.GENERAL_WRITE_PROBLEM_CLOSING_FILE_HANDLE.getMsg(af.getFile(), ioe.getMessage()), ioe2);
- }
-
- // Delete the temp file ( we cannot delete until closed corresponding
- // rafTemp)
- if (!newFile.delete()) {
- // Non critical failed deletion
- logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_TEMPORARY_FILE.getMsg(newFile.getAbsolutePath()));
- }
-
- throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_TO_OPEN_FILE_FOR_EDITING.getMsg(af.getFile().getAbsolutePath()));
- }
-
- // Write data to File
- try {
-
- raf.seek(0);
- rafTemp.seek(0);
- try {
- if (this.modificationListener != null) {
- this.modificationListener.fileWillBeModified(af, false);
- }
- writeTag(af, af.getTag(), raf, rafTemp);
- if (this.modificationListener != null) {
- this.modificationListener.fileModified(af, newFile);
- }
- } catch (ModifyVetoException veto) {
- throw new CannotWriteException(veto);
- }
- } catch (Exception e) {
- logger.log(Level.SEVERE, ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE.getMsg(af.getFile(), e.getMessage()), e);
-
- try {
- if (raf != null) {
- raf.close();
- }
- if (rafTemp != null) {
- rafTemp.close();
- }
- } catch (IOException ioe) {
- // Warn but assume has worked okay
- logger.log(Level.WARNING, ErrorMessage.GENERAL_WRITE_PROBLEM_CLOSING_FILE_HANDLE.getMsg(af.getFile().getAbsolutePath(), ioe.getMessage()), ioe);
- }
-
- // Delete the temporary file because either it was never used so
- // lets just tidy up or we did start writing to it but
- // the write failed and we havent renamed it back to the original
- // file so we can just delete it.
- if (!newFile.delete()) {
- // Non critical failed deletion
- logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_TEMPORARY_FILE.getMsg(newFile.getAbsolutePath()));
- }
- throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE.getMsg(af.getFile(), e.getMessage()));
- } finally {
- try {
- if (raf != null) {
- raf.close();
- }
- if (rafTemp != null) {
- rafTemp.close();
- }
- } catch (IOException ioe) {
- // Warn but assume has worked okay
- logger.log(Level.WARNING, ErrorMessage.GENERAL_WRITE_PROBLEM_CLOSING_FILE_HANDLE.getMsg(af.getFile().getAbsolutePath(), ioe.getMessage()), ioe);
- }
- }
-
- // Result held in this file
- result = af.getFile();
-
- // If the temporary file was used
- if (newFile.length() > 0) {
- transferNewFileToOriginalFile(newFile, af.getFile(), TagOptionSingleton.getInstance().isPreserveFileIdentity());
- } else {
- // Delete the temporary file that wasn't ever used
- if (!newFile.delete()) {
- // Non critical failed deletion
- logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_TEMPORARY_FILE.getMsg(newFile.getPath()));
- }
- }
-
- if (this.modificationListener != null) {
- this.modificationListener.fileOperationFinished(result);
- }
- }
-
- /**
- *
- *
- *
- * @param newFile File containing the data we want in the {@code originalFile}
- * @param originalFile Before execution this denotes the original, unmodified file.
- * After execution it denotes the name of the file with the modified content and new inode/fileIndex.
- * @throws CannotWriteException if the file cannot be written
- */
- private void transferNewFileContentToOriginalFile(final File newFile, final File originalFile) throws CannotWriteException {
- // try to obtain exclusive lock on the file
- RandomAccessFile raf = null;
- try {
- raf = new RandomAccessFile(originalFile, "rw");
- final FileChannel outChannel = raf.getChannel();
- FileLock lock = null;
- try {
- lock = outChannel.tryLock();
- if (lock != null) {
- transferNewFileContentToOriginalFile(newFile, originalFile, raf, outChannel);
- } else {
- // we didn't get a lock
- logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_FILE_LOCKED.getMsg(originalFile.getPath()));
- throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_FILE_LOCKED.getMsg(originalFile.getPath()));
- }
- } catch (IOException e) {
- logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_FILE_LOCKED.getMsg(originalFile.getPath()));
- // we didn't get a lock, this may be, because locking is not supported by the OS/JRE
- // this can happen on OS X with network shares (samba, afp)
- // for details see https://stackoverflow.com/questions/33220148/samba-share-gradle-java-io-exception
- // coarse check that works on OS X:
- if ("Operation not supported".equals(e.getMessage())) {
- // transfer without lock
- transferNewFileContentToOriginalFile(newFile, originalFile, raf, outChannel);
- } else {
- throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_FILE_LOCKED.getMsg(originalFile.getPath()), e);
- }
- } catch (Exception e) {
- // tryLock failed for some reason other than an IOException — we're definitely doomed
- logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_FILE_LOCKED.getMsg(originalFile.getPath()));
- throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_FILE_LOCKED.getMsg(originalFile.getPath()), e);
- } finally {
- if (lock != null)
- lock.release();
- }
- } catch (FileNotFoundException e) {
- logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_NOT_FOUND.getMsg(originalFile.getAbsolutePath()));
- throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_NOT_FOUND.getMsg(originalFile.getPath()), e);
- } catch (Exception e) {
- logger.warning(ErrorMessage.GENERAL_WRITE_FAILED.getMsg(originalFile.getAbsolutePath()));
- throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED.getMsg(originalFile.getPath()), e);
- } finally {
- AudioFileIO.closeQuietly(raf);
- }
- }
-
- private void transferNewFileContentToOriginalFile(final File newFile, final File originalFile, final RandomAccessFile raf, final FileChannel outChannel) throws CannotWriteException {
- FileInputStream in = null;
- try {
- in = new FileInputStream(newFile);
- FileChannel inChannel = in.getChannel();
- // copy contents of newFile to originalFile,
- // overwriting the old content in that file
- final long size = inChannel.size();
- long position = 0;
- while (position < size) {
- position += inChannel.transferTo(position, 1024L * 1024L, outChannel);
- }
- // truncate raf, in case it used to be longer
- raf.setLength(size);
- } catch (FileNotFoundException e) {
- logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_NEW_FILE_DOESNT_EXIST.getMsg(newFile.getAbsolutePath()));
- throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_NEW_FILE_DOESNT_EXIST.getMsg(newFile.getName()), e);
- } catch (IOException e) {
- logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_TO_ORIGINAL_FILE.getMsg(originalFile.getAbsolutePath(), newFile.getName()));
- throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_TO_ORIGINAL_FILE.getMsg(originalFile.getAbsolutePath(), newFile.getName()), e);
- } finally {
- AudioFileIO.closeQuietly(in);
- }
- // file is written, all is good, let's delete newFile, as it's not needed anymore
- if (newFile.exists() && !newFile.delete()) {
- // non-critical failed deletion
- logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_TEMPORARY_FILE.getMsg(newFile.getPath()));
- }
- }
-
- /**
- * originalFile
to originalFile.old
newFile
to originalFile
(this implies a file identity change for originalFile
)originalFile.old
newFile
- *
- *
- * @param newFile File containing the data we want in the {@code originalFile}
- * @param originalFile Before execution this denotes the original, unmodified file.
- * After execution it denotes the name of the file with the modified content and new inode/fileIndex.
- * @throws CannotWriteException if the file cannot be written
- */
- private void transferNewFileToNewOriginalFile(final File newFile, final File originalFile) throws CannotWriteException {
- // Rename Original File
- // Can fail on Vista if have Special Permission 'Delete' set Deny
- File originalFileBackup = new File(originalFile.getAbsoluteFile().getParentFile().getPath(), AudioFile.getBaseFilename(originalFile) + ".old");
-
- //If already exists modify the suffix
- int count = 1;
- while (originalFileBackup.exists()) {
- originalFileBackup = new File(originalFile.getAbsoluteFile().getParentFile().getPath(), AudioFile.getBaseFilename(originalFile) + ".old" + count);
- count++;
- }
-
- boolean renameResult = Utils.rename(originalFile, originalFileBackup);
- if (!renameResult) {
- logger.log(Level.SEVERE, ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_ORIGINAL_FILE_TO_BACKUP.getMsg(originalFile.getAbsolutePath(), originalFileBackup.getName()));
- //Delete the temp file because write has failed
- // TODO: Simplify: newFile is always != null, otherwise we would not have entered this block (-> if (newFile.length() > 0) {})
- if (newFile != null) {
- newFile.delete();
- }
- throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_ORIGINAL_FILE_TO_BACKUP.getMsg(originalFile.getPath(), originalFileBackup.getName()));
- }
-
- // Rename Temp File to Original File
- renameResult = Utils.rename(newFile, originalFile);
- if (!renameResult) {
- // Renamed failed so lets do some checks rename the backup back to the original file
- // New File doesnt exist
- if (!newFile.exists()) {
- logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_NEW_FILE_DOESNT_EXIST.getMsg(newFile.getAbsolutePath()));
- }
-
- // Rename the backup back to the original
- if (!originalFileBackup.renameTo(originalFile)) {
- // TODO now if this happens we are left with testfile.old
- // instead of testfile.mp4
- logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_ORIGINAL_BACKUP_TO_ORIGINAL.getMsg(originalFileBackup.getAbsolutePath(), originalFile.getName()));
- }
-
- logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_TO_ORIGINAL_FILE.getMsg(originalFile.getAbsolutePath(), newFile.getName()));
- throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_TO_RENAME_TO_ORIGINAL_FILE.getMsg(originalFile.getAbsolutePath(), newFile.getName()));
- } else {
- // Rename was okay so we can now delete the backup of the
- // original
- boolean deleteResult = originalFileBackup.delete();
- if (!deleteResult) {
- // Not a disaster but can't delete the backup so make a
- // warning
- logger.warning(ErrorMessage.GENERAL_WRITE_WARNING_UNABLE_TO_DELETE_BACKUP_FILE.getMsg(originalFileBackup.getAbsolutePath()));
- }
-
- }
-
- // Delete the temporary file if still exists
- if (newFile.exists()) {
- if (!newFile.delete()) {
- // Non critical failed deletion
- logger.warning(ErrorMessage.GENERAL_WRITE_FAILED_TO_DELETE_TEMPORARY_FILE.getMsg(newFile.getPath()));
- }
- }
- }
-
- /**
- * This is called when a tag has to be written in a file. Three parameters
- * are provided, the tag to write (not empty) Two randomaccessfiles, the
- * first points to the file where we want to write the given tag, and the
- * second is an empty temporary file that can be used if e.g. the file has
- * to be bigger than the original.
- *
- * If something has been written in the temporary file, when this method
- * returns, the original file is deleted, and the temporary file is renamed
- * the the original name
- *
- * If nothing has been written to it, it is simply deleted.
- *
- * This method can assume the raf, rafTemp are pointing to the first byte of
- * the file. The subclass must not close these two files when the method
- * returns.
- *
- * @param audioFile
- * @param tag
- * @param raf
- * @param rafTemp
- * @throws IOException is thrown when the RandomAccessFile operations throw it (you
- * should never throw them manually)
- * @throws CannotWriteException when an error occured during the generation of the tag
- * @throws com.mp3.jaudiotagger.audio.exceptions.CannotReadException
- */
- protected abstract void writeTag(AudioFile audioFile, Tag tag, RandomAccessFile raf, RandomAccessFile rafTemp) throws CannotReadException, CannotWriteException, IOException;
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/generic/AudioFileWriter2.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/generic/AudioFileWriter2.java
deleted file mode 100644
index 761a8d75..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/generic/AudioFileWriter2.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package com.mp3.jaudiotagger.audio.generic;
-
-import com.mp3.jaudiotagger.audio.AudioFile;
-import com.mp3.jaudiotagger.audio.exceptions.CannotReadException;
-import com.mp3.jaudiotagger.audio.exceptions.CannotWriteException;
-import com.mp3.jaudiotagger.logging.ErrorMessage;
-import com.mp3.jaudiotagger.tag.Tag;
-import com.mp3.jaudiotagger.tag.TagOptionSingleton;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-
-/**
- * Created by Paul on 28/01/2016.
- */
-public abstract class AudioFileWriter2 extends AudioFileWriter
-{
- /**
- * Delete the tag (if any) present in the given file
- *
- * @param af The file to process
- *
- * @throws CannotWriteException if anything went wrong
- * @throws com.mp3.jaudiotagger.audio.exceptions.CannotReadException
- */
- @Override
- public void delete(AudioFile af) throws CannotReadException, CannotWriteException
- {
- File file = af.getFile();
-
- if (TagOptionSingleton.getInstance().isCheckIsWritable() && !file.canWrite())
- {
- throw new CannotWriteException(ErrorMessage.GENERAL_DELETE_FAILED
- .getMsg(file));
- }
-
- if (af.getFile().length() <= MINIMUM_FILESIZE)
- {
- throw new CannotWriteException(ErrorMessage.GENERAL_DELETE_FAILED_BECAUSE_FILE_IS_TOO_SMALL
- .getMsg(file));
- }
- deleteTag(af.getTag(), file);
- }
-
- /**
- * Replace with new tag
- *
- * @param af The file we want to process
- * @throws CannotWriteException
- */
- @Override
- public void write(AudioFile af) throws CannotWriteException
- {
- File file = af.getFile();
-
- if (TagOptionSingleton.getInstance().isCheckIsWritable() && !file.canWrite())
- {
- logger.severe(ErrorMessage.GENERAL_WRITE_FAILED.getMsg(af.getFile()
- .getPath()));
- throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_TO_OPEN_FILE_FOR_EDITING
- .getMsg(file));
- }
-
- if (af.getFile().length() <= MINIMUM_FILESIZE)
- {
- throw new CannotWriteException(ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_IS_TOO_SMALL
- .getMsg(file));
- }
- writeTag(af.getTag(), file);
- }
-
- /**
- * Must be implemented by each audio format
- *
- * @param tag
- * @param file
- * @throws CannotReadException
- * @throws CannotWriteException
- */
- protected abstract void deleteTag(Tag tag, File file) throws CannotReadException, CannotWriteException;
-
-
- public void deleteTag(Tag tag, RandomAccessFile raf, RandomAccessFile tempRaf) throws CannotReadException, CannotWriteException, IOException
- {
- throw new UnsupportedOperationException("Old method not used in version 2");
- }
-
- /**
- * Must be implemented by each audio format
- *
- * @param tag
- * @param file
- * @throws CannotWriteException
- */
- protected abstract void writeTag(Tag tag, File file) throws CannotWriteException;
-
- protected void writeTag(AudioFile audioFile, Tag tag, RandomAccessFile raf, RandomAccessFile rafTemp) throws CannotReadException, CannotWriteException, IOException
- {
- throw new UnsupportedOperationException("Old method not used in version 2");
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/generic/GenericAudioHeader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/generic/GenericAudioHeader.java
deleted file mode 100644
index 2bdd106c..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/generic/GenericAudioHeader.java
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2003-2005 Rapha�l Slinckx originalFile
to originalFile.old
newFile
to originalFile
(this implies a file identity change for originalFile
)originalFile.old
newFile
- * Most of the parameters are available for nearly each audio format. Some
- * others would result in standard values.
- * Consider: None of the setter methods will actually affect the audio
- * file. This is just a structure for retrieving information, not manipulating
- * the audio file.
- *
- * @author Raphael Slinckx
- */
-public class GenericAudioHeader implements AudioHeader
-{
- //Use objects so clearer wherher has been set or not
- private Long audioDataLength;
- private Long audioDataStartPosition;
- private Long audioDataEndPosition;
- private Integer bitRate;
- private Integer noOfChannels;
- private Integer samplingRate;
- private Integer bitsPerSample;
- private String encodingType;
- private Boolean isVbr = Boolean.TRUE; //TODO this is a weird default
- private Boolean isLossless;
- private Double trackLength;
- private Long noOfSamples;
- private Integer byteRate;
-
-
-
- /**
- * Creates an instance with emtpy values.
- */
- public GenericAudioHeader()
- {
-
- }
-
- public String getBitRate()
- {
- return String.valueOf(bitRate);
- }
-
-
- /**
- * This method returns the bitRate of the represented audio clip in
- * "Kbps".
- *
- * @return The bitRate in Kbps.
- */
- public long getBitRateAsNumber()
- {
- return bitRate;
- }
-
- /**
- * This method returns the number of audio channels the clip contains.
- * (The stereo, mono thing).
- *
- * @return The number of channels. (2 for stereo, 1 for mono)
- */
- public int getChannelNumber()
- {
- return noOfChannels;
- }
-
- /**
- * @return
- */
- public String getChannels()
- {
- return String.valueOf(getChannelNumber());
- }
-
- /**
- * Returns the encoding type.
- *
- * @return The encoding type
- */
- public String getEncodingType()
- {
- return encodingType;
- }
-
- /**
- * Returns the format, same as encoding type
- *
- * @return The encoding type
- */
- public String getFormat()
- {
- return encodingType;
- }
-
-
-
- /**
- * This method returns the duration of the represented audio clip in
- * seconds.
- *
- * @return The duration to the nearest seconds.
- * @see #getPreciseTrackLength()
- */
- public int getTrackLength()
- {
- return (int) Math.round(getPreciseTrackLength());
- }
-
- /**
- * This method returns the duration of the represented audio clip in seconds
- * (single-precision).
- *
- * @return The duration in seconds.
- * @see #getTrackLength()
- */
- public double getPreciseTrackLength()
- {
- return trackLength;
- }
-
- /**
- * This method returns the sample rate, the audio clip was encoded with.
- *
- * @return Sample rate of the audio clip in "Hz".
- */
- public String getSampleRate()
- {
- return String.valueOf(samplingRate);
- }
-
- public int getSampleRateAsNumber()
- {
- return samplingRate;
- }
-
- /**
- * @return The number of bits per sample
- */
- public int getBitsPerSample()
- {
- //TODO remove bandaid
- if(bitsPerSample==null)
- {
- return -1;
- }
- return bitsPerSample;
- }
-
- /**
- * This method returns true
, if the audio file is encoded
- * with "Variable Bitrate".
- *
- * @return true
if audio clip is encoded with VBR.
- */
- public boolean isVariableBitRate()
- {
- //TODO remove this bandaid
- if(isVbr==null)
- {
- return false;
- }
- return isVbr;
- }
-
- /**
- * This method returns true
, if the audio file is encoded
- * with "Lossless".
- *
- * @return true
if audio clip is encoded with VBR.
- */
- public boolean isLossless()
- {
- //TODO remove this bandaid
- if(isLossless==null)
- {
- return false;
- }
- return isLossless;
- }
-
- /**
- * This Method sets the bitRate in "Kbps".
- *
- * @param bitRate bitRate in kbps.
- */
- public void setBitRate(int bitRate)
- {
- this.bitRate = bitRate;
- }
-
- /**
- * Sets the number of channels.
- *
- * @param channelMode number of channels (2 for stereo, 1 for mono).
- */
- public void setChannelNumber(int channelMode)
- {
- this.noOfChannels = channelMode;
- }
-
- /**
- * Sets the type of the encoding.
- * This is a bit format specific.
- * eg:Layer I/II/III
- *
- * @param encodingType Encoding type.
- */
- public void setEncodingType(String encodingType)
- {
- this.encodingType=encodingType;
- }
-
- /**
- * This method sets the audio duration of the represented clip.
- *
- * @param length The duration of the audio in seconds (single-precision).
- */
- public void setPreciseLength(double length)
- {
- this.trackLength = length;
- }
-
- /**
- * Sets the Sampling rate in "Hz"
- *
- * @param samplingRate Sample rate.
- */
- public void setSamplingRate(int samplingRate)
- {
- this.samplingRate = samplingRate;
- }
-
- /*
- * Sets the Bits per Sample
- *
- * @params bitsPerSample Bits Per Sample
- */
- public void setBitsPerSample(int bitsPerSample)
- {
- this.bitsPerSample = bitsPerSample;
- }
-
- /*
- * Sets the ByteRate (per second)
- *
- * @params ByteRate
- */
- public void setByteRate(int byteRate)
- {
- this.byteRate = byteRate;
- }
-
-
- /**
- * Sets the VBR flag for the represented audio clip.
- *
- * @param isVbr true
if VBR.
- */
- public void setVariableBitRate(boolean isVbr)
- {
- this.isVbr=isVbr;
- }
-
- /**
- * Sets the Lossless flag for the represented audio clip.
- *
- * @param isLossless true
if Lossless.
- */
- public void setLossless(boolean isLossless)
- {
- this.isLossless = isLossless;
- }
-
-
-
- /**
- * Pretty prints this encoding info
- *
- * @see Object#toString()
- */
- public String toString()
- {
- StringBuilder out = new StringBuilder();
- out.append("Audio Header content:\n");
- if(audioDataLength!=null)
- {
- out.append("\taudioDataLength:"+audioDataLength+"\n");
- }
- if(audioDataStartPosition!=null)
- {
- out.append("\taudioDataStartPosition:"+audioDataStartPosition+"\n");
- }
- if(audioDataEndPosition!=null)
- {
- out.append("\taudioDataEndPosition:"+audioDataEndPosition+"\n");
- }
- if(byteRate!=null)
- {
- out.append("\tbyteRate:"+byteRate+"\n");
- }
- if(bitRate!=null)
- {
- out.append("\tbitRate:"+bitRate+"\n");
- }
- if(samplingRate!=null)
- {
- out.append("\tsamplingRate:"+samplingRate+"\n");
- }
- if(bitsPerSample!=null)
- {
- out.append("\tbitsPerSample:"+bitsPerSample+"\n");
- }
- if(noOfSamples!=null)
- {
- out.append("\ttotalNoSamples:"+noOfSamples+"\n");
- }
- if(noOfChannels!=null)
- {
- out.append("\tnumberOfChannels:"+noOfChannels+"\n");
- }
- if(encodingType!=null)
- {
- out.append("\tencodingType:"+encodingType+"\n");
- }
- if(isVbr!=null)
- {
- out.append("\tisVbr:"+isVbr+"\n");
- }
- if(isLossless!=null)
- {
- out.append("\tisLossless:"+isLossless+"\n");
- }
- if(trackLength!=null)
- {
- out.append("\ttrackDuration:"+trackLength+"\n");
- }
- return out.toString();
- }
-
- public Long getAudioDataLength()
- {
- return audioDataLength;
- }
-
- public void setAudioDataLength(long audioDataLength)
- {
- this.audioDataLength = audioDataLength;
- }
-
- public Integer getByteRate()
- {
- return byteRate;
- }
-
- public Long getNoOfSamples()
- {
- return noOfSamples;
- }
-
- public void setNoOfSamples(Long noOfSamples)
- {
- this.noOfSamples = noOfSamples;
- }
-
-
- @Override
- public Long getAudioDataStartPosition()
- {
- return audioDataStartPosition;
- }
-
- public void setAudioDataStartPosition(Long audioDataStartPosition)
- {
- this.audioDataStartPosition = audioDataStartPosition;
- }
-
- @Override
- public Long getAudioDataEndPosition()
- {
- return audioDataEndPosition;
- }
-
- public void setAudioDataEndPosition(Long audioDataEndPosition)
- {
- this.audioDataEndPosition = audioDataEndPosition;
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/generic/GenericTag.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/generic/GenericTag.java
deleted file mode 100644
index 43a5633e..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/generic/GenericTag.java
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Entagged Audio Tag library
- * Copyright (c) 2003-2005 Raphaël Slinckx
- * Additionally the Vetos are handled. (other listeners are notified).
- *
- * @author Christian Laireiter
- */
-public class ModificationHandler implements AudioFileModificationListener
-{
-
- /**
- * The listeners to wich events are broadcasted are stored here.
- */
- private Vectortrue
if and only if the renaming succeeded;
- * false
otherwise
- */
- public static boolean copy(final File fromFile, final File toFile) {
- try {
- copyThrowsOnException(fromFile, toFile);
- return true;
- } catch (IOException e) {
- e.printStackTrace();
- return false;
- }
- }
-
- /**
- * Reads 4 bytes and concatenates them into a String.
- * This pattern is used for ID's of various kinds.
- *
- * @param bytes
- * @return
- * @throws IOException
- */
- public static String readFourBytesAsChars(final ByteBuffer bytes) {
- byte[] b = new byte[4];
- bytes.get(b);
- return new String(b, ISO_8859_1);
- }
-
- /**
- * Reads 3 bytes and concatenates them into a String.
- * This pattern is used for ID's of various kinds.
- *
- * @param bytes
- * @return
- */
- public static String readThreeBytesAsChars(final ByteBuffer bytes) {
- byte[] b = new byte[3];
- bytes.get(b);
- return new String(b, ISO_8859_1);
- }
-
- /**
- * Used to convert (signed integer) to an long as if signed integer was unsigned hence allowing
- * it to represent full range of integral values.
- *
- * @param n
- * @return
- */
- public static long u(final int n) {
- return n & 0xffffffffl;
- }
-
- /**
- * Used to convert (signed short) to an integer as if signed short was unsigned hence allowing
- * it to represent values 0 -> 65536 rather than -32786 -> 32786
- *
- * @param n
- * @return
- */
- public static int u(final short n) {
- return n & 0xffff;
- }
-
- /**
- * Used to convert (signed byte) to an integer as if signed byte was unsigned hence allowing
- * it to represent values 0 -> 255 rather than -128 -> 127.
- *
- * @param n
- * @return
- */
- public static int u(final byte n) {
- return n & 0xff;
- }
-
- /**
- * @param fc
- * @param size
- * @return
- * @throws IOException
- */
- public static ByteBuffer readFileDataIntoBufferLE(FileChannel fc, final int size) throws IOException {
- final ByteBuffer tagBuffer = ByteBuffer.allocateDirect(size);
- fc.read(tagBuffer);
- tagBuffer.position(0);
- tagBuffer.order(ByteOrder.LITTLE_ENDIAN);
- return tagBuffer;
- }
-
- /**
- * @param fc
- * @param size
- * @return
- * @throws IOException
- */
- public static ByteBuffer readFileDataIntoBufferBE(FileChannel fc, final int size) throws IOException {
- final ByteBuffer tagBuffer = ByteBuffer.allocateDirect(size);
- fc.read(tagBuffer);
- tagBuffer.position(0);
- tagBuffer.order(ByteOrder.BIG_ENDIAN);
- return tagBuffer;
- }
-
- /**
- * Copy src file to dst file. FileChannels are used to maximize performance.
- *
- * @param source source File
- * @param destination destination File which will be created or truncated, before copying, if it already exists
- * @throws IOException if any error occurS
- */
- public static void copyThrowsOnException(final File source, final File destination) throws IOException {
- // Must be done in a loop as there's no guarantee that a request smaller than request count will complete in one invocation.
- // Setting the transfer size more than about 1MB is pretty pointless because there is no asymptotic benefit. What you're trying
- // to achieve with larger transfer sizes is fewer context switches, and every time you double the transfer size you halve the
- // context switch cost. Pretty soon it vanishes into the noise.
- FileInputStream inStream = null;
- FileOutputStream outStream = null;
- try {
- inStream = new FileInputStream(source);
- outStream = new FileOutputStream(destination);
- final FileChannel inChannel = inStream.getChannel();
- final FileChannel outChannel = outStream.getChannel();
- final long size = inChannel.size();
- long position = 0;
- while (position < size) {
- position += inChannel.transferTo(position, 1024L * 1024L, outChannel);
- }
- } finally { //Closeables closed exiting try block in all circumstances
- AudioFileIO.closeQuietly(inStream, outStream);
- }
- }
-
- /**
- * @param length
- * @return true if length is an odd number
- */
- public static boolean isOddLength(long length) {
- if ((length & 1) != 0) {
- return true;
- }
- return false;
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/iff/Chunk.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/iff/Chunk.java
deleted file mode 100644
index 2ac16932..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/iff/Chunk.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.mp3.jaudiotagger.audio.iff;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-
-/**
- * Abstract superclass for IFF/AIFF chunks.
- *
- * @author Gary McGath
- */
-public abstract class Chunk
-{
- protected ByteBuffer chunkData;
- protected ChunkHeader chunkHeader;
-
-
-
- /**
- * Constructor used by Wav
- *
- * @param chunkData
- * @param chunkHeader
- */
- public Chunk(ByteBuffer chunkData, ChunkHeader chunkHeader)
- {
- this.chunkData = chunkData;
- this.chunkHeader = chunkHeader;
- }
-
- /**
- * Reads a chunk and puts appropriate information into
- * the RepInfo object.
- *
- * @return false
if the chunk is structurally
- * invalid, otherwise true
- */
- public abstract boolean readChunk() throws IOException;
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/iff/ChunkHeader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/iff/ChunkHeader.java
deleted file mode 100644
index 5f7a1be0..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/iff/ChunkHeader.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package com.mp3.jaudiotagger.audio.iff;
-
-import com.mp3.jaudiotagger.StandardCharsets;
-import com.mp3.jaudiotagger.audio.generic.Utils;
-
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.channels.FileChannel;
-
-/**
- * Each {@link Chunk} starts with a chunk header consisting of a 4 byte id and then a 4 byte size field, the size field
- * stores the size of the chunk itself excluding the size of the header.
- */
-public class ChunkHeader
-{
- public static final int CHUNK_HEADER_SIZE = 8;
-
- private long size; // This does not include the 8 bytes of header itself
- private String chunkId; // Four character Id of the chunk
- private ByteOrder byteOrder;
- private long startLocationInFile;
-
-
- public ChunkHeader(ByteOrder byteOrder)
- {
- this.byteOrder=byteOrder;
- }
- /**
- * Reads the header of a chunk.
- *
- * @return {@code true}, if we were able to read a chunk header and believe we found a valid chunk id.
- */
- public boolean readHeader(final FileChannel fc) throws IOException
- {
- ByteBuffer header = ByteBuffer.allocate(CHUNK_HEADER_SIZE);
- startLocationInFile = fc.position();
- fc.read(header);
- header.order(byteOrder);
- header.position(0);
- this.chunkId = Utils.readFourBytesAsChars(header);
- this.size = header.getInt();
-
- return true;
- }
-
- /**
- * Reads the header of a chunk.
- *
- * @return {@code true}, if we were able to read a chunk header and believe we found a valid chunk id.
- */
- public boolean readHeader(final RandomAccessFile raf) throws IOException
- {
- ByteBuffer header = ByteBuffer.allocate(CHUNK_HEADER_SIZE);
- startLocationInFile = raf.getFilePointer();
- raf.getChannel().read(header);
- header.order(byteOrder);
- header.position(0);
- this.chunkId = Utils.readFourBytesAsChars(header);
- this.size = header.getInt();
-
- return true;
- }
-
- /**
- * Writes this chunk header to a {@link ByteBuffer}.
- *
- * @return the byte buffer containing the
- */
- public ByteBuffer writeHeader()
- {
- final ByteBuffer bb = ByteBuffer.allocate(CHUNK_HEADER_SIZE);
- bb.order(byteOrder);
- bb.put(chunkId.getBytes(StandardCharsets.US_ASCII));
- bb.putInt((int)size);
- bb.flip();
- return bb;
- }
-
- /**
- * Sets the chunk type, which is a 4-character code, directly.
- *
- * @param id 4-char id
- */
- public void setID(final String id)
- {
- this.chunkId = id;
- }
-
- /**
- * Returns the chunk type, which is a 4-character code.
- *
- * @return id
- */
- public String getID()
- {
- return this.chunkId;
- }
-
- /**
- * Returns the chunk size (excluding the first 8 bytes).
- *
- * @see #setSize(long)
- */
- public long getSize()
- {
- return size;
- }
-
- /**
- * Set chunk size.
- *
- * @param size chunk size without header
- * @see #getSize()
- */
- public void setSize(final long size)
- {
- this.size=size;
- }
-
- /** The start of this chunk(header) in the file */
- public long getStartLocationInFile()
- {
- return startLocationInFile;
- }
-
- public String toString()
- {
- return getID() +":Size:" + getSize() +"startLocation:"+getStartLocationInFile();
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/iff/ChunkSummary.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/iff/ChunkSummary.java
deleted file mode 100644
index 0cc0d07d..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/iff/ChunkSummary.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.mp3.jaudiotagger.audio.iff;
-
-import com.mp3.jaudiotagger.logging.Hex;
-
-/**
- * Created by Paul on 22/01/2016.
- */
-public class ChunkSummary
-{
- private String chunkId;
- private long fileStartLocation;
- private long chunkSize;
-
- public ChunkSummary(String chunkId, long fileStartLocation, long chunkSize)
- {
- this.chunkId=chunkId;
- this.fileStartLocation=fileStartLocation;
- this.chunkSize=chunkSize;
- }
-
- @Override
- public String toString()
- {
- long endLocation = fileStartLocation + chunkSize + ChunkHeader.CHUNK_HEADER_SIZE;
- return chunkId+":StartLocation:"
- + Hex.asDecAndHex(fileStartLocation)
- + ":SizeIncHeader:"
- + chunkSize + ChunkHeader.CHUNK_HEADER_SIZE
- + ":EndLocation:"
- + Hex.asDecAndHex(endLocation);
- }
-
- public long getEndLocation()
- {
- return fileStartLocation + chunkSize + ChunkHeader.CHUNK_HEADER_SIZE;
- }
- public String getChunkId()
- {
- return chunkId;
- }
-
- public void setChunkId(String chunkId)
- {
- this.chunkId = chunkId;
- }
-
- public long getFileStartLocation()
- {
- return fileStartLocation;
- }
-
- public void setFileStartLocation(long fileStartLocation)
- {
- this.fileStartLocation = fileStartLocation;
- }
-
- public long getChunkSize()
- {
- return chunkSize;
- }
-
- public void setChunkSize(long chunkSize)
- {
- this.chunkSize = chunkSize;
- }
-
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/iff/IffHeaderChunk.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/iff/IffHeaderChunk.java
deleted file mode 100644
index 867bbf50..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/iff/IffHeaderChunk.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.mp3.jaudiotagger.audio.iff;
-
-import com.mp3.jaudiotagger.audio.generic.Utils;
-
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.channels.FileChannel;
-import java.util.logging.Logger;
-
-/**
- * Common to all IFF formats such as Wav and Aiff
- */
-public class IffHeaderChunk
-{
- public static Logger logger = Logger.getLogger("com.mp3.jaudiotagger.audio.iff");
-
- public static int SIGNATURE_LENGTH = 4;
- public static int SIZE_LENGTH = 4;
- public static int TYPE_LENGTH = 4;
- public static int HEADER_LENGTH = SIGNATURE_LENGTH + SIZE_LENGTH + TYPE_LENGTH;
-
- /**
- * If Size is not even then we skip a byte, because chunks have to be aligned
- *
- * @param raf
- * @param chunkHeader
- * @throws IOException
- */
- public static void ensureOnEqualBoundary(final RandomAccessFile raf,ChunkHeader chunkHeader) throws IOException
- {
- if (Utils.isOddLength(chunkHeader.getSize()))
- {
- // Must come out to an even byte boundary unless at end of file
- if(raf.getFilePointer()file
arguement refers to. This is the first byte of music
- * data and not the ID3 Tag Frame.
- *
- * @return the byte position of the first MP3 Frame
- */
- public long getMp3StartByte()
- {
- return startByte;
- }
-
-
- /**
- * Set number of frames in this file, use Xing if exists otherwise ((File Size - Non Audio Part)/Frame Size)
- */
- protected void setNumberOfFrames()
- {
- numberOfFramesEstimate = (fileSize - startByte) / mp3FrameHeader.getFrameLength();
-
- if (mp3XingFrame != null && mp3XingFrame.isFrameCountEnabled())
- {
- numberOfFrames = mp3XingFrame.getFrameCount();
- }
- else if (mp3VbriFrame != null)
- {
- numberOfFrames = mp3VbriFrame.getFrameCount();
- }
- else
- {
- numberOfFrames = numberOfFramesEstimate;
- }
-
- }
-
- /**
- * @return The number of frames within the Audio File, calculated as accurately as possible
- */
- public long getNumberOfFrames()
- {
- return numberOfFrames;
- }
-
- @Override
- public Long getNoOfSamples()
- {
- return numberOfFrames;
- }
- /**
- * @return The number of frames within the Audio File, calculated by dividing the filesize by
- * the number of frames, this may not be the most accurate method available.
- */
- public long getNumberOfFramesEstimate()
- {
- return numberOfFramesEstimate;
- }
-
- /**
- * Set the time each frame contributes to the audio in fractions of seconds, the higher
- * the sampling rate the shorter the audio segment provided by the frame,
- * the number of samples is fixed by the MPEG Version and Layer
- */
- protected void setTimePerFrame()
- {
- timePerFrame = mp3FrameHeader.getNoOfSamples() / mp3FrameHeader.getSamplingRate().doubleValue();
-
- //Because when calculating framelength we may have altered the calculation slightly for MPEGVersion2
- //to account for mono/stereo we seem to have to make a corresponding modification to get the correct time
- if ((mp3FrameHeader.getVersion() == MPEGFrameHeader.VERSION_2) || (mp3FrameHeader.getVersion() == MPEGFrameHeader.VERSION_2_5))
- {
- if ((mp3FrameHeader.getLayer() == MPEGFrameHeader.LAYER_II) || (mp3FrameHeader.getLayer() == MPEGFrameHeader.LAYER_III))
- {
- if (mp3FrameHeader.getNumberOfChannels() == 1)
- {
- timePerFrame = timePerFrame / 2;
- }
- }
- }
- }
-
- /**
- * @return the the time each frame contributes to the audio in fractions of seconds
- */
- private double getTimePerFrame()
- {
- return timePerFrame;
- }
-
- /**
- * Estimate the length of the audio track in seconds
- * Calculation is Number of frames multiplied by the Time Per Frame using the first frame as a prototype
- * Time Per Frame is the number of samples in the frame (which is defined by the MPEGVersion/Layer combination)
- * divided by the sampling rate, i.e the higher the sampling rate the shorter the audio represented by the frame is going
- * to be.
- */
- protected void setTrackLength()
- {
- trackLength = numberOfFrames * getTimePerFrame();
- }
-
-
- /**
- * @return Track Length in seconds
- */
- public double getPreciseTrackLength()
- {
- return trackLength;
- }
-
- public int getTrackLength()
- {
- return (int) getPreciseTrackLength();
- }
-
- /**
- * Return the length in user friendly format
- * @return
- */
- public String getTrackLengthAsString()
- {
- final Date timeIn;
- try
- {
- final long lengthInSecs = getTrackLength();
- synchronized(timeInFormat)
- {
- timeIn = timeInFormat.parse(String.valueOf(lengthInSecs));
- }
-
- if (lengthInSecs < NO_SECONDS_IN_HOUR)
- {
- synchronized(timeOutFormat)
- {
- return timeOutFormat.format(timeIn);
- }
- }
- else
- {
- synchronized(timeOutOverAnHourFormat)
- {
- return timeOutOverAnHourFormat.format(timeIn);
- }
- }
- }
- catch (ParseException pe)
- {
- logger.warning("Unable to parse:"+getPreciseTrackLength() +" failed with ParseException:"+pe.getMessage());
- return "";
- }
- }
-
- /**
- * @return the audio file type
- */
- public String getEncodingType()
- {
- return TYPE_MP3;
- }
-
- /**
- * Set bitrate in kbps, if Vbr use Xingheader if possible
- */
- protected void setBitRate()
- {
-
- if (mp3XingFrame != null && mp3XingFrame.isVbr())
- {
- if (mp3XingFrame.isAudioSizeEnabled() && mp3XingFrame.getAudioSize() > 0)
- {
- bitrate = (long) ((mp3XingFrame.getAudioSize() * CONVERTS_BYTE_TO_BITS) / (timePerFrame * getNumberOfFrames() * CONVERT_TO_KILOBITS));
- }
- else
- {
- bitrate = (long) (((fileSize - startByte) * CONVERTS_BYTE_TO_BITS) / (timePerFrame * getNumberOfFrames() * CONVERT_TO_KILOBITS));
- }
- }
- else if (mp3VbriFrame != null)
- {
- if (mp3VbriFrame.getAudioSize() > 0)
- {
- bitrate = (long) ((mp3VbriFrame.getAudioSize() * CONVERTS_BYTE_TO_BITS) / (timePerFrame * getNumberOfFrames() * CONVERT_TO_KILOBITS));
- }
- else
- {
- bitrate = (long) (((fileSize - startByte) * CONVERTS_BYTE_TO_BITS) / (timePerFrame * getNumberOfFrames() * CONVERT_TO_KILOBITS));
- }
- }
- else
- {
- bitrate = mp3FrameHeader.getBitRate();
- }
- }
-
- protected void setEncoder()
- {
- if (mp3XingFrame != null)
- {
- if (mp3XingFrame.getLameFrame() != null)
- {
- encoder = mp3XingFrame.getLameFrame().getEncoder();
- }
- }
- else if (mp3VbriFrame != null)
- {
- encoder = mp3VbriFrame.getEncoder();
- }
- }
-
- /**
- * @return bitrate in kbps, no indicator is provided as to whether or not it is vbr
- */
- public long getBitRateAsNumber()
- {
- return bitrate;
- }
-
- /**
- * @return the BitRate of the Audio, to distinguish cbr from vbr we add a '~'
- * for vbr.
- */
- public String getBitRate()
- {
- if (mp3XingFrame != null && mp3XingFrame.isVbr())
- {
- return isVbrIdentifier + String.valueOf(bitrate);
- }
- else if (mp3VbriFrame != null)
- {
- return isVbrIdentifier + String.valueOf(bitrate);
- }
- else
- {
- return String.valueOf(bitrate);
- }
- }
-
-
- /**
- * @return the sampling rate in Hz
- */
- public int getSampleRateAsNumber()
- {
- return mp3FrameHeader.getSamplingRate();
- }
-
- /**
- * @return the number of bits per sample
- */
- public int getBitsPerSample()
- {
- //TODO: can it really be different in such an MP3 ? I think not.
- return 16;
- }
-
- /**
- * @return the sampling rate as string
- */
- public String getSampleRate()
- {
- return String.valueOf(mp3FrameHeader.getSamplingRate());
- }
-
- /**
- * @return MPEG Version (1-3)
- */
- public String getMpegVersion()
- {
- return mp3FrameHeader.getVersionAsString();
- }
-
- /**
- * @return MPEG Layer (1-3)
- */
- public String getMpegLayer()
- {
- return mp3FrameHeader.getLayerAsString();
- }
-
- /**
- * @return the format of the audio (i.e. MPEG-1 Layer3)
- */
- public String getFormat()
- {
- return mp3FrameHeader.getVersionAsString() + " " + mp3FrameHeader.getLayerAsString();
- }
-
- /**
- * @return the Channel Mode such as Stero or Mono
- */
- public String getChannels()
- {
- return mp3FrameHeader.getChannelModeAsString();
- }
-
- /**
- * @return Emphasis
- */
- public String getEmphasis()
- {
- return mp3FrameHeader.getEmphasisAsString();
- }
-
- /**
- * @return if the bitrate is variable, Xing header takes precedence if we have one
- */
- public boolean isVariableBitRate()
- {
- if (mp3XingFrame != null)
- {
- return mp3XingFrame.isVbr();
- }
- else if (mp3VbriFrame != null)
- {
- return mp3VbriFrame.isVbr();
- }
- else
- {
- return mp3FrameHeader.isVariableBitRate();
- }
- }
-
- public boolean isProtected()
- {
- return mp3FrameHeader.isProtected();
- }
-
- public boolean isPrivate()
- {
- return mp3FrameHeader.isPrivate();
- }
-
- public boolean isCopyrighted()
- {
- return mp3FrameHeader.isCopyrighted();
- }
-
- public boolean isOriginal()
- {
- return mp3FrameHeader.isOriginal();
- }
-
- public boolean isPadding()
- {
- return mp3FrameHeader.isPadding();
- }
-
- public boolean isLossless()
- {
- return false;
- }
-
- /**
- * @return encoder
- */
- public String getEncoder()
- {
- return encoder;
- }
-
- /**
- * Set the size of the file, required in some calculations
- *
- * @param fileSize
- */
- protected void setFileSize(long fileSize)
- {
- this.fileSize = fileSize;
- }
-
-
- /**
- * @return a string representation
- */
- public String toString()
- {
- String s = "fileSize:" + fileSize
- + " encoder:" + encoder
- + " startByte:" + Hex.asHex(startByte)
- + " numberOfFrames:" + numberOfFrames
- + " numberOfFramesEst:" + numberOfFramesEstimate
- + " timePerFrame:" + timePerFrame
- + " bitrate:" + bitrate
- + " trackLength:" + getTrackLengthAsString();
-
- if (this.mp3FrameHeader != null)
- {
- s += mp3FrameHeader.toString();
- }
- else
- {
- s +=" mpegframeheader:false";
- }
-
- if (this.mp3XingFrame != null)
- {
- s += mp3XingFrame.toString();
- }
- else
- {
- s +=" mp3XingFrame:false";
- }
-
- if (this.mp3VbriFrame != null)
- {
- s +=mp3VbriFrame.toString();
- }
- else
- {
- s +=" mp3VbriFrame:false";
- }
- return s;
- }
-
- /**
- * TODO (Was originally added for Wavs)
- * @return
- */
- public Integer getByteRate()
- {
- return null;
- }
-
- /**
- * TODO (Was origjnally added for Wavs)
- * @return
- */
- public Long getAudioDataLength()
- {
- return Long.valueOf(0);
- }
-
- @Override
- public Long getAudioDataStartPosition()
- {
- return audioDataStartPosition;
- }
-
- public void setAudioDataStartPosition(Long audioDataStartPosition)
- {
- this.audioDataStartPosition = audioDataStartPosition;
- }
-
- @Override
- public Long getAudioDataEndPosition()
- {
- return audioDataEndPosition;
- }
-
- public void setAudioDataEndPosition(Long audioDataEndPosition)
- {
- this.audioDataEndPosition = audioDataEndPosition;
- }
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/mp3/MP3File.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/mp3/MP3File.java
deleted file mode 100644
index 0f4fbf6a..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/mp3/MP3File.java
+++ /dev/null
@@ -1,1152 +0,0 @@
-package com.mp3.jaudiotagger.audio.mp3;
-/**
- * @author : Paul Taylor
- * @author : Eric Farng
- *
- * Version @version:$Id$
- *
- * MusicTag Copyright (C)2003,2004
- *
- * 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,
- * you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-
-import com.mp3.jaudiotagger.audio.AudioFile;
-import com.mp3.jaudiotagger.audio.AudioFileIO;
-import com.mp3.jaudiotagger.audio.exceptions.*;
-import com.mp3.jaudiotagger.logging.*;
-import com.mp3.jaudiotagger.tag.Tag;
-import com.mp3.jaudiotagger.tag.TagException;
-import com.mp3.jaudiotagger.tag.TagNotFoundException;
-import com.mp3.jaudiotagger.tag.TagOptionSingleton;
-import com.mp3.jaudiotagger.tag.id3.*;
-import com.mp3.jaudiotagger.tag.lyrics3.AbstractLyrics3;
-import com.mp3.jaudiotagger.tag.reference.ID3V2Version;
-
-import java.io.*;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.logging.Level;
-
-/**
- * This class represents a physical MP3 File
- */
-public class MP3File extends AudioFile
-{
- private static final int MINIMUM_FILESIZE = 150;
-
- protected static AbstractTagDisplayFormatter tagFormatter;
-
- /**
- * the ID3v2 tag that this file contains.
- */
- private AbstractID3v2Tag id3v2tag = null;
-
- /**
- * Representation of the idv2 tag as a idv24 tag
- */
- private ID3v24Tag id3v2Asv24tag = null;
-
- /**
- * The Lyrics3 tag that this file contains.
- */
- private AbstractLyrics3 lyrics3tag = null;
-
-
- /**
- * The ID3v1 tag that this file contains.
- */
- private ID3v1Tag id3v1tag = null;
-
- /**
- * Creates a new empty MP3File datatype that is not associated with a
- * specific file.
- */
- public MP3File()
- {
- }
-
- /**
- * Creates a new MP3File datatype and parse the tag from the given filename.
- *
- * @param filename MP3 file
- * @throws IOException on any I/O error
- * @throws TagException on any exception generated by this library.
- * @throws com.mp3.jaudiotagger.audio.exceptions.ReadOnlyFileException
- * @throws com.mp3.jaudiotagger.audio.exceptions.InvalidAudioFrameException
- */
- public MP3File(String filename) throws IOException, TagException, ReadOnlyFileException, CannotReadException, InvalidAudioFrameException
- {
- this(new File(filename));
- }
-
-
- /* Load ID3V1tag if exists */
- public static final int LOAD_IDV1TAG = 2;
-
- /* Load ID3V2tag if exists */
- public static final int LOAD_IDV2TAG = 4;
-
- /**
- * This option is currently ignored
- */
- public static final int LOAD_LYRICS3 = 8;
-
- public static final int LOAD_ALL = LOAD_IDV1TAG | LOAD_IDV2TAG | LOAD_LYRICS3;
-
- /**
- * Creates a new MP3File dataType and parse the tag from the given file
- * Object, files must be writable to use this constructor.
- *
- * @param file MP3 file
- * @param loadOptions decide what tags to load
- * @throws IOException on any I/O error
- * @throws TagException on any exception generated by this library.
- * @throws com.mp3.jaudiotagger.audio.exceptions.ReadOnlyFileException
- * @throws com.mp3.jaudiotagger.audio.exceptions.InvalidAudioFrameException
- */
- public MP3File(File file, int loadOptions) throws IOException, TagException, ReadOnlyFileException, CannotReadException, InvalidAudioFrameException
- {
- this(file, loadOptions, false);
- }
-
- /**
- * Read v1 tag
- *
- * @param file
- * @param newFile
- * @param loadOptions
- * @throws IOException
- */
- private void readV1Tag(File file, RandomAccessFile newFile, int loadOptions) throws IOException
- {
- if ((loadOptions & LOAD_IDV1TAG) != 0)
- {
- logger.finer("Attempting to read id3v1tags");
- try
- {
- id3v1tag = new ID3v11Tag(newFile, file.getName());
- }
- catch (TagNotFoundException ex)
- {
- logger.config("No ids3v11 tag found");
- }
-
- try
- {
- if (id3v1tag == null)
- {
- id3v1tag = new ID3v1Tag(newFile, file.getName());
- }
- }
- catch (TagNotFoundException ex)
- {
- logger.config("No id3v1 tag found");
- }
- }
- }
-
- /**
- * Read V2tag, if exists.
- *
- * TODO:shouldn't we be handing TagExceptions:when will they be thrown
- *
- * @param file the file to read tags from
- * @param loadOptions load options
- * @throws IOException IO issues
- * @throws TagException tag issues
- */
- private void readV2Tag(File file, int loadOptions, int startByte) throws IOException, TagException
- {
- //We know where the actual Audio starts so load all the file from start to that point into
- //a buffer then we can read the IDv2 information without needing any more File I/O
- if (startByte >= AbstractID3v2Tag.TAG_HEADER_LENGTH)
- {
- logger.finer("Attempting to read id3v2tags");
- FileInputStream fis = null;
- try
- {
- fis = new FileInputStream(file);
- final ByteBuffer bb = ByteBuffer.allocateDirect(startByte);
- fis.getChannel().read(bb,0);
- bb.rewind();
-
- if ((loadOptions & LOAD_IDV2TAG) != 0)
- {
- logger.config("Attempting to read id3v2tags");
- try
- {
- this.setID3v2Tag(new ID3v24Tag(bb, file.getName()));
- }
- catch (TagNotFoundException ex)
- {
- logger.config("No id3v24 tag found");
- }
-
- try
- {
- if (id3v2tag == null)
- {
- this.setID3v2Tag(new ID3v23Tag(bb, file.getName()));
- }
- }
- catch (TagNotFoundException ex)
- {
- logger.config("No id3v23 tag found");
- }
-
- try
- {
- if (id3v2tag == null)
- {
- this.setID3v2Tag(new ID3v22Tag(bb, file.getName()));
- }
- }
- catch (TagNotFoundException ex)
- {
- logger.config("No id3v22 tag found");
- }
- }
- } finally {
- AudioFileIO.closeQuietly(fis);
- }
- }
- else
- {
- logger.config("Not enough room for valid id3v2 tag:" + startByte);
- }
- }
-
- /**
- * Read lyrics3 Tag
- *
- * TODO:not working
- *
- * @param file
- * @param newFile
- * @param loadOptions
- * @throws IOException
- */
- private void readLyrics3Tag(File file, RandomAccessFile newFile, int loadOptions) throws IOException
- {
- /*if ((loadOptions & LOAD_LYRICS3) != 0)
- {
- try
- {
- lyrics3tag = new Lyrics3v2(newFile);
- }
- catch (TagNotFoundException ex)
- {
- }
- try
- {
- if (lyrics3tag == null)
- {
- lyrics3tag = new Lyrics3v1(newFile);
- }
- }
- catch (TagNotFoundException ex)
- {
- }
- }
- */
- }
-
-
- /**
- *
- * @param startByte
- * @param endByte
- * @return
- * @throws IOException
- *
- * @return true if all the bytes between in the file between startByte and endByte are null, false
- * otherwise
- */
- private boolean isFilePortionNull(int startByte, int endByte) throws IOException
- {
- logger.config("Checking file portion:" + Hex.asHex(startByte) + ":" + Hex.asHex(endByte));
- FileInputStream fis=null;
- FileChannel fc=null;
- try
- {
- fis = new FileInputStream(file);
- fc = fis.getChannel();
- fc.position(startByte);
- ByteBuffer bb = ByteBuffer.allocateDirect(endByte - startByte);
- fc.read(bb);
- while(bb.hasRemaining())
- {
- if(bb.get()!=0)
- {
- return false;
- }
- }
- }
- finally
- {
- if (fc != null)
- {
- fc.close();
- }
-
- if (fis != null)
- {
- fis.close();
- }
- }
- return true;
- }
- /**
- * Regets the audio header starting from start of file, and write appropriate logging to indicate
- * potential problem to user.
- *
- * @param startByte
- * @param firstHeaderAfterTag
- * @return
- * @throws IOException
- * @throws InvalidAudioFrameException
- */
- private MP3AudioHeader checkAudioStart(long startByte, MP3AudioHeader firstHeaderAfterTag) throws IOException, InvalidAudioFrameException
- {
- MP3AudioHeader headerOne;
- MP3AudioHeader headerTwo;
-
- logger.warning(ErrorMessage.MP3_ID3TAG_LENGTH_INCORRECT.getMsg(file.getPath(), Hex.asHex(startByte), Hex.asHex(firstHeaderAfterTag.getMp3StartByte())));
-
- //because we cant agree on start location we reread the audioheader from the start of the file, at least
- //this way we cant overwrite the audio although we might overwrite part of the tag if we write this file
- //back later
- headerOne = new MP3AudioHeader(file, 0);
- logger.config("Checking from start:" + headerOne);
-
- //Although the id3 tag size appears to be incorrect at least we have found the same location for the start
- //of audio whether we start searching from start of file or at the end of the alleged of file so no real
- //problem
- if (firstHeaderAfterTag.getMp3StartByte() == headerOne.getMp3StartByte())
- {
- logger.config(ErrorMessage.MP3_START_OF_AUDIO_CONFIRMED.getMsg(file.getPath(),
- Hex.asHex(headerOne.getMp3StartByte())));
- return firstHeaderAfterTag;
- }
- else
- {
-
- //We get a different value if read from start, can't guarantee 100% correct lets do some more checks
- logger.config((ErrorMessage.MP3_RECALCULATED_POSSIBLE_START_OF_MP3_AUDIO.getMsg(file.getPath(),
- Hex.asHex(headerOne.getMp3StartByte()))));
-
- //Same frame count so probably both audio headers with newAudioHeader being the first one
- if (firstHeaderAfterTag.getNumberOfFrames() == headerOne.getNumberOfFrames())
- {
- logger.warning((ErrorMessage.MP3_RECALCULATED_START_OF_MP3_AUDIO.getMsg(file.getPath(),
- Hex.asHex(headerOne.getMp3StartByte()))));
- return headerOne;
- }
-
- //If the size reported by the tag header is a little short and there is only nulls between the recorded value
- //and the start of the first audio found then we stick with the original header as more likely that currentHeader
- //DataInputStream not really a header
- if(isFilePortionNull((int) startByte,(int) firstHeaderAfterTag.getMp3StartByte()))
- {
- return firstHeaderAfterTag;
- }
-
- //Skip to the next header (header 2, counting from start of file)
- headerTwo = new MP3AudioHeader(file, headerOne.getMp3StartByte()
- + headerOne.mp3FrameHeader.getFrameLength());
-
- //It matches the header we found when doing the original search from after the ID3Tag therefore it
- //seems that newAudioHeader was a false match and the original header was correct
- if (headerTwo.getMp3StartByte() == firstHeaderAfterTag.getMp3StartByte())
- {
- logger.warning((ErrorMessage.MP3_START_OF_AUDIO_CONFIRMED.getMsg(file.getPath(),
- Hex.asHex(firstHeaderAfterTag.getMp3StartByte()))));
- return firstHeaderAfterTag;
- }
-
- //It matches the frameCount the header we just found so lends weight to the fact that the audio does indeed start at new header
- //however it maybe that neither are really headers and just contain the same data being misrepresented as headers.
- if (headerTwo.getNumberOfFrames() == headerOne.getNumberOfFrames())
- {
- logger.warning((ErrorMessage.MP3_RECALCULATED_START_OF_MP3_AUDIO.getMsg(file.getPath(),
- Hex.asHex(headerOne.getMp3StartByte()))));
- return headerOne;
- }
- ///Doesnt match the frameCount lets go back to the original header
- else
- {
- logger.warning((ErrorMessage.MP3_RECALCULATED_START_OF_MP3_AUDIO.getMsg(file.getPath(),
- Hex.asHex(firstHeaderAfterTag.getMp3StartByte()))));
- return firstHeaderAfterTag;
- }
- }
- }
-
- /**
- * Creates a new MP3File dataType and parse the tag from the given file
- * Object, files can be opened read only if required.
- *
- * @param file MP3 file
- * @param loadOptions decide what tags to load
- * @param readOnly causes the files to be opened readonly
- * @throws IOException on any I/O error
- * @throws TagException on any exception generated by this library.
- * @throws com.mp3.jaudiotagger.audio.exceptions.ReadOnlyFileException
- * @throws com.mp3.jaudiotagger.audio.exceptions.InvalidAudioFrameException
- */
- public MP3File(File file, int loadOptions, boolean readOnly) throws IOException, TagException, ReadOnlyFileException, CannotReadException, InvalidAudioFrameException
- {
- RandomAccessFile newFile = null;
- try
- {
- this.file = file;
-
- //Check File accessibility
- newFile = checkFilePermissions(file, readOnly);
-
- //Read ID3v2 tag size (if tag exists) to allow audioHeader parsing to skip over tag
- long tagSizeReportedByHeader = AbstractID3v2Tag.getV2TagSizeIfExists(file);
- logger.config("TagHeaderSize:" + Hex.asHex(tagSizeReportedByHeader));
- audioHeader = new MP3AudioHeader(file, tagSizeReportedByHeader);
-
- //If the audio header is not straight after the end of the tag then search from start of file
- if (tagSizeReportedByHeader != ((MP3AudioHeader) audioHeader).getMp3StartByte())
- {
- logger.config("First header found after tag:" + audioHeader);
- audioHeader = checkAudioStart(tagSizeReportedByHeader, (MP3AudioHeader) audioHeader);
- }
-
- //Read v1 tags (if any)
- readV1Tag(file, newFile, loadOptions);
-
- //Read v2 tags (if any)
- readV2Tag(file, loadOptions, (int)((MP3AudioHeader) audioHeader).getMp3StartByte());
-
- //If we have a v2 tag use that, if we do not but have v1 tag use that
- //otherwise use nothing
- //TODO:if have both should we merge
- //rather than just returning specific ID3v22 tag, would it be better to return v24 version ?
- if (this.getID3v2Tag() != null)
- {
- tag = this.getID3v2Tag();
- }
- else if (id3v1tag != null)
- {
- tag = id3v1tag;
- }
- }
- finally
- {
- if (newFile != null)
- {
- newFile.close();
- }
- }
- }
-
- /**
- * Used by tags when writing to calculate the location of the music file
- *
- * @param file
- * @return the location within the file that the audio starts
- * @throws IOException
- * @throws com.mp3.jaudiotagger.audio.exceptions.InvalidAudioFrameException
- */
- public long getMP3StartByte(File file) throws InvalidAudioFrameException, IOException
- {
- try
- {
- //Read ID3v2 tag size (if tag exists) to allow audio header parsing to skip over tag
- long startByte = AbstractID3v2Tag.getV2TagSizeIfExists(file);
-
- MP3AudioHeader audioHeader = new MP3AudioHeader(file, startByte);
- if (startByte != audioHeader.getMp3StartByte())
- {
- logger.config("First header found after tag:" + audioHeader);
- audioHeader = checkAudioStart(startByte, audioHeader);
- }
- return audioHeader.getMp3StartByte();
- }
- catch (InvalidAudioFrameException iafe)
- {
- throw iafe;
- }
- catch (IOException ioe)
- {
- throw ioe;
- }
- }
-
- /**
- * Extracts the raw ID3v2 tag data into a file.
- *
- * This provides access to the raw data before manipulation, the data is written from the start of the file
- * to the start of the Audio Data. This is primarily useful for manipulating corrupted tags that are not
- * (fully) loaded using the standard methods.
- *
- * @param outputFile to write the data to
- * @return
- * @throws TagNotFoundException
- * @throws IOException
- */
- public File extractID3v2TagDataIntoFile(File outputFile) throws TagNotFoundException, IOException
- {
- int startByte = (int) ((MP3AudioHeader) audioHeader).getMp3StartByte();
- if (startByte >= 0)
- {
-
- //Read byte into buffer
- FileInputStream fis = new FileInputStream(file);
- FileChannel fc = fis.getChannel();
- ByteBuffer bb = ByteBuffer.allocate(startByte);
- fc.read(bb);
-
- //Write bytes to outputFile
- FileOutputStream out = new FileOutputStream(outputFile);
- out.write(bb.array());
- out.close();
- fc.close();
- fis.close();
- return outputFile;
- }
- throw new TagNotFoundException("There is no ID3v2Tag data in this file");
- }
-
- /**
- * Return audio header
- * @return
- */
- public MP3AudioHeader getMP3AudioHeader()
- {
- return (MP3AudioHeader) getAudioHeader();
- }
-
- /**
- * Returns true if this datatype contains an Id3v1
tag
- *
- * @return true if this datatype contains an Id3v1
tag
- */
- public boolean hasID3v1Tag()
- {
- return (id3v1tag != null);
- }
-
- /**
- * Returns true if this datatype contains an Id3v2
tag
- *
- * @return true if this datatype contains an Id3v2
tag
- */
- public boolean hasID3v2Tag()
- {
- return (id3v2tag != null);
- }
-
- /**
- * Returns true if this datatype contains a Lyrics3
tag
- * TODO disabled until Lyrics3 fixed
- * @return true if this datatype contains a Lyrics3
tag
- */
- /*
- public boolean hasLyrics3Tag()
- {
- return (lyrics3tag != null);
- }
- */
-
- /**
- * Creates a new MP3File datatype and parse the tag from the given file
- * Object.
- *
- * @param file MP3 file
- * @throws IOException on any I/O error
- * @throws TagException on any exception generated by this library.
- * @throws com.mp3.jaudiotagger.audio.exceptions.ReadOnlyFileException
- * @throws com.mp3.jaudiotagger.audio.exceptions.InvalidAudioFrameException
- */
- public MP3File(File file) throws IOException, TagException, ReadOnlyFileException, CannotReadException, InvalidAudioFrameException
- {
- this(file, LOAD_ALL);
- }
-
- /**
- * Sets the ID3v1(_1)tag to the tag provided as an argument.
- *
- * @param id3v1tag
- */
- public void setID3v1Tag(ID3v1Tag id3v1tag)
- {
- logger.config("setting tagv1:v1 tag");
- this.id3v1tag = id3v1tag;
- }
-
- public void setID3v1Tag(Tag id3v1tag)
- {
- logger.config("setting tagv1:v1 tag");
- this.id3v1tag = (ID3v1Tag) id3v1tag;
- }
-
- /**
- * Sets the ID3v1
tag for this dataType. A new
- * ID3v1_1
dataType is created from the argument and then used
- * here.
- *
- * @param mp3tag Any MP3Tag dataType can be used and will be converted into a
- * new ID3v1_1 dataType.
- */
- public void setID3v1Tag(AbstractTag mp3tag)
- {
- logger.config("setting tagv1:abstract");
- id3v1tag = new ID3v11Tag(mp3tag);
- }
-
- /**
- * Returns the ID3v1
tag for this dataType.
- *
- * @return the ID3v1
tag for this dataType
- */
- public ID3v1Tag getID3v1Tag()
- {
- return id3v1tag;
- }
-
- /**
- * Calculates hash with given algorithm. Buffer size is 32768 byte.
- * Hash is calculated EXCLUDING meta-data, like id3v1 or id3v2
- *
- * @return hash value in byte
- * @param algorithm options MD5,SHA-1,SHA-256
- * @throws IOException
- * @throws InvalidAudioFrameException
- * @throws NoSuchAlgorithmException
- */
-
- public byte[] getHash(String algorithm) throws NoSuchAlgorithmException, InvalidAudioFrameException, IOException{
-
- return getHash(algorithm, 32768);
-
-
- }
-
- /**
- * Calculates hash with given buffer size.
- * Hash is calculated EXCLUDING meta-data, like id3v1 or id3v2
- * @param buffer
- * @return byte[] hash value in byte
- * @throws IOException
- * @throws InvalidAudioFrameException
- * @throws NoSuchAlgorithmException
- */
-
- public byte[] getHash(int buffer) throws NoSuchAlgorithmException, InvalidAudioFrameException, IOException{
-
- return getHash("MD5", buffer);
-
-
- }
- /**
- * Calculates hash with algorithm "MD5". Buffer size is 32768 byte.
- * Hash is calculated EXCLUDING meta-data, like id3v1 or id3v2
- *
- * @return byte[] hash value.
- * @throws IOException
- * @throws InvalidAudioFrameException
- * @throws NoSuchAlgorithmException
- */
-
- public byte[] getHash() throws NoSuchAlgorithmException, InvalidAudioFrameException, IOException{
-
- return getHash("MD5", 32768);
-
- }
-
- /**
- * Calculates hash with algorithm "MD5", "SHA-1" or SHA-256".
- * Hash is calculated EXCLUDING meta-data, like id3v1 or id3v2
- *
- * @return byte[] hash value in byte
- * @throws IOException
- * @throws InvalidAudioFrameException
- * @throws NoSuchAlgorithmException
- */
-
- public byte[] getHash(String algorithm, int bufferSize) throws InvalidAudioFrameException, IOException, NoSuchAlgorithmException
- {
- File mp3File = getFile();
- long startByte = getMP3StartByte(mp3File);
-
- int id3v1TagSize = 0;
- if (hasID3v1Tag()){
- ID3v1Tag id1tag= getID3v1Tag();
- id3v1TagSize = id1tag.getSize();
- }
-
- InputStream inStream = new FileInputStream(mp3File);
-
- byte[] buffer = new byte[bufferSize];
-
- MessageDigest digest = MessageDigest.getInstance(algorithm);
-
- inStream.skip(startByte);
-
- int read;
- long totalSize = mp3File.length() - startByte - id3v1TagSize;
- int pointer = buffer.length;
-
- while (pointer <= totalSize ) {
-
- read = inStream.read(buffer);
-
- digest.update(buffer, 0, read);
- pointer += buffer.length;
- }
- read = inStream.read(buffer,0,(int)totalSize - pointer + buffer.length);
- digest.update(buffer, 0, read);
-
- byte[] hash = digest.digest();
-
- inStream.close();
- return hash;
- }
-
- /**
- * Sets the ID3v2
tag for this dataType. A new
- * ID3v2_4
dataType is created from the argument and then used
- * here.
- *
- * @param mp3tag Any MP3Tag dataType can be used and will be converted into a
- * new ID3v2_4 dataType.
- */
- public void setID3v2Tag(AbstractTag mp3tag)
- {
- id3v2tag = new ID3v24Tag(mp3tag);
-
- }
-
- /**
- * Sets the v2 tag to the v2 tag provided as an argument.
- * Also store a v24 version of tag as v24 is the interface to be used
- * when talking with client applications.
- *
- * @param id3v2tag
- */
- public void setID3v2Tag(AbstractID3v2Tag id3v2tag)
- {
- this.id3v2tag = id3v2tag;
- if (id3v2tag instanceof ID3v24Tag)
- {
- this.id3v2Asv24tag = (ID3v24Tag) this.id3v2tag;
- }
- else
- {
- this.id3v2Asv24tag = new ID3v24Tag(id3v2tag);
- }
- }
-
- /**
- * Set v2 tag ,don't need to set v24 tag because saving
- *
-
- * @param id3v2tag
- */
- //TODO temp its rather messy
- public void setID3v2TagOnly(AbstractID3v2Tag id3v2tag)
- {
- this.id3v2tag = id3v2tag;
- this.id3v2Asv24tag = null;
- }
-
- /**
- * Returns the ID3v2
tag for this datatype.
- *
- * @return the ID3v2
tag for this datatype
- */
- public AbstractID3v2Tag getID3v2Tag()
- {
- return id3v2tag;
- }
-
- /**
- * @return a representation of tag as v24
- */
- public ID3v24Tag getID3v2TagAsv24()
- {
- return id3v2Asv24tag;
- }
-
- /**
- * Sets the Lyrics3
tag for this dataType. A new
- * Lyrics3v2
dataType is created from the argument and then
- *
- * used here.
- *
- * @param mp3tag Any MP3Tag dataType can be used and will be converted into a
- * new Lyrics3v2 dataType.
- */
- /*
- public void setLyrics3Tag(AbstractTag mp3tag)
- {
- lyrics3tag = new Lyrics3v2(mp3tag);
- }
- */
-
- /**
- *
- *
- * @param lyrics3tag
- */
- /*
- public void setLyrics3Tag(AbstractLyrics3 lyrics3tag)
- {
- this.lyrics3tag = lyrics3tag;
- }
- */
-
- /**
- * Returns the ID3v1
tag for this datatype.
- *
- * @return the ID3v1
tag for this datatype
- */
- /*
- public AbstractLyrics3 getLyrics3Tag()
- {
- return lyrics3tag;
- }
- */
-
- /**
- * Remove tag from file
- *
- * @param mp3tag
- * @throws FileNotFoundException
- * @throws IOException
- */
- public void delete(AbstractTag mp3tag) throws FileNotFoundException, IOException
- {
- RandomAccessFile raf = new RandomAccessFile(this.file, "rw");
- mp3tag.delete(raf);
- raf.close();
- if(mp3tag instanceof ID3v1Tag)
- {
- id3v1tag=null;
- }
-
- if(mp3tag instanceof AbstractID3v2Tag)
- {
- id3v2tag=null;
- }
- }
-
- /**
- * Saves the tags in this dataType to the file referred to by this dataType.
- *
- * @throws IOException on any I/O error
- * @throws TagException on any exception generated by this library.
- */
- public void save() throws IOException, TagException
- {
- save(this.file);
- }
-
- /**
- * Overridden for compatibility with merged code
- *
- * @throws NoWritePermissionsException if the file could not be written to due to file permissions
- * @throws CannotWriteException
- */
- public void commit() throws CannotWriteException
- {
- try
- {
- save();
- }
- catch (UnableToModifyFileException umfe)
- {
- throw new NoWritePermissionsException(umfe);
- }
- catch (IOException ioe)
- {
- throw new CannotWriteException(ioe);
- }
- catch (TagException te)
- {
- throw new CannotWriteException(te);
- }
- }
-
- /**
- * Check can write to file
- *
- * @param file
- * @throws IOException
- */
- public void precheck(File file) throws IOException
- {
- if (!file.exists())
- {
- logger.severe(ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_NOT_FOUND.getMsg(file.getName()));
- throw new IOException(ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_NOT_FOUND.getMsg(file.getName()));
- }
-
- if (TagOptionSingleton.getInstance().isCheckIsWritable() && !file.canWrite())
- {
- logger.severe(ErrorMessage.GENERAL_WRITE_FAILED.getMsg(file.getName()));
- throw new IOException(ErrorMessage.GENERAL_WRITE_FAILED.getMsg(file.getName()));
- }
-
- if (file.length() <= MINIMUM_FILESIZE)
- {
- logger.severe(ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_IS_TOO_SMALL.getMsg(file.getName()));
- throw new IOException(ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_IS_TOO_SMALL.getMsg(file.getName()));
- }
- }
-
- /**
- * Saves the tags in this dataType to the file argument. It will be saved as
- * TagConstants.MP3_FILE_SAVE_WRITE
- *
- * @param fileToSave file to save the this dataTypes tags to
- * @throws FileNotFoundException if unable to find file
- * @throws IOException on any I/O error
- */
- public void save(File fileToSave) throws IOException
- {
- //Ensure we are dealing with absolute filepaths not relative ones
- File file = fileToSave.getAbsoluteFile();
-
- logger.config("Saving : " + file.getPath());
-
- //Checks before starting write
- precheck(file);
-
- RandomAccessFile rfile = null;
- try
- {
- //ID3v2 Tag
- if (TagOptionSingleton.getInstance().isId3v2Save())
- {
- if (id3v2tag == null)
- {
- rfile = new RandomAccessFile(file, "rw");
- (new ID3v24Tag()).delete(rfile);
- (new ID3v23Tag()).delete(rfile);
- (new ID3v22Tag()).delete(rfile);
- logger.config("Deleting ID3v2 tag:"+file.getName());
- rfile.close();
- }
- else
- {
- logger.config("Writing ID3v2 tag:"+file.getName());
- final MP3AudioHeader mp3AudioHeader = (MP3AudioHeader) this.getAudioHeader();
- final long mp3StartByte = mp3AudioHeader.getMp3StartByte();
- final long newMp3StartByte = id3v2tag.write(file, mp3StartByte);
- if (mp3StartByte != newMp3StartByte) {
- logger.config("New mp3 start byte: " + newMp3StartByte);
- mp3AudioHeader.setMp3StartByte(newMp3StartByte);
- }
-
- }
- }
- rfile = new RandomAccessFile(file, "rw");
-
- //Lyrics 3 Tag
- if (TagOptionSingleton.getInstance().isLyrics3Save())
- {
- if (lyrics3tag != null)
- {
- lyrics3tag.write(rfile);
- }
- }
- //ID3v1 tag
- if (TagOptionSingleton.getInstance().isId3v1Save())
- {
- logger.config("Processing ID3v1");
- if (id3v1tag == null)
- {
- logger.config("Deleting ID3v1");
- (new ID3v1Tag()).delete(rfile);
- }
- else
- {
- logger.config("Saving ID3v1");
- id3v1tag.write(rfile);
- }
- }
- }
- catch (FileNotFoundException ex)
- {
- logger.log(Level.SEVERE, ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE_FILE_NOT_FOUND.getMsg(file.getName()), ex);
- throw ex;
- }
- catch (IOException iex)
- {
- logger.log(Level.SEVERE, ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE.getMsg(file.getName(), iex.getMessage()), iex);
- throw iex;
- }
- catch (RuntimeException re)
- {
- logger.log(Level.SEVERE, ErrorMessage.GENERAL_WRITE_FAILED_BECAUSE.getMsg(file.getName(), re.getMessage()), re);
- throw re;
- }
- finally
- {
- if (rfile != null)
- {
- rfile.close();
- }
- }
- }
-
- /**
- * Displays MP3File Structure
- */
- public String displayStructureAsXML()
- {
- createXMLStructureFormatter();
- tagFormatter.openHeadingElement("file", this.getFile().getAbsolutePath());
- if (this.getID3v1Tag() != null)
- {
- this.getID3v1Tag().createStructure();
- }
- if (this.getID3v2Tag() != null)
- {
- this.getID3v2Tag().createStructure();
- }
- tagFormatter.closeHeadingElement("file");
- return tagFormatter.toString();
- }
-
- /**
- * Displays MP3File Structure
- */
- public String displayStructureAsPlainText()
- {
- createPlainTextStructureFormatter();
- tagFormatter.openHeadingElement("file", this.getFile().getAbsolutePath());
- if (this.getID3v1Tag() != null)
- {
- this.getID3v1Tag().createStructure();
- }
- if (this.getID3v2Tag() != null)
- {
- this.getID3v2Tag().createStructure();
- }
- tagFormatter.closeHeadingElement("file");
- return tagFormatter.toString();
- }
-
- private static void createXMLStructureFormatter()
- {
- tagFormatter = new XMLTagDisplayFormatter();
- }
-
- private static void createPlainTextStructureFormatter()
- {
- tagFormatter = new PlainTextTagDisplayFormatter();
- }
-
- public static AbstractTagDisplayFormatter getStructureFormatter()
- {
- return tagFormatter;
- }
-
- /**
- * Set the Tag
- *
- * If the parameter tag is a v1tag then the v1 tag is set if v2tag then the v2tag.
- *
- * @param tag
- */
- public void setTag(Tag tag)
- {
- this.tag = tag;
- if (tag instanceof ID3v1Tag)
- {
- setID3v1Tag((ID3v1Tag) tag);
- }
- else
- {
- setID3v2Tag((AbstractID3v2Tag) tag);
- }
- }
-
-
- /** Create Default Tag
- *
- * @return
- */
- @Override
- public Tag createDefaultTag()
- {
- if(TagOptionSingleton.getInstance().getID3V2Version()==ID3V2Version.ID3_V24)
- {
- return new ID3v24Tag();
- }
- else if(TagOptionSingleton.getInstance().getID3V2Version()==ID3V2Version.ID3_V23)
- {
- return new ID3v23Tag();
- }
- else if(TagOptionSingleton.getInstance().getID3V2Version()==ID3V2Version.ID3_V22)
- {
- return new ID3v22Tag();
- }
- //Default in case not set somehow
- return new ID3v24Tag();
- }
-
-
-
- /**
- * Overridden to only consider ID3v2 Tag
- *
- * @return
- */
- @Override
- public Tag getTagOrCreateDefault()
- {
- Tag tag = getID3v2Tag();
- if(tag==null)
- {
- return createDefaultTag();
- }
- return tag;
- }
-
-
- /**
- * Get the ID3v2 tag and convert to preferred version or if the file doesn't have one at all
- * create a default tag of preferred version and set it. The file may already contain a ID3v1 tag but because
- * this is not terribly useful the v1tag is not considered for this problem.
- *
- * @return
- */
- @Override
- public Tag getTagAndConvertOrCreateAndSetDefault()
- {
- Tag tag = getTagOrCreateDefault();
- Tag convertedTag = convertID3Tag((AbstractID3v2Tag)tag, TagOptionSingleton.getInstance().getID3V2Version());
- if(convertedTag!=null)
- {
- setTag(convertedTag);
- }
- else
- {
- setTag(tag);
- }
- return getTag();
- }
-}
-
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/mp3/MP3FileReader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/mp3/MP3FileReader.java
deleted file mode 100644
index 80d20cf2..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/mp3/MP3FileReader.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.mp3.jaudiotagger.audio.mp3;
-
-import com.mp3.jaudiotagger.audio.AudioFile;
-import com.mp3.jaudiotagger.audio.exceptions.CannotReadException;
-import com.mp3.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
-import com.mp3.jaudiotagger.audio.exceptions.ReadOnlyFileException;
-import com.mp3.jaudiotagger.audio.generic.AudioFileReader;
-import com.mp3.jaudiotagger.audio.generic.GenericAudioHeader;
-import com.mp3.jaudiotagger.tag.Tag;
-import com.mp3.jaudiotagger.tag.TagException;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-
-/**
- * Read Mp3 Info (retrofitted to entagged ,done differently to entagged which is why some methods throw RuntimeException)
- * because done elsewhere
- */
-public class MP3FileReader extends AudioFileReader
-{
- protected GenericAudioHeader getEncodingInfo(RandomAccessFile raf) throws CannotReadException, IOException
- {
- throw new RuntimeException("MP3FileReader.getEncodingInfo should be called");
- }
-
- protected Tag getTag(RandomAccessFile raf) throws CannotReadException, IOException
- {
- throw new RuntimeException("MP3FileReader.getEncodingInfo should be called");
- }
-
- /**
- * @param f
- * @return
- */
- //Override because we read mp3s differently to the entagged code
- public AudioFile read(File f) throws IOException, TagException, ReadOnlyFileException, CannotReadException, InvalidAudioFrameException
- {
- MP3File mp3File = new MP3File(f, MP3File.LOAD_IDV1TAG | MP3File.LOAD_IDV2TAG, true);
- return mp3File;
- }
-
- /**
- * Read
- *
- * @param f
- * @return
- * @throws ReadOnlyFileException thrown if the file is not writable
- * @throws TagException
- * @throws IOException
- * @throws com.mp3.jaudiotagger.audio.exceptions.InvalidAudioFrameException
- */
- public AudioFile readMustBeWritable(File f) throws IOException, TagException, ReadOnlyFileException, CannotReadException, InvalidAudioFrameException
- {
- MP3File mp3File = new MP3File(f, MP3File.LOAD_IDV1TAG | MP3File.LOAD_IDV2TAG, false);
- return mp3File;
- }
-
-}
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/mp3/MP3FileWriter.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/mp3/MP3FileWriter.java
deleted file mode 100644
index 46e467fc..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/mp3/MP3FileWriter.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.mp3.jaudiotagger.audio.mp3;
-
-import com.mp3.jaudiotagger.audio.AudioFile;
-import com.mp3.jaudiotagger.audio.exceptions.CannotReadException;
-import com.mp3.jaudiotagger.audio.exceptions.CannotWriteException;
-import com.mp3.jaudiotagger.audio.generic.AudioFileWriter;
-import com.mp3.jaudiotagger.tag.Tag;
-
-import java.io.IOException;
-import java.io.RandomAccessFile;
-
-/**
- * Write Mp3 Info (retrofitted to entagged ,done differently to entagged which is why some methods throw RuntimeException)
- * because done elsewhere
- */
-public class MP3FileWriter extends AudioFileWriter
-{
- public void deleteTag(AudioFile f) throws CannotWriteException
- {
- //Because audio file is an instanceof MP3File this directs it to save
- //taking into account if the tag has been sent to null in which case it will be deleted
- f.commit();
- }
-
- public void writeFile(AudioFile f) throws CannotWriteException
- {
- //Because audio file is an instanceof MP3File this directs it to save
- f.commit();
- }
-
- /**
- * Delete the Id3v1 and ID3v2 tags from file
- *
- * @param af
- * @throws CannotReadException
- * @throws CannotWriteException
- */
- @Override
- public synchronized void delete(AudioFile af) throws CannotReadException, CannotWriteException
- {
- ((MP3File)af).setID3v1Tag(null);
- ((MP3File)af).setID3v2Tag(null);
- af.commit();
- }
-
- protected void writeTag(AudioFile audioFile, Tag tag, RandomAccessFile raf, RandomAccessFile rafTemp) throws CannotWriteException, IOException
- {
- throw new RuntimeException("MP3FileReaderwriteTag should not be called");
- }
-
- protected void deleteTag(Tag tag, RandomAccessFile raf, RandomAccessFile tempRaf) throws CannotWriteException, IOException
- {
- throw new RuntimeException("MP3FileReader.getEncodingInfo should be called");
- }
-}
-
-
diff --git a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/mp3/MPEGFrameHeader.java b/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/mp3/MPEGFrameHeader.java
deleted file mode 100644
index b564f6b8..00000000
--- a/jaudiotagger/src/main/java/com/mp3/jaudiotagger/audio/mp3/MPEGFrameHeader.java
+++ /dev/null
@@ -1,888 +0,0 @@
-/**
- * @author : Paul Taylor
- *
- * Version @version:$Id$
- * Date :${DATE}
- *
- * Jaikoz Copyright Copyright (C) 2003 -2005 JThink Ltd
- */
-package com.mp3.jaudiotagger.audio.mp3;
-
-import com.mp3.jaudiotagger.FileConstants;
-import com.mp3.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
-import com.mp3.jaudiotagger.logging.AbstractTagDisplayFormatter;
-
-import java.nio.ByteBuffer;
-import java.util.HashMap;
-import java.util.Map;
-
-
-/**
- * Represents a MPEGFrameHeader, an MP3 is made up of a number of frames each frame starts with a four
- * byte frame header.
- */
-@SuppressWarnings({"PointlessArithmeticExpression"})
-public class MPEGFrameHeader
-{
- /**
- * Constants for MP3 Frame header, each frame has a basic header of
- * 4 bytes
- */
- private static final int BYTE_1 = 0;
- private static final int BYTE_2 = 1;
- private static final int BYTE_3 = 2;
- private static final int BYTE_4 = 3;
- public static final int HEADER_SIZE = 4;
-
- /**
- * Sync Value to identify the start of an MPEGFrame
- */
- public static final int SYNC_SIZE = 2;
-
- public static final int SYNC_BYTE1 = 0xFF;
- public static final int SYNC_BYTE2 = 0xE0;
- public static final int SYNC_BIT_ANDSAMPING_BYTE3 = 0xFC;
-
- private static final byte[] header = new byte[HEADER_SIZE];
-
-
- /**
- * Constants for MPEG Version
- */
- public static final Map