2004-04-09 09:05:39 -04:00
|
|
|
/* ====================================================================
|
2006-12-22 14:18:16 -05:00
|
|
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
|
|
|
contributor license agreements. See the NOTICE file distributed with
|
|
|
|
this work for additional information regarding copyright ownership.
|
|
|
|
The ASF licenses this file to You 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
|
2004-04-09 09:05:39 -04:00
|
|
|
|
|
|
|
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.
|
|
|
|
==================================================================== */
|
2009-02-19 20:57:45 -05:00
|
|
|
|
2004-04-09 07:45:38 -04:00
|
|
|
package org.apache.poi.ddf;
|
|
|
|
|
2011-07-28 07:45:25 -04:00
|
|
|
import java.io.PrintWriter;
|
2004-04-09 07:45:38 -04:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Iterator;
|
|
|
|
import java.util.List;
|
2009-02-19 20:57:45 -05:00
|
|
|
import java.util.NoSuchElementException;
|
2011-07-28 07:45:25 -04:00
|
|
|
|
|
|
|
import org.apache.poi.util.HexDump;
|
|
|
|
import org.apache.poi.util.LittleEndian;
|
2004-04-09 07:45:38 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Escher container records store other escher records as children.
|
|
|
|
* The container records themselves never store any information beyond
|
|
|
|
* the standard header used by all escher records. This one record is
|
|
|
|
* used to represent many different types of records.
|
|
|
|
*
|
|
|
|
* @author Glen Stampoultzis
|
|
|
|
*/
|
2009-02-19 17:02:14 -05:00
|
|
|
public final class EscherContainerRecord extends EscherRecord {
|
2004-04-09 07:45:38 -04:00
|
|
|
public static final short DGG_CONTAINER = (short)0xF000;
|
|
|
|
public static final short BSTORE_CONTAINER = (short)0xF001;
|
|
|
|
public static final short DG_CONTAINER = (short)0xF002;
|
|
|
|
public static final short SPGR_CONTAINER = (short)0xF003;
|
|
|
|
public static final short SP_CONTAINER = (short)0xF004;
|
|
|
|
public static final short SOLVER_CONTAINER = (short)0xF005;
|
|
|
|
|
2009-02-19 14:50:20 -05:00
|
|
|
private final List<EscherRecord> _childRecords = new ArrayList<EscherRecord>();
|
2004-04-09 07:45:38 -04:00
|
|
|
|
2009-02-19 20:57:45 -05:00
|
|
|
public int fillFields(byte[] data, int pOffset, EscherRecordFactory recordFactory) {
|
|
|
|
int bytesRemaining = readHeader(data, pOffset);
|
2004-04-09 07:45:38 -04:00
|
|
|
int bytesWritten = 8;
|
2009-02-19 20:57:45 -05:00
|
|
|
int offset = pOffset + 8;
|
|
|
|
while (bytesRemaining > 0 && offset < data.length) {
|
2004-04-09 07:45:38 -04:00
|
|
|
EscherRecord child = recordFactory.createRecord(data, offset);
|
2009-02-19 20:57:45 -05:00
|
|
|
int childBytesWritten = child.fillFields(data, offset, recordFactory);
|
2004-04-09 07:45:38 -04:00
|
|
|
bytesWritten += childBytesWritten;
|
|
|
|
offset += childBytesWritten;
|
|
|
|
bytesRemaining -= childBytesWritten;
|
2009-02-19 17:02:14 -05:00
|
|
|
addChildRecord(child);
|
2009-02-19 20:57:45 -05:00
|
|
|
if (offset >= data.length && bytesRemaining > 0) {
|
2004-04-09 07:45:38 -04:00
|
|
|
System.out.println("WARNING: " + bytesRemaining + " bytes remaining but no space left");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return bytesWritten;
|
|
|
|
}
|
|
|
|
|
|
|
|
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());
|
|
|
|
int remainingBytes = 0;
|
2009-02-19 17:02:14 -05:00
|
|
|
Iterator<EscherRecord> iterator = _childRecords.iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
|
|
EscherRecord r = iterator.next();
|
2004-04-09 07:45:38 -04:00
|
|
|
remainingBytes += r.getRecordSize();
|
|
|
|
}
|
|
|
|
LittleEndian.putInt(data, offset+4, remainingBytes);
|
|
|
|
int pos = offset+8;
|
2009-02-19 17:02:14 -05:00
|
|
|
iterator = _childRecords.iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
|
|
EscherRecord r = iterator.next();
|
2004-04-09 07:45:38 -04:00
|
|
|
pos += r.serialize(pos, data, listener );
|
|
|
|
}
|
|
|
|
|
|
|
|
listener.afterRecordSerialize( pos, getRecordId(), pos - offset, this );
|
|
|
|
return pos - offset;
|
|
|
|
}
|
|
|
|
|
2009-02-19 17:02:14 -05:00
|
|
|
public int getRecordSize() {
|
2004-04-09 07:45:38 -04:00
|
|
|
int childRecordsSize = 0;
|
2009-02-19 17:02:14 -05:00
|
|
|
Iterator<EscherRecord> iterator = _childRecords.iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
|
|
EscherRecord r = iterator.next();
|
2004-04-09 07:45:38 -04:00
|
|
|
childRecordsSize += r.getRecordSize();
|
|
|
|
}
|
|
|
|
return 8 + childRecordsSize;
|
|
|
|
}
|
2009-02-19 20:57:45 -05:00
|
|
|
|
2008-01-15 11:31:29 -05:00
|
|
|
/**
|
|
|
|
* Do any of our (top level) children have the
|
|
|
|
* given recordId?
|
|
|
|
*/
|
|
|
|
public boolean hasChildOfType(short recordId) {
|
2009-02-19 17:02:14 -05:00
|
|
|
Iterator<EscherRecord> iterator = _childRecords.iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
|
|
EscherRecord r = iterator.next();
|
2008-01-15 11:31:29 -05:00
|
|
|
if(r.getRecordId() == recordId) {
|
2009-02-19 14:50:20 -05:00
|
|
|
return true;
|
2008-01-15 11:31:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2009-02-19 20:57:45 -05:00
|
|
|
public EscherRecord getChild( int index ) {
|
|
|
|
return _childRecords.get(index);
|
|
|
|
}
|
|
|
|
|
2008-01-15 11:31:29 -05:00
|
|
|
/**
|
2009-02-19 17:02:14 -05:00
|
|
|
* @return a copy of the list of all the child records of the container.
|
2008-01-15 11:31:29 -05:00
|
|
|
*/
|
2009-02-19 14:50:20 -05:00
|
|
|
public List<EscherRecord> getChildRecords() {
|
2009-02-19 17:02:14 -05:00
|
|
|
return new ArrayList<EscherRecord>(_childRecords);
|
2004-04-09 07:45:38 -04:00
|
|
|
}
|
2009-02-19 20:57:45 -05:00
|
|
|
|
|
|
|
public Iterator<EscherRecord> getChildIterator() {
|
|
|
|
return new ReadOnlyIterator(_childRecords);
|
|
|
|
}
|
|
|
|
private static final class ReadOnlyIterator implements Iterator<EscherRecord> {
|
|
|
|
private final List<EscherRecord> _list;
|
|
|
|
private int _index;
|
|
|
|
|
|
|
|
public ReadOnlyIterator(List<EscherRecord> list) {
|
|
|
|
_list = list;
|
|
|
|
_index = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean hasNext() {
|
|
|
|
return _index < _list.size();
|
|
|
|
}
|
|
|
|
public EscherRecord next() {
|
|
|
|
if (!hasNext()) {
|
|
|
|
throw new NoSuchElementException();
|
|
|
|
}
|
|
|
|
return _list.get(_index++);
|
|
|
|
}
|
|
|
|
public void remove() {
|
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
|
|
|
}
|
2009-02-19 17:02:14 -05:00
|
|
|
/**
|
|
|
|
* replaces the internal child list with the contents of the supplied <tt>childRecords</tt>
|
|
|
|
*/
|
|
|
|
public void setChildRecords(List<EscherRecord> childRecords) {
|
2009-02-19 20:57:45 -05:00
|
|
|
if (childRecords == _childRecords) {
|
|
|
|
throw new IllegalStateException("Child records private data member has escaped");
|
|
|
|
}
|
2009-02-19 17:02:14 -05:00
|
|
|
_childRecords.clear();
|
|
|
|
_childRecords.addAll(childRecords);
|
|
|
|
}
|
|
|
|
|
2009-02-19 20:57:45 -05:00
|
|
|
public boolean removeChildRecord(EscherRecord toBeRemoved) {
|
|
|
|
return _childRecords.remove(toBeRemoved);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-01-15 11:31:29 -05:00
|
|
|
/**
|
|
|
|
* Returns all of our children which are also
|
|
|
|
* EscherContainers (may be 0, 1, or vary rarely
|
|
|
|
* 2 or 3)
|
|
|
|
*/
|
2009-02-19 17:02:14 -05:00
|
|
|
public List<EscherContainerRecord> getChildContainers() {
|
|
|
|
List<EscherContainerRecord> containers = new ArrayList<EscherContainerRecord>();
|
|
|
|
Iterator<EscherRecord> iterator = _childRecords.iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
|
|
EscherRecord r = iterator.next();
|
2008-01-15 11:31:29 -05:00
|
|
|
if(r instanceof EscherContainerRecord) {
|
2009-02-19 20:57:45 -05:00
|
|
|
containers.add((EscherContainerRecord) r);
|
2008-01-15 11:31:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return containers;
|
|
|
|
}
|
2004-04-09 07:45:38 -04:00
|
|
|
|
2009-02-19 14:50:20 -05:00
|
|
|
public String getRecordName() {
|
|
|
|
switch (getRecordId()) {
|
2004-04-09 07:45:38 -04:00
|
|
|
case DGG_CONTAINER:
|
|
|
|
return "DggContainer";
|
|
|
|
case BSTORE_CONTAINER:
|
|
|
|
return "BStoreContainer";
|
|
|
|
case DG_CONTAINER:
|
|
|
|
return "DgContainer";
|
|
|
|
case SPGR_CONTAINER:
|
|
|
|
return "SpgrContainer";
|
|
|
|
case SP_CONTAINER:
|
|
|
|
return "SpContainer";
|
|
|
|
case SOLVER_CONTAINER:
|
|
|
|
return "SolverContainer";
|
|
|
|
default:
|
|
|
|
return "Container 0x" + HexDump.toHex(getRecordId());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-19 17:02:14 -05:00
|
|
|
public void display(PrintWriter w, int indent) {
|
|
|
|
super.display(w, indent);
|
|
|
|
for (Iterator<EscherRecord> iterator = _childRecords.iterator(); iterator.hasNext();)
|
2004-04-09 07:45:38 -04:00
|
|
|
{
|
2009-02-19 17:02:14 -05:00
|
|
|
EscherRecord escherRecord = iterator.next();
|
|
|
|
escherRecord.display(w, indent + 1);
|
2004-04-09 07:45:38 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-19 14:50:20 -05:00
|
|
|
public void addChildRecord(EscherRecord record) {
|
2009-02-19 20:57:45 -05:00
|
|
|
_childRecords.add(record);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addChildBefore(EscherRecord record, int insertBeforeRecordId) {
|
|
|
|
for (int i = 0; i < _childRecords.size(); i++) {
|
|
|
|
EscherRecord rec = _childRecords.get(i);
|
|
|
|
if(rec.getRecordId() == insertBeforeRecordId){
|
|
|
|
_childRecords.add(i++, record);
|
|
|
|
// TODO - keep looping? Do we expect multiple matches?
|
|
|
|
}
|
|
|
|
}
|
2004-04-09 07:45:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
public String toString()
|
|
|
|
{
|
|
|
|
String nl = System.getProperty( "line.separator" );
|
|
|
|
|
|
|
|
StringBuffer children = new StringBuffer();
|
2011-07-28 07:45:25 -04:00
|
|
|
if ( _childRecords.size() > 0 )
|
|
|
|
{
|
2004-04-09 07:45:38 -04:00
|
|
|
children.append( " children: " + nl );
|
2009-02-19 20:57:45 -05:00
|
|
|
|
2008-01-15 11:31:29 -05:00
|
|
|
int count = 0;
|
2011-07-28 07:45:25 -04:00
|
|
|
for ( Iterator<EscherRecord> iterator = _childRecords.iterator(); iterator
|
|
|
|
.hasNext(); )
|
2004-04-09 07:45:38 -04:00
|
|
|
{
|
2009-02-19 17:02:14 -05:00
|
|
|
EscherRecord record = iterator.next();
|
2011-07-28 07:45:25 -04:00
|
|
|
children.append( " Child " + count + ":" + nl );
|
|
|
|
String childResult = String.valueOf( record );
|
|
|
|
childResult = childResult.replaceAll( "\n", "\n " );
|
|
|
|
children.append( " " );
|
|
|
|
children.append( childResult );
|
|
|
|
children.append( nl );
|
2008-01-15 11:31:29 -05:00
|
|
|
count++;
|
2004-04-09 07:45:38 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-28 07:45:25 -04:00
|
|
|
return getClass().getName() + " (" + getRecordName() + "):" + nl
|
|
|
|
+ " isContainer: " + isContainerRecord() + nl
|
|
|
|
+ " options: 0x" + HexDump.toHex( getOptions() ) + nl
|
|
|
|
+ " recordId: 0x" + HexDump.toHex( getRecordId() ) + nl
|
|
|
|
+ " numchildren: " + _childRecords.size() + nl
|
|
|
|
+ children.toString();
|
2004-04-09 07:45:38 -04:00
|
|
|
}
|
|
|
|
|
2011-07-28 10:21:26 -04:00
|
|
|
public <T extends EscherRecord> T getChildById( short recordId )
|
|
|
|
{
|
|
|
|
for ( EscherRecord childRecord : _childRecords )
|
|
|
|
{
|
|
|
|
if ( childRecord.getRecordId() == recordId )
|
|
|
|
{
|
|
|
|
@SuppressWarnings( "unchecked" )
|
|
|
|
final T result = (T) childRecord;
|
|
|
|
return result;
|
|
|
|
}
|
2004-04-09 07:45:38 -04:00
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2008-09-07 12:30:35 -04:00
|
|
|
/**
|
|
|
|
* Recursively find records with the specified record ID
|
|
|
|
*
|
|
|
|
* @param out - list to store found records
|
|
|
|
*/
|
2009-02-19 17:02:14 -05:00
|
|
|
public void getRecordsById(short recordId, List<EscherRecord> out){
|
|
|
|
Iterator<EscherRecord> iterator = _childRecords.iterator();
|
|
|
|
while (iterator.hasNext()) {
|
|
|
|
EscherRecord r = iterator.next();
|
2008-09-09 02:58:35 -04:00
|
|
|
if(r instanceof EscherContainerRecord) {
|
|
|
|
EscherContainerRecord c = (EscherContainerRecord)r;
|
2008-09-07 12:30:35 -04:00
|
|
|
c.getRecordsById(recordId, out );
|
2008-09-09 02:58:35 -04:00
|
|
|
} else if (r.getRecordId() == recordId){
|
2009-02-19 17:02:14 -05:00
|
|
|
out.add(r);
|
2008-09-07 12:30:35 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-04-09 07:45:38 -04:00
|
|
|
}
|