Coverage Report - org.jaudiotagger.audio.asf.data.ContainerType
 
Classes in this File Line Coverage Branch Coverage Complexity
ContainerType
97%
48/49
96%
56/58
3.333
 
 1  
 package org.jaudiotagger.audio.asf.data;
 2  
 
 3  
 import org.jaudiotagger.audio.asf.util.Utils;
 4  
 import org.jaudiotagger.logging.ErrorMessage;
 5  
 
 6  
 import java.math.BigInteger;
 7  
 import java.util.Arrays;
 8  
 import java.util.List;
 9  
 
 10  
 /**
 11  
  * Enumerates capabilities, respectively uses, of metadata descriptors.<br>
 12  
  * <br>
 13  
  * The {@link #METADATA_LIBRARY_OBJECT} allows the most variations of data, as
 14  
  * well as no size limitation (if it can be stored within a DWORD amount of
 15  
  * bytes).<br>
 16  
  * 
 17  
  * @author Christian Laireiter
 18  
  */
 19  3059
 public enum ContainerType
 20  
 {
 21  
 
 22  
     /**
 23  
      * The descriptor is used in the content branding object (chunk)
 24  
      */
 25  4
     CONTENT_BRANDING(GUID.GUID_CONTENT_BRANDING, 32, false, false, false, false),
 26  
 
 27  
     /**
 28  
      * The descriptor is used in the content description object (chunk), so
 29  
      * {@linkplain MetadataDescriptor#DWORD_MAXVALUE maximum data length}
 30  
      * applies, no language index and stream number are allowed, as well as no
 31  
      * multiple values.
 32  
      */
 33  4
     CONTENT_DESCRIPTION(GUID.GUID_CONTENTDESCRIPTION, 16, false, false, false,
 34  
             false),
 35  
     /**
 36  
      * The descriptor is used in an extended content description object, so the
 37  
      * {@linkplain MetadataDescriptor#DWORD_MAXVALUE maximum data size} applies,
 38  
      * and no language index and stream number other than &quot;0&quot; is
 39  
      * allowed. Additionally no multiple values are permitted.
 40  
      */
 41  4
     EXTENDED_CONTENT(GUID.GUID_EXTENDED_CONTENT_DESCRIPTION, 16, false, false,
 42  
             false, false),
 43  
     /**
 44  
      * The descriptor is used in a metadata library object. No real size limit
 45  
      * (except DWORD range) applies. Stream numbers and language indexes can be
 46  
      * specified.
 47  
      */
 48  4
     METADATA_LIBRARY_OBJECT(GUID.GUID_METADATA_LIBRARY, 32, true, true, true,
 49  
             true),
 50  
     /**
 51  
      * The descriptor is used in a metadata object. The
 52  
      * {@linkplain MetadataDescriptor#DWORD_MAXVALUE maximum data size} applies.
 53  
      * Stream numbers can be specified. But no language index (always
 54  
      * &quot;0&quot;).
 55  
      */
 56  4
     METADATA_OBJECT(GUID.GUID_METADATA, 16, false, true, false, true);
 57  
 
 58  
     /**
 59  
      * Determines if low has <= index as high, in respect to
 60  
      * {@link #getOrdered()}
 61  
      * 
 62  
      * @param low
 63  
      * @param high
 64  
      * @return <code>true</code> if in correct order.
 65  
      */
 66  
     public static boolean areInCorrectOrder(final ContainerType low,
 67  
             final ContainerType high) {
 68  7689
         final List<ContainerType> asList = Arrays.asList(getOrdered());
 69  7689
         return asList.indexOf(low) <= asList.indexOf(high);
 70  
     }
 71  
 
 72  
     /**
 73  
      * Returns the elements in an order, that indicates more capabilities
 74  
      * (ascending).<br>
 75  
      * 
 76  
      * @return capability ordered types
 77  
      */
 78  
     public static ContainerType[] getOrdered() {
 79  8030
         return new ContainerType[] {CONTENT_DESCRIPTION, CONTENT_BRANDING, EXTENDED_CONTENT, METADATA_OBJECT, METADATA_LIBRARY_OBJECT};
 80  
     }
 81  
 
 82  
     /**
 83  
      * Stores the guid that identifies ASF chunks which store metadata of the
 84  
      * current type.
 85  
      */
 86  
     private final GUID containerGUID;
 87  
 
 88  
     /**
 89  
      * <code>true</code> if the descriptor field can store {@link GUID} values.
 90  
      */
 91  
     private final boolean guidEnabled;
 92  
 
 93  
     /**
 94  
      * <code>true</code> if descriptor field can refer to a language.
 95  
      */
 96  
     private final boolean languageEnabled;
 97  
 
 98  
     /**
 99  
      * The maximum amount of bytes the descriptor data may consume.<br>
 100  
      */
 101  
     private final BigInteger maximumDataLength;
 102  
 
 103  
     /**
 104  
      * <code>true</code> if the container may store multiple values of the same
 105  
      * metadata descriptor specification (equality on name, language, and
 106  
      * stream).<br>
 107  
      * WindowsMedia players advanced tag editor for example stores the
 108  
      * WM/Picture attribute once in the extended content description, and all
 109  
      * others in the metadata library object.
 110  
      */
 111  
     private final boolean multiValued;
 112  
 
 113  
     /**
 114  
      * if <code>-1</code> a size value has to be compared against
 115  
      * {@link #maximumDataLength} because {@link Long#MAX_VALUE} is exceeded.<br>
 116  
      * Otherwise this is the {@link BigInteger#longValue()} representation.
 117  
      */
 118  
     private final long perfMaxDataLen;
 119  
 
 120  
     /**
 121  
      * <code>true</code> if descriptor field can refer to specific streams.
 122  
      */
 123  
     private final boolean streamEnabled;
 124  
 
 125  
     /**
 126  
      * Creates an instance
 127  
      * 
 128  
      * @param guid
 129  
      *            see {@link #containerGUID}
 130  
      * @param maxDataLenBits
 131  
      *            The amount of bits that is used to represent an unsigned value
 132  
      *            for the containers size descriptors. Will create a maximum
 133  
      *            value for {@link #maximumDataLength}. (2 ^ maxDataLenBits -1)
 134  
      * @param guidAllowed
 135  
      *            see {@link #guidEnabled}
 136  
      * @param stream
 137  
      *            see {@link #streamEnabled}
 138  
      * @param language
 139  
      *            see {@link #languageEnabled}
 140  
      * @param multiValue
 141  
      *            see {@link #multiValued}
 142  
      */
 143  
     private ContainerType(final GUID guid, final int maxDataLenBits,
 144  
             final boolean guidAllowed, final boolean stream,
 145  20
             final boolean language, final boolean multiValue) {
 146  20
         this.containerGUID = guid;
 147  20
         this.maximumDataLength = BigInteger.valueOf(2).pow(maxDataLenBits)
 148  
                 .subtract(BigInteger.ONE);
 149  20
         if (this.maximumDataLength
 150  
                 .compareTo(BigInteger.valueOf(Long.MAX_VALUE)) <= 0) {
 151  20
             this.perfMaxDataLen = this.maximumDataLength.longValue();
 152  
         } else {
 153  0
             this.perfMaxDataLen = -1;
 154  
         }
 155  20
         this.guidEnabled = guidAllowed;
 156  20
         this.streamEnabled = stream;
 157  20
         this.languageEnabled = language;
 158  20
         this.multiValued = multiValue;
 159  20
     }
 160  
 
 161  
     /**
 162  
      * Calls {@link #checkConstraints(String, byte[], int, int, int)} and
 163  
      * actually throws the exception if there is one.
 164  
      * 
 165  
      * @param name
 166  
      *            name of the descriptor
 167  
      * @param data
 168  
      *            content
 169  
      * @param type
 170  
      *            data type
 171  
      * @param stream
 172  
      *            stream number
 173  
      * @param language
 174  
      *            language index
 175  
      */
 176  
     public void assertConstraints(final String name, final byte[] data,
 177  
             final int type, final int stream, final int language) {
 178  32056
         final RuntimeException result = checkConstraints(name, data, type,
 179  
                 stream, language);
 180  32056
         if (result != null) {
 181  64
             throw result;
 182  
         }
 183  31992
     }
 184  
 
 185  
     /**
 186  
      * Checks if the values for a {@linkplain MetadataDescriptor content
 187  
      * descriptor} match the contraints of the container type, and returns a
 188  
      * {@link RuntimeException} if the requirements aren't met.
 189  
      * 
 190  
      * @param name
 191  
      *            name of the descriptor
 192  
      * @param data
 193  
      *            content
 194  
      * @param type
 195  
      *            data type
 196  
      * @param stream
 197  
      *            stream number
 198  
      * @param language
 199  
      *            language index
 200  
      * @return <code>null</code> if everything is fine.
 201  
      */
 202  
     public RuntimeException checkConstraints(final String name,
 203  
             final byte[] data, final int type, final int stream,
 204  
             final int language) {
 205  49531
         RuntimeException result = null;
 206  
         // TODO generate tests
 207  49531
         if (name == null || data == null) {
 208  12
             result = new IllegalArgumentException("Arguments must not be null.");
 209  
         } else {
 210  49519
             if (!Utils.isStringLengthValidNullSafe(name)) {
 211  4
                 result = new IllegalArgumentException(
 212  
                         ErrorMessage.WMA_LENGTH_OF_STRING_IS_TOO_LARGE
 213  
                                 .getMsg(name.length()));
 214  
             }
 215  
         }
 216  49531
         if (result == null && !isWithinValueRange(data.length)) {
 217  8
             result = new IllegalArgumentException(
 218  
                     ErrorMessage.WMA_LENGTH_OF_DATA_IS_TOO_LARGE.getMsg(
 219  
                             data.length, getMaximumDataLength(),
 220  
                             getContainerGUID().getDescription()));
 221  
         }
 222  49531
         if (result == null
 223  
                 && (stream < 0 || stream > MetadataDescriptor.MAX_STREAM_NUMBER || (!isStreamNumberEnabled() && stream != 0))) {
 224  216
             final String streamAllowed = isStreamNumberEnabled() ? "0 to 127"
 225  
                     : "0";
 226  216
             result = new IllegalArgumentException(
 227  
                     ErrorMessage.WMA_INVALID_STREAM_REFERNCE.getMsg(stream,
 228  
                             streamAllowed, getContainerGUID().getDescription()));
 229  
         }
 230  49531
         if (result == null && type == MetadataDescriptor.TYPE_GUID
 231  
                 && !isGuidEnabled()) {
 232  42
             result = new IllegalArgumentException(
 233  
                     ErrorMessage.WMA_INVALID_GUID_USE.getMsg(getContainerGUID()
 234  
                             .getDescription()));
 235  
         }
 236  49531
         if (result == null
 237  
                 && ((language != 0 && !isLanguageEnabled()) || (language < 0 || language >= MetadataDescriptor.MAX_LANG_INDEX))) {
 238  16
             final String langAllowed = isStreamNumberEnabled() ? "0 to 126"
 239  
                     : "0";
 240  16
             result = new IllegalArgumentException(
 241  
                     ErrorMessage.WMA_INVALID_LANGUAGE_USE.getMsg(language,
 242  
                             getContainerGUID().getDescription(), langAllowed));
 243  
         }
 244  49531
         if (result == null && this == CONTENT_DESCRIPTION
 245  
                 && type != MetadataDescriptor.TYPE_STRING) {
 246  4
             result = new IllegalArgumentException(
 247  
                     ErrorMessage.WMA_ONLY_STRING_IN_CD.getMsg());
 248  
         }
 249  49531
         return result;
 250  
     }
 251  
 
 252  
     /**
 253  
      * @return the containerGUID
 254  
      */
 255  
     public GUID getContainerGUID() {
 256  7357
         return this.containerGUID;
 257  
     }
 258  
 
 259  
     /**
 260  
      * @return the maximumDataLength
 261  
      */
 262  
     public BigInteger getMaximumDataLength() {
 263  76
         return this.maximumDataLength;
 264  
     }
 265  
 
 266  
     /**
 267  
      * @return the guidEnabled
 268  
      */
 269  
     public boolean isGuidEnabled() {
 270  803
         return this.guidEnabled;
 271  
     }
 272  
 
 273  
     /**
 274  
      * @return the languageEnabled
 275  
      */
 276  
     public boolean isLanguageEnabled() {
 277  1152
         return this.languageEnabled;
 278  
     }
 279  
 
 280  
     /**
 281  
      * Tests if the given value is less than or equal to
 282  
      * {@link #getMaximumDataLength()}, and greater or equal to zero.<br>
 283  
      * 
 284  
      * @param value
 285  
      *            The value to test
 286  
      * @return <code>true</code> if size restrictions for binary data are met
 287  
      *         with this container type.
 288  
      */
 289  
     public boolean isWithinValueRange(final long value) {
 290  58969
         return (this.perfMaxDataLen == -1 || this.perfMaxDataLen >= value)
 291  
                 && value >= 0;
 292  
     }
 293  
 
 294  
     /**
 295  
      * @return the multiValued
 296  
      */
 297  
     public boolean isMultiValued() {
 298  17913
         return this.multiValued;
 299  
     }
 300  
 
 301  
     /**
 302  
      * @return the streamEnabled
 303  
      */
 304  
     public boolean isStreamNumberEnabled() {
 305  50179
         return this.streamEnabled;
 306  
     }
 307  
 }