add user-friendly way to access field properties if char is a beginning of field

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1144336 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Sergey Vladimirov 2011-07-08 14:32:20 +00:00
parent 34b6794422
commit 63c571ca1f
5 changed files with 334 additions and 10 deletions

View File

@ -0,0 +1,150 @@
package org.apache.poi.hwpf.model;
import org.apache.poi.hwpf.usermodel.Range;
public class Field
{
private PlexOfField startPlex;
private PlexOfField separatorPlex;
private PlexOfField endPlex;
public Field( PlexOfField startPlex, PlexOfField separatorPlex,
PlexOfField endPlex )
{
if ( startPlex == null )
throw new IllegalArgumentException( "startPlex == null" );
if ( endPlex == null )
throw new IllegalArgumentException( "endPlex == null" );
if ( startPlex.getFld().getBoundaryType() != FieldDescriptor.FIELD_BEGIN_MARK )
throw new IllegalArgumentException( "startPlex (" + startPlex
+ ") is not type of FIELD_BEGIN" );
if ( separatorPlex != null
&& separatorPlex.getFld().getBoundaryType() != FieldDescriptor.FIELD_SEPARATOR_MARK )
throw new IllegalArgumentException( "separatorPlex" + separatorPlex
+ ") is not type of FIELD_SEPARATOR" );
if ( endPlex.getFld().getBoundaryType() != FieldDescriptor.FIELD_END_MARK )
throw new IllegalArgumentException( "endPlex (" + endPlex
+ ") is not type of FIELD_END" );
this.startPlex = startPlex;
this.separatorPlex = separatorPlex;
this.endPlex = endPlex;
}
public int getStartOffset()
{
return startPlex.getFcStart();
}
public int getEndOffset()
{
return endPlex.getFcEnd();
}
public boolean hasSeparator()
{
return separatorPlex != null;
}
public int getSeparatorOffset()
{
return separatorPlex.getFcStart();
}
public int getType()
{
return startPlex.getFld().getFieldType();
}
public boolean isZombieEmbed()
{
return endPlex.getFld().isFZombieEmbed();
}
public boolean isResultDirty()
{
return endPlex.getFld().isFResultDirty();
}
public boolean isResultEdited()
{
return endPlex.getFld().isFResultEdited();
}
public boolean isLocked()
{
return endPlex.getFld().isFLocked();
}
public boolean isPrivateResult()
{
return endPlex.getFld().isFPrivateResult();
}
public boolean isNested()
{
return endPlex.getFld().isFNested();
}
public boolean isHasSep()
{
return endPlex.getFld().isFHasSep();
}
public Range firstSubrange( Range parent )
{
if ( hasSeparator() )
{
if ( getStartOffset() + 1 == getSeparatorOffset() )
return null;
return new Range( getStartOffset() + 1, getSeparatorOffset(),
parent )
{
@Override
public String toString()
{
return "FieldSubrange1 (" + super.toString() + ")";
}
};
}
if ( getStartOffset() + 1 == getEndOffset() )
return null;
return new Range( getStartOffset() + 1, getEndOffset(), parent )
{
@Override
public String toString()
{
return "FieldSubrange1 (" + super.toString() + ")";
}
};
}
public Range secondSubrange( Range parent )
{
if ( !hasSeparator() || getSeparatorOffset() + 1 == getEndOffset() )
return null;
return new Range( getSeparatorOffset() + 1, getEndOffset(), parent )
{
@Override
public String toString()
{
return "FieldSubrange2 (" + super.toString() + ")";
}
};
}
@Override
public String toString()
{
return "Field [" + getStartOffset() + "; " + getEndOffset()
+ "] (type: 0x" + Integer.toHexString( getType() ) + " = "
+ getType() + " )";
}
}

View File

