introduce SubdocumentPart and simplify CP start/end FIB API
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1148303 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
a1223d163e
commit
acc635adee
@ -42,6 +42,7 @@ import org.apache.poi.hwpf.model.SavedByTable;
|
|||||||
import org.apache.poi.hwpf.model.SectionTable;
|
import org.apache.poi.hwpf.model.SectionTable;
|
||||||
import org.apache.poi.hwpf.model.ShapesTable;
|
import org.apache.poi.hwpf.model.ShapesTable;
|
||||||
import org.apache.poi.hwpf.model.StyleSheet;
|
import org.apache.poi.hwpf.model.StyleSheet;
|
||||||
|
import org.apache.poi.hwpf.model.SubdocumentType;
|
||||||
import org.apache.poi.hwpf.model.TextPiece;
|
import org.apache.poi.hwpf.model.TextPiece;
|
||||||
import org.apache.poi.hwpf.model.TextPieceTable;
|
import org.apache.poi.hwpf.model.TextPieceTable;
|
||||||
import org.apache.poi.hwpf.model.io.HWPFFileSystem;
|
import org.apache.poi.hwpf.model.io.HWPFFileSystem;
|
||||||
@ -64,6 +65,7 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
|||||||
public final class HWPFDocument extends HWPFDocumentCore
|
public final class HWPFDocument extends HWPFDocumentCore
|
||||||
{
|
{
|
||||||
/** And for making sense of CP lengths in the FIB */
|
/** And for making sense of CP lengths in the FIB */
|
||||||
|
@Deprecated
|
||||||
protected CPSplitCalculator _cpSplit;
|
protected CPSplitCalculator _cpSplit;
|
||||||
|
|
||||||
/** table stream buffer*/
|
/** table stream buffer*/
|
||||||
@ -268,6 +270,7 @@ public final class HWPFDocument extends HWPFDocumentCore
|
|||||||
return _cft.getTextPieceTable();
|
return _cft.getTextPieceTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public CPSplitCalculator getCPSplitCalculator()
|
public CPSplitCalculator getCPSplitCalculator()
|
||||||
{
|
{
|
||||||
return _cpSplit;
|
return _cpSplit;
|
||||||
@ -319,7 +322,9 @@ public final class HWPFDocument extends HWPFDocumentCore
|
|||||||
int bytesStart = getFileInformationBlock().getFcMin();
|
int bytesStart = getFileInformationBlock().getFcMin();
|
||||||
|
|
||||||
int charsStart = getTextTable().getCharIndex( bytesStart );
|
int charsStart = getTextTable().getCharIndex( bytesStart );
|
||||||
int charsEnd = charsStart + getFileInformationBlock().getCcpText();
|
int charsEnd = charsStart
|
||||||
|
+ getFileInformationBlock().getSubdocumentTextStreamLength(
|
||||||
|
SubdocumentType.MAIN );
|
||||||
|
|
||||||
return new Range( charsStart, charsEnd, this );
|
return new Range( charsStart, charsEnd, this );
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ 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.DocumentPart;
|
import org.apache.poi.hwpf.model.FieldsDocumentPart;
|
||||||
import org.apache.poi.hwpf.model.Field;
|
import org.apache.poi.hwpf.model.Field;
|
||||||
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;
|
||||||
@ -111,7 +111,7 @@ public abstract class AbstractWordConverter
|
|||||||
{
|
{
|
||||||
Field aliveField = ( (HWPFDocument) hwpfDocument )
|
Field aliveField = ( (HWPFDocument) hwpfDocument )
|
||||||
.getFieldsTables().lookupFieldByStartOffset(
|
.getFieldsTables().lookupFieldByStartOffset(
|
||||||
DocumentPart.MAIN,
|
FieldsDocumentPart.MAIN,
|
||||||
characterRun.getStartOffset() );
|
characterRun.getStartOffset() );
|
||||||
if ( aliveField != null )
|
if ( aliveField != null )
|
||||||
{
|
{
|
||||||
@ -309,7 +309,7 @@ public abstract class AbstractWordConverter
|
|||||||
|
|
||||||
HWPFDocument hwpfDocument = (HWPFDocument) wordDocument;
|
HWPFDocument hwpfDocument = (HWPFDocument) wordDocument;
|
||||||
Field field = hwpfDocument.getFieldsTables().lookupFieldByStartOffset(
|
Field field = hwpfDocument.getFieldsTables().lookupFieldByStartOffset(
|
||||||
DocumentPart.MAIN, startOffset );
|
FieldsDocumentPart.MAIN, startOffset );
|
||||||
if ( field == null )
|
if ( field == null )
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ import org.apache.poi.hwpf.HWPFDocumentCore;
|
|||||||
import org.apache.poi.hwpf.HWPFOldDocument;
|
import org.apache.poi.hwpf.HWPFOldDocument;
|
||||||
import org.apache.poi.hwpf.OldWordFileFormatException;
|
import org.apache.poi.hwpf.OldWordFileFormatException;
|
||||||
import org.apache.poi.hwpf.model.CHPX;
|
import org.apache.poi.hwpf.model.CHPX;
|
||||||
import org.apache.poi.hwpf.model.DocumentPart;
|
import org.apache.poi.hwpf.model.FieldsDocumentPart;
|
||||||
import org.apache.poi.hwpf.model.FileInformationBlock;
|
import org.apache.poi.hwpf.model.FileInformationBlock;
|
||||||
import org.apache.poi.hwpf.model.GenericPropertyNode;
|
import org.apache.poi.hwpf.model.GenericPropertyNode;
|
||||||
import org.apache.poi.hwpf.model.PAPFormattedDiskPage;
|
import org.apache.poi.hwpf.model.PAPFormattedDiskPage;
|
||||||
@ -315,6 +315,7 @@ public final class HWPFLister
|
|||||||
{
|
{
|
||||||
FileInformationBlock fib = _doc.getFileInformationBlock();
|
FileInformationBlock fib = _doc.getFileInformationBlock();
|
||||||
System.out.println( fib );
|
System.out.println( fib );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dumpFields()
|
private void dumpFields()
|
||||||
@ -327,7 +328,7 @@ public final class HWPFLister
|
|||||||
|
|
||||||
HWPFDocument document = (HWPFDocument) _doc;
|
HWPFDocument document = (HWPFDocument) _doc;
|
||||||
|
|
||||||
for ( DocumentPart part : DocumentPart.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 ( org.apache.poi.hwpf.model.Field field : document
|
||||||
|
@ -24,6 +24,7 @@ import org.apache.poi.hwpf.HWPFDocument;
|
|||||||
* where different kinds of text can be found within the
|
* where different kinds of text can be found within the
|
||||||
* overall CP splurge.
|
* overall CP splurge.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public final class CPSplitCalculator {
|
public final class CPSplitCalculator {
|
||||||
private FileInformationBlock fib;
|
private FileInformationBlock fib;
|
||||||
public CPSplitCalculator(FileInformationBlock fib) {
|
public CPSplitCalculator(FileInformationBlock fib) {
|
||||||
|
@ -29,33 +29,53 @@ public final class FIBLongHandler {
|
|||||||
public static final int PRODUCTREVISED = 2;
|
public static final int PRODUCTREVISED = 2;
|
||||||
/**
|
/**
|
||||||
* Pointer to length of main document text stream 1
|
* Pointer to length of main document text stream 1
|
||||||
|
*
|
||||||
|
* @since Word 97
|
||||||
*/
|
*/
|
||||||
public static final int CCPTEXT = 3;
|
public static final int CCPTEXT = 3;
|
||||||
/**
|
/**
|
||||||
* Pointer to length of footnote subdocument text stream
|
* Pointer to length of footnote subdocument text stream
|
||||||
|
*
|
||||||
|
* @since Word 97
|
||||||
*/
|
*/
|
||||||
public static final int CCPFTN = 4;
|
public static final int CCPFTN = 4;
|
||||||
/**
|
/**
|
||||||
* Pointer to length of header subdocument text stream
|
* Pointer to length of header subdocument text stream
|
||||||
|
*
|
||||||
|
* @since Word 97
|
||||||
*/
|
*/
|
||||||
public static final int CCPHDD = 5;
|
public static final int CCPHDD = 5;
|
||||||
/**
|
/**
|
||||||
* Pointer to length of macro subdocument text stream, which should now
|
* Pointer to length of macro subdocument text stream, which should now
|
||||||
* always be 0
|
* always be 0
|
||||||
|
*
|
||||||
|
* @since Word 97
|
||||||
*/
|
*/
|
||||||
public static final int CCPMCR = 6;
|
public static final int CCPMCR = 6;
|
||||||
/**
|
/**
|
||||||
* Pointer to length of annotation subdocument text stream
|
* Pointer to length of annotation subdocument text stream
|
||||||
|
*
|
||||||
|
* @since Word 97
|
||||||
*/
|
*/
|
||||||
public static final int CCPATN = 7;
|
public static final int CCPATN = 7;
|
||||||
/**
|
/**
|
||||||
* Pointer to length of endnote subdocument text stream
|
* Pointer to length of endnote subdocument text stream
|
||||||
|
*
|
||||||
|
* @since Word 97
|
||||||
*/
|
*/
|
||||||
public static final int CCPEDN = 8;
|
public static final int CCPEDN = 8;
|
||||||
/**
|
/**
|
||||||
* Pointer to length of textbox subdocument text stream
|
* Pointer to length of textbox subdocument text stream
|
||||||
|
*
|
||||||
|
* @since Word 97
|
||||||
*/
|
*/
|
||||||
public static final int CCPTXBX = 9;
|
public static final int CCPTXBX = 9;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Length of header textbox subdocument text stream
|
||||||
|
*
|
||||||
|
* @since Word 97
|
||||||
|
*/
|
||||||
public static final int CCPHDRTXBX = 10;
|
public static final int CCPHDRTXBX = 10;
|
||||||
public static final int PNFBPCHPFIRST = 11;
|
public static final int PNFBPCHPFIRST = 11;
|
||||||
public static final int PNCHPFIRST = 12;
|
public static final int PNCHPFIRST = 12;
|
||||||
|
@ -1,46 +1,52 @@
|
|||||||
package org.apache.poi.hwpf.model;
|
package org.apache.poi.hwpf.model;
|
||||||
|
|
||||||
public enum DocumentPart {
|
public enum FieldsDocumentPart {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* annotation subdocument
|
* annotation subdocument
|
||||||
*/
|
*/
|
||||||
ANNOTATIONS( FIBFieldHandler.PLCFFLDATN ),
|
ANNOTATIONS( FIBFieldHandler.PLCFFLDATN ),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* endnote subdocument
|
* endnote subdocument
|
||||||
*/
|
*/
|
||||||
ENDNOTES( FIBFieldHandler.PLCFFLDEDN ),
|
ENDNOTES( FIBFieldHandler.PLCFFLDEDN ),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* footnote subdocument
|
* footnote subdocument
|
||||||
*/
|
*/
|
||||||
FOOTNOTES( FIBFieldHandler.PLCFFLDFTN ),
|
FOOTNOTES( FIBFieldHandler.PLCFFLDFTN ),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* header subdocument
|
* header subdocument
|
||||||
*/
|
*/
|
||||||
HEADER( FIBFieldHandler.PLCFFLDHDR ),
|
HEADER( FIBFieldHandler.PLCFFLDHDR ),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* header textbox subdoc
|
* header textbox subdoc
|
||||||
*/
|
*/
|
||||||
HEADER_TEXTBOX( FIBFieldHandler.PLCFFLDHDRTXBX ),
|
HEADER_TEXTBOX( FIBFieldHandler.PLCFFLDHDRTXBX ),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* main document
|
* main document
|
||||||
*/
|
*/
|
||||||
MAIN( FIBFieldHandler.PLCFFLDMOM ),
|
MAIN( FIBFieldHandler.PLCFFLDMOM ),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* textbox subdoc
|
* textbox subdoc
|
||||||
*/
|
*/
|
||||||
TEXTBOX( FIBFieldHandler.PLCFFLDTXBX );
|
TEXTBOX( FIBFieldHandler.PLCFFLDTXBX );
|
||||||
|
|
||||||
private final int fibHandlerFieldsField;
|
private final int fibFieldsField;
|
||||||
|
|
||||||
private DocumentPart( final int fibHandlerField )
|
private FieldsDocumentPart( final int fibHandlerField )
|
||||||
{
|
{
|
||||||
this.fibHandlerFieldsField = fibHandlerField;
|
this.fibFieldsField = fibHandlerField;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFibHandlerFieldsPosition()
|
public int getFibFieldsField()
|
||||||
{
|
{
|
||||||
return fibHandlerFieldsField;
|
return fibFieldsField;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -39,24 +39,15 @@ import org.apache.poi.hwpf.model.io.HWPFOutputStream;
|
|||||||
*/
|
*/
|
||||||
public class FieldsTables
|
public class FieldsTables
|
||||||
{
|
{
|
||||||
private static final class GenericPropertyNodeComparator implements
|
// The size in bytes of the FLD data structure
|
||||||
Comparator<GenericPropertyNode>
|
private static final int FLD_SIZE = 2;
|
||||||
{
|
|
||||||
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
|
* annotation subdocument
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static final int PLCFFLDATN = 0;
|
public static final int PLCFFLDATN = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* endnote subdocument
|
* endnote subdocument
|
||||||
*/
|
*/
|
||||||
@ -88,33 +79,135 @@ public class FieldsTables
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
public static final int PLCFFLDTXBX = 6;
|
public static final int PLCFFLDTXBX = 6;
|
||||||
|
|
||||||
// The size in bytes of the FLD data structure
|
/**
|
||||||
private static final int FLD_SIZE = 2;
|
* 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 );
|
||||||
|
|
||||||
private Map<DocumentPart, PlexOfCps> _tables;
|
int low = startIndex, mid = -1, high = endIndex - 1, result = 0;
|
||||||
private Map<DocumentPart, Map<Integer, Field>> _fieldsByOffset;
|
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() );
|
||||||
|
|
||||||
|
for ( int i = 0; i < plexOfCps.length(); i++ )
|
||||||
|
{
|
||||||
|
GenericPropertyNode propNode = plexOfCps.getProperty( i );
|
||||||
|
PlexOfField plex = new PlexOfField( propNode );
|
||||||
|
fields.add( plex );
|
||||||
|
}
|
||||||
|
|
||||||
|
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 )
|
public FieldsTables( byte[] tableStream, FileInformationBlock fib )
|
||||||
{
|
{
|
||||||
_tables = new HashMap<DocumentPart, PlexOfCps>(
|
_tables = new HashMap<FieldsDocumentPart, PlexOfCps>(
|
||||||
DocumentPart.values().length );
|
FieldsDocumentPart.values().length );
|
||||||
_fieldsByOffset = new HashMap<DocumentPart, Map<Integer, Field>>(
|
_fieldsByOffset = new HashMap<FieldsDocumentPart, Map<Integer, Field>>(
|
||||||
DocumentPart.values().length );
|
FieldsDocumentPart.values().length );
|
||||||
|
|
||||||
for ( DocumentPart documentPart : DocumentPart.values() )
|
for ( FieldsDocumentPart part : FieldsDocumentPart.values() )
|
||||||
{
|
{
|
||||||
final PlexOfCps plexOfCps = readPLCF( tableStream, fib,
|
final PlexOfCps plexOfCps = readPLCF( tableStream, fib, part );
|
||||||
documentPart );
|
|
||||||
|
|
||||||
_fieldsByOffset
|
_fieldsByOffset.put( part, parseFieldStructure( plexOfCps ) );
|
||||||
.put( documentPart, parseFieldStructure( plexOfCps ) );
|
_tables.put( part, plexOfCps );
|
||||||
_tables.put( documentPart, 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 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public ArrayList<PlexOfField> getFieldsPLCF( int 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 )
|
private Map<Integer, Field> parseFieldStructure( PlexOfCps plexOfCps )
|
||||||
{
|
{
|
||||||
if (plexOfCps == null)
|
if ( plexOfCps == null )
|
||||||
return new HashMap<Integer, Field>();
|
return new HashMap<Integer, Field>();
|
||||||
|
|
||||||
GenericPropertyNode[] nodes = plexOfCps.toPropertiesArray();
|
GenericPropertyNode[] nodes = plexOfCps.toPropertiesArray();
|
||||||
@ -242,73 +335,8 @@ public class FieldsTables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Field lookupFieldByStartOffset( DocumentPart documentPart, int offset )
|
|
||||||
{
|
|
||||||
Map<Integer, Field> map = _fieldsByOffset.get( documentPart);
|
|
||||||
if ( map == null || map.isEmpty() )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return map.get( Integer.valueOf( offset ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
private PlexOfCps readPLCF( byte[] tableStream, FileInformationBlock fib,
|
private PlexOfCps readPLCF( byte[] tableStream, FileInformationBlock fib,
|
||||||
DocumentPart documentPart )
|
FieldsDocumentPart documentPart )
|
||||||
{
|
{
|
||||||
int start = fib.getFieldsPlcfOffset( documentPart );
|
int start = fib.getFieldsPlcfOffset( documentPart );
|
||||||
int length = fib.getFieldsPlcfLength( documentPart );
|
int length = fib.getFieldsPlcfLength( documentPart );
|
||||||
@ -319,45 +347,7 @@ public class FieldsTables
|
|||||||
return new PlexOfCps( tableStream, start, length, FLD_SIZE );
|
return new PlexOfCps( tableStream, start, length, FLD_SIZE );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Field> getFields( DocumentPart part )
|
private int savePlex( FileInformationBlock fib, FieldsDocumentPart part,
|
||||||
{
|
|
||||||
Map<Integer, Field> map = _fieldsByOffset.get( part );
|
|
||||||
if ( map == null || map.isEmpty() )
|
|
||||||
return Collections.emptySet();
|
|
||||||
|
|
||||||
return Collections.unmodifiableCollection( map.values() );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public ArrayList<PlexOfField> getFieldsPLCF( int partIndex )
|
|
||||||
{
|
|
||||||
return getFieldsPLCF( DocumentPart.values()[partIndex] );
|
|
||||||
}
|
|
||||||
|
|
||||||
public ArrayList<PlexOfField> getFieldsPLCF( DocumentPart documentPart )
|
|
||||||
{
|
|
||||||
return toArrayList( _tables.get( documentPart ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ArrayList<PlexOfField> toArrayList( PlexOfCps plexOfCps )
|
|
||||||
{
|
|
||||||
if ( plexOfCps == null )
|
|
||||||
return new ArrayList<PlexOfField>();
|
|
||||||
|
|
||||||
ArrayList<PlexOfField> fields = new ArrayList<PlexOfField>();
|
|
||||||
fields.ensureCapacity( plexOfCps.length() );
|
|
||||||
|
|
||||||
for ( int i = 0; i < plexOfCps.length(); i++ )
|
|
||||||
{
|
|
||||||
GenericPropertyNode propNode = plexOfCps.getProperty( i );
|
|
||||||
PlexOfField plex = new PlexOfField( propNode );
|
|
||||||
fields.add( plex );
|
|
||||||
}
|
|
||||||
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int savePlex( FileInformationBlock fib, DocumentPart documentPart,
|
|
||||||
PlexOfCps plexOfCps, HWPFOutputStream outputStream )
|
PlexOfCps plexOfCps, HWPFOutputStream outputStream )
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
@ -371,8 +361,8 @@ public class FieldsTables
|
|||||||
|
|
||||||
outputStream.write( data );
|
outputStream.write( data );
|
||||||
|
|
||||||
fib.setFieldsPlcfOffset( documentPart, start );
|
fib.setFieldsPlcfOffset( part, start );
|
||||||
fib.setFieldsPlcfLength( documentPart, length );
|
fib.setFieldsPlcfLength( part, length );
|
||||||
|
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
@ -380,10 +370,21 @@ public class FieldsTables
|
|||||||
public void write( FileInformationBlock fib, HWPFOutputStream tableStream )
|
public void write( FileInformationBlock fib, HWPFOutputStream tableStream )
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
for ( DocumentPart part : DocumentPart.values() )
|
for ( FieldsDocumentPart part : FieldsDocumentPart.values() )
|
||||||
{
|
{
|
||||||
PlexOfCps plexOfCps = _tables.get( part );
|
PlexOfCps plexOfCps = _tables.get( part );
|
||||||
savePlex( fib, part, plexOfCps, tableStream );
|
savePlex( fib, part, plexOfCps, tableStream );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
package org.apache.poi.hwpf.model;
|
package org.apache.poi.hwpf.model;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
import org.apache.poi.hwpf.model.io.HWPFOutputStream;
|
import org.apache.poi.hwpf.model.io.HWPFOutputStream;
|
||||||
@ -84,6 +86,56 @@ public final class FileInformationBlock extends FIBAbstractType
|
|||||||
tableStream, fieldSet, true);
|
tableStream, fieldSet, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder stringBuilder = new StringBuilder( super.toString() );
|
||||||
|
stringBuilder.append( "[FIB2]\n" );
|
||||||
|
stringBuilder.append( "\tSubdocuments info:\n" );
|
||||||
|
for ( SubdocumentType type : SubdocumentType.values() )
|
||||||
|
{
|
||||||
|
stringBuilder.append( "\t\t" );
|
||||||
|
stringBuilder.append( type );
|
||||||
|
stringBuilder.append( " has length of " );
|
||||||
|
stringBuilder.append( getSubdocumentTextStreamLength( type ) );
|
||||||
|
stringBuilder.append( " char(s)\n" );
|
||||||
|
}
|
||||||
|
stringBuilder.append( "\tFields PLCF info:\n" );
|
||||||
|
for ( FieldsDocumentPart part : FieldsDocumentPart.values() )
|
||||||
|
{
|
||||||
|
stringBuilder.append( "\t\t" );
|
||||||
|
stringBuilder.append( part );
|
||||||
|
stringBuilder.append( ": PLCF starts at " );
|
||||||
|
stringBuilder.append( getFieldsPlcfOffset( part ) );
|
||||||
|
stringBuilder.append( " and have length of " );
|
||||||
|
stringBuilder.append( getFieldsPlcfLength( part ) );
|
||||||
|
stringBuilder.append( "\n" );
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
stringBuilder.append( "\tJava reflection info:\n" );
|
||||||
|
for ( Method method : FileInformationBlock.class.getMethods() )
|
||||||
|
{
|
||||||
|
if ( !method.getName().startsWith( "get" )
|
||||||
|
|| !Modifier.isPublic( method.getModifiers() )
|
||||||
|
|| Modifier.isStatic( method.getModifiers() )
|
||||||
|
|| method.getParameterTypes().length > 0 )
|
||||||
|
continue;
|
||||||
|
stringBuilder.append( "\t\t" );
|
||||||
|
stringBuilder.append( method.getName() );
|
||||||
|
stringBuilder.append( " => " );
|
||||||
|
stringBuilder.append( method.invoke( this ) );
|
||||||
|
stringBuilder.append( "\n" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch ( Exception exc )
|
||||||
|
{
|
||||||
|
stringBuilder.append( "(exc: " + exc.getMessage() + ")" );
|
||||||
|
}
|
||||||
|
stringBuilder.append( "[/FIB2]\n" );
|
||||||
|
return stringBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public int getFcDop()
|
public int getFcDop()
|
||||||
{
|
{
|
||||||
return _fieldHandler.getFieldOffset(FIBFieldHandler.DOP);
|
return _fieldHandler.getFieldOffset(FIBFieldHandler.DOP);
|
||||||
@ -345,13 +397,13 @@ public final class FileInformationBlock extends FIBAbstractType
|
|||||||
_fieldHandler.setFieldSize(FIBFieldHandler.PLFLFO, modifiedHigh);
|
_fieldHandler.setFieldSize(FIBFieldHandler.PLFLFO, modifiedHigh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How many bytes of the main stream contain real data.
|
* How many bytes of the main stream contain real data.
|
||||||
*/
|
*/
|
||||||
public int getCbMac() {
|
public int getCbMac() {
|
||||||
return _longHandler.getLong(FIBLongHandler.CBMAC);
|
return _longHandler.getLong(FIBLongHandler.CBMAC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the count of the number of bytes in the
|
* Updates the count of the number of bytes in the
|
||||||
* main stream which contain real data
|
* main stream which contain real data
|
||||||
@ -360,15 +412,30 @@ public final class FileInformationBlock extends FIBAbstractType
|
|||||||
_longHandler.setLong(FIBLongHandler.CBMAC, cbMac);
|
_longHandler.setLong(FIBLongHandler.CBMAC, cbMac);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return length of specified subdocument text stream in characters
|
||||||
|
*/
|
||||||
|
public int getSubdocumentTextStreamLength( SubdocumentType type )
|
||||||
|
{
|
||||||
|
return _longHandler.getLong( type.getFibLongFieldIndex() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSubdocumentTextStreamLength( SubdocumentType type, int length )
|
||||||
|
{
|
||||||
|
_longHandler.setLong( type.getFibLongFieldIndex(), length );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The count of CPs in the main document
|
* The count of CPs in the main document
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public int getCcpText() {
|
public int getCcpText() {
|
||||||
return _longHandler.getLong(FIBLongHandler.CCPTEXT);
|
return _longHandler.getLong(FIBLongHandler.CCPTEXT);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Updates the count of CPs in the main document
|
* Updates the count of CPs in the main document
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setCcpText(int ccpText) {
|
public void setCcpText(int ccpText) {
|
||||||
_longHandler.setLong(FIBLongHandler.CCPTEXT, ccpText);
|
_longHandler.setLong(FIBLongHandler.CCPTEXT, ccpText);
|
||||||
}
|
}
|
||||||
@ -376,12 +443,14 @@ public final class FileInformationBlock extends FIBAbstractType
|
|||||||
/**
|
/**
|
||||||
* The count of CPs in the footnote subdocument
|
* The count of CPs in the footnote subdocument
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public int getCcpFtn() {
|
public int getCcpFtn() {
|
||||||
return _longHandler.getLong(FIBLongHandler.CCPFTN);
|
return _longHandler.getLong(FIBLongHandler.CCPFTN);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Updates the count of CPs in the footnote subdocument
|
* Updates the count of CPs in the footnote subdocument
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setCcpFtn(int ccpFtn) {
|
public void setCcpFtn(int ccpFtn) {
|
||||||
_longHandler.setLong(FIBLongHandler.CCPFTN, ccpFtn);
|
_longHandler.setLong(FIBLongHandler.CCPFTN, ccpFtn);
|
||||||
}
|
}
|
||||||
@ -389,12 +458,14 @@ public final class FileInformationBlock extends FIBAbstractType
|
|||||||
/**
|
/**
|
||||||
* The count of CPs in the header story subdocument
|
* The count of CPs in the header story subdocument
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public int getCcpHdd() {
|
public int getCcpHdd() {
|
||||||
return _longHandler.getLong(FIBLongHandler.CCPHDD);
|
return _longHandler.getLong(FIBLongHandler.CCPHDD);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Updates the count of CPs in the header story subdocument
|
* Updates the count of CPs in the header story subdocument
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setCcpHdd(int ccpHdd) {
|
public void setCcpHdd(int ccpHdd) {
|
||||||
_longHandler.setLong(FIBLongHandler.CCPHDD, ccpHdd);
|
_longHandler.setLong(FIBLongHandler.CCPHDD, ccpHdd);
|
||||||
}
|
}
|
||||||
@ -402,15 +473,19 @@ public final class FileInformationBlock extends FIBAbstractType
|
|||||||
/**
|
/**
|
||||||
* The count of CPs in the comments (atn) subdocument
|
* The count of CPs in the comments (atn) subdocument
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public int getCcpAtn() {
|
public int getCcpAtn() {
|
||||||
return _longHandler.getLong(FIBLongHandler.CCPATN);
|
return _longHandler.getLong(FIBLongHandler.CCPATN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public int getCcpCommentAtn() {
|
public int getCcpCommentAtn() {
|
||||||
return getCcpAtn();
|
return getCcpAtn();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Updates the count of CPs in the comments (atn) story subdocument
|
* Updates the count of CPs in the comments (atn) story subdocument
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setCcpAtn(int ccpAtn) {
|
public void setCcpAtn(int ccpAtn) {
|
||||||
_longHandler.setLong(FIBLongHandler.CCPATN, ccpAtn);
|
_longHandler.setLong(FIBLongHandler.CCPATN, ccpAtn);
|
||||||
}
|
}
|
||||||
@ -418,12 +493,14 @@ public final class FileInformationBlock extends FIBAbstractType
|
|||||||
/**
|
/**
|
||||||
* The count of CPs in the end note subdocument
|
* The count of CPs in the end note subdocument
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public int getCcpEdn() {
|
public int getCcpEdn() {
|
||||||
return _longHandler.getLong(FIBLongHandler.CCPEDN);
|
return _longHandler.getLong(FIBLongHandler.CCPEDN);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Updates the count of CPs in the end note subdocument
|
* Updates the count of CPs in the end note subdocument
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setCcpEdn(int ccpEdn) {
|
public void setCcpEdn(int ccpEdn) {
|
||||||
_longHandler.setLong(FIBLongHandler.CCPEDN, ccpEdn);
|
_longHandler.setLong(FIBLongHandler.CCPEDN, ccpEdn);
|
||||||
}
|
}
|
||||||
@ -431,12 +508,14 @@ public final class FileInformationBlock extends FIBAbstractType
|
|||||||
/**
|
/**
|
||||||
* The count of CPs in the main document textboxes
|
* The count of CPs in the main document textboxes
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public int getCcpTxtBx() {
|
public int getCcpTxtBx() {
|
||||||
return _longHandler.getLong(FIBLongHandler.CCPTXBX);
|
return _longHandler.getLong(FIBLongHandler.CCPTXBX);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Updates the count of CPs in the main document textboxes
|
* Updates the count of CPs in the main document textboxes
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setCcpTxtBx(int ccpTxtBx) {
|
public void setCcpTxtBx(int ccpTxtBx) {
|
||||||
_longHandler.setLong(FIBLongHandler.CCPTXBX, ccpTxtBx);
|
_longHandler.setLong(FIBLongHandler.CCPTXBX, ccpTxtBx);
|
||||||
}
|
}
|
||||||
@ -444,12 +523,14 @@ public final class FileInformationBlock extends FIBAbstractType
|
|||||||
/**
|
/**
|
||||||
* The count of CPs in the header textboxes
|
* The count of CPs in the header textboxes
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public int getCcpHdrTxtBx() {
|
public int getCcpHdrTxtBx() {
|
||||||
return _longHandler.getLong(FIBLongHandler.CCPHDRTXBX);
|
return _longHandler.getLong(FIBLongHandler.CCPHDRTXBX);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Updates the count of CPs in the header textboxes
|
* Updates the count of CPs in the header textboxes
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setCcpHdrTxtBx(int ccpTxtBx) {
|
public void setCcpHdrTxtBx(int ccpTxtBx) {
|
||||||
_longHandler.setLong(FIBLongHandler.CCPHDRTXBX, ccpTxtBx);
|
_longHandler.setLong(FIBLongHandler.CCPHDRTXBX, ccpTxtBx);
|
||||||
}
|
}
|
||||||
@ -460,165 +541,189 @@ public final class FileInformationBlock extends FIBAbstractType
|
|||||||
_fieldHandler.clearFields();
|
_fieldHandler.clearFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFieldsPlcfOffset( DocumentPart documentPart )
|
public int getFieldsPlcfOffset( FieldsDocumentPart part )
|
||||||
{
|
{
|
||||||
return _fieldHandler.getFieldOffset( documentPart
|
return _fieldHandler.getFieldOffset( part.getFibFieldsField() );
|
||||||
.getFibHandlerFieldsPosition() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFieldsPlcfLength( DocumentPart documentPart )
|
public int getFieldsPlcfLength( FieldsDocumentPart part )
|
||||||
{
|
{
|
||||||
return _fieldHandler.getFieldSize( documentPart
|
return _fieldHandler.getFieldSize( part.getFibFieldsField() );
|
||||||
.getFibHandlerFieldsPosition() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFieldsPlcfOffset( DocumentPart documentPart, int offset )
|
public void setFieldsPlcfOffset( FieldsDocumentPart part, int offset )
|
||||||
{
|
{
|
||||||
_fieldHandler.setFieldOffset(
|
_fieldHandler.setFieldOffset( part.getFibFieldsField(), offset );
|
||||||
documentPart.getFibHandlerFieldsPosition(), offset );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFieldsPlcfLength( DocumentPart documentPart, int length )
|
public void setFieldsPlcfLength( FieldsDocumentPart part, int length )
|
||||||
{
|
{
|
||||||
_fieldHandler.setFieldSize( documentPart.getFibHandlerFieldsPosition(),
|
_fieldHandler.setFieldSize( part.getFibFieldsField(), length );
|
||||||
length );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public int getFcPlcffldAtn()
|
public int getFcPlcffldAtn()
|
||||||
{
|
{
|
||||||
return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDATN);
|
return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDATN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public int getLcbPlcffldAtn()
|
public int getLcbPlcffldAtn()
|
||||||
{
|
{
|
||||||
return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDATN);
|
return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDATN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void setFcPlcffldAtn( int offset )
|
public void setFcPlcffldAtn( int offset )
|
||||||
{
|
{
|
||||||
_fieldHandler.setFieldOffset( FIBFieldHandler.PLCFFLDATN, offset );
|
_fieldHandler.setFieldOffset( FIBFieldHandler.PLCFFLDATN, offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void setLcbPlcffldAtn( int size )
|
public void setLcbPlcffldAtn( int size )
|
||||||
{
|
{
|
||||||
_fieldHandler.setFieldSize( FIBFieldHandler.PLCFFLDATN, size );
|
_fieldHandler.setFieldSize( FIBFieldHandler.PLCFFLDATN, size );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public int getFcPlcffldEdn()
|
public int getFcPlcffldEdn()
|
||||||
{
|
{
|
||||||
return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDEDN);
|
return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDEDN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public int getLcbPlcffldEdn()
|
public int getLcbPlcffldEdn()
|
||||||
{
|
{
|
||||||
return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDEDN);
|
return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDEDN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void setFcPlcffldEdn( int offset )
|
public void setFcPlcffldEdn( int offset )
|
||||||
{
|
{
|
||||||
_fieldHandler.setFieldOffset( FIBFieldHandler.PLCFFLDEDN, offset );
|
_fieldHandler.setFieldOffset( FIBFieldHandler.PLCFFLDEDN, offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void setLcbPlcffldEdn( int size )
|
public void setLcbPlcffldEdn( int size )
|
||||||
{
|
{
|
||||||
_fieldHandler.setFieldSize( FIBFieldHandler.PLCFFLDEDN, size );
|
_fieldHandler.setFieldSize( FIBFieldHandler.PLCFFLDEDN, size );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public int getFcPlcffldFtn()
|
public int getFcPlcffldFtn()
|
||||||
{
|
{
|
||||||
return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDFTN);
|
return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDFTN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public int getLcbPlcffldFtn()
|
public int getLcbPlcffldFtn()
|
||||||
{
|
{
|
||||||
return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDFTN);
|
return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDFTN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void setFcPlcffldFtn( int offset )
|
public void setFcPlcffldFtn( int offset )
|
||||||
{
|
{
|
||||||
_fieldHandler.setFieldOffset( FIBFieldHandler.PLCFFLDFTN, offset );
|
_fieldHandler.setFieldOffset( FIBFieldHandler.PLCFFLDFTN, offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void setLcbPlcffldFtn( int size )
|
public void setLcbPlcffldFtn( int size )
|
||||||
{
|
{
|
||||||
_fieldHandler.setFieldSize( FIBFieldHandler.PLCFFLDFTN, size );
|
_fieldHandler.setFieldSize( FIBFieldHandler.PLCFFLDFTN, size );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public int getFcPlcffldHdr()
|
public int getFcPlcffldHdr()
|
||||||
{
|
{
|
||||||
return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDHDR);
|
return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDHDR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public int getLcbPlcffldHdr()
|
public int getLcbPlcffldHdr()
|
||||||
{
|
{
|
||||||
return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDHDR);
|
return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDHDR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void setFcPlcffldHdr( int offset )
|
public void setFcPlcffldHdr( int offset )
|
||||||
{
|
{
|
||||||
_fieldHandler.setFieldOffset( FIBFieldHandler.PLCFFLDHDR, offset );
|
_fieldHandler.setFieldOffset( FIBFieldHandler.PLCFFLDHDR, offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void setLcbPlcffldHdr( int size )
|
public void setLcbPlcffldHdr( int size )
|
||||||
{
|
{
|
||||||
_fieldHandler.setFieldSize( FIBFieldHandler.PLCFFLDHDR, size );
|
_fieldHandler.setFieldSize( FIBFieldHandler.PLCFFLDHDR, size );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public int getFcPlcffldHdrtxbx()
|
public int getFcPlcffldHdrtxbx()
|
||||||
{
|
{
|
||||||
return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDHDRTXBX);
|
return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDHDRTXBX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public int getLcbPlcffldHdrtxbx()
|
public int getLcbPlcffldHdrtxbx()
|
||||||
{
|
{
|
||||||
return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDHDRTXBX);
|
return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDHDRTXBX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void setFcPlcffldHdrtxbx( int offset )
|
public void setFcPlcffldHdrtxbx( int offset )
|
||||||
{
|
{
|
||||||
_fieldHandler.setFieldOffset( FIBFieldHandler.PLCFFLDHDRTXBX, offset );
|
_fieldHandler.setFieldOffset( FIBFieldHandler.PLCFFLDHDRTXBX, offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void setLcbPlcffldHdrtxbx( int size )
|
public void setLcbPlcffldHdrtxbx( int size )
|
||||||
{
|
{
|
||||||
_fieldHandler.setFieldSize( FIBFieldHandler.PLCFFLDHDRTXBX, size );
|
_fieldHandler.setFieldSize( FIBFieldHandler.PLCFFLDHDRTXBX, size );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public int getFcPlcffldMom()
|
public int getFcPlcffldMom()
|
||||||
{
|
{
|
||||||
return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDMOM);
|
return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDMOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public int getLcbPlcffldMom()
|
public int getLcbPlcffldMom()
|
||||||
{
|
{
|
||||||
return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDMOM);
|
return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDMOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void setFcPlcffldMom( int offset )
|
public void setFcPlcffldMom( int offset )
|
||||||
{
|
{
|
||||||
_fieldHandler.setFieldOffset( FIBFieldHandler.PLCFFLDMOM, offset );
|
_fieldHandler.setFieldOffset( FIBFieldHandler.PLCFFLDMOM, offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void setLcbPlcffldMom( int size )
|
public void setLcbPlcffldMom( int size )
|
||||||
{
|
{
|
||||||
_fieldHandler.setFieldSize( FIBFieldHandler.PLCFFLDMOM, size );
|
_fieldHandler.setFieldSize( FIBFieldHandler.PLCFFLDMOM, size );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public int getFcPlcffldTxbx()
|
public int getFcPlcffldTxbx()
|
||||||
{
|
{
|
||||||
return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDTXBX);
|
return _fieldHandler.getFieldOffset(FIBFieldHandler.PLCFFLDTXBX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public int getLcbPlcffldTxbx()
|
public int getLcbPlcffldTxbx()
|
||||||
{
|
{
|
||||||
return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDTXBX);
|
return _fieldHandler.getFieldSize(FIBFieldHandler.PLCFFLDTXBX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void setFcPlcffldTxbx( int offset )
|
public void setFcPlcffldTxbx( int offset )
|
||||||
{
|
{
|
||||||
_fieldHandler.setFieldOffset( FIBFieldHandler.PLCFFLDTXBX, offset );
|
_fieldHandler.setFieldOffset( FIBFieldHandler.PLCFFLDTXBX, offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public void setLcbPlcffldTxbx( int size )
|
public void setLcbPlcffldTxbx( int size )
|
||||||
{
|
{
|
||||||
_fieldHandler.setFieldSize( FIBFieldHandler.PLCFFLDTXBX, size );
|
_fieldHandler.setFieldSize( FIBFieldHandler.PLCFFLDTXBX, size );
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package org.apache.poi.hwpf.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Document text parts that can have text pieces (CPs)
|
||||||
|
*
|
||||||
|
* @author Sergey Vladimirov (vlsergey {at} gmail {dot} com)
|
||||||
|
*/
|
||||||
|
public enum SubdocumentType {
|
||||||
|
MAIN( FIBLongHandler.CCPTEXT ),
|
||||||
|
|
||||||
|
FOOTNOTE( FIBLongHandler.CCPFTN ),
|
||||||
|
|
||||||
|
HEADER( FIBLongHandler.CCPHDD ),
|
||||||
|
|
||||||
|
MACRO( FIBLongHandler.CCPMCR ),
|
||||||
|
|
||||||
|
ANNOTATION( FIBLongHandler.CCPATN ),
|
||||||
|
|
||||||
|
ENDNOTE( FIBLongHandler.CCPEDN ),
|
||||||
|
|
||||||
|
TEXTBOX( FIBLongHandler.CCPTXBX ),
|
||||||
|
|
||||||
|
HEADER_TEXTBOX( FIBLongHandler.CCPHDRTXBX );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of {@link SubdocumentType}s ordered by document position and FIB
|
||||||
|
* field order
|
||||||
|
*/
|
||||||
|
public static final SubdocumentType[] ORDERED = new SubdocumentType[] {
|
||||||
|
MAIN, FOOTNOTE, HEADER, MACRO, ANNOTATION, ENDNOTE, TEXTBOX,
|
||||||
|
HEADER_TEXTBOX };
|
||||||
|
|
||||||
|
private final int fibLongFieldIndex;
|
||||||
|
|
||||||
|
private SubdocumentType( int fibLongFieldIndex )
|
||||||
|
{
|
||||||
|
this.fibLongFieldIndex = fibLongFieldIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFibLongFieldIndex()
|
||||||
|
{
|
||||||
|
return fibLongFieldIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -21,6 +21,7 @@ import org.apache.poi.hwpf.HWPFDocument;
|
|||||||
import org.apache.poi.hwpf.model.FileInformationBlock;
|
import org.apache.poi.hwpf.model.FileInformationBlock;
|
||||||
import org.apache.poi.hwpf.model.GenericPropertyNode;
|
import org.apache.poi.hwpf.model.GenericPropertyNode;
|
||||||
import org.apache.poi.hwpf.model.PlexOfCps;
|
import org.apache.poi.hwpf.model.PlexOfCps;
|
||||||
|
import org.apache.poi.hwpf.model.SubdocumentType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A HeaderStory is a Header, a Footer, or footnote/endnote
|
* A HeaderStory is a Header, a Footer, or footnote/endnote
|
||||||
@ -42,10 +43,14 @@ public final class HeaderStories {
|
|||||||
this.headerStories = doc.getHeaderStoryRange();
|
this.headerStories = doc.getHeaderStoryRange();
|
||||||
FileInformationBlock fib = doc.getFileInformationBlock();
|
FileInformationBlock fib = doc.getFileInformationBlock();
|
||||||
|
|
||||||
// If there's no PlcfHdd, nothing to do
|
// // If there's no PlcfHdd, nothing to do
|
||||||
if(fib.getCcpHdd() == 0) {
|
// if(fib.getCcpHdd() == 0) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (fib.getSubdocumentTextStreamLength( SubdocumentType.HEADER ) == 0)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
if(fib.getPlcfHddSize() == 0) {
|
if(fib.getPlcfHddSize() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -24,13 +24,13 @@ import java.util.NoSuchElementException;
|
|||||||
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.model.CHPX;
|
import org.apache.poi.hwpf.model.CHPX;
|
||||||
import org.apache.poi.hwpf.model.CPSplitCalculator;
|
|
||||||
import org.apache.poi.hwpf.model.FileInformationBlock;
|
import org.apache.poi.hwpf.model.FileInformationBlock;
|
||||||
import org.apache.poi.hwpf.model.ListTables;
|
import org.apache.poi.hwpf.model.ListTables;
|
||||||
import org.apache.poi.hwpf.model.PAPX;
|
import org.apache.poi.hwpf.model.PAPX;
|
||||||
import org.apache.poi.hwpf.model.PropertyNode;
|
import org.apache.poi.hwpf.model.PropertyNode;
|
||||||
import org.apache.poi.hwpf.model.SEPX;
|
import org.apache.poi.hwpf.model.SEPX;
|
||||||
import org.apache.poi.hwpf.model.StyleSheet;
|
import org.apache.poi.hwpf.model.StyleSheet;
|
||||||
|
import org.apache.poi.hwpf.model.SubdocumentType;
|
||||||
import org.apache.poi.hwpf.model.TextPiece;
|
import org.apache.poi.hwpf.model.TextPiece;
|
||||||
import org.apache.poi.hwpf.sprm.CharacterSprmCompressor;
|
import org.apache.poi.hwpf.sprm.CharacterSprmCompressor;
|
||||||
import org.apache.poi.hwpf.sprm.ParagraphSprmCompressor;
|
import org.apache.poi.hwpf.sprm.ParagraphSprmCompressor;
|
||||||
@ -1053,8 +1053,9 @@ public class Range { // TODO -instantiable superclass
|
|||||||
* @param adjustment
|
* @param adjustment
|
||||||
* The (signed) value that should be added to the FIB CCP fields
|
* The (signed) value that should be added to the FIB CCP fields
|
||||||
*/
|
*/
|
||||||
protected void adjustFIB(int adjustment) {
|
protected void adjustFIB( int adjustment )
|
||||||
assert (_doc instanceof HWPFDocument);
|
{
|
||||||
|
assert ( _doc instanceof HWPFDocument );
|
||||||
|
|
||||||
// update the FIB.CCPText field (this should happen once per adjustment,
|
// update the FIB.CCPText field (this should happen once per adjustment,
|
||||||
// so we don't want it in
|
// so we don't want it in
|
||||||
@ -1063,31 +1064,46 @@ public class Range { // TODO -instantiable superclass
|
|||||||
// without this, OpenOffice.org (v. 2.2.x) does not see all the text in
|
// without this, OpenOffice.org (v. 2.2.x) does not see all the text in
|
||||||
// the document
|
// the document
|
||||||
|
|
||||||
CPSplitCalculator cpS = ((HWPFDocument)_doc).getCPSplitCalculator();
|
|
||||||
FileInformationBlock fib = _doc.getFileInformationBlock();
|
FileInformationBlock fib = _doc.getFileInformationBlock();
|
||||||
|
|
||||||
// Do for each affected part
|
// // Do for each affected part
|
||||||
if (_start < cpS.getMainDocumentEnd()) {
|
// if (_start < cpS.getMainDocumentEnd()) {
|
||||||
fib.setCcpText(fib.getCcpText() + adjustment);
|
// fib.setCcpText(fib.getCcpText() + adjustment);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
// if (_start < cpS.getCommentsEnd()) {
|
||||||
|
// fib.setCcpAtn(fib.getCcpAtn() + adjustment);
|
||||||
|
// }
|
||||||
|
// if (_start < cpS.getEndNoteEnd()) {
|
||||||
|
// fib.setCcpEdn(fib.getCcpEdn() + adjustment);
|
||||||
|
// }
|
||||||
|
// if (_start < cpS.getFootnoteEnd()) {
|
||||||
|
// fib.setCcpFtn(fib.getCcpFtn() + adjustment);
|
||||||
|
// }
|
||||||
|
// if (_start < cpS.getHeaderStoryEnd()) {
|
||||||
|
// fib.setCcpHdd(fib.getCcpHdd() + adjustment);
|
||||||
|
// }
|
||||||
|
// if (_start < cpS.getHeaderTextboxEnd()) {
|
||||||
|
// fib.setCcpHdrTxtBx(fib.getCcpHdrTxtBx() + adjustment);
|
||||||
|
// }
|
||||||
|
// if (_start < cpS.getMainTextboxEnd()) {
|
||||||
|
// fib.setCcpTxtBx(fib.getCcpTxtBx() + adjustment);
|
||||||
|
// }
|
||||||
|
|
||||||
if (_start < cpS.getCommentsEnd()) {
|
// much simple implementation base on SubdocumentType --sergey
|
||||||
fib.setCcpAtn(fib.getCcpAtn() + adjustment);
|
|
||||||
|
int currentEnd = 0;
|
||||||
|
for ( SubdocumentType type : SubdocumentType.ORDERED )
|
||||||
|
{
|
||||||
|
int currentLength = fib.getSubdocumentTextStreamLength( type );
|
||||||
|
currentEnd += currentLength;
|
||||||
|
|
||||||
|
// do we need to shift this part?
|
||||||
|
if ( _start < currentEnd )
|
||||||
|
{
|
||||||
|
fib.setSubdocumentTextStreamLength( type, currentLength
|
||||||
|
+ adjustment );
|
||||||
}
|
}
|
||||||
if (_start < cpS.getEndNoteEnd()) {
|
|
||||||
fib.setCcpEdn(fib.getCcpEdn() + adjustment);
|
|
||||||
}
|
|
||||||
if (_start < cpS.getFootnoteEnd()) {
|
|
||||||
fib.setCcpFtn(fib.getCcpFtn() + adjustment);
|
|
||||||
}
|
|
||||||
if (_start < cpS.getHeaderStoryEnd()) {
|
|
||||||
fib.setCcpHdd(fib.getCcpHdd() + adjustment);
|
|
||||||
}
|
|
||||||
if (_start < cpS.getHeaderTextboxEnd()) {
|
|
||||||
fib.setCcpHdrTxtBx(fib.getCcpHdrTxtBx() + adjustment);
|
|
||||||
}
|
|
||||||
if (_start < cpS.getMainTextboxEnd()) {
|
|
||||||
fib.setCcpTxtBx(fib.getCcpTxtBx() + adjustment);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ package org.apache.poi.hwpf;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import org.apache.poi.hwpf.model.DocumentPart;
|
import org.apache.poi.hwpf.model.FieldsDocumentPart;
|
||||||
import org.apache.poi.hwpf.model.FieldsTables;
|
import org.apache.poi.hwpf.model.FieldsTables;
|
||||||
import org.apache.poi.hwpf.model.FileInformationBlock;
|
import org.apache.poi.hwpf.model.FileInformationBlock;
|
||||||
import org.apache.poi.hwpf.model.PlexOfField;
|
import org.apache.poi.hwpf.model.PlexOfField;
|
||||||
@ -80,9 +80,9 @@ public class TestFieldsTables extends HWPFTestCase
|
|||||||
|
|
||||||
FieldsTables fieldsTables = new FieldsTables( tableStream, fib );
|
FieldsTables fieldsTables = new FieldsTables( tableStream, fib );
|
||||||
|
|
||||||
for ( int i = 0; i < DocumentPart.values().length; i++ )
|
for ( int i = 0; i < FieldsDocumentPart.values().length; i++ )
|
||||||
{
|
{
|
||||||
DocumentPart part = DocumentPart.values()[i];
|
FieldsDocumentPart part = FieldsDocumentPart.values()[i];
|
||||||
|
|
||||||
ArrayList<PlexOfField> fieldsPlexes = fieldsTables
|
ArrayList<PlexOfField> fieldsPlexes = fieldsTables
|
||||||
.getFieldsPLCF( part );
|
.getFieldsPLCF( part );
|
||||||
|
@ -32,7 +32,7 @@ import org.apache.poi.hwpf.HWPFTestCase;
|
|||||||
import org.apache.poi.hwpf.HWPFTestDataSamples;
|
import org.apache.poi.hwpf.HWPFTestDataSamples;
|
||||||
import org.apache.poi.hwpf.extractor.Word6Extractor;
|
import org.apache.poi.hwpf.extractor.Word6Extractor;
|
||||||
import org.apache.poi.hwpf.extractor.WordExtractor;
|
import org.apache.poi.hwpf.extractor.WordExtractor;
|
||||||
import org.apache.poi.hwpf.model.DocumentPart;
|
import org.apache.poi.hwpf.model.FieldsDocumentPart;
|
||||||
import org.apache.poi.hwpf.model.PlexOfField;
|
import org.apache.poi.hwpf.model.PlexOfField;
|
||||||
import org.apache.poi.hwpf.model.StyleSheet;
|
import org.apache.poi.hwpf.model.StyleSheet;
|
||||||
import org.apache.poi.util.IOUtils;
|
import org.apache.poi.util.IOUtils;
|
||||||
@ -554,9 +554,9 @@ public final class TestProblems extends HWPFTestCase {
|
|||||||
.getCharacterTable().getTextRuns().size() );
|
.getCharacterTable().getTextRuns().size() );
|
||||||
|
|
||||||
List<PlexOfField> expectedFields = doc1.getFieldsTables()
|
List<PlexOfField> expectedFields = doc1.getFieldsTables()
|
||||||
.getFieldsPLCF( DocumentPart.MAIN );
|
.getFieldsPLCF( FieldsDocumentPart.MAIN );
|
||||||
List<PlexOfField> actualFields = doc2.getFieldsTables()
|
List<PlexOfField> actualFields = doc2.getFieldsTables()
|
||||||
.getFieldsPLCF( DocumentPart.MAIN );
|
.getFieldsPLCF( FieldsDocumentPart.MAIN );
|
||||||
assertEquals( expectedFields.size(), actualFields.size() );
|
assertEquals( expectedFields.size(), actualFields.size() );
|
||||||
|
|
||||||
assertTableStructures( doc1.getRange(), doc2.getRange() );
|
assertTableStructures( doc1.getRange(), doc2.getRange() );
|
||||||
|
Loading…
Reference in New Issue
Block a user