View | Details | Raw Unified | Return to bug 49050
Collapse All | Expand All

(-)src/java/org/apache/poi/hssf/util/LazilyConcatenatedByteArray.java (+86 lines)
Line 0 Link Here
1
/* ====================================================================
2
   Licensed to the Apache Software Foundation (ASF) under one or more
3
   contributor license agreements.  See the NOTICE file distributed with
4
   this work for additional information regarding copyright ownership.
5
   The ASF licenses this file to You under the Apache License, Version 2.0
6
   (the "License"); you may not use this file except in compliance with
7
   the License.  You may obtain a copy of the License at
8
9
       http://www.apache.org/licenses/LICENSE-2.0
10
11
   Unless required by applicable law or agreed to in writing, software
12
   distributed under the License is distributed on an "AS IS" BASIS,
13
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
   See the License for the specific language governing permissions and
15
   limitations under the License.
16
==================================================================== */
17
18
19
package org.apache.poi.hssf.util;
20
21
import java.util.ArrayList;
22
import java.util.List;
23
24
/**
25
 * Utility for delaying the concatenation of multiple byte arrays.  Doing this up-front
26
 * causes significantly more copying, which for a large number of byte arrays can cost
27
 * a large amount of time.
28
 *
29
 * @author Trejkaz (trejkaz at trypticon.org)
30
 */
31
public class LazilyConcatenatedByteArray {
32
    private final List<byte[]> arrays = new ArrayList<byte[]>(1);
33
34
    /**
35
     * Clears the array (sets the concatenated length back to zero.
36
     */
37
    public void clear() {
38
        arrays.clear();
39
    }
40
41
    /**
42
     * Concatenates an array onto the end of our array.
43
     * This is a relatively fast operation.
44
     *
45
     * @param array the array to concatenate.
46
     * @throws IllegalArgumentException if {@code array} is {@code null}.
47
     */
48
    public void concatenate(byte[] array) {
49
        if (array == null) {
50
            throw new IllegalArgumentException("array cannot be null");
51
        }
52
        arrays.add(array);
53
    }
54
55
    /**
56
     * Gets the concatenated contents as a single byte array.
57
     *
58
     * This is a slower operation, but the concatenated array is stored off as a single
59
     * array again so that subsequent calls will not perform additional copying.
60
     *
61
     * @return the byte array.  Returns {@code null} if no data has been placed into it.
62
     */
63
    public byte[] toArray() {
64
        if (arrays.isEmpty()) {
65
            return null;
66
        } else if (arrays.size() > 1) {
67
            int totalLength = 0;
68
            for (byte[] array : arrays) {
69
                totalLength += array.length;
70
            }
71
72
            byte[] concatenated = new byte[totalLength];
73
            int destPos = 0;
74
            for (byte[] array : arrays) {
75
                System.arraycopy(array, 0, concatenated, destPos, array.length);
76
                destPos += array.length;
77
            }
78
79
            arrays.clear();
80
            arrays.add(concatenated);
81
        }
82
83
        return arrays.get(0);
84
    }
85
}
86
(-)src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java (-14 / +13 lines)
Lines 28-33 Link Here
28
import org.apache.poi.ddf.EscherRecordFactory;
28
import org.apache.poi.ddf.EscherRecordFactory;
29
import org.apache.poi.ddf.NullEscherSerializationListener;
29
import org.apache.poi.ddf.NullEscherSerializationListener;
30
import org.apache.poi.util.LittleEndian;
30
import org.apache.poi.util.LittleEndian;
31
import org.apache.poi.hssf.util.LazilyConcatenatedByteArray;
31
32
32
/**
33
/**
33
 * The escher container record is used to hold escher records.  It is abstract and
34
 * The escher container record is used to hold escher records.  It is abstract and
Lines 47-53 Link Here
47
    }
48
    }
48
49
49
    private List escherRecords;
50
    private List escherRecords;
50
    private byte[] rawData;
51
    private LazilyConcatenatedByteArray rawDataContainer = new LazilyConcatenatedByteArray();
51
52
52
53
53
    public AbstractEscherHolderRecord()
54
    public AbstractEscherHolderRecord()
Lines 60-66 Link Here
60
        escherRecords = new ArrayList();
61
        escherRecords = new ArrayList();
61
        if (! DESERIALISE )
62
        if (! DESERIALISE )
62
        {
63
        {
63
            rawData = in.readRemainder();
64
            rawDataContainer.concatenate(in.readRemainder());
64
        }
65
        }
65
        else
66
        else
66
        {
67
        {
Lines 70-75 Link Here
70
    }
71
    }
71
72
72
    protected void convertRawBytesToEscherRecords() {
73
    protected void convertRawBytesToEscherRecords() {
74
        byte[] rawData = getRawData();
73
    	convertToEscherRecords(0, rawData.length, rawData);
75
    	convertToEscherRecords(0, rawData.length, rawData);
74
    }
76
    }
75
    private void convertToEscherRecords( int offset, int size, byte[] data )
77
    private void convertToEscherRecords( int offset, int size, byte[] data )
Lines 109-114 Link Here
109
    {
111
    {
110
        LittleEndian.putShort( data, 0 + offset, getSid() );
112
        LittleEndian.putShort( data, 0 + offset, getSid() );
111
        LittleEndian.putShort( data, 2 + offset, (short) ( getRecordSize() - 4 ) );
113
        LittleEndian.putShort( data, 2 + offset, (short) ( getRecordSize() - 4 ) );
114
        byte[] rawData = getRawData();
112
        if ( escherRecords.size() == 0 && rawData != null )
115
        if ( escherRecords.size() == 0 && rawData != null )
113
        {
116
        {
114
            LittleEndian.putShort(data, 0 + offset, getSid());
117
            LittleEndian.putShort(data, 0 + offset, getSid());
Lines 129-135 Link Here
129
    }
132
    }
130
133
131
    public int getRecordSize() {
134
    public int getRecordSize() {
135
        byte[] rawData = getRawData();
132
        if (escherRecords.size() == 0 && rawData != null) {
136
        if (escherRecords.size() == 0 && rawData != null) {
137
            // XXX: It should be possible to derive this without concatenating the array, too.
133
            return rawData.length;
138
            return rawData.length;
134
        }
139
        }
135
        int size = 0;
140
        int size = 0;
Lines 229-258 Link Here
229
     */
