| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| ContainerType |
|
| 3.3333333333333335;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 "0" 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 | * "0"). | |
| 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 | } |