From e0e44fee69f7051aa3c4f82b25113c8da2024a4f Mon Sep 17 00:00:00 2001 From: Sergey Vladimirov Date: Fri, 22 Jul 2011 19:38:14 +0000 Subject: [PATCH] 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 --- .../src/org/apache/poi/hwpf/HWPFDocument.java | 23 +- .../hwpf/converter/AbstractWordConverter.java | 9 +- .../org/apache/poi/hwpf/dev/HWPFLister.java | 10 +- .../apache/poi/hwpf/model/FieldsTables.java | 233 +-------------- .../org/apache/poi/hwpf/usermodel/Field.java | 55 ++++ .../Field.java => usermodel/FieldImpl.java} | 36 ++- .../org/apache/poi/hwpf/usermodel/Fields.java | 33 +++ .../apache/poi/hwpf/usermodel/FieldsImpl.java | 276 ++++++++++++++++++ 8 files changed, 427 insertions(+), 248 deletions(-) create mode 100644 src/scratchpad/src/org/apache/poi/hwpf/usermodel/Field.java rename src/scratchpad/src/org/apache/poi/hwpf/{model/Field.java => usermodel/FieldImpl.java} (78%) create mode 100644 src/scratchpad/src/org/apache/poi/hwpf/usermodel/Fields.java create mode 100644 src/scratchpad/src/org/apache/poi/hwpf/usermodel/FieldsImpl.java diff --git a/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java b/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java index 852e895506..c2e5659984 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/HWPFDocument.java @@ -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. * diff --git a/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordConverter.java b/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordConverter.java index fc9ece7a51..faee8345a6 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordConverter.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/converter/AbstractWordConverter.java @@ -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; diff --git a/src/scratchpad/src/org/apache/poi/hwpf/dev/HWPFLister.java b/src/scratchpad/src/org/apache/poi/hwpf/dev/HWPFLister.java index 5b1df39e13..751081abdf 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/dev/HWPFLister.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/dev/HWPFLister.java @@ -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 ); diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/FieldsTables.java b/src/scratchpad/src/org/apache/poi/hwpf/model/FieldsTables.java index 2c2b766a03..3bc59fbf64 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/model/FieldsTables.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/FieldsTables.java @@ -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 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 toArrayList( PlexOfCps plexOfCps ) { if ( plexOfCps == null ) return new ArrayList(); - ArrayList fields = new ArrayList(); - fields.ensureCapacity( plexOfCps.length() ); - + ArrayList fields = new ArrayList( + 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> _fieldsByOffset; - private Map _tables; - private GenericPropertyNodeComparator comparator = new GenericPropertyNodeComparator(); - public FieldsTables( byte[] tableStream, FileInformationBlock fib ) { _tables = new HashMap( FieldsDocumentPart.values().length ); - _fieldsByOffset = new HashMap>( - 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 getFields( FieldsDocumentPart part ) - { - Map map = _fieldsByOffset.get( part ); - if ( map == null || map.isEmpty() ) - return Collections.emptySet(); - - return Collections.unmodifiableCollection( map.values() ); - } - public ArrayList 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 map = _fieldsByOffset.get( documentPart ); - if ( map == null || map.isEmpty() ) - return null; - - return map.get( Integer.valueOf( offset ) ); - } - - private Map parseFieldStructure( PlexOfCps plexOfCps ) - { - if ( plexOfCps == null ) - return new HashMap(); - - GenericPropertyNode[] nodes = plexOfCps.toPropertiesArray(); - Arrays.sort( nodes, comparator ); - List fields = new ArrayList( nodes.length / 3 + 1 ); - parseFieldStructureImpl( nodes, 0, nodes.length, fields ); - - HashMap result = new HashMap( - 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 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 - { - public int compare( GenericPropertyNode o1, GenericPropertyNode o2 ) - { - int thisVal = o1.getStart(); - int anotherVal = o2.getStart(); - return thisVal < anotherVal ? -1 : thisVal == anotherVal ? 0 : 1; - } - } } diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Field.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Field.java new file mode 100644 index 0000000000..72b5220dde --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Field.java @@ -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 ); +} \ No newline at end of file diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/Field.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/FieldImpl.java similarity index 78% rename from src/scratchpad/src/org/apache/poi/hwpf/model/Field.java rename to src/scratchpad/src/org/apache/poi/hwpf/usermodel/FieldImpl.java index f12209a16b..4832b23f96 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/model/Field.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/FieldImpl.java @@ -1,14 +1,38 @@ -package org.apache.poi.hwpf.model; - -import org.apache.poi.hwpf.usermodel.Range; - -public class Field +/* ==================================================================== + 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 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 ) diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Fields.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Fields.java new file mode 100644 index 0000000000..2db551e5e2 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/Fields.java @@ -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 getFields( FieldsDocumentPart part ); +} diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/FieldsImpl.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/FieldsImpl.java new file mode 100644 index 0000000000..3c5eba60e3 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/FieldsImpl.java @@ -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 int binarySearch( List 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> _fieldsByOffset; + + private PlexOfFieldComparator comparator = new PlexOfFieldComparator(); + + public FieldsImpl( FieldsTables fieldsTables ) + { + _fieldsByOffset = new HashMap>( + FieldsDocumentPart.values().length ); + + for ( FieldsDocumentPart part : FieldsDocumentPart.values() ) + { + List plexOfCps = fieldsTables.getFieldsPLCF( part ); + _fieldsByOffset.put( part, parseFieldStructure( plexOfCps ) ); + } + } + + public Collection getFields( FieldsDocumentPart part ) + { + Map map = _fieldsByOffset.get( part ); + if ( map == null || map.isEmpty() ) + return Collections.emptySet(); + + return Collections. unmodifiableCollection( map.values() ); + } + + public FieldImpl getFieldByStartOffset( FieldsDocumentPart documentPart, + int offset ) + { + Map map = _fieldsByOffset.get( documentPart ); + if ( map == null || map.isEmpty() ) + return null; + + return map.get( Integer.valueOf( offset ) ); + } + + private Map parseFieldStructure( + List plexOfFields ) + { + if ( plexOfFields == null || plexOfFields.isEmpty() ) + return new HashMap(); + + Collections.sort( plexOfFields, comparator ); + List fields = new ArrayList( + plexOfFields.size() / 3 + 1 ); + parseFieldStructureImpl( plexOfFields, 0, plexOfFields.size(), fields ); + + HashMap result = new HashMap( + fields.size() ); + for ( FieldImpl field : fields ) + { + result.put( Integer.valueOf( field.getFieldStartOffset() ), field ); + } + return result; + } + + private void parseFieldStructureImpl( List plexOfFields, + int startOffsetInclusive, int endOffsetExclusive, + List 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 + { + public int compare( PlexOfField o1, PlexOfField o2 ) + { + int thisVal = o1.getFcStart(); + int anotherVal = o2.getFcStart(); + return thisVal < anotherVal ? -1 : thisVal == anotherVal ? 0 : 1; + } + } + +} -- 2.39.5