diff --git a/src/java/org/apache/poi/ddf/EscherBitmapBlip.java b/src/java/org/apache/poi/ddf/EscherBitmapBlip.java new file mode 100644 index 0000000000..6222aeceb2 --- /dev/null +++ b/src/java/org/apache/poi/ddf/EscherBitmapBlip.java @@ -0,0 +1,139 @@ +package org.apache.poi.ddf; + +import org.apache.poi.util.HexDump; +import org.apache.poi.util.LittleEndian; + +import java.io.ByteArrayOutputStream; + +/** + * @author Glen Stampoultzis + * @version $Id$ + */ +public class EscherBitmapBlip + extends EscherBlipRecord +{ + public static final short RECORD_ID_JPEG = (short) 0xF018 + 5; + public static final short RECORD_ID_PNG = (short) 0xF018 + 6; + public static final short RECORD_ID_DIB = (short) 0xF018 + 7; + + private static final int HEADER_SIZE = 8; + + private byte[] field_1_UID; + private byte field_2_marker = (byte) 0xFF; + + + /** + * This method deserializes the record from a byte array. + * + * @param data The byte array containing the escher record information + * @param offset The starting offset into data. + * @param recordFactory May be null since this is not a container record. + * @return The number of bytes read from the byte array. + */ + public int fillFields( byte[] data, int offset, EscherRecordFactory recordFactory ) + { + int bytesAfterHeader = readHeader( data, offset ); + int pos = offset + HEADER_SIZE; + + field_1_UID = new byte[16]; + System.arraycopy( data, pos, field_1_UID, 0, 16 ); pos += 16; + field_2_marker = data[pos]; pos++; + + field_pictureData = new byte[bytesAfterHeader - 17]; + System.arraycopy( data, pos, field_pictureData, 0, field_pictureData.length ); + + return bytesAfterHeader + HEADER_SIZE; + } + + /** + * Serializes the record to an existing byte array. + * + * @param offset the offset within the byte array + * @param data the data array to serialize to + * @param listener a listener for begin and end serialization events. This + * is useful because the serialization is + * hierarchical/recursive and sometimes you need to be able + * break into that. + * @return the number of bytes written. + */ + public int serialize( int offset, byte[] data, EscherSerializationListener listener ) + { + listener.beforeRecordSerialize(offset, getRecordId(), this); + + LittleEndian.putShort( data, offset, getOptions() ); + LittleEndian.putShort( data, offset + 2, getRecordId() ); + LittleEndian.putInt( data, offset + 4, getRecordSize() - HEADER_SIZE ); + int pos = offset + HEADER_SIZE; + + System.arraycopy( field_1_UID, 0, data, pos, 16 ); + data[pos + 16] = field_2_marker; + System.arraycopy( field_pictureData, 0, data, pos + 17, field_pictureData.length ); + + listener.afterRecordSerialize(offset + getRecordSize(), getRecordId(), getRecordSize(), this); + return HEADER_SIZE + 16 + 1 + field_pictureData.length; + } + + /** + * Returns the number of bytes that are required to serialize this record. + * + * @return Number of bytes + */ + public int getRecordSize() + { + return 8 + 16 + 1 + field_pictureData.length; + } + + public byte[] getUID() + { + return field_1_UID; + } + + public void setUID( byte[] field_1_UID ) + { + this.field_1_UID = field_1_UID; + } + + public byte getMarker() + { + return field_2_marker; + } + + public void setMarker( byte field_2_marker ) + { + this.field_2_marker = field_2_marker; + } + + public byte[] getPicturedata() + { + return field_pictureData; + } + + public void setPictureData(byte[] pictureData) + { + field_pictureData = pictureData; + } + + public String toString() + { + String nl = System.getProperty( "line.separator" ); + + String extraData; + ByteArrayOutputStream b = new ByteArrayOutputStream(); + try + { + HexDump.dump( this.field_pictureData, 0, b, 0 ); + extraData = b.toString(); + } + catch ( Exception e ) + { + extraData = e.toString(); + } + return getClass().getName() + ":" + nl + + " RecordId: 0x" + HexDump.toHex( getRecordId() ) + nl + + " Options: 0x" + HexDump.toHex( getOptions() ) + nl + + " UID: 0x" + HexDump.toHex( field_1_UID ) + nl + + " Marker: 0x" + HexDump.toHex( field_2_marker ) + nl + + " Extra Data:" + nl + extraData; + } + +} diff --git a/src/java/org/apache/poi/hssf/model/DrawingManager2.java b/src/java/org/apache/poi/hssf/model/DrawingManager2.java new file mode 100644 index 0000000000..5efd53bd0f --- /dev/null +++ b/src/java/org/apache/poi/hssf/model/DrawingManager2.java @@ -0,0 +1,130 @@ +/* ==================================================================== + Copyright 2004 Apache Software Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hssf.model; + +import org.apache.poi.ddf.EscherDgRecord; +import org.apache.poi.ddf.EscherDggRecord; + +import java.util.List; +import java.util.ArrayList; + + +/** + * Provides utilities to manage drawing groups. + * + * @author Glen Stampoultzis (glens at apache.org) + */ +public class DrawingManager2 +{ + EscherDggRecord dgg; + List drawingGroups = new ArrayList( ); + + + public DrawingManager2( EscherDggRecord dgg ) + { + this.dgg = dgg; + } + + public EscherDgRecord createDgRecord() + { + EscherDgRecord dg = new EscherDgRecord(); + dg.setRecordId( EscherDgRecord.RECORD_ID ); + short dgId = findNewDrawingGroupId(); + dg.setOptions( (short) ( dgId << 4 ) ); + dg.setNumShapes( 0 ); + dg.setLastMSOSPID( -1 ); + drawingGroups.add(dg); + dgg.addCluster( dgId, 0 ); + dgg.setDrawingsSaved( dgg.getDrawingsSaved() + 1 ); + return dg; + } + + /** + * Allocates new shape id for the new drawing group id. + * + * @return a new shape id. + */ + public int allocateShapeId(short drawingGroupId) + { + dgg.setNumShapesSaved( dgg.getNumShapesSaved() + 1 ); + + // Add to existing cluster if space available + for (int i = 0; i < dgg.getFileIdClusters().length; i++) + { + EscherDggRecord.FileIdCluster c = dgg.getFileIdClusters()[i]; + if (c.getDrawingGroupId() == drawingGroupId && c.getNumShapeIdsUsed() != 1024) + { + int result = c.getNumShapeIdsUsed() + (1024 * (i+1)); + c.incrementShapeId(); + EscherDgRecord dg = getDrawingGroup(drawingGroupId); + dg.setNumShapes( dg.getNumShapes() + 1 ); + dg.setLastMSOSPID( result ); + if (result >= dgg.getShapeIdMax()) + dgg.setShapeIdMax( result + 1 ); + return result; + } + } + + // Create new cluster + dgg.addCluster( drawingGroupId, 0 ); + dgg.getFileIdClusters()[dgg.getFileIdClusters().length-1].incrementShapeId(); + EscherDgRecord dg = getDrawingGroup(drawingGroupId); + dg.setNumShapes( dg.getNumShapes() + 1 ); + int result = (1024 * dgg.getFileIdClusters().length); + dg.setLastMSOSPID( result ); + if (result >= dgg.getShapeIdMax()) + dgg.setShapeIdMax( result + 1 ); + return result; + } + + //////////// Non-public methods ///////////// + short findNewDrawingGroupId() + { + short dgId = 1; + while ( drawingGroupExists( dgId ) ) + dgId++; + return dgId; + } + + EscherDgRecord getDrawingGroup(int drawingGroupId) + { + return (EscherDgRecord) drawingGroups.get(drawingGroupId-1); + } + + boolean drawingGroupExists( short dgId ) + { + for ( int i = 0; i < dgg.getFileIdClusters().length; i++ ) + { + if ( dgg.getFileIdClusters()[i].getDrawingGroupId() == dgId ) + return true; + } + return false; + } + + int findFreeSPIDBlock() + { + int max = dgg.getShapeIdMax(); + int next = ( ( max / 1024 ) + 1 ) * 1024; + return next; + } + + public EscherDggRecord getDgg() + { + return dgg; + } + +} diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFPicture.java b/src/java/org/apache/poi/hssf/usermodel/HSSFPicture.java new file mode 100644 index 0000000000..7baf6d2fce --- /dev/null +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFPicture.java @@ -0,0 +1,39 @@ +package org.apache.poi.hssf.usermodel; + +/** + * Represents a escher picture. Eg. A GIF, JPEG etc... + * + * @author Glen Stampoultzis + * @version $Id$ + */ +public class HSSFPicture + extends HSSFSimpleShape +{ + public static final int PICTURE_TYPE_EMF = 0; // Windows Enhanced Metafile + public static final int PICTURE_TYPE_WMF = 1; // Windows Metafile + public static final int PICTURE_TYPE_PICT = 2; // Macintosh PICT + public static final int PICTURE_TYPE_JPEG = 3; // JFIF + public static final int PICTURE_TYPE_PNG = 4; // PNG + public static final int PICTURE_TYPE_DIB = 5; // Windows DIB + + int pictureIndex; + + /** + * Constructs a picture object. + */ + HSSFPicture( HSSFShape parent, HSSFAnchor anchor ) + { + super( parent, anchor ); + setShapeType(OBJECT_TYPE_PICTURE); + } + + public int getPictureIndex() + { + return pictureIndex; + } + + public void setPictureIndex( int pictureIndex ) + { + this.pictureIndex = pictureIndex; + } +} diff --git a/src/java/org/apache/poi/util/ArrayUtil.java b/src/java/org/apache/poi/util/ArrayUtil.java new file mode 100644 index 0000000000..1d05a5ff36 --- /dev/null +++ b/src/java/org/apache/poi/util/ArrayUtil.java @@ -0,0 +1,51 @@ +/* ==================================================================== + Copyright 2003-2004 Apache Software Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.util; + +/** + * Utility classes for dealing with arrays. + * + * @author Glen Stampoultzis + * @version $Id$ + */ +public class ArrayUtil +{ + /** + * This is really a debugging version of System.arraycopy(). + * Use it to provide better exception messages when copying arrays around. + * For production use it's better to use the original for speed. + */ + public static void arraycopy(byte[] src, int src_position, byte[] dst, int dst_position, int length) + { + if (src_position < 0) + throw new IllegalArgumentException("src_position was less than 0. Actual value " + src_position); + if (src_position >= src.length) + throw new IllegalArgumentException( "src_position was greater than src array size. Tried to write starting at position " + src_position + " but the array length is " + src.length ); + if (src_position + length > src.length) + throw new IllegalArgumentException("src_position + length would overrun the src array. Expected end at " + (src_position + length) + " actual end at " + src.length); + if (dst_position < 0) + throw new IllegalArgumentException("dst_position was less than 0. Actual value " + dst_position); + if (dst_position >= dst.length) + throw new IllegalArgumentException( "dst_position was greater than dst array size. Tried to write starting at position " + dst_position + " but the array length is " + dst.length ); + if (dst_position + length > dst.length) + throw new IllegalArgumentException("dst_position + length would overrun the dst array. Expected end at " + (dst_position + length) + " actual end at " + dst.length); + + System.arraycopy( src, src_position, dst, dst_position, length); + } + + +}