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:
parent
34b6794422
commit
63c571ca1f
150
src/scratchpad/src/org/apache/poi/hwpf/model/Field.java
Normal file
150
src/scratchpad/src/org/apache/poi/hwpf/model/Field.java
Normal 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() + " )";
|
||||
}
|
||||
}
|
@ -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 )
|
||||
{
|
||||
|
@ -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()] );
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user