package org.jaudiotagger.audio.asf.io;
import org.jaudiotagger.audio.asf.data.*;
import org.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.<br>
*
* @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).<br>
* All other bytes must be zero. (if assertions enabled).
*
* @param stream
* stream to read from.
* @param bytes
* amount of bytes
* @return <code>true</code> or <code>false</code>.
* @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;
}
}
|