@ -21,7 +21,11 @@ package org.apache.poi.hwpf.model;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.poi.hwpf.model.io.HWPFOutputStream;
@ -33,6 +37,21 @@ import org.apache.poi.hwpf.model.io.HWPFOutputStream;
*/
public class FieldsTables
{
private static final byte[] BYTES_EMPTY = new byte[0];
private static final class GenericPropertyNodeComparator implements
Comparator<GenericPropertyNode>
{
public int compare( GenericPropertyNode o1, GenericPropertyNode o2 )
{
int thisVal = o1.getStart();
int anotherVal = o2.getStart();
return thisVal < anotherVal ? -1 : thisVal == anotherVal ? 0 : 1;
}
}
private GenericPropertyNodeComparator comparator = new GenericPropertyNodeComparator();
/**
* annotation subdocument
*/
@ -65,18 +84,163 @@ public class FieldsTables
// The size in bytes of the FLD data structure
private static final int FLD_SIZE = 2;
private HashMap<Integer, PlexOfCps> _tables;
private Map<Integer, PlexOfCps> _tables;
private Map<Integer, Map<Integer, Field>> _fieldsByOffset;
public FieldsTables( byte[] tableStream, FileInformationBlock fib )
{
_tables = new HashMap<Integer, PlexOfCps>();
_tables = new HashMap<Integer, PlexOfCps>( PLCFFLDTXBX - PLCFFLDATN + 1 );
_fieldsByOffset = new HashMap<Integer, Map<Integer, Field>>(
PLCFFLDTXBX - PLCFFLDATN + 1 );
for ( int i = PLCFFLDATN; i <= PLCFFLDTXBX; i++ )
{
_tables.put( Integer.valueOf( i ), readPLCF( tableStream, fib, i ) );
final PlexOfCps plexOfCps = readPLCF( tableStream, fib, i );
_fieldsByOffset.put( Integer.valueOf( i ),
parseFieldStructure( plexOfCps ) );
_tables.put( Integer.valueOf( i ), plexOfCps );
}
}
private Map<Integer, Field> parseFieldStructure( PlexOfCps plexOfCps )
{
if (plexOfCps == null)
return new HashMap<Integer, Field>();
GenericPropertyNode[] nodes = plexOfCps.toPropertiesArray();
Arrays.sort( nodes, comparator );
List<Field> fields = new ArrayList<Field>( nodes.length / 3 + 1 );
parseFieldStructureImpl( nodes, 0, nodes.length, fields );
HashMap<Integer, Field> result = new HashMap<Integer, Field>(
fields.size() );
for ( Field field : fields )
{
result.put( Integer.valueOf( field.getStartOffset() ), field );
}
return result;
}
private void parseFieldStructureImpl( GenericPropertyNode[] nodes,
int startOffsetInclusive, int endOffsetExclusive, List<Field> result )
{
int next = startOffsetInclusive;
while ( next < endOffsetExclusive )
{
GenericPropertyNode startNode = nodes[next];
PlexOfField startPlexOfField = new PlexOfField( startNode );
if ( startPlexOfField.getFld().getBoundaryType() != FieldDescriptor.FIELD_BEGIN_MARK )
{
/* Start mark seems to be missing */
next++;
continue;
}
/*
* we have start node. end offset points to next node, separator or
* end
*/
int nextNodePositionInArray = Arrays.binarySearch(
nodes,
next + 1,
endOffsetExclusive,
new GenericPropertyNode( startNode.getEnd(), startNode
.getEnd() + 1, BYTES_EMPTY ), comparator );
if ( nextNodePositionInArray < 0 )
{
/*
* too bad, this start field mark doesn't have corresponding end
* field mark or separator field mark in fields table
*/
next++;
continue;
}
GenericPropertyNode nextNode = nodes[nextNodePositionInArray];
PlexOfField nextPlexOfField = new PlexOfField( nextNode );
switch ( nextPlexOfField.getFld().getBoundaryType() )
{
case FieldDescriptor.FIELD_SEPARATOR_MARK:
{
GenericPropertyNode separatorNode = nextNode;
PlexOfField separatorPlexOfField = nextPlexOfField;
int endNodePositionInArray = Arrays.binarySearch( nodes,
nextNodePositionInArray, endOffsetExclusive,
new GenericPropertyNode( separatorNode.getEnd(),
separatorNode.getEnd() + 1, BYTES_EMPTY ),
comparator );
if ( endNodePositionInArray < 0 )
{
/*
* too bad, this separator field mark doesn't have
* corresponding end field mark in fields table
*/
next++;
continue;
}
GenericPropertyNode endNode = nodes[endNodePositionInArray];
PlexOfField endPlexOfField = new PlexOfField( endNode );
Field field = new Field( startPlexOfField,
separatorPlexOfField, endPlexOfField );
result.add( field );
// adding included fields
if ( startNode.getStart() + 1 < separatorNode.getStart() - 1 )
{
parseFieldStructureImpl( nodes, next + 1,
nextNodePositionInArray, result );
}
if ( separatorNode.getStart() + 1 < endNode.getStart() - 1 )
{
parseFieldStructureImpl( nodes,
nextNodePositionInArray + 1,
endNodePositionInArray, result );
}
next = endNodePositionInArray + 1;
break;
}
case FieldDescriptor.FIELD_END_MARK:
{
// we have no separator
Field field = new Field( startPlexOfField, null,
nextPlexOfField );
result.add( field );
// adding included fields
if ( startNode.getStart() + 1 < nextNode.getStart() - 1 )
{
parseFieldStructureImpl( nodes, next + 1,
nextNodePositionInArray, result );
}
next = nextNodePositionInArray + 1;
break;
}
case FieldDescriptor.FIELD_BEGIN_MARK:
default:
{
/* something is wrong, ignoring this mark along with start mark */
next++;
continue;
}
}
}
}
public Field lookupFieldByStartOffset( int documentPart, int offset )
{
Map<Integer, Field> map = _fieldsByOffset.get( Integer
.valueOf( documentPart ) );
if ( map == null || map.isEmpty() )
return null;
return map.get( Integer.valueOf( offset ) );
}
private PlexOfCps readPLCF( byte[] tableStream, FileInformationBlock fib,
int type )
{

View File

@ -146,4 +146,12 @@ public final class PlexOfCps
{
return ( 4 * ( _iMac + 1 ) ) + ( _cbStruct * index );
}
GenericPropertyNode[] toPropertiesArray()
{
if ( _props == null || _props.isEmpty() )
return new GenericPropertyNode[0];
return _props.toArray( new GenericPropertyNode[_props.size()] );
}
}

View File

@ -17,12 +17,13 @@
package org.apache.poi.hwpf.model;
import junit.framework.*;
import org.apache.poi.hwpf.*;
import java.lang.reflect.*;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.Arrays;
import junit.framework.TestCase;
import org.apache.poi.hwpf.HWPFDocFixture;
public final class TestDocumentProperties
extends TestCase
{

View File

@ -17,10 +17,11 @@
package org.apache.poi.hwpf.model;
import junit.framework.*;
import org.apache.poi.hwpf.*;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.*;
import junit.framework.TestCase;
import org.apache.poi.hwpf.HWPFDocFixture;
public final class TestFileInformationBlock
extends TestCase