mirror of https://github.com/apache/poi.git
move Field interface to usermodel and create Fields interface as user-friendly replace for FieldsTables
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1149704 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
7aaa047ff6
commit
e0e44fee69
|
@ -52,6 +52,9 @@ import org.apache.poi.hwpf.model.io.HWPFFileSystem;
|
||||||
import org.apache.poi.hwpf.model.io.HWPFOutputStream;
|
import org.apache.poi.hwpf.model.io.HWPFOutputStream;
|
||||||
import org.apache.poi.hwpf.usermodel.Bookmarks;
|
import org.apache.poi.hwpf.usermodel.Bookmarks;
|
||||||
import org.apache.poi.hwpf.usermodel.BookmarksImpl;
|
import org.apache.poi.hwpf.usermodel.BookmarksImpl;
|
||||||
|
import org.apache.poi.hwpf.usermodel.Field;
|
||||||
|
import org.apache.poi.hwpf.usermodel.Fields;
|
||||||
|
import org.apache.poi.hwpf.usermodel.FieldsImpl;
|
||||||
import org.apache.poi.hwpf.usermodel.HWPFList;
|
import org.apache.poi.hwpf.usermodel.HWPFList;
|
||||||
import org.apache.poi.hwpf.usermodel.Notes;
|
import org.apache.poi.hwpf.usermodel.Notes;
|
||||||
import org.apache.poi.hwpf.usermodel.NotesImpl;
|
import org.apache.poi.hwpf.usermodel.NotesImpl;
|
||||||
|
@ -60,6 +63,7 @@ import org.apache.poi.poifs.common.POIFSConstants;
|
||||||
import org.apache.poi.poifs.filesystem.DirectoryNode;
|
import org.apache.poi.poifs.filesystem.DirectoryNode;
|
||||||
import org.apache.poi.poifs.filesystem.DocumentEntry;
|
import org.apache.poi.poifs.filesystem.DocumentEntry;
|
||||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||||
|
import org.apache.poi.util.Internal;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -129,6 +133,9 @@ public final class HWPFDocument extends HWPFDocumentCore
|
||||||
/** Holds the fields PLCFs */
|
/** Holds the fields PLCFs */
|
||||||
protected FieldsTables _fieldsTables;
|
protected FieldsTables _fieldsTables;
|
||||||
|
|
||||||
|
/** Holds the fields */
|
||||||
|
protected Fields _fields;
|
||||||
|
|
||||||
protected HWPFDocument()
|
protected HWPFDocument()
|
||||||
{
|
{
|
||||||
super();
|
super();
|
||||||
|
@ -296,6 +303,7 @@ public final class HWPFDocument extends HWPFDocumentCore
|
||||||
_footnotes = new NotesImpl( _footnotesTables );
|
_footnotes = new NotesImpl( _footnotesTables );
|
||||||
|
|
||||||
_fieldsTables = new FieldsTables(_tableStream, _fib);
|
_fieldsTables = new FieldsTables(_tableStream, _fib);
|
||||||
|
_fields = new FieldsImpl(_fieldsTables);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextPieceTable getTextTable()
|
public TextPieceTable getTextTable()
|
||||||
|
@ -510,11 +518,24 @@ public final class HWPFDocument extends HWPFDocumentCore
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return FieldsTables object, that is able to extract fields descriptors from this document
|
* @return FieldsTables object, that is able to extract fields descriptors from this document
|
||||||
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
|
@Internal
|
||||||
public FieldsTables getFieldsTables() {
|
public FieldsTables getFieldsTables() {
|
||||||
return _fieldsTables;
|
return _fieldsTables;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns user-friendly interface to access document {@link Field}s
|
||||||
|
*
|
||||||
|
* @return user-friendly interface to access document {@link Field}s
|
||||||
|
*/
|
||||||
|
public Fields getFields()
|
||||||
|
{
|
||||||
|
return _fields;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes out the word file that is represented by an instance of this class.
|
* Writes out the word file that is represented by an instance of this class.
|
||||||
*
|
*
|
||||||
|
|
|
@ -29,12 +29,12 @@ import org.apache.poi.hpsf.SummaryInformation;
|
||||||
import org.apache.poi.hwpf.HWPFDocument;
|
import org.apache.poi.hwpf.HWPFDocument;
|
||||||
import org.apache.poi.hwpf.HWPFDocumentCore;
|
import org.apache.poi.hwpf.HWPFDocumentCore;
|
||||||
import org.apache.poi.hwpf.converter.FontReplacer.Triplet;
|
import org.apache.poi.hwpf.converter.FontReplacer.Triplet;
|
||||||
import org.apache.poi.hwpf.model.Field;
|
|
||||||
import org.apache.poi.hwpf.model.FieldsDocumentPart;
|
import org.apache.poi.hwpf.model.FieldsDocumentPart;
|
||||||
import org.apache.poi.hwpf.model.ListFormatOverride;
|
import org.apache.poi.hwpf.model.ListFormatOverride;
|
||||||
import org.apache.poi.hwpf.model.ListTables;
|
import org.apache.poi.hwpf.model.ListTables;
|
||||||
import org.apache.poi.hwpf.usermodel.Bookmark;
|
import org.apache.poi.hwpf.usermodel.Bookmark;
|
||||||
import org.apache.poi.hwpf.usermodel.CharacterRun;
|
import org.apache.poi.hwpf.usermodel.CharacterRun;
|
||||||
|
import org.apache.poi.hwpf.usermodel.Field;
|
||||||
import org.apache.poi.hwpf.usermodel.Notes;
|
import org.apache.poi.hwpf.usermodel.Notes;
|
||||||
import org.apache.poi.hwpf.usermodel.Paragraph;
|
import org.apache.poi.hwpf.usermodel.Paragraph;
|
||||||
import org.apache.poi.hwpf.usermodel.Picture;
|
import org.apache.poi.hwpf.usermodel.Picture;
|
||||||
|
@ -229,9 +229,8 @@ public abstract class AbstractWordConverter
|
||||||
{
|
{
|
||||||
if ( document instanceof HWPFDocument )
|
if ( document instanceof HWPFDocument )
|
||||||
{
|
{
|
||||||
Field aliveField = ( (HWPFDocument) document )
|
Field aliveField = ( (HWPFDocument) document ).getFields()
|
||||||
.getFieldsTables().lookupFieldByStartOffset(
|
.getFieldByStartOffset( FieldsDocumentPart.MAIN,
|
||||||
FieldsDocumentPart.MAIN,
|
|
||||||
characterRun.getStartOffset() );
|
characterRun.getStartOffset() );
|
||||||
if ( aliveField != null )
|
if ( aliveField != null )
|
||||||
{
|
{
|
||||||
|
@ -453,7 +452,7 @@ public abstract class AbstractWordConverter
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
HWPFDocument hwpfDocument = (HWPFDocument) wordDocument;
|
HWPFDocument hwpfDocument = (HWPFDocument) wordDocument;
|
||||||
Field field = hwpfDocument.getFieldsTables().lookupFieldByStartOffset(
|
Field field = hwpfDocument.getFields().getFieldByStartOffset(
|
||||||
FieldsDocumentPart.MAIN, startOffset );
|
FieldsDocumentPart.MAIN, startOffset );
|
||||||
if ( field == null )
|
if ( field == null )
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -23,7 +23,6 @@ import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -46,6 +45,7 @@ import org.apache.poi.hwpf.model.StyleSheet;
|
||||||
import org.apache.poi.hwpf.model.TextPiece;
|
import org.apache.poi.hwpf.model.TextPiece;
|
||||||
import org.apache.poi.hwpf.sprm.SprmIterator;
|
import org.apache.poi.hwpf.sprm.SprmIterator;
|
||||||
import org.apache.poi.hwpf.sprm.SprmOperation;
|
import org.apache.poi.hwpf.sprm.SprmOperation;
|
||||||
|
import org.apache.poi.hwpf.usermodel.Field;
|
||||||
import org.apache.poi.hwpf.usermodel.Paragraph;
|
import org.apache.poi.hwpf.usermodel.Paragraph;
|
||||||
import org.apache.poi.hwpf.usermodel.Picture;
|
import org.apache.poi.hwpf.usermodel.Picture;
|
||||||
import org.apache.poi.hwpf.usermodel.Range;
|
import org.apache.poi.hwpf.usermodel.Range;
|
||||||
|
@ -311,7 +311,8 @@ public final class HWPFLister
|
||||||
for ( char c : text.toCharArray() )
|
for ( char c : text.toCharArray() )
|
||||||
{
|
{
|
||||||
if ( c < 30 )
|
if ( c < 30 )
|
||||||
stringBuilder.append( "\\0x" + Integer.toHexString( c ) );
|
stringBuilder
|
||||||
|
.append( "\\0x" + Integer.toHexString( c ) );
|
||||||
else
|
else
|
||||||
stringBuilder.append( c );
|
stringBuilder.append( c );
|
||||||
}
|
}
|
||||||
|
@ -340,8 +341,7 @@ public final class HWPFLister
|
||||||
for ( FieldsDocumentPart part : FieldsDocumentPart.values() )
|
for ( FieldsDocumentPart part : FieldsDocumentPart.values() )
|
||||||
{
|
{
|
||||||
System.out.println( "=== Document part: " + part + " ===" );
|
System.out.println( "=== Document part: " + part + " ===" );
|
||||||
for ( org.apache.poi.hwpf.model.Field field : document
|
for ( Field field : document.getFields().getFields( part ) )
|
||||||
.getFieldsTables().getFields( part ) )
|
|
||||||
{
|
{
|
||||||
System.out.println( field );
|
System.out.println( field );
|
||||||
}
|
}
|
||||||
|
@ -356,7 +356,7 @@ public final class HWPFLister
|
||||||
|
|
||||||
HWPFDocument doc = (HWPFDocument) _doc;
|
HWPFDocument doc = (HWPFDocument) _doc;
|
||||||
|
|
||||||
Field fMainStream = HWPFDocumentCore.class
|
java.lang.reflect.Field fMainStream = HWPFDocumentCore.class
|
||||||
.getDeclaredField( "_mainStream" );
|
.getDeclaredField( "_mainStream" );
|
||||||
fMainStream.setAccessible( true );
|
fMainStream.setAccessible( true );
|
||||||
byte[] mainStream = (byte[]) fMainStream.get( _doc );
|
byte[] mainStream = (byte[]) fMainStream.get( _doc );
|
||||||
|
|
|
@ -21,12 +21,7 @@ package org.apache.poi.hwpf.model;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.poi.hwpf.model.io.HWPFOutputStream;
|
import org.apache.poi.hwpf.model.io.HWPFOutputStream;
|
||||||
|
@ -79,70 +74,13 @@ public class FieldsTables
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static final int PLCFFLDTXBX = 6;
|
public static final int PLCFFLDTXBX = 6;
|
||||||
|
|
||||||
/**
|
|
||||||
* This is port and adaptation of Arrays.binarySearch from Java 6 (Apache
|
|
||||||
* Harmony).
|
|
||||||
*/
|
|
||||||
private static <T> int binarySearch( GenericPropertyNode[] array,
|
|
||||||
int startIndex, int endIndex, int requiredStartOffset )
|
|
||||||
{
|
|
||||||
checkIndexForBinarySearch( array.length, startIndex, endIndex );
|
|
||||||
|
|
||||||
int low = startIndex, mid = -1, high = endIndex - 1, result = 0;
|
|
||||||
while ( low <= high )
|
|
||||||
{
|
|
||||||
mid = ( low + high ) >>> 1;
|
|
||||||
int midStart = array[mid].getStart();
|
|
||||||
|
|
||||||
if ( midStart == requiredStartOffset )
|
|
||||||
{
|
|
||||||
return mid;
|
|
||||||
}
|
|
||||||
else if ( midStart < requiredStartOffset )
|
|
||||||
{
|
|
||||||
low = mid + 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
high = mid - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( mid < 0 )
|
|
||||||
{
|
|
||||||
int insertPoint = endIndex;
|
|
||||||
for ( int index = startIndex; index < endIndex; index++ )
|
|
||||||
{
|
|
||||||
if ( requiredStartOffset < array[index].getStart() )
|
|
||||||
{
|
|
||||||
insertPoint = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -insertPoint - 1;
|
|
||||||
}
|
|
||||||
return -mid - ( result >= 0 ? 1 : 2 );
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void checkIndexForBinarySearch( int length, int start,
|
|
||||||
int end )
|
|
||||||
{
|
|
||||||
if ( start > end )
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
if ( length < end || 0 > start )
|
|
||||||
{
|
|
||||||
throw new ArrayIndexOutOfBoundsException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ArrayList<PlexOfField> toArrayList( PlexOfCps plexOfCps )
|
private static ArrayList<PlexOfField> toArrayList( PlexOfCps plexOfCps )
|
||||||
{
|
{
|
||||||
if ( plexOfCps == null )
|
if ( plexOfCps == null )
|
||||||
return new ArrayList<PlexOfField>();
|
return new ArrayList<PlexOfField>();
|
||||||
|
|
||||||
ArrayList<PlexOfField> fields = new ArrayList<PlexOfField>();
|
ArrayList<PlexOfField> fields = new ArrayList<PlexOfField>(
|
||||||
fields.ensureCapacity( plexOfCps.length() );
|
plexOfCps.length() );
|
||||||
|
|
||||||
for ( int i = 0; i < plexOfCps.length(); i++ )
|
for ( int i = 0; i < plexOfCps.length(); i++ )
|
||||||
{
|
{
|
||||||
GenericPropertyNode propNode = plexOfCps.getProperty( i );
|
GenericPropertyNode propNode = plexOfCps.getProperty( i );
|
||||||
|
@ -153,37 +91,20 @@ public class FieldsTables
|
||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<FieldsDocumentPart, Map<Integer, Field>> _fieldsByOffset;
|
|
||||||
|
|
||||||
private Map<FieldsDocumentPart, PlexOfCps> _tables;
|
private Map<FieldsDocumentPart, PlexOfCps> _tables;
|
||||||
|
|
||||||
private GenericPropertyNodeComparator comparator = new GenericPropertyNodeComparator();
|
|
||||||
|
|
||||||
public FieldsTables( byte[] tableStream, FileInformationBlock fib )
|
public FieldsTables( byte[] tableStream, FileInformationBlock fib )
|
||||||
{
|
{
|
||||||
_tables = new HashMap<FieldsDocumentPart, PlexOfCps>(
|
_tables = new HashMap<FieldsDocumentPart, PlexOfCps>(
|
||||||
FieldsDocumentPart.values().length );
|
FieldsDocumentPart.values().length );
|
||||||
_fieldsByOffset = new HashMap<FieldsDocumentPart, Map<Integer, Field>>(
|
|
||||||
FieldsDocumentPart.values().length );
|
|
||||||
|
|
||||||
for ( FieldsDocumentPart part : FieldsDocumentPart.values() )
|
for ( FieldsDocumentPart part : FieldsDocumentPart.values() )
|
||||||
{
|
{
|
||||||
final PlexOfCps plexOfCps = readPLCF( tableStream, fib, part );
|
final PlexOfCps plexOfCps = readPLCF( tableStream, fib, part );
|
||||||
|
|
||||||
_fieldsByOffset.put( part, parseFieldStructure( plexOfCps ) );
|
|
||||||
_tables.put( part, plexOfCps );
|
_tables.put( part, plexOfCps );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Field> getFields( FieldsDocumentPart part )
|
|
||||||
{
|
|
||||||
Map<Integer, Field> map = _fieldsByOffset.get( part );
|
|
||||||
if ( map == null || map.isEmpty() )
|
|
||||||
return Collections.emptySet();
|
|
||||||
|
|
||||||
return Collections.unmodifiableCollection( map.values() );
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList<PlexOfField> getFieldsPLCF( FieldsDocumentPart part )
|
public ArrayList<PlexOfField> getFieldsPLCF( FieldsDocumentPart part )
|
||||||
{
|
{
|
||||||
return toArrayList( _tables.get( part ) );
|
return toArrayList( _tables.get( part ) );
|
||||||
|
@ -195,146 +116,6 @@ public class FieldsTables
|
||||||
return getFieldsPLCF( FieldsDocumentPart.values()[partIndex] );
|
return getFieldsPLCF( FieldsDocumentPart.values()[partIndex] );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Field lookupFieldByStartOffset( FieldsDocumentPart documentPart,
|
|
||||||
int offset )
|
|
||||||
{
|
|
||||||
Map<Integer, Field> map = _fieldsByOffset.get( documentPart );
|
|
||||||
if ( map == null || map.isEmpty() )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return map.get( Integer.valueOf( offset ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
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.getFieldStartOffset() ), 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 = binarySearch( nodes, next + 1,
|
|
||||||
endOffsetExclusive, startNode.getEnd() );
|
|
||||||
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 = binarySearch( nodes,
|
|
||||||
nextNodePositionInArray, endOffsetExclusive,
|
|
||||||
separatorNode.getEnd() );
|
|
||||||
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 );
|
|
||||||
|
|
||||||
if ( endPlexOfField.getFld().getBoundaryType() != FieldDescriptor.FIELD_END_MARK )
|
|
||||||
{
|
|
||||||
/* Not and ending mark */
|
|
||||||
next++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private PlexOfCps readPLCF( byte[] tableStream, FileInformationBlock fib,
|
private PlexOfCps readPLCF( byte[] tableStream, FileInformationBlock fib,
|
||||||
FieldsDocumentPart documentPart )
|
FieldsDocumentPart documentPart )
|
||||||
{
|
{
|
||||||
|
@ -377,14 +158,4 @@ public class FieldsTables
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
package org.apache.poi.hwpf.usermodel;
|
||||||
|
|
||||||
|
public interface Field
|
||||||
|
{
|
||||||
|
|
||||||
|
Range firstSubrange( Range parent );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return character position of first character after field (i.e.
|
||||||
|
* {@link #getMarkEndOffset()} + 1)
|
||||||
|
*/
|
||||||
|
int getFieldEndOffset();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return character position of first character in field (i.e.
|
||||||
|
* {@link #getFieldStartOffset()})
|
||||||
|
*/
|
||||||
|
int getFieldStartOffset();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return character position of end field mark
|
||||||
|
*/
|
||||||
|
int getMarkEndOffset();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return character position of separator field mark (if present,
|
||||||
|
* {@link NullPointerException} otherwise)
|
||||||
|
*/
|
||||||
|
int getMarkSeparatorOffset();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return character position of start field mark
|
||||||
|
*/
|
||||||
|
int getMarkStartOffset();
|
||||||
|
|
||||||
|
int getType();
|
||||||
|
|
||||||
|
boolean hasSeparator();
|
||||||
|
|
||||||
|
boolean isHasSep();
|
||||||
|
|
||||||
|
boolean isLocked();
|
||||||
|
|
||||||
|
boolean isNested();
|
||||||
|
|
||||||
|
boolean isPrivateResult();
|
||||||
|
|
||||||
|
boolean isResultDirty();
|
||||||
|
|
||||||
|
boolean isResultEdited();
|
||||||
|
|
||||||
|
boolean isZombieEmbed();
|
||||||
|
|
||||||
|
Range secondSubrange( Range parent );
|
||||||
|
}
|
|
@ -1,14 +1,38 @@
|
||||||
package org.apache.poi.hwpf.model;
|
/* ====================================================================
|
||||||
|
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
|
||||||
|
|
||||||
import org.apache.poi.hwpf.usermodel.Range;
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
public class Field
|
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.hwpf.usermodel;
|
||||||
|
|
||||||
|
import org.apache.poi.hwpf.model.FieldDescriptor;
|
||||||
|
import org.apache.poi.hwpf.model.PlexOfField;
|
||||||
|
import org.apache.poi.util.Internal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: document me
|
||||||
|
*
|
||||||
|
* @author Sergey Vladimirov (vlsergey {at} gmail {dot} com)
|
||||||
|
*/
|
||||||
|
@Internal
|
||||||
|
class FieldImpl implements Field
|
||||||
{
|
{
|
||||||
private PlexOfField endPlex;
|
private PlexOfField endPlex;
|
||||||
private PlexOfField separatorPlex;
|
private PlexOfField separatorPlex;
|
||||||
private PlexOfField startPlex;
|
private PlexOfField startPlex;
|
||||||
|
|
||||||
public Field( PlexOfField startPlex, PlexOfField separatorPlex,
|
public FieldImpl( PlexOfField startPlex, PlexOfField separatorPlex,
|
||||||
PlexOfField endPlex )
|
PlexOfField endPlex )
|
||||||
{
|
{
|
||||||
if ( startPlex == null )
|
if ( startPlex == null )
|
|
@ -0,0 +1,33 @@
|
||||||
|
/* ====================================================================
|
||||||
|
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
|
||||||
|
|
||||||
|
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.hwpf.usermodel;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.apache.poi.hwpf.model.FieldsDocumentPart;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User-friendly interface to access document {@link Field}s
|
||||||
|
*
|
||||||
|
* @author Sergey Vladimirov (vlsergey {at} gmail {dot} com)
|
||||||
|
*/
|
||||||
|
public interface Fields
|
||||||
|
{
|
||||||
|
Field getFieldByStartOffset( FieldsDocumentPart documentPart, int offset );
|
||||||
|
|
||||||
|
Collection<Field> getFields( FieldsDocumentPart part );
|
||||||
|
}
|
|
@ -0,0 +1,276 @@
|
||||||
|
/* ====================================================================
|
||||||
|
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
|
||||||
|
|
||||||
|
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.hwpf.usermodel;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.poi.hwpf.model.FieldDescriptor;
|
||||||
|
import org.apache.poi.hwpf.model.FieldsDocumentPart;
|
||||||
|
import org.apache.poi.hwpf.model.FieldsTables;
|
||||||
|
import org.apache.poi.hwpf.model.PlexOfField;
|
||||||
|
import org.apache.poi.util.Internal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation of {@link Field}
|
||||||
|
*
|
||||||
|
* @author Sergey Vladimirov (vlsergey {at} gmail {dot} com)
|
||||||
|
*/
|
||||||
|
@Internal
|
||||||
|
public class FieldsImpl implements Fields
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* This is port and adaptation of Arrays.binarySearch from Java 6 (Apache
|
||||||
|
* Harmony).
|
||||||
|
*/
|
||||||
|
private static <T> int binarySearch( List<PlexOfField> list,
|
||||||
|
int startIndex, int endIndex, int requiredStartOffset )
|
||||||
|
{
|
||||||
|
checkIndexForBinarySearch( list.size(), startIndex, endIndex );
|
||||||
|
|
||||||
|
int low = startIndex, mid = -1, high = endIndex - 1, result = 0;
|
||||||
|
while ( low <= high )
|
||||||
|
{
|
||||||
|
mid = ( low + high ) >>> 1;
|
||||||
|
int midStart = list.get( mid ).getFcStart();
|
||||||
|
|
||||||
|
if ( midStart == requiredStartOffset )
|
||||||
|
{
|
||||||
|
return mid;
|
||||||
|
}
|
||||||
|
else if ( midStart < requiredStartOffset )
|
||||||
|
{
|
||||||
|
low = mid + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
high = mid - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( mid < 0 )
|
||||||
|
{
|
||||||
|
int insertPoint = endIndex;
|
||||||
|
for ( int index = startIndex; index < endIndex; index++ )
|
||||||
|
{
|
||||||
|
if ( requiredStartOffset < list.get( index ).getFcStart() )
|
||||||
|
{
|
||||||
|
insertPoint = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -insertPoint - 1;
|
||||||
|
}
|
||||||
|
return -mid - ( result >= 0 ? 1 : 2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkIndexForBinarySearch( int length, int start,
|
||||||
|
int end )
|
||||||
|
{
|
||||||
|
if ( start > end )
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
if ( length < end || 0 > start )
|
||||||
|
{
|
||||||
|
throw new ArrayIndexOutOfBoundsException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<FieldsDocumentPart, Map<Integer, FieldImpl>> _fieldsByOffset;
|
||||||
|
|
||||||
|
private PlexOfFieldComparator comparator = new PlexOfFieldComparator();
|
||||||
|
|
||||||
|
public FieldsImpl( FieldsTables fieldsTables )
|
||||||
|
{
|
||||||
|
_fieldsByOffset = new HashMap<FieldsDocumentPart, Map<Integer, FieldImpl>>(
|
||||||
|
FieldsDocumentPart.values().length );
|
||||||
|
|
||||||
|
for ( FieldsDocumentPart part : FieldsDocumentPart.values() )
|
||||||
|
{
|
||||||
|
List<PlexOfField> plexOfCps = fieldsTables.getFieldsPLCF( part );
|
||||||
|
_fieldsByOffset.put( part, parseFieldStructure( plexOfCps ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Field> getFields( FieldsDocumentPart part )
|
||||||
|
{
|
||||||
|
Map<Integer, FieldImpl> map = _fieldsByOffset.get( part );
|
||||||
|
if ( map == null || map.isEmpty() )
|
||||||
|
return Collections.emptySet();
|
||||||
|
|
||||||
|
return Collections.<Field> unmodifiableCollection( map.values() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldImpl getFieldByStartOffset( FieldsDocumentPart documentPart,
|
||||||
|
int offset )
|
||||||
|
{
|
||||||
|
Map<Integer, FieldImpl> map = _fieldsByOffset.get( documentPart );
|
||||||
|
if ( map == null || map.isEmpty() )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return map.get( Integer.valueOf( offset ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<Integer, FieldImpl> parseFieldStructure(
|
||||||
|
List<PlexOfField> plexOfFields )
|
||||||
|
{
|
||||||
|
if ( plexOfFields == null || plexOfFields.isEmpty() )
|
||||||
|
return new HashMap<Integer, FieldImpl>();
|
||||||
|
|
||||||
|
Collections.sort( plexOfFields, comparator );
|
||||||
|
List<FieldImpl> fields = new ArrayList<FieldImpl>(
|
||||||
|
plexOfFields.size() / 3 + 1 );
|
||||||
|
parseFieldStructureImpl( plexOfFields, 0, plexOfFields.size(), fields );
|
||||||
|
|
||||||
|
HashMap<Integer, FieldImpl> result = new HashMap<Integer, FieldImpl>(
|
||||||
|
fields.size() );
|
||||||
|
for ( FieldImpl field : fields )
|
||||||
|
{
|
||||||
|
result.put( Integer.valueOf( field.getFieldStartOffset() ), field );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseFieldStructureImpl( List<PlexOfField> plexOfFields,
|
||||||
|
int startOffsetInclusive, int endOffsetExclusive,
|
||||||
|
List<FieldImpl> result )
|
||||||
|
{
|
||||||
|
int next = startOffsetInclusive;
|
||||||
|
while ( next < endOffsetExclusive )
|
||||||
|
{
|
||||||
|
PlexOfField startPlexOfField = plexOfFields.get( next );
|
||||||
|
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 nextNodePositionInList = binarySearch( plexOfFields, next + 1,
|
||||||
|
endOffsetExclusive, startPlexOfField.getFcEnd() );
|
||||||
|
if ( nextNodePositionInList < 0 )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* too bad, this start field mark doesn't have corresponding end
|
||||||
|
* field mark or separator field mark in fields table
|
||||||
|
*/
|
||||||
|
next++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PlexOfField nextPlexOfField = plexOfFields
|
||||||
|
.get( nextNodePositionInList );
|
||||||
|
|
||||||
|
switch ( nextPlexOfField.getFld().getBoundaryType() )
|
||||||
|
{
|
||||||
|
case FieldDescriptor.FIELD_SEPARATOR_MARK:
|
||||||
|
{
|
||||||
|
PlexOfField separatorPlexOfField = nextPlexOfField;
|
||||||
|
|
||||||
|
int endNodePositionInList = binarySearch( plexOfFields,
|
||||||
|
nextNodePositionInList, endOffsetExclusive,
|
||||||
|
separatorPlexOfField.getFcEnd() );
|
||||||
|
if ( endNodePositionInList < 0 )
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* too bad, this separator field mark doesn't have
|
||||||
|
* corresponding end field mark in fields table
|
||||||
|
*/
|
||||||
|
next++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PlexOfField endPlexOfField = plexOfFields
|
||||||
|
.get( endNodePositionInList );
|
||||||
|
|
||||||
|
if ( endPlexOfField.getFld().getBoundaryType() != FieldDescriptor.FIELD_END_MARK )
|
||||||
|
{
|
||||||
|
/* Not and ending mark */
|
||||||
|
next++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldImpl field = new FieldImpl( startPlexOfField,
|
||||||
|
separatorPlexOfField, endPlexOfField );
|
||||||
|
result.add( field );
|
||||||
|
|
||||||
|
// adding included fields
|
||||||
|
if ( startPlexOfField.getFcStart() + 1 < separatorPlexOfField
|
||||||
|
.getFcStart() - 1 )
|
||||||
|
{
|
||||||
|
parseFieldStructureImpl( plexOfFields, next + 1,
|
||||||
|
nextNodePositionInList, result );
|
||||||
|
}
|
||||||
|
if ( separatorPlexOfField.getFcStart() + 1 < endPlexOfField
|
||||||
|
.getFcStart() - 1 )
|
||||||
|
{
|
||||||
|
parseFieldStructureImpl( plexOfFields,
|
||||||
|
nextNodePositionInList + 1, endNodePositionInList,
|
||||||
|
result );
|
||||||
|
}
|
||||||
|
|
||||||
|
next = endNodePositionInList + 1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FieldDescriptor.FIELD_END_MARK:
|
||||||
|
{
|
||||||
|
// we have no separator
|
||||||
|
FieldImpl field = new FieldImpl( startPlexOfField, null,
|
||||||
|
nextPlexOfField );
|
||||||
|
result.add( field );
|
||||||
|
|
||||||
|
// adding included fields
|
||||||
|
if ( startPlexOfField.getFcStart() + 1 < nextPlexOfField
|
||||||
|
.getFcStart() - 1 )
|
||||||
|
{
|
||||||
|
parseFieldStructureImpl( plexOfFields, next + 1,
|
||||||
|
nextNodePositionInList, result );
|
||||||
|
}
|
||||||
|
|
||||||
|
next = nextNodePositionInList + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FieldDescriptor.FIELD_BEGIN_MARK:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
/* something is wrong, ignoring this mark along with start mark */
|
||||||
|
next++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class PlexOfFieldComparator implements
|
||||||
|
Comparator<PlexOfField>
|
||||||
|
{
|
||||||
|
public int compare( PlexOfField o1, PlexOfField o2 )
|
||||||
|
{
|
||||||
|
int thisVal = o1.getFcStart();
|
||||||
|
int anotherVal = o2.getFcStart();
|
||||||
|
return thisVal < anotherVal ? -1 : thisVal == anotherVal ? 0 : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue