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
584897b99e
commit
18c247b0d3
@ -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.usermodel.Bookmarks;
|
||||
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.Notes;
|
||||
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.DocumentEntry;
|
||||
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 */
|
||||
protected FieldsTables _fieldsTables;
|
||||
|
||||
/** Holds the fields */
|
||||
protected Fields _fields;
|
||||
|
||||
protected HWPFDocument()
|
||||
{
|
||||
super();
|
||||
@ -296,6 +303,7 @@ public final class HWPFDocument extends HWPFDocumentCore
|
||||
_footnotes = new NotesImpl( _footnotesTables );
|
||||
|
||||
_fieldsTables = new FieldsTables(_tableStream, _fib);
|
||||
_fields = new FieldsImpl(_fieldsTables);
|
||||
}
|
||||
|
||||
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
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
@Internal
|
||||
public FieldsTables getFieldsTables() {
|
||||
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.
|
||||
*
|
||||
|
@ -29,12 +29,12 @@ import org.apache.poi.hpsf.SummaryInformation;
|
||||
import org.apache.poi.hwpf.HWPFDocument;
|
||||
import org.apache.poi.hwpf.HWPFDocumentCore;
|
||||
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.ListFormatOverride;
|
||||
import org.apache.poi.hwpf.model.ListTables;
|
||||
import org.apache.poi.hwpf.usermodel.Bookmark;
|
||||
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.Paragraph;
|
||||
import org.apache.poi.hwpf.usermodel.Picture;
|
||||
@ -229,9 +229,8 @@ public abstract class AbstractWordConverter
|
||||
{
|
||||
if ( document instanceof HWPFDocument )
|
||||
{
|
||||
Field aliveField = ( (HWPFDocument) document )
|
||||
.getFieldsTables().lookupFieldByStartOffset(
|
||||
FieldsDocumentPart.MAIN,
|
||||
Field aliveField = ( (HWPFDocument) document ).getFields()
|
||||
.getFieldByStartOffset( FieldsDocumentPart.MAIN,
|
||||
characterRun.getStartOffset() );
|
||||
if ( aliveField != null )
|
||||
{
|
||||
@ -453,7 +452,7 @@ public abstract class AbstractWordConverter
|
||||
return null;
|
||||
|
||||
HWPFDocument hwpfDocument = (HWPFDocument) wordDocument;
|
||||
Field field = hwpfDocument.getFieldsTables().lookupFieldByStartOffset(
|
||||
Field field = hwpfDocument.getFields().getFieldByStartOffset(
|
||||
FieldsDocumentPart.MAIN, startOffset );
|
||||
if ( field == null )
|
||||
return null;
|
||||
|
@ -23,7 +23,6 @@ import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
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.sprm.SprmIterator;
|
||||
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.Picture;
|
||||
import org.apache.poi.hwpf.usermodel.Range;
|
||||
@ -311,7 +311,8 @@ public final class HWPFLister
|
||||
for ( char c : text.toCharArray() )
|
||||
{
|
||||
if ( c < 30 )
|
||||
stringBuilder.append( "\\0x" + Integer.toHexString( c ) );
|
||||
stringBuilder
|
||||
.append( "\\0x" + Integer.toHexString( c ) );
|
||||
else
|
||||
stringBuilder.append( c );
|
||||
}
|
||||
@ -340,8 +341,7 @@ public final class HWPFLister
|
||||
for ( FieldsDocumentPart part : FieldsDocumentPart.values() )
|
||||
{
|
||||
System.out.println( "=== Document part: " + part + " ===" );
|
||||
for ( org.apache.poi.hwpf.model.Field field : document
|
||||
.getFieldsTables().getFields( part ) )
|
||||
for ( Field field : document.getFields().getFields( part ) )
|
||||
{
|
||||
System.out.println( field );
|
||||
}
|
||||
@ -356,7 +356,7 @@ public final class HWPFLister
|
||||
|
||||
HWPFDocument doc = (HWPFDocument) _doc;
|
||||
|
||||
Field fMainStream = HWPFDocumentCore.class
|
||||
java.lang.reflect.Field fMainStream = HWPFDocumentCore.class
|
||||
.getDeclaredField( "_mainStream" );
|
||||
fMainStream.setAccessible( true );
|
||||
byte[] mainStream = (byte[]) fMainStream.get( _doc );
|
||||
|
@ -21,12 +21,7 @@ package org.apache.poi.hwpf.model;
|
||||
|
||||
import java.io.IOException;
|
||||
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.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.poi.hwpf.model.io.HWPFOutputStream;
|
||||
@ -79,70 +74,13 @@ public class FieldsTables
|
||||
@Deprecated
|
||||
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 )
|
||||
{
|
||||
if ( plexOfCps == null )
|
||||
return new ArrayList<PlexOfField>();
|
||||
|
||||
ArrayList<PlexOfField> fields = new ArrayList<PlexOfField>();
|
||||
fields.ensureCapacity( plexOfCps.length() );
|
||||
|
||||
ArrayList<PlexOfField> fields = new ArrayList<PlexOfField>(
|
||||
plexOfCps.length() );
|
||||
for ( int i = 0; i < plexOfCps.length(); i++ )
|
||||
{
|
||||
GenericPropertyNode propNode = plexOfCps.getProperty( i );
|
||||
@ -153,37 +91,20 @@ public class FieldsTables
|
||||
return fields;
|
||||
}
|
||||
|
||||
private Map<FieldsDocumentPart, Map<Integer, Field>> _fieldsByOffset;
|
||||
|
||||
private Map<FieldsDocumentPart, PlexOfCps> _tables;
|
||||
|
||||
private GenericPropertyNodeComparator comparator = new GenericPropertyNodeComparator();
|
||||
|
||||
public FieldsTables( byte[] tableStream, FileInformationBlock fib )
|
||||
{
|
||||
_tables = new HashMap<FieldsDocumentPart, PlexOfCps>(
|
||||
FieldsDocumentPart.values().length );
|
||||
_fieldsByOffset = new HashMap<FieldsDocumentPart, Map<Integer, Field>>(
|
||||
FieldsDocumentPart.values().length );
|
||||
|
||||
for ( FieldsDocumentPart part : FieldsDocumentPart.values() )
|
||||
{
|
||||
final PlexOfCps plexOfCps = readPLCF( tableStream, fib, part );
|
||||
|
||||
_fieldsByOffset.put( part, parseFieldStructure( 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 )
|
||||
{
|
||||
return toArrayList( _tables.get( part ) );
|
||||
@ -195,146 +116,6 @@ public class FieldsTables
|
||||
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,
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
55
src/scratchpad/src/org/apache/poi/hwpf/usermodel/Field.java
Normal file
55
src/scratchpad/src/org/apache/poi/hwpf/usermodel/Field.java
Normal file
@ -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 separatorPlex;
|
||||
private PlexOfField startPlex;
|
||||
|
||||
public Field( PlexOfField startPlex, PlexOfField separatorPlex,
|
||||
public FieldImpl( PlexOfField startPlex, PlexOfField separatorPlex,
|
||||
PlexOfField endPlex )
|
||||
{
|
||||
if ( startPlex == null )
|
33
src/scratchpad/src/org/apache/poi/hwpf/usermodel/Fields.java
Normal file
33
src/scratchpad/src/org/apache/poi/hwpf/usermodel/Fields.java
Normal file
@ -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 );
|
||||
}
|
276
src/scratchpad/src/org/apache/poi/hwpf/usermodel/FieldsImpl.java
Normal file
276
src/scratchpad/src/org/apache/poi/hwpf/usermodel/FieldsImpl.java
Normal file
@ -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
Block a user