blob: 342fcd38bd7c98feef53b3c4f2c82bd0a1ed0b5e [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2003, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
****************************************************************************/
package org.eclipse.gmf.runtime.draw2d.ui.render.awt.internal.svg.metafile;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.io.IOException;
import java.io.InputStream;
/**
* This class represents one record of a metafile. It contains the type of the
* record, the size of the record (in bytes) and all the data contained in the
* record excluding the type/size information (each record is prefixed with the
* size and type information).
* @author dhabib
*/
public class Record
{
private int m_size = 0;
private int m_type = 0;
private byte[] m_data = null;
/**
* Default constructor.
*/
protected Record()
{
// Nothing to initialize
}
/**
* Initializes a record with a specific type and size. Reads 'size' bytes from the input
* stream, but does not interpret the results.
* @throws IOException Thrown if there is an error in stream (end of stream encountered before all the data could be read)
*/
public Record( int type, int size, InputStream stream ) throws IOException
{
m_type = type;
m_size = size;
readData( stream );
}
/**
* @return The type of the record. See the EMR_ constants in EMFTranscoder.
*/
public int getType()
{
return m_type;
}
/**
* Sets the type of the record. Only derived classes are allowed to do this.
* @param type
*/
protected void setType( int type )
{
m_type = type;
}
/**
* @return The size of the record, excluding the size of the header.
*/
public int getSize()
{
return m_size;
}
/**
* Sets the size of the record. Only derived classes are allowed to do this.
* @param type
*/
protected void setSize( int size )
{
m_size = size;
}
protected void readData( InputStream stream ) throws IOException
{
m_data = new byte[ m_size ];
stream.read( m_data, 0, m_size );
}
/**
* Retrieves the DWORD at the specified offset. Returns a 'long' instead of an 'int' since
* DWORD's are not signed, but it only reads 4 bytes.
* @param offset Offset into the data where the DWORD resides.
* @return The DWORD at the specified location.
* @throws IOException Thrown if the offset plus the size of the DWORD is greater than the size of the data buffer.
*/
public long getDWORDAt( int offset ) throws IOException
{
long retval = 0;
if( offset <= m_size - 4 )
{
int byte1 = m_data[offset] & 0xff;
int byte2 = ( m_data[ offset + 1 ] & 0xff ) << 8;
int byte3 = ( m_data[ offset + 2 ] & 0xff ) << 16;
int byte4 = ( m_data[ offset + 3 ] & 0xff ) << 24;
retval = ( byte1 + byte2 + byte3 + byte4 ) & 0xffffffff;
}
else
{
throw new IOException( "Read beyond end of data" ); //$NON-NLS-1$
}
return retval;
}
/**
* Retrieves the integer at the specified offset.
* @param offset Offset into the data where the integer resides.
* @return The value at the specified location.
* @throws IOException Thrown if the offset plus the size of the integer is greater than the size of the data buffer.
*/
public int getIntAt( int offset ) throws IOException
{
int retval = 0;
if( offset <= m_size - 4 )
{
int byte1 = m_data[offset] & 0xff;
int byte2 = ( m_data[ offset + 1 ] & 0xff ) << 8;
int byte3 = ( m_data[ offset + 2 ] & 0xff ) << 16;
int byte4 = ( m_data[ offset + 3 ] & 0xff ) << 24;
retval = ( byte1 | byte2 | byte3 | byte4 );
}
else
{
throw new IOException( "Read beyond end of data" ); //$NON-NLS-1$
}
return retval;
}
/**
* Retrieves the short at the specified offset.
* @param offset Offset into the data where the short resides.
* @return The value at the specified location.
* @throws IOException Thrown if the offset plus the size of the short is greater than the size of the data buffer.
*/
public short getShortAt( int offset ) throws IOException
{
short retval = 0;
if( offset <= m_size - 2 )
{
int byte1 = m_data[offset] & 0xff;
int byte2 = ( m_data[ offset + 1 ] & 0xff ) << 8;
retval = (short)( byte2 & 0xffff );
retval |= (short)( byte1 & 0xff );
}
else
{
throw new IOException( "Read beyond end of data" ); //$NON-NLS-1$
}
return retval;
}
/**
* Retrieves the Color value at the specified offset. The color is a windows COLORREF, which is
* converted into an appropriate Java Color object.
* @param offset Offset into the data where the color resides.
* @return The value at the specified location.
* @throws IOException Thrown if the offset plus the size of the color is greater than the size of the data buffer.
*/
public Color getColorAt( int offset ) throws IOException
{
int colorref = (int) getDWORDAt( offset );
int red = colorref & 0xff;
int green = ( colorref & 0xff00 ) >> 8;
int blue = ( colorref & 0xff0000 ) >> 16;
//int flags = ( colorref & 0x3000000 ) >> 24;
return new Color( red, green, blue );
}
/**
* Retrieves the byte at the specified offset.
* @param offset Offset into the data where the byte resides.
* @return The value at the specified location.
* @throws IOException Thrown if the offset is greater than or equal to the size of the data buffer.
*/
public int getByteAt( int offset ) throws IOException
{
int retval = 0;
if( offset < m_size )
{
retval = m_data[ offset ] & 0xff;
}
else
{
throw new IOException( "Read beyond end of data" ); //$NON-NLS-1$
}
return retval;
}
/**
* Retrieves the set of bytes at the specified offset.
* @param offset Offset into the data where the block of bytes begins
* @param count Number of bytes to retrieve
* @return An array containing the block of bytes.
* @throws IOException Thrown if the offset plus the count is greater thn the size of the data buffer.
*/
public byte[] getBytesAt( int offset, int count ) throws IOException
{
byte[] retval = null;
if( offset + count <= m_size )
{
retval = new byte[ count ];
for( int i = 0; i < count; i++ )
{
retval[ i ] = m_data[ offset + i ];
}
}
else
{
throw new IOException( "Read beyond end of data" ); //$NON-NLS-1$
}
return retval;
}
/**
* Retrieves a 'long Dimension' at the specified offset. That is, retrieves a Dimension that is stored
* in the data as two integers.
* @param offset Offset to the dimension in the data.
* @return A Dimension object with the value at the specified location.
* @throws IOException Thrown if the offset plus the size of the dimension is greater than the size of the data buffer.
*/
public Dimension getDimensionLAt( int offset ) throws IOException
{
int w = getIntAt( offset );
int h = getIntAt( offset + 4 );
return new Dimension( w, h );
}
/**
* Retrieves a 'short Dimension' at the specified offset. That is, retrieves a Dimension that is stored
* in the data as two shorts.
* @param offset Offset to the dimension in the data.
* @return A Dimension object with the value at the specified location.
* @throws IOException Thrown if the offset plus the size of the dimension is greater than the size of the data buffer.
*/
public Dimension getDimensionAt( int offset ) throws IOException
{
int w = getShortAt( offset );
int h = getShortAt( offset + 2 );
return new Dimension( w, h );
}
/**
* Retrieves a 'short Point' at the specified offset. That is, retrieves a Point that is stored
* in the data as two shorts.
* @param offset Offset to the point in the data.
* @return A Point object with the value at the specified location.
* @throws IOException Thrown if the offset plus the size of the point is greater than the size of the data buffer.
*/
public Point getPointAt( int offset ) throws IOException
{
int x = getShortAt( offset );
int y = getShortAt( offset + 2 );
return new Point( x, y );
}
/**
* Retrieves a 'long Point' at the specified offset. That is, retrieves a Point that is stored
* in the data as two integers.
* @param offset Offset to the point in the data.
* @return A Point object with the value at the specified location.
* @throws IOException Thrown if the offset plus the size of the point is greater than the size of the data buffer.
*/
public Point getPointLAt( int offset ) throws IOException
{
int x = getIntAt( offset );
int y = getIntAt( offset + 4 );
return new Point( x, y );
}
/**
* Retrieves a 'short Rectangle' at the specified offset. That is, retrieves a Rectangle that is stored
* in the data as four shorts.
* @param offset Offset to the rectangle in the data.
* @return A Rectangle object with the value at the specified location.
* @throws IOException Thrown if the offset plus the size of the Rectangle is greater than the size of the data buffer.
*/
public Rectangle getRectangeAt( int offset ) throws IOException
{
int x = getShortAt( offset );
int y = getShortAt( offset + 2 );
int w = getShortAt( offset + 4 );
int h = getShortAt( offset + 6 );
return new Rectangle( x, y, w, h );
}
/**
* Retrieves a 'long Rectangle' at the specified offset. That is, retrieves a Rectangle that is stored
* in the data as four integers.
* @param offset Offset to the rectangle in the data.
* @return A Rectangle object with the value at the specified location.
* @throws IOException Thrown if the offset plus the size of the Rectangle is greater than the size of the data buffer.
*/
public Rectangle getRectangleLAt( int offset ) throws IOException
{
int x = getIntAt( offset );
int y = getIntAt( offset + 4 );
int x1 = getIntAt( offset + 8 );
int y1 = getIntAt( offset + 12 );
int w = x1 - x;
int h = y1 - y;
return new Rectangle( x, y, w, h );
}
/**
* Retrieves a 2D scale/translate/rotate transform as a float[6] array.
* @param offset Offset to the transform in the data.
* @return A float[] with the value at the specified location.
* @throws IOException
*/
public float[] getTransformAt( int offset ) throws IOException
{
float[] xform = new float[6];
for (int i = 0; i < 6; ++i) {
xform[i] = getFloatAt( offset + i * 4);
}
return xform;
}
/**
* Retrieves the floating point value at the specified offset.
* @param offset Offset into the data where the float resides.
* @return The value at the specified location.
* @throws IOException Thrown if the offset plus the size of the float is greater than the size of the data buffer.
*/
public float getFloatAt( int offset ) throws IOException
{
int bits = (int) ( getDWORDAt( offset ) & 0xffffffff );
return Float.intBitsToFloat( bits );
}
/**
* Retrieves the set of characters at the specified offset.
* @param offset Offset into the data where the characters reside.
* @param numChars Number of characters to retrieve
* @return Array of characters at the specified location
* @throws IOException Thrown if the offset plus the (number of characters * 2) is greater than the size of the data buffer.
*/
public char[] getCharsAt( int offset, int numChars ) throws IOException
{
char [] retval = null;
if( offset + ( numChars * 2 ) < m_size )
{
retval = new char[ numChars ];
for( int index = 0; index < numChars; index++ )
{
char lowByte = (char) (m_data[ offset + ( index * 2 ) ] & 0xff);
char highByte = (char) (m_data[ offset + 1 + ( index * 2 ) ] & 0xff);
retval[ index ] = (char) (lowByte + (highByte << 8));
}
}
else
{
throw new IOException( "Read beyond end of data" ); //$NON-NLS-1$
}
return retval;
}
protected long readDWORD( InputStream stream ) throws IOException
{
int byte1 = stream.read();
int byte2 = stream.read();
int byte3 = stream.read();
int byte4 = stream.read();
int retval = byte1 +
(byte2 << 8) +
(byte3 << 16) +
(byte4 << 24);
return retval;
}
protected int readShort( InputStream stream ) throws IOException
{
int byte1 = stream.read();
int byte2 = stream.read();
int retval = byte1 +
(byte2 << 8);
return retval;
}
}