234
     */
230
    public void join( AbstractEscherHolderRecord record )
235
    public void join( AbstractEscherHolderRecord record )
231
    {
236
    {
232
        int length = this.rawData.length + record.getRawData().length;
237
        rawDataContainer.concatenate(record.getRawData());
233
        byte[] data = new byte[length];
234
        System.arraycopy( rawData, 0, data, 0, rawData.length );
235
        System.arraycopy( record.getRawData(), 0, data, rawData.length, record.getRawData().length );
236
        rawData = data;
237
    }
238
    }
238
239
239
    public void processContinueRecord( byte[] record )
240
    public void processContinueRecord( byte[] record )
240
    {
241
    {
241
        int length = this.rawData.length + record.length;
242
        rawDataContainer.concatenate(record);
242
        byte[] data = new byte[length];
243
        System.arraycopy( rawData, 0, data, 0, rawData.length );
244
        System.arraycopy( record, 0, data, rawData.length, record.length );
245
        rawData = data;
246
    }
243
    }
247
244
248
    public byte[] getRawData()
245
    public byte[] getRawData()
249
    {
246
    {
250
        return rawData;
247
        return rawDataContainer.toArray();
251
    }
248
    }
252
249
253
    public void setRawData( byte[] rawData )
250
    public void setRawData( byte[] rawData )
254
    {
251
    {
255
        this.rawData = rawData;
252
        rawDataContainer.clear();
253
        rawDataContainer.concatenate(rawData);
256
    }
254
    }
257
255
258
    /**
256
    /**
Lines 260-265 Link Here
260
     */
258
     */
261
    public void decode()
259
    public void decode()
262
    {
260
    {
261
        byte[] rawData = getRawData();
263
        convertToEscherRecords(0, rawData.length, rawData );
262
        convertToEscherRecords(0, rawData.length, rawData );
264
    }
263
    }
265
}
264
}

Return to bug 49050