public void rebuild()

in poi-scratchpad/src/main/java/org/apache/poi/hwpf/model/CHPBinTable.java [118:304]


    public void rebuild( ComplexFileTable complexFileTable )
    {
        long start = currentTimeMillis();

        if ( complexFileTable != null )
        {
            SprmBuffer[] sprmBuffers = complexFileTable.getGrpprls();

            // adding CHPX from fast-saved SPRMs
            for ( TextPiece textPiece : complexFileTable.getTextPieceTable()
                    .getTextPieces() )
            {
                PropertyModifier prm = textPiece.getPieceDescriptor().getPrm();
                if ( !prm.isComplex() )
                    continue;
                int igrpprl = prm.getIgrpprl();

                if ( igrpprl < 0 || igrpprl >= sprmBuffers.length )
                {
                    LOG.atWarn().log("{}'s PRM references to unknown grpprl", textPiece);
                    continue;
                }

                boolean hasChp = false;
                SprmBuffer sprmBuffer = sprmBuffers[igrpprl];
                for ( SprmIterator iterator = sprmBuffer.iterator(); iterator
                        .hasNext(); )
                {
                    SprmOperation sprmOperation = iterator.next();
                    if ( sprmOperation.getType() == SprmOperation.TYPE_CHP )
                    {
                        hasChp = true;
                        break;
                    }
                }

                if ( hasChp )
                {
                    SprmBuffer newSprmBuffer = sprmBuffer.copy();

                    CHPX chpx = new CHPX( textPiece.getStart(),
                            textPiece.getEnd(), newSprmBuffer );
                    _textRuns.add( chpx );
                }
            }
            LOG.atDebug().log("Merged with CHPX from complex file table in {} ms ({} elements in total)", box(currentTimeMillis() - start),box(_textRuns.size()));
            start = currentTimeMillis();
        }

        List<CHPX> oldChpxSortedByStartPos = new ArrayList<>(_textRuns);
        oldChpxSortedByStartPos.sort(PropertyNode.StartComparator);

        LOG.atDebug().log("CHPX sorted by start position in {} ms", box(currentTimeMillis() - start));
        start = currentTimeMillis();

        final Map<CHPX, Integer> chpxToFileOrder = new IdentityHashMap<>();
        {
            int counter = 0;
            for ( CHPX chpx : _textRuns )
            {
                chpxToFileOrder.put( chpx, Integer.valueOf( counter++ ) );
            }
        }
        final Comparator<CHPX> chpxFileOrderComparator = (o1, o2) -> {
            Integer i1 = chpxToFileOrder.get( o1 );
            Integer i2 = chpxToFileOrder.get( o2 );
            return i1.compareTo( i2 );
        };

        LOG.atDebug().log("CHPX's order map created in {} ms", box(currentTimeMillis() - start));
        start = currentTimeMillis();

        List<Integer> textRunsBoundariesList;
        {
            Set<Integer> textRunsBoundariesSet = new HashSet<>();
            for ( CHPX chpx : _textRuns )
            {
                textRunsBoundariesSet.add( Integer.valueOf( chpx.getStart() ) );
                textRunsBoundariesSet.add( Integer.valueOf( chpx.getEnd() ) );
            }
            textRunsBoundariesSet.remove( Integer.valueOf( 0 ) );
            textRunsBoundariesList = new ArrayList<>(
                    textRunsBoundariesSet);
            Collections.sort( textRunsBoundariesList );
        }

        LOG.atDebug().log("Texts CHPX boundaries collected in {} ms", box(currentTimeMillis() - start));
        start = currentTimeMillis();

        List<CHPX> newChpxs = new LinkedList<>();
        int lastTextRunStart = 0;
        for ( Integer objBoundary : textRunsBoundariesList )
        {
            final int boundary = objBoundary.intValue();

            final int startInclusive = lastTextRunStart;
            lastTextRunStart = boundary;

            int startPosition = binarySearch( oldChpxSortedByStartPos, boundary );
            startPosition = Math.abs( startPosition );
            while ( startPosition >= oldChpxSortedByStartPos.size() )
                startPosition--;
            while ( startPosition > 0
                    && oldChpxSortedByStartPos.get( startPosition ).getStart() >= boundary )
                startPosition--;

            List<CHPX> chpxs = new LinkedList<>();
            for ( int c = startPosition; c < oldChpxSortedByStartPos.size(); c++ )
            {
                CHPX chpx = oldChpxSortedByStartPos.get( c );

                if ( boundary < chpx.getStart() )
                    break;

                int left = Math.max( startInclusive, chpx.getStart() );
                int right = Math.min(boundary, chpx.getEnd() );

                if ( left < right )
                {
                    chpxs.add( chpx );
                }
            }

            if ( chpxs.isEmpty() )
            {
                LOG.atWarn().log("Text piece [{}; {}) has no CHPX. Creating new one.", box(startInclusive),box(boundary));
                // create it manually
                CHPX chpx = new CHPX( startInclusive, boundary,
                        new SprmBuffer( 0 ) );
                newChpxs.add( chpx );
                continue;
            }

            if ( chpxs.size() == 1 )
            {
                // can we reuse existing?
                CHPX existing = chpxs.get( 0 );
                if ( existing.getStart() == startInclusive
                        && existing.getEnd() == boundary)
                {
                    newChpxs.add( existing );
                    continue;
                }
            }

            chpxs.sort(chpxFileOrderComparator);

            SprmBuffer sprmBuffer = new SprmBuffer( 0 );
            for ( CHPX chpx : chpxs )
            {
                sprmBuffer.append( chpx.getGrpprl(), 0 );
            }
            CHPX newChpx = new CHPX( startInclusive, boundary, sprmBuffer );
            newChpxs.add( newChpx );

            continue;
        }
        this._textRuns = new ArrayList<>(newChpxs);

        LOG.atDebug().log("CHPX rebuilt in {} ms ({} elements)", box(currentTimeMillis() - start),box(_textRuns.size()));
        start = currentTimeMillis();

        CHPX previous = null;
        for ( Iterator<CHPX> iterator = _textRuns.iterator(); iterator
                .hasNext(); )
        {
            CHPX current = iterator.next();
            if ( previous == null )
            {
                previous = current;
                continue;
            }

            if ( previous.getEnd() == current.getStart()
                    && Arrays
                            .equals( previous.getGrpprl(), current.getGrpprl() ) )
            {
                previous.setEnd( current.getEnd() );
                iterator.remove();
                continue;
            }

            previous = current;
        }

        LOG.atDebug().log("CHPX compacted in {} ms ({} elements)", box(currentTimeMillis() - start),box(_textRuns.size()));
    }