Coverage Report - org.jaudiotagger.audio.asf.io.MetadataReader
 
Classes in this File Line Coverage Branch Coverage Complexity
MetadataReader
93%
57/61
60%
58/96
6.75
 
 1  
 package org.jaudiotagger.audio.asf.io;
 2  
 
 3  
 import org.jaudiotagger.audio.asf.data.*;
 4  
 import org.jaudiotagger.audio.asf.util.Utils;
 5  
 
 6  
 import java.io.IOException;
 7  
 import java.io.InputStream;
 8  
 import java.math.BigInteger;
 9  
 
 10  
 /**
 11  
  * Reads an interprets "Metadata Object", "Metadata Library
 12  
  * Object&quot; and &quot;Extended Content Description&quot; of ASF files.<br>
 13  
  * 
 14  
  * @author Christian Laireiter
 15  
  */
 16  32
 public class MetadataReader implements ChunkReader {
 17  
 
 18  
     /**
 19  
      * The GUID this reader {@linkplain #getApplyingIds() applies to}
 20  
      */
 21  4
     private final static GUID[] APPLYING = {
 22  
             ContainerType.EXTENDED_CONTENT.getContainerGUID(),
 23  
             ContainerType.METADATA_OBJECT.getContainerGUID(),
 24  
             ContainerType.METADATA_LIBRARY_OBJECT.getContainerGUID() };
 25  
 
 26  
     /**
 27  
      * {@inheritDoc}
 28  
      */
 29  
     public boolean canFail() {
 30  481
         return false;
 31  
     }
 32  
 
 33  
     /**
 34  
      * {@inheritDoc}
 35  
      */
 36  
     public GUID[] getApplyingIds() {
 37  24
         return APPLYING.clone();
 38  
     }
 39  
 
 40  
     /**
 41  
      * {@inheritDoc}
 42  
      */
 43  
     public Chunk read(final GUID guid, final InputStream stream,
 44  
             final long streamPosition) throws IOException {
 45  489
         final BigInteger chunkLen = Utils.readBig64(stream);
 46  
 
 47  489
         final MetadataContainer result = new MetadataContainer(guid,
 48  
                 streamPosition, chunkLen);
 49  
         // isExtDesc will be set to true, if a extended content description
 50  
         // chunk is read
 51  
         // otherwise it is a metadata object, there are only slight differences
 52  489
         final boolean isExtDesc = result.getContainerType() == ContainerType.EXTENDED_CONTENT;
 53  489
         final int recordCount = Utils.readUINT16(stream);
 54  8466
         for (int i = 0; i < recordCount; i++) {
 55  7977
             int languageIndex = 0;
 56  7977
             int streamNumber = 0;
 57  7977
             if (!isExtDesc) {
 58  
                 /*
 59  
                  * Metadata objects have a language index and a stream number
 60  
                  */
 61  854
                 languageIndex = Utils.readUINT16(stream);
 62  854
                 assert languageIndex >= 0
 63  
                         && languageIndex < MetadataDescriptor.MAX_LANG_INDEX;
 64  854
                 assert result.getContainerType() == ContainerType.METADATA_LIBRARY_OBJECT
 65  
                         || languageIndex == 0;
 66  854
                 streamNumber = Utils.readUINT16(stream);
 67  854
                 assert streamNumber >= 0
 68  
                         && streamNumber <= MetadataDescriptor.MAX_STREAM_NUMBER;
 69  
             }
 70  7977
             final int nameLen = Utils.readUINT16(stream);
 71  7977
             String recordName = null;
 72  7977
             if (isExtDesc) {
 73  7123
                 recordName = Utils.readFixedSizeUTF16Str(stream, nameLen);
 74  
             }
 75  7977
             final int dataType = Utils.readUINT16(stream);
 76  7977
             assert dataType >= 0 && dataType <= 6;
 77  7977
             final long dataLen = isExtDesc ? Utils.readUINT16(stream) : Utils
 78  
                     .readUINT32(stream);
 79  7977
             assert dataLen >= 0;
 80  7977
             assert result.getContainerType() == ContainerType.METADATA_LIBRARY_OBJECT
 81  
                     || dataLen <= MetadataDescriptor.DWORD_MAXVALUE;
 82  7977
             if (!isExtDesc) {
 83  854
                 recordName = Utils.readFixedSizeUTF16Str(stream, nameLen);
 84  
             }
 85  7977
             final MetadataDescriptor descriptor = new MetadataDescriptor(result
 86  
                     .getContainerType(), recordName, dataType, streamNumber,
 87  
                     languageIndex);
 88  7977
             switch (dataType) {
 89  
             case MetadataDescriptor.TYPE_STRING:
 90  6734
                 descriptor.setStringValue(Utils.readFixedSizeUTF16Str(stream,
 91  
                         (int) dataLen));
 92  6734
                 break;
 93  
             case MetadataDescriptor.TYPE_BINARY:
 94  162
                 descriptor.setBinaryValue(Utils.readBinary(stream, dataLen));
 95  162
                 break;
 96  
             case MetadataDescriptor.TYPE_BOOLEAN:
 97  398
                 assert isExtDesc && dataLen == 4 || !isExtDesc && dataLen == 2;
 98  398
                 descriptor.setBooleanValue(readBoolean(stream, (int) dataLen));
 99  398
                 break;
 100  
             case MetadataDescriptor.TYPE_DWORD:
 101  641
                 assert dataLen == 4;
 102  641
                 descriptor.setDWordValue(Utils.readUINT32(stream));
 103  641
                 break;
 104  
             case MetadataDescriptor.TYPE_WORD:
 105  0
                 assert dataLen == 2;
 106  0
                 descriptor.setWordValue(Utils.readUINT16(stream));
 107  0
                 break;
 108  
             case MetadataDescriptor.TYPE_QWORD:
 109  11
                 assert dataLen == 8;
 110  11
                 descriptor.setQWordValue(Utils.readUINT64(stream));
 111  11
                 break;
 112  
             case MetadataDescriptor.TYPE_GUID:
 113  31
                 assert dataLen == GUID.GUID_LENGTH;
 114  31
                 descriptor.setGUIDValue(Utils.readGUID(stream));
 115  31
                 break;
 116  
             default:
 117  
                 // Unknown, hopefully the convention for the size of the
 118  
                 // value
 119  
                 // is given, so we could read it binary
 120  0
                 descriptor.setStringValue("Invalid datatype: "
 121  
                         + new String(Utils.readBinary(stream, dataLen)));
 122  
             }
 123  7977
             result.addDescriptor(descriptor);
 124  
         }
 125  489
         return result;
 126  
     }
 127  
 
 128  
     /**
 129  
      * Reads the given amount of bytes and checks the last byte, if its equal to
 130  
      * one or zero (true / false).<br>
 131  
      * All other bytes must be zero. (if assertions enabled).
 132  
      * 
 133  
      * @param stream
 134  
      *            stream to read from.
 135  
      * @param bytes
 136  
      *            amount of bytes
 137  
      * @return <code>true</code> or <code>false</code>.
 138  
      * @throws IOException
 139  
      *             on I/O Errors
 140  
      */
 141  
     private boolean readBoolean(final InputStream stream, final int bytes)
 142  
             throws IOException {
 143  398
         final byte[] tmp = new byte[bytes];
 144  398
         stream.read(tmp);
 145  398
         boolean result = false;
 146  1592
         for (int i = 0; i < bytes; i++) {
 147  1194
             if (i == bytes - 1) {
 148  398
                 result = tmp[i] == 1;
 149  398
                 assert tmp[i] == 0 || tmp[i] == 1;
 150  
             } else {
 151  796
                 assert tmp[i] == 0;
 152  
             }
 153  
         }
 154  398
         return result;
 155  
     }
 156  
 
 157  
 }