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

(-)src/scratchpad/src/org/apache/poi/hemf/record/HemfComment.java (+31 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
package org.apache.poi.hemf.record;
19
20
import org.apache.poi.util.Internal;
21
22
/**
23
 * Contains arbitrary data
24
 */
25
@Internal
26
public class HemfComment extends  AbstractHemfComment {
27
28
    public HemfComment(byte[] rawBytes) {
29
        super(rawBytes);
30
    }
31
}
(-)src/scratchpad/src/org/apache/poi/hemf/hemfplus/record/UnimplementedHemfPlusRecord.java (+53 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
package org.apache.poi.hemf.hemfplus.record;
19
20
21
import java.io.IOException;
22
23
import org.apache.poi.util.Internal;
24
25
@Internal
26
public class UnimplementedHemfPlusRecord implements HemfPlusRecord {
27
28
    private int recordId;
29
    private int flags;
30
    private byte[] recordBytes;
31
32
    @Override
33
    public HemfPlusRecordType getRecordType() {
34
        return HemfPlusRecordType.getById(recordId);
35
    }
36
37
    @Override
38
    public int getFlags() {
39
        return flags;
40
    }
41
42
    @Override
43
    public void init(byte[] recordBytes, int recordId, int flags) throws IOException {
44
        this.recordId = recordId;
45
        this.flags = flags;
46
        this.recordBytes = recordBytes;
47
    }
48
49
    public byte[] getRecordBytes() {
50
        //should probably defensively return a copy.
51
        return recordBytes;
52
    }
53
}
(-)src/scratchpad/testcases/org/apache/poi/hemf/extractor/HemfExtractorTest.java (+158 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.hemf.extractor;
20
21
import static org.apache.poi.POITestCase.assertContains;
22
import static org.junit.Assert.assertEquals;
23
import static org.junit.Assert.assertTrue;
24
25
import java.io.InputStream;
26
27
import org.apache.poi.POIDataSamples;
28
import org.apache.poi.hemf.record.AbstractHemfComment;
29
import org.apache.poi.hemf.record.HemfCommentPublic;
30
import org.apache.poi.hemf.record.HemfCommentRecord;
31
import org.apache.poi.hemf.record.HemfRecord;
32
import org.apache.poi.hemf.record.HemfRecordType;
33
import org.apache.poi.hemf.record.HemfText;
34
import org.apache.poi.hemf.record.HemfHeader;
35
import org.junit.Test;
36
37
public class HemfExtractorTest {
38
    static {
39
        System.setProperty("POI.testdata.path", "C:/users/tallison/Idea Projects/poi-trunk/test-data");
40
    }
41
42
    @Test
43
    public void testBasicWindows() throws Exception {
44
        InputStream is = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SimpleEMF_windows.emf");
45
        HemfExtractor ex = new HemfExtractor(is);
46
        HemfHeader header = ex.getHeader();
47
        assertEquals(27864, header.getBytes());
48
        assertEquals(31, header.getRecords());
49
        assertEquals(3, header.getHandles());
50
        assertEquals(346000, header.getMicrometersX());
51
        assertEquals(194000, header.getMicrometersY());
52
53
        int records = 0;
54
        for (HemfRecord record : ex) {
55
            records++;
56
        }
57
58
        assertEquals(header.getRecords() - 1, records);
59
    }
60
61
    @Test
62
    public void testBasicMac() throws Exception {
63
        InputStream is =
64
                POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SimpleEMF_mac.emf");
65
        HemfExtractor ex = new HemfExtractor(is);
66
        HemfHeader header = ex.getHeader();
67
68
        int records = 0;
69
        boolean extractedData = false;
70
        for (HemfRecord record : ex) {
71
            if (record.getRecordType() == HemfRecordType.comment) {
72
                AbstractHemfComment comment = ((HemfCommentRecord) record).getComment();
73
                if (comment instanceof HemfCommentPublic.MultiFormats) {
74
                    for (HemfCommentPublic.HemfMultiFormatsData d : ((HemfCommentPublic.MultiFormats) comment).getData()) {
75
                        byte[] data = d.getData();
76
                        //make sure header starts at 0
77
                        assertEquals('%', data[0]);
78
                        assertEquals('P', data[1]);
79
                        assertEquals('D', data[2]);
80
                        assertEquals('F', data[3]);
81
82
                        //make sure byte array ends at EOF\n
83
                        assertEquals('E', data[data.length - 4]);
84
                        assertEquals('O', data[data.length - 3]);
85
                        assertEquals('F', data[data.length - 2]);
86
                        assertEquals('\n', data[data.length - 1]);
87
                        extractedData = true;
88
                    }
89
                }
90
            }
91
            records++;
92
        }
93
        assertTrue(extractedData);
94
        assertEquals(header.getRecords() - 1, records);
95
    }
96
97
    @Test
98
    public void testMacText() throws Exception {
99
        InputStream is =
100
                POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SimpleEMF_mac.emf");
101
        HemfExtractor ex = new HemfExtractor(is);
102
103
        long lastY = -1;
104
        long lastX = -1;
105
        long fudgeFactorX = 1000;//derive this from the font information!
106
        StringBuilder sb = new StringBuilder();
107
        for (HemfRecord record : ex) {
108
            if (record.getRecordType().equals(HemfRecordType.exttextoutw)) {
109
                HemfText.ExtTextOutW extTextOutW = (HemfText.ExtTextOutW) record;
110
                HemfText.EmrTextObject emrTextObject = extTextOutW.getTextObject();
111
                if (lastY > -1 && lastY != emrTextObject.getY()) {
112
                    sb.append("\n");
113
                    lastX = -1;
114
                }
115
                if (lastX > -1 && emrTextObject.getX() - lastX > fudgeFactorX) {
116
                    sb.append(" ");
117
                }
118
                sb.append(emrTextObject.getText());
119
                lastY = emrTextObject.getY();
120
                lastX = emrTextObject.getX();
121
            }
122
        }
123
        String txt = sb.toString();
124
        assertContains(txt, "Tika http://incubator.apache.org");
125
        assertContains(txt, "Latest News\n");
126
    }
127
128
    @Test
129
    public void testWindowsText() throws Exception {
130
        InputStream is = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SimpleEMF_windows.emf");
131
        HemfExtractor ex = new HemfExtractor(is);
132
        long lastY = -1;
133
        long lastX = -1;
134
        long fudgeFactorX = 1000;//derive this from the font information!
135
        StringBuilder sb = new StringBuilder();
136
        for (HemfRecord record : ex) {
137
            if (record.getRecordType().equals(HemfRecordType.exttextoutw)) {
138
                HemfText.ExtTextOutW extTextOutW = (HemfText.ExtTextOutW) record;
139
                HemfText.EmrTextObject emrTextObject = extTextOutW.getTextObject();
140
                if (lastY > -1 && lastY != emrTextObject.getY()) {
141
                    sb.append("\n");
142
                    lastX = -1;
143
                }
144
                if (lastX > -1 && emrTextObject.getX() - lastX > fudgeFactorX) {
145
                    sb.append(" ");
146
                }
147
                sb.append(emrTextObject.getText());
148
                lastY = emrTextObject.getY();
149
                lastX = emrTextObject.getX();
150
            }
151
        }
152
        String txt = sb.toString();
153
        assertContains(txt, "C:\\Users\\tallison\\\n");
154
        assertContains(txt, "asf2-git-1.x\\tika-\n");
155
    }
156
157
158
}
(-)src/scratchpad/src/org/apache/poi/hemf/record/UnimplementedHemfRecord.java (+46 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
package org.apache.poi.hemf.record;
19
20
21
import java.io.IOException;
22
23
import org.apache.poi.util.IOUtils;
24
import org.apache.poi.util.Internal;
25
import org.apache.poi.util.LittleEndianInputStream;
26
27
@Internal
28
public class UnimplementedHemfRecord implements HemfRecord {
29
30
    private long recordId;
31
32
    @Override
33
    public HemfRecordType getRecordType() {
34
        return HemfRecordType.getById(recordId);
35
    }
36
37
    @Override
38
    public long init(LittleEndianInputStream leis, long recordId, long recordSize) throws IOException {
39
        this.recordId = recordId;
40
        long skipped = IOUtils.skipFully(leis, recordSize);
41
        if (skipped < 0) {
42
            throw new IOException("End of stream reached before record read");
43
        }
44
        return skipped;
45
    }
46
}
(-)src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentPublic.java (+149 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
package org.apache.poi.hemf.record;
19
20
21
import java.util.ArrayList;
22
import java.util.List;
23
24
import org.apache.poi.util.Internal;
25
import org.apache.poi.util.LittleEndian;
26
import org.apache.poi.util.RecordFormatException;
27
28
/**
29
 * Container class for four subtypes of HemfCommentPublic: BeginGroup, EndGroup, MultiFormats
30
 * and Windows Metafile.
31
 */
32
@Internal
33
public class HemfCommentPublic  {
34
35
    /**
36
     * Stub, to be implemented
37
     */
38
    public static class BeginGroup extends AbstractHemfComment {
39
40
        public BeginGroup(byte[] rawBytes) {
41
            super(rawBytes);
42
        }
43
44
    }
45
46
    /**
47
     * Stub, to be implemented
48
     */
49
    public static class EndGroup extends AbstractHemfComment {
50
51
        public EndGroup(byte[] rawBytes) {
52
            super(rawBytes);
53
        }
54
    }
55
56
    public static class MultiFormats extends AbstractHemfComment {
57
58
        public MultiFormats(byte[] rawBytes) {
59
            super(rawBytes);
60
        }
61
62
        /**
63
         *
64
         * @return a list of HemfMultFormatsData
65
         */
66
        public List<HemfMultiFormatsData> getData() {
67
68
            byte[] rawBytes = getRawBytes();
69
            //note that raw bytes includes the public comment identifier
70
            int currentOffset = 4 + 16;//4 public comment identifier, 16 for outputrect
71
            long countFormats = LittleEndian.getUInt(rawBytes, currentOffset);
72
            currentOffset += LittleEndian.INT_SIZE;
73
            List<EmrFormat> emrFormatList = new ArrayList<EmrFormat>();
74
            for (long i = 0; i < countFormats; i++) {
75
                emrFormatList.add(new EmrFormat(rawBytes, currentOffset));
76
                currentOffset += 4 * LittleEndian.INT_SIZE;
77
            }
78
            List<HemfMultiFormatsData> list = new ArrayList<HemfMultiFormatsData>();
79
            for (EmrFormat emrFormat : emrFormatList) {
80
                byte[] data = new byte[emrFormat.size];
81
                System.arraycopy(rawBytes, emrFormat.offset-4, data, 0, emrFormat.size);
82
                list.add(new HemfMultiFormatsData(emrFormat.signature, emrFormat.version, data));
83
            }
84
            return list;
85
        }
86
87
        private class EmrFormat {
88
            long signature;
89
            long version;
90
            int size;
91
            int offset;
92
93
            public EmrFormat(byte[] rawBytes, int currentOffset) {
94
                signature = LittleEndian.getUInt(rawBytes, currentOffset); currentOffset += LittleEndian.INT_SIZE;
95
                version = LittleEndian.getUInt(rawBytes, currentOffset); currentOffset += LittleEndian.INT_SIZE;
96
                //spec says this must be a 32bit "aligned" typo for "signed"?
97
                //realistically, this has to be an int...
98
                size = LittleEndian.getInt(rawBytes, currentOffset); currentOffset += LittleEndian.INT_SIZE;
99
                //y, can be long, but realistically?
100
                offset = LittleEndian.getInt(rawBytes, currentOffset); currentOffset += LittleEndian.INT_SIZE;
101
                if (size < 0) {
102
                    throw new RecordFormatException("size for emrformat must be > 0");
103
                }
104
                if (offset < 0) {
105
                    throw new RecordFormatException("offset for emrformat must be > 0");
106
                }
107
            }
108
        }
109
    }
110
111
    /**
112
     * Stub, to be implemented
113
     */
114
    public static class WindowsMetafile extends AbstractHemfComment {
115
116
        public WindowsMetafile(byte[] rawBytes) {
117
            super(rawBytes);
118
        }
119
    }
120
121
    /**
122
     * This encapulates a single record stored within
123
     * a HemfCommentPublic.MultiFormats record.
124
     */
125
    public static class HemfMultiFormatsData {
126
127
        long signature;
128
        long version;
129
        byte[] data;
130
131
        public HemfMultiFormatsData(long signature, long version, byte[] data) {
132
            this.signature = signature;
133
            this.version = version;
134
            this.data = data;
135
        }
136
137
        public long getSignature() {
138
            return signature;
139
        }
140
141
        public long getVersion() {
142
            return version;
143
        }
144
145
        public byte[] getData() {
146
            return data;
147
        }
148
    }
149
}
(-)src/scratchpad/src/org/apache/poi/hemf/hemfplus/record/HemfPlusRecordType.java (+97 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
package org.apache.poi.hemf.hemfplus.record;
19
20
import org.apache.poi.util.Internal;
21
22
@Internal
23
public enum HemfPlusRecordType {
24
    header(0x4001, HemfPlusHeader.class),
25
    endOfFile(0x4002, UnimplementedHemfPlusRecord.class),
26
    comment(0x4003, UnimplementedHemfPlusRecord.class),
27
    getDC(0x4004, UnimplementedHemfPlusRecord.class),
28
    multiFormatStart(0x4005, UnimplementedHemfPlusRecord.class),
29
    multiFormatSection(0x4006, UnimplementedHemfPlusRecord.class),
30
    multiFormatEnd(0x4007, UnimplementedHemfPlusRecord.class),
31
    object(0x4008, UnimplementedHemfPlusRecord.class),
32
    clear(0x4009, UnimplementedHemfPlusRecord.class),
33
    fillRects(0x400A, UnimplementedHemfPlusRecord.class),
34
    drawRects(0x400B, UnimplementedHemfPlusRecord.class),
35
    fillPolygon(0x400C, UnimplementedHemfPlusRecord.class),
36
    drawLines(0x400D, UnimplementedHemfPlusRecord.class),
37
    fillEllipse(0x400E, UnimplementedHemfPlusRecord.class),
38
    drawEllipse(0x400F, UnimplementedHemfPlusRecord.class),
39
    fillPie(0x4010, UnimplementedHemfPlusRecord.class),
40
    drawPie(0x4011, UnimplementedHemfPlusRecord.class),
41
    drawArc(0x4012, UnimplementedHemfPlusRecord.class),
42
    fillRegion(0x4013, UnimplementedHemfPlusRecord.class),
43
    fillPath(0x4014, UnimplementedHemfPlusRecord.class),
44
    drawPath(0x4015, UnimplementedHemfPlusRecord.class),
45
    fillClosedCurve(0x4016, UnimplementedHemfPlusRecord.class),
46
    drawClosedCurve(0x4017, UnimplementedHemfPlusRecord.class),
47
    drawCurve(0x4018, UnimplementedHemfPlusRecord.class),
48
    drawBeziers(0x4019, UnimplementedHemfPlusRecord.class),
49
    drawImage(0x401A, UnimplementedHemfPlusRecord.class),
50
    drawImagePoints(0x401B, UnimplementedHemfPlusRecord.class),
51
    drawString(0x401C, UnimplementedHemfPlusRecord.class),
52
    setRenderingOrigin(0x401D, UnimplementedHemfPlusRecord.class),
53
    setAntiAliasMode(0x401E, UnimplementedHemfPlusRecord.class),
54
    setTextRenderingHint(0x401F, UnimplementedHemfPlusRecord.class),
55
    setTextContrast(0x4020, UnimplementedHemfPlusRecord.class),
56
    setInterpolationMode(0x4021, UnimplementedHemfPlusRecord.class),
57
    setPixelOffsetMode(0x4022, UnimplementedHemfPlusRecord.class),
58
    setComositingMode(0x4023, UnimplementedHemfPlusRecord.class),
59
    setCompositingQuality(0x4024, UnimplementedHemfPlusRecord.class),
60
    save(0x4025, UnimplementedHemfPlusRecord.class),
61
    restore(0x4026, UnimplementedHemfPlusRecord.class),
62
    beginContainer(0x4027, UnimplementedHemfPlusRecord.class),
63
    beginContainerNoParams(0x428, UnimplementedHemfPlusRecord.class),
64
    endContainer(0x4029, UnimplementedHemfPlusRecord.class),
65
    setWorldTransform(0x402A, UnimplementedHemfPlusRecord.class),
66
    resetWorldTransform(0x402B, UnimplementedHemfPlusRecord.class),
67
    multiplyWorldTransform(0x402C, UnimplementedHemfPlusRecord.class),
68
    translateWorldTransform(0x402D, UnimplementedHemfPlusRecord.class),
69
    scaleWorldTransform(0x402E, UnimplementedHemfPlusRecord.class),
70
    rotateWorldTransform(0x402F, UnimplementedHemfPlusRecord.class),
71
    setPageTransform(0x4030, UnimplementedHemfPlusRecord.class),
72
    resetClip(0x4031, UnimplementedHemfPlusRecord.class),
73
    setClipRect(0x4032, UnimplementedHemfPlusRecord.class),
74
    setClipRegion(0x4033, UnimplementedHemfPlusRecord.class),
75
    setClipPath(0x4034, UnimplementedHemfPlusRecord.class),
76
    offsetClip(0x4035, UnimplementedHemfPlusRecord.class),
77
    drawDriverstring(0x4036, UnimplementedHemfPlusRecord.class),
78
    strokeFillPath(0x4037, UnimplementedHemfPlusRecord.class),
79
    serializableObject(0x4038, UnimplementedHemfPlusRecord.class),
80
    setTSGraphics(0x4039, UnimplementedHemfPlusRecord.class),
81
    setTSClip(0x403A, UnimplementedHemfPlusRecord.class);
82
83
    public final long id;
84
    public final Class<? extends HemfPlusRecord> clazz;
85
86
    HemfPlusRecordType(long id, Class<? extends HemfPlusRecord> clazz) {
87
        this.id = id;
88
        this.clazz = clazz;
89
    }
90
91
    public static HemfPlusRecordType getById(long id) {
92
        for (HemfPlusRecordType wrt : values()) {
93
            if (wrt.id == id) return wrt;
94
        }
95
        return null;
96
    }
97
}
(-)src/scratchpad/src/org/apache/poi/hemf/record/HemfHeader.java (+260 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
package org.apache.poi.hemf.record;
19
20
import java.awt.Rectangle;
21
import java.io.IOException;
22
23
import org.apache.poi.util.Internal;
24
import org.apache.poi.util.LittleEndianInputStream;
25
26
/**
27
 * Extracts the full header from EMF files.
28
 * @see org.apache.poi.sl.image.ImageHeaderEMF
29
 */
30
@Internal
31
public class HemfHeader {
32
33
    private Rectangle boundsRectangle;
34
    private Rectangle frameRectangle;
35
    private long bytes;
36
    private long records;
37
    private int handles;
38
    private long nDescription;
39
    private long offDescription;
40
    private long nPalEntries;
41
    private boolean hasExtension1;
42
    private long cbPixelFormat;
43
    private long offPixelFormat;
44
    private long bOpenGL;
45
    private boolean hasExtension2;
46
    private long micrometersX;
47
    private long micrometersY;
48
49
    /**
50
     * Parses the EMF header from the InputStream and leaves the stream
51
     * at the end of the header/beginning of the first record.
52
     *
53
     * @param is InputStream to read from
54
     * @return header
55
     * @throws IOException on exception
56
     */
57
    public static HemfHeader parse(LittleEndianInputStream is) throws IOException {
58
        HemfHeader header = new HemfHeader();
59
        long type = is.readUInt();
60
        if (type != 1L) {
61
            throw new IOException("Not a valid EMF header");
62
        }
63
        //if >= 108, extension2, if >=100, extension1, else EMFMetafileHeader
64
        long headerSize = is.readUInt();
65
66
        //bounds
67
        int boundsLeft = is.readInt();
68
        int boundsTop = is.readInt();
69
        int boundsRight = is.readInt();
70
        int boundsBottom = is.readInt();
71
        header.setBoundsRectangle(new Rectangle(boundsLeft, boundsTop,
72
                boundsRight - boundsLeft, boundsBottom - boundsTop));
73
74
        int frameLeft = is.readInt();
75
        int frameTop = is.readInt();
76
        int frameRight = is.readInt();
77
        int frameBottom = is.readInt();
78
        header.setFrameRectangle(new Rectangle(frameLeft, frameTop,
79
                frameRight - frameLeft, frameBottom - frameTop));
80
81
        long recordSignature = is.readInt();
82
        if (recordSignature != 0x464D4520) {
83
            throw new IOException("bad record signature: " + recordSignature);
84
        }
85
86
        long version = is.readInt();
87
        if (version != 0x00010000) {
88
            throw new IOException("bad version: " + version);
89
        }
90
        header.setBytes(is.readUInt());
91
        header.setRecords(is.readUInt());
92
        header.setHandles(is.readUShort());
93
        is.readUShort();//reserved
94
        header.setnDescription(is.readUInt());
95
        header.setOffDescription(is.readUInt());
96
        header.setnPalEntries(is.readUInt());
97
98
        //should be skips
99
        is.readFully(new byte[8]); //device
100
        is.readFully(new byte[8]); //millimeters
101
102
        if (headerSize >= 100) {
103
            header.setHasExtension1(true);
104
            header.setCbPixelFormat(is.readUInt());
105
            header.setOffPixelFormat(is.readUInt());
106
            header.setbOpenGL(is.readUInt());
107
        }
108
109
        if (headerSize >= 108) {
110
            header.setHasExtension2(true);
111
            header.setMicrometersX(is.readUInt());
112
            header.setMicrometersY(is.readUInt());
113
        }
114
115
        //should we keep track of bytes read and slurp
116
        //whatever is left over headerSize?
117
        return header;
118
    }
119
120
    private void setBoundsRectangle(Rectangle boundsRectangle) {
121
        this.boundsRectangle = boundsRectangle;
122
    }
123
124
    private void setFrameRectangle(Rectangle frameRectangle) {
125
        this.frameRectangle = frameRectangle;
126
    }
127
128
    private void setBytes(long bytes) {
129
        this.bytes = bytes;
130
    }
131
132
    private void setRecords(long records) {
133
        this.records = records;
134
    }
135
136
    private void setHandles(int handles) {
137
        this.handles = handles;
138
    }
139
140
    private void setnDescription(long nDescription) {
141
        this.nDescription = nDescription;
142
    }
143
144
    private void setOffDescription(long offDescription) {
145
        this.offDescription = offDescription;
146
    }
147
148
    private void setnPalEntries(long nPalEntries) {
149
        this.nPalEntries = nPalEntries;
150
    }
151
152
    private void setHasExtension1(boolean hasExtension1) {
153
        this.hasExtension1 = hasExtension1;
154
    }
155
156
    private void setCbPixelFormat(long cbPixelFormat) {
157
        this.cbPixelFormat = cbPixelFormat;
158
    }
159
160
    private void setOffPixelFormat(long offPixelFormat) {
161
        this.offPixelFormat = offPixelFormat;
162
    }
163
164
    private void setbOpenGL(long bOpenGL) {
165
        this.bOpenGL = bOpenGL;
166
    }
167
168
    private void setHasExtension2(boolean hasExtension2) {
169
        this.hasExtension2 = hasExtension2;
170
    }
171
172
    private void setMicrometersX(long micrometersX) {
173
        this.micrometersX = micrometersX;
174
    }
175
176
    private void setMicrometersY(long micrometersY) {
177
        this.micrometersY = micrometersY;
178
    }
179
180
    public Rectangle getBoundsRectangle() {
181
        return boundsRectangle;
182
    }
183
184
    public Rectangle getFrameRectangle() {
185
        return frameRectangle;
186
    }
187
188
    public long getBytes() {
189
        return bytes;
190
    }
191
192
    public long getRecords() {
193
        return records;
194
    }
195
196
    public int getHandles() {
197
        return handles;
198
    }
199
200
    public long getnDescription() {
201
        return nDescription;
202
    }
203
204
    public long getOffDescription() {
205
        return offDescription;
206
    }
207
208
    public long getnPalEntries() {
209
        return nPalEntries;
210
    }
211
212
    public boolean isHasExtension1() {
213
        return hasExtension1;
214
    }
215
216
    public long getCbPixelFormat() {
217
        return cbPixelFormat;
218
    }
219
220
    public long getOffPixelFormat() {
221
        return offPixelFormat;
222
    }
223
224
    public long getbOpenGL() {
225
        return bOpenGL;
226
    }
227
228
    public boolean isHasExtension2() {
229
        return hasExtension2;
230
    }
231
232
    public long getMicrometersX() {
233
        return micrometersX;
234
    }
235
236
    public long getMicrometersY() {
237
        return micrometersY;
238
    }
239
240
    @Override
241
    public String toString() {
242
        return "HemfHeader{" +
243
                "boundsRectangle=" + boundsRectangle +
244
                ", frameRectangle=" + frameRectangle +
245
                ", bytes=" + bytes +
246
                ", records=" + records +
247
                ", handles=" + handles +
248
                ", nDescription=" + nDescription +
249
                ", offDescription=" + offDescription +
250
                ", nPalEntries=" + nPalEntries +
251
                ", hasExtension1=" + hasExtension1 +
252
                ", cbPixelFormat=" + cbPixelFormat +
253
                ", offPixelFormat=" + offPixelFormat +
254
                ", bOpenGL=" + bOpenGL +
255
                ", hasExtension2=" + hasExtension2 +
256
                ", micrometersX=" + micrometersX +
257
                ", micrometersY=" + micrometersY +
258
                '}';
259
    }
260
}
(-)src/scratchpad/src/org/apache/poi/hemf/record/HemfText.java (+146 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
package org.apache.poi.hemf.record;
19
20
21
import java.io.IOException;
22
import java.nio.charset.Charset;
23
24
import org.apache.poi.util.IOUtils;
25
import org.apache.poi.util.Internal;
26
import org.apache.poi.util.LittleEndian;
27
import org.apache.poi.util.LittleEndianInputStream;
28
import org.apache.poi.util.RecordFormatException;
29
import org.apache.poi.util.StringUtil;
30
31
/**
32
 * Container class to gather all text-related commands
33
 * This is starting out as read only, and very little is actually
34
 * implemented at this point!
35
 */
36
@Internal
37
public class HemfText {
38
39
    private final static Charset UTF16LE = Charset.forName("UTF-16LE");
40
41
    public static class ExtCreateFontIndirectW extends UnimplementedHemfRecord {
42
    }
43
44
    public static class ExtTextOutA extends UnimplementedHemfRecord {
45
46
    }
47
48
    public static class ExtTextOutW implements HemfRecord {
49
50
        private long left,top,right,bottom;
51
52
        //TODO: translate this to a graphicsmode enum
53
        private long graphicsMode;
54
55
        private long exScale;
56
        private long eyScale;
57
        EmrTextObject textObject;
58
59
        @Override
60
        public HemfRecordType getRecordType() {
61
            return HemfRecordType.exttextoutw;
62
        }
63
64
        @Override
65
        public long init(LittleEndianInputStream leis, long recordId, long recordSize) throws IOException {
66
            //note that the first 2 uInts have been read off and the recordsize has
67
            //been decreased by 8
68
            left = leis.readUInt();
69
            top = leis.readUInt();
70
            right = leis.readUInt();
71
            bottom = leis.readUInt();
72
            graphicsMode = leis.readUInt();
73
            exScale = leis.readUInt();
74
            eyScale = leis.readUInt();
75
76
            int recordSizeInt = -1;
77
            if (recordSize < Integer.MAX_VALUE) {
78
                recordSizeInt = (int)recordSize;
79
            } else {
80
                throw new RecordFormatException("can't have text length > Integer.MAX_VALUE");
81
            }
82
            //guarantee to read the rest of the EMRTextObjectRecord
83
            //emrtextbytes start after 7*4 bytes read above
84
            byte[] emrTextBytes = new byte[recordSizeInt-(7*LittleEndian.INT_SIZE)];
85
            IOUtils.readFully(leis, emrTextBytes);
86
            textObject = new EmrTextObject(emrTextBytes, UTF16LE, 20);//should be 28, but recordSizeInt has already subtracted 8
87
            return recordSize;
88
        }
89
90
        public EmrTextObject getTextObject() {
91
            return textObject;
92
        }
93
    }
94
95
    public static class PolyTextOutA extends UnimplementedHemfRecord {
96
97
    }
98
99
    public static class PolyTextOutW extends UnimplementedHemfRecord {
100
101
    }
102
103
    public static class SetTextAlign extends UnimplementedHemfRecord {
104
    }
105
106
    public static class SetTextColor extends UnimplementedHemfRecord {
107
    }
108
109
110
    public class SetTextJustification extends UnimplementedHemfRecord {
111
    }
112
113
    public static class EmrTextObject {
114
        long x;
115
        long y;
116
117
        String text;
118
        public EmrTextObject(byte[] emrTextObjBytes, Charset charset, int readSoFar) throws IOException {
119
120
            int offset = 0;
121
            x = LittleEndian.getUInt(emrTextObjBytes, offset); offset+= LittleEndian.INT_SIZE;
122
            y = LittleEndian.getUInt(emrTextObjBytes, offset); offset+= LittleEndian.INT_SIZE;
123
            long numChars = LittleEndian.getUInt(emrTextObjBytes, offset); offset += LittleEndian.INT_SIZE;
124
            long offString = LittleEndian.getUInt(emrTextObjBytes, offset); offset += LittleEndian.INT_SIZE;
125
            int start = (int)offString-offset-readSoFar;
126
127
            if (charset.equals(UTF16LE)) {
128
                text = StringUtil.getFromUnicodeLE(emrTextObjBytes, start, (int)numChars);
129
            }
130
        }
131
132
        public long getX() {
133
            return x;
134
        }
135
136
        public long getY() {
137
            return y;
138
        }
139
140
        public String getText() {
141
            return text;
142
        }
143
    }
144
145
146
}
(-)src/scratchpad/testcases/org/apache/poi/hemf/hemfplus/extractor/HemfPlusExtractorTest.java (+100 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
package org.apache.poi.hemf.hemfplus.extractor;
19
20
21
import static org.junit.Assert.assertEquals;
22
23
import java.io.InputStream;
24
import java.util.ArrayList;
25
import java.util.List;
26
27
import org.apache.poi.POIDataSamples;
28
import org.apache.poi.hemf.extractor.HemfExtractor;
29
import org.apache.poi.hemf.hemfplus.record.HemfPlusHeader;
30
import org.apache.poi.hemf.hemfplus.record.HemfPlusRecord;
31
import org.apache.poi.hemf.hemfplus.record.HemfPlusRecordType;
32
import org.apache.poi.hemf.record.HemfCommentEMFPlus;
33
import org.apache.poi.hemf.record.HemfCommentRecord;
34
import org.apache.poi.hemf.record.HemfRecord;
35
import org.junit.Test;
36
37
public class HemfPlusExtractorTest {
38
39
    static {
40
        System.setProperty("POI.testdata.path", "C:/users/tallison/Idea Projects/poi-trunk/test-data");
41
    }
42
43
    @Test
44
    public void testBasic() throws Exception {
45
        //test header
46
        HemfCommentEMFPlus emfPlus = getCommentRecord("SimpleEMF_windows.emf", 0);
47
        List<HemfPlusRecord> records = emfPlus.getRecords();
48
        assertEquals(1, records.size());
49
        assertEquals(HemfPlusRecordType.header, records.get(0).getRecordType());
50
51
        HemfPlusHeader header = (HemfPlusHeader)records.get(0);
52
        assertEquals(240, header.getLogicalDpiX());
53
        assertEquals(240, header.getLogicalDpiY());
54
        assertEquals(1, header.getFlags());
55
        assertEquals(1, header.getEmfPlusFlags());
56
57
58
59
        //test that the HemfCommentEMFPlus record at offset 1
60
        //contains 6 HemfCommentEMFPlus records within it
61
        List<HemfPlusRecordType> expected = new ArrayList<HemfPlusRecordType>();
62
        expected.add(HemfPlusRecordType.setPixelOffsetMode);
63
        expected.add(HemfPlusRecordType.setAntiAliasMode);
64
        expected.add(HemfPlusRecordType.setCompositingQuality);
65
        expected.add(HemfPlusRecordType.setPageTransform);
66
        expected.add(HemfPlusRecordType.setInterpolationMode);
67
        expected.add(HemfPlusRecordType.getDC);
68
69
        emfPlus = getCommentRecord("SimpleEMF_windows.emf", 1);
70
        records = emfPlus.getRecords();
71
        assertEquals(expected.size(), records.size());
72
73
        for (int i = 0; i < expected.size(); i++) {
74
            assertEquals(expected.get(i), records.get(i).getRecordType());
75
        }
76
    }
77
78
79
    private HemfCommentEMFPlus getCommentRecord(String testFileName, int recordIndex) throws Exception {
80
        InputStream is = null;
81
        HemfCommentEMFPlus returnRecord = null;
82
83
        try {
84
            is = POIDataSamples.getSpreadSheetInstance().openResourceAsStream(testFileName);
85
            HemfExtractor ex = new HemfExtractor(is);
86
            int i = 0;
87
            for (HemfRecord record : ex) {
88
                if (i == recordIndex) {
89
                    HemfCommentRecord commentRecord = ((HemfCommentRecord) record);
90
                    returnRecord = (HemfCommentEMFPlus) commentRecord.getComment();
91
                    break;
92
                }
93
                i++;
94
            }
95
        } finally {
96
            is.close();
97
        }
98
        return returnRecord;
99
    }
100
}
(-)src/java/org/apache/poi/util/IOUtils.java (+23 lines)
Lines 251-254 Link Here
251
                    exc );
251
                    exc );
252
        }
252
        }
253
    }
253
    }
254
255
    /**
256
     * Skips bytes from a stream.  Returns -1L if EOF was hit before
257
     * the end of the stream.
258
     *
259
     * @param in inputstream
260
     * @param len length to skip
261
     * @return number of bytes skipped
262
     * @throws IOException on IOException
263
     */
264
    public static long skipFully(InputStream in, long len) throws IOException {
265
        int total = 0;
266
        while (true) {
267
            long got = in.skip(len-total);
268
            if (got < 0) {
269
                return -1L;
270
            }
271
            total += got;
272
            if (total == len) {
273
                return total;
274
            }
275
        }
276
    }
254
}
277
}
(-)src/scratchpad/src/org/apache/poi/hemf/hemfplus/record/HemfPlusHeader.java (+82 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
package org.apache.poi.hemf.hemfplus.record;
19
20
21
import java.io.IOException;
22
23
import org.apache.poi.util.Internal;
24
import org.apache.poi.util.LittleEndian;
25
26
@Internal
27
public class HemfPlusHeader implements HemfPlusRecord {
28
29
    private int flags;
30
    private long version; //hack for now; replace with EmfPlusGraphicsVersion object
31
    private long emfPlusFlags;
32
    private long logicalDpiX;
33
    private long logicalDpiY;
34
35
    @Override
36
    public HemfPlusRecordType getRecordType() {
37
        return HemfPlusRecordType.header;
38
    }
39
40
    public int getFlags() {
41
        return flags;
42
    }
43
44
    @Override
45
    public void init(byte[] dataBytes, int recordId, int flags) throws IOException {
46
        //assert record id == header
47
        this.flags = flags;
48
        int offset = 0;
49
        this.version = LittleEndian.getUInt(dataBytes, offset); offset += LittleEndian.INT_SIZE;
50
        this.emfPlusFlags = LittleEndian.getUInt(dataBytes, offset); offset += LittleEndian.INT_SIZE;
51
        this.logicalDpiX = LittleEndian.getUInt(dataBytes, offset); offset += LittleEndian.INT_SIZE;
52
        this.logicalDpiY = LittleEndian.getUInt(dataBytes, offset);
53
54
    }
55
56
    public long getVersion() {
57
        return version;
58
    }
59
60
    public long getEmfPlusFlags() {
61
        return emfPlusFlags;
62
    }
63
64
    public long getLogicalDpiX() {
65
        return logicalDpiX;
66
    }
67
68
    public long getLogicalDpiY() {
69
        return logicalDpiY;
70
    }
71
72
    @Override
73
    public String toString() {
74
        return "HemfPlusHeader{" +
75
                "flags=" + flags +
76
                ", version=" + version +
77
                ", emfPlusFlags=" + emfPlusFlags +
78
                ", logicalDpiX=" + logicalDpiX +
79
                ", logicalDpiY=" + logicalDpiY +
80
                '}';
81
    }
82
}
(-)src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentEMFSpool.java (+31 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
package org.apache.poi.hemf.record;
19
20
import org.apache.poi.util.Internal;
21
22
/**
23
 * Not yet implemented
24
 */
25
@Internal
26
public class HemfCommentEMFSpool extends AbstractHemfComment {
27
28
    public HemfCommentEMFSpool(byte[] rawBytes) {
29
        super(rawBytes);
30
    }
31
}
(-)src/scratchpad/src/org/apache/poi/hemf/record/HemfRecord.java (+41 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
package org.apache.poi.hemf.record;
19
20
21
import java.io.IOException;
22
23
import org.apache.poi.util.Internal;
24
import org.apache.poi.util.LittleEndianInputStream;
25
26
@Internal
27
public interface HemfRecord {
28
29
    HemfRecordType getRecordType();
30
31
    /**
32
     * Init record from stream
33
     *
34
     * @param leis the little endian input stream
35
     * @return count of processed bytes
36
     * @throws IOException
37
     */
38
    long init(LittleEndianInputStream leis, long recordId, long recordSize) throws IOException;
39
40
41
}
(-)src/scratchpad/src/org/apache/poi/hemf/hemfplus/record/HemfPlusRecord.java (+45 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
package org.apache.poi.hemf.hemfplus.record;
19
20
21
import java.io.IOException;
22
23
import org.apache.poi.util.Internal;
24
25
@Internal
26
public interface HemfPlusRecord {
27
28
    HemfPlusRecordType getRecordType();
29
30
    int getFlags();
31
32
    /**
33
     *
34
     * @param dataBytes these are the bytes that start after the id, flags, record size
35
     *                    and go to the end of the record; they do not include any required padding
36
     *                    at the end.
37
     * @param recordId record type id
38
     * @param flags flags
39
     * @return
40
     * @throws IOException, RecordFormatException
41
     */
42
    void init(byte[] dataBytes, int recordId, int flags) throws IOException;
43
44
45
}
(-)src/scratchpad/src/org/apache/poi/hemf/record/AbstractHemfComment.java (+39 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
package org.apache.poi.hemf.record;
19
20
import org.apache.poi.util.Internal;
21
22
/**
23
 * Syntactic utility to allow for four different
24
 * comment classes
25
 */
26
@Internal
27
public abstract class AbstractHemfComment {
28
29
    private final byte[] rawBytes;
30
31
    public AbstractHemfComment(byte[] rawBytes) {
32
        this.rawBytes = rawBytes;
33
    }
34
35
    public byte[] getRawBytes() {
36
        return rawBytes;
37
    }
38
39
}
(-)src/scratchpad/src/org/apache/poi/hemf/extractor/HemfExtractor.java (+109 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
package org.apache.poi.hemf.extractor;
19
20
21
import java.io.IOException;
22
import java.io.InputStream;
23
import java.util.Iterator;
24
25
import org.apache.poi.hemf.record.HemfRecord;
26
import org.apache.poi.hemf.record.HemfRecordType;
27
import org.apache.poi.hemf.record.HemfHeader;
28
import org.apache.poi.util.Internal;
29
import org.apache.poi.util.LittleEndianInputStream;
30
31
/**
32
 * Read-only EMF extractor.  Lots remain
33
 */
34
@Internal
35
public class HemfExtractor implements Iterable<HemfRecord> {
36
37
    private final HemfHeader header;
38
    private final LittleEndianInputStream stream;
39
40
    public HemfExtractor(InputStream is) throws IOException {
41
        stream = new LittleEndianInputStream(is);
42
        header = HemfHeader.parse(stream);
43
    }
44
45
    public HemfHeader getHeader() {
46
        return header;
47
    }
48
49
    @Override
50
    public Iterator<HemfRecord> iterator() {
51
        return new HemfRecordIterator();
52
    }
53
54
    private class HemfRecordIterator implements Iterator<HemfRecord> {
55
56
        private HemfRecord currentRecord = null;
57
        private long recordsRead = 1;//header is the first record, and that was already read!
58
59
        HemfRecordIterator() {
60
            //queue the first non-header record
61
            currentRecord = _next();
62
        }
63
64
        @Override
65
        public boolean hasNext() {
66
            return currentRecord != null;
67
        }
68
69
        @Override
70
        public HemfRecord next() {
71
            HemfRecord toReturn = currentRecord;
72
            currentRecord = _next();
73
            return toReturn;
74
        }
75
76
        private HemfRecord _next() {
77
            recordsRead++;
78
            if (recordsRead > header.getRecords()) {
79
                return null;
80
            }
81
            long recordId = stream.readUInt();
82
            long recordSize = stream.readUInt();
83
            HemfRecord record = null;
84
            HemfRecordType type = HemfRecordType.getById(recordId);
85
            if (type == null) {
86
                throw new RuntimeException("Undefined record of type:"+recordId);
87
            }
88
            try {
89
                record = type.clazz.newInstance();
90
            } catch (InstantiationException e) {
91
                throw new RuntimeException(e);
92
            } catch (IllegalAccessException e) {
93
                throw new RuntimeException(e);
94
            }
95
            try {
96
                record.init(stream, recordId, recordSize-8);
97
            } catch (IOException e) {
98
                throw new RuntimeException(e);
99
            }
100
            return record;
101
        }
102
103
        @Override
104
        public void remove() {
105
            throw new UnsupportedOperationException("Remove not supported");
106
        }
107
108
    }
109
}
(-)src/scratchpad/src/org/apache/poi/hemf/record/HemfRecordType.java (+159 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
package org.apache.poi.hemf.record;
19
20
import org.apache.poi.util.Internal;
21
22
@Internal
23
public enum HemfRecordType {
24
25
    header(0x00000001, UnimplementedHemfRecord.class),
26
    polybeizer(0x00000002, UnimplementedHemfRecord.class),
27
    polygon(0x00000003, UnimplementedHemfRecord.class),
28
    polyline(0x00000004, UnimplementedHemfRecord.class),
29
    polybezierto(0x00000005, UnimplementedHemfRecord.class),
30
    polylineto(0x00000006, UnimplementedHemfRecord.class),
31
    polypolyline(0x00000007, UnimplementedHemfRecord.class),
32
    polypolygon(0x00000008, UnimplementedHemfRecord.class),
33
    setwindowextex(0x00000009, UnimplementedHemfRecord.class),
34
    setwindoworgex(0x0000000A, UnimplementedHemfRecord.class),
35
    setviewportextex(0x0000000B, UnimplementedHemfRecord.class),
36
    setviewportorgex(0x0000000C, UnimplementedHemfRecord.class),
37
    setbrushorgex(0x0000000D, UnimplementedHemfRecord.class),
38
    eof(0x0000000E, UnimplementedHemfRecord.class),
39
    setpixelv(0x0000000F, UnimplementedHemfRecord.class),
40
    setmapperflags(0x00000010, UnimplementedHemfRecord.class),
41
    setmapmode(0x00000011, UnimplementedHemfRecord.class),
42
    setbkmode(0x00000012, UnimplementedHemfRecord.class),
43
    setpolyfillmode(0x00000013, UnimplementedHemfRecord.class),
44
    setrop2(0x00000014, UnimplementedHemfRecord.class),
45
    setstretchbltmode(0x00000015, UnimplementedHemfRecord.class),
46
    settextalign(0x00000016, HemfText.SetTextAlign.class),
47
    setcoloradjustment(0x00000017, UnimplementedHemfRecord.class),
48
    settextcolor(0x00000018, HemfText.SetTextColor.class),
49
    setbkcolor(0x00000019, UnimplementedHemfRecord.class),
50
    setoffsetcliprgn(0x0000001A, UnimplementedHemfRecord.class),
51
    setmovetoex(0x0000001B, UnimplementedHemfRecord.class),
52
    setmetargn(0x0000001C, UnimplementedHemfRecord.class),
53
    setexcludecliprect(0x0000001D, UnimplementedHemfRecord.class),
54
    setintersectcliprect(0x0000001E, UnimplementedHemfRecord.class),
55
    scaleviewportextex(0x0000001F, UnimplementedHemfRecord.class),
56
    scalewindowextex(0x00000020, UnimplementedHemfRecord.class),
57
    savedc(0x00000021, UnimplementedHemfRecord.class),
58
    restoredc(0x00000022, UnimplementedHemfRecord.class),
59
    setworldtransform(0x00000023, UnimplementedHemfRecord.class),
60
    modifyworldtransform(0x00000024, UnimplementedHemfRecord.class),
61
    selectobject(0x00000025, UnimplementedHemfRecord.class),
62
    createpen(0x00000026, UnimplementedHemfRecord.class),
63
    createbrushindirect(0x00000027, UnimplementedHemfRecord.class),
64
    deleteobject(0x00000028, UnimplementedHemfRecord.class),
65
    anglearc(0x00000029, UnimplementedHemfRecord.class),
66
    ellipse(0x0000002A, UnimplementedHemfRecord.class),
67
    rectangle(0x0000002B, UnimplementedHemfRecord.class),
68
    roundirect(0x0000002C, UnimplementedHemfRecord.class),
69
    arc(0x0000002D, UnimplementedHemfRecord.class),
70
    chord(0x0000002E, UnimplementedHemfRecord.class),
71
    pie(0x0000002F, UnimplementedHemfRecord.class),
72
    selectpalette(0x00000030, UnimplementedHemfRecord.class),
73
    createpalette(0x00000031, UnimplementedHemfRecord.class),
74
    setpaletteentries(0x00000032, UnimplementedHemfRecord.class),
75
    resizepalette(0x00000033, UnimplementedHemfRecord.class),
76
    realizepalette(0x0000034, UnimplementedHemfRecord.class),
77
    extfloodfill(0x00000035, UnimplementedHemfRecord.class),
78
    lineto(0x00000036, UnimplementedHemfRecord.class),
79
    arcto(0x00000037, UnimplementedHemfRecord.class),
80
    polydraw(0x00000038, UnimplementedHemfRecord.class),
81
    setarcdirection(0x00000039, UnimplementedHemfRecord.class),
82
    setmiterlimit(0x0000003A, UnimplementedHemfRecord.class),
83
    beginpath(0x0000003B, UnimplementedHemfRecord.class),
84
    endpath(0x0000003C, UnimplementedHemfRecord.class),
85
    closefigure(0x0000003D, UnimplementedHemfRecord.class),
86
    fillpath(0x0000003E, UnimplementedHemfRecord.class),
87
    strokeandfillpath(0x0000003F, UnimplementedHemfRecord.class),
88
    strokepath(0x00000040, UnimplementedHemfRecord.class),
89
    flattenpath(0x00000041, UnimplementedHemfRecord.class),
90
    widenpath(0x00000042, UnimplementedHemfRecord.class),
91
    selectclippath(0x00000043, UnimplementedHemfRecord.class),
92
    abortpath(0x00000044, UnimplementedHemfRecord.class), //no 45?!
93
    comment(0x00000046, HemfCommentRecord.class),
94
    fillrgn(0x00000047, UnimplementedHemfRecord.class),
95
    framergn(0x00000048, UnimplementedHemfRecord.class),
96
    invertrgn(0x00000049, UnimplementedHemfRecord.class),
97
    paintrgn(0x0000004A, UnimplementedHemfRecord.class),
98
    extselectciprrgn(0x0000004B, UnimplementedHemfRecord.class),
99
    bitblt(0x0000004C, UnimplementedHemfRecord.class),
100
    stretchblt(0x0000004D, UnimplementedHemfRecord.class),
101
    maskblt(0x0000004E, UnimplementedHemfRecord.class),
102
    plgblt(0x0000004F, UnimplementedHemfRecord.class),
103
    setbitstodevice(0x00000050, UnimplementedHemfRecord.class),
104
    stretchdibits(0x00000051, UnimplementedHemfRecord.class),
105
    extcreatefontindirectw(0x00000052, HemfText.ExtCreateFontIndirectW.class),
106
    exttextouta(0x00000053, HemfText.ExtTextOutA.class),
107
    exttextoutw(0x00000054, HemfText.ExtTextOutW.class),
108
    polybezier16(0x00000055, UnimplementedHemfRecord.class),
109
    polygon16(0x00000056, UnimplementedHemfRecord.class),
110
    polyline16(0x00000057, UnimplementedHemfRecord.class),
111
    polybezierto16(0x00000058, UnimplementedHemfRecord.class),
112
    polylineto16(0x00000059, UnimplementedHemfRecord.class),
113
    polypolyline16(0x0000005A, UnimplementedHemfRecord.class),
114
    polypolygon16(0x0000005B, UnimplementedHemfRecord.class),
115
    polydraw16(0x0000005C, UnimplementedHemfRecord.class),
116
    createmonobrush16(0x0000005D, UnimplementedHemfRecord.class),
117
    createdibpatternbrushpt(0x0000005E, UnimplementedHemfRecord.class),
118
    extcreatepen(0x0000005F, UnimplementedHemfRecord.class),
119
    polytextouta(0x00000060, HemfText.PolyTextOutA.class),
120
    polytextoutw(0x00000061, HemfText.PolyTextOutW.class),
121
    seticmmode(0x00000062, UnimplementedHemfRecord.class),
122
    createcolorspace(0x00000063, UnimplementedHemfRecord.class),
123
    setcolorspace(0x00000064, UnimplementedHemfRecord.class),
124
    deletecolorspace(0x00000065, UnimplementedHemfRecord.class),
125
    glsrecord(0x00000066, UnimplementedHemfRecord.class),
126
    glsboundedrecord(0x00000067, UnimplementedHemfRecord.class),
127
    pixelformat(0x00000068, UnimplementedHemfRecord.class),
128
    drawescape(0x00000069, UnimplementedHemfRecord.class),
129
    extescape(0x0000006A, UnimplementedHemfRecord.class),//no 6b?!
130
    smalltextout(0x0000006C, UnimplementedHemfRecord.class),
131
    forceufimapping(0x0000006D, UnimplementedHemfRecord.class),
132
    namedescape(0x0000006E, UnimplementedHemfRecord.class),
133
    colorcorrectpalette(0x0000006F, UnimplementedHemfRecord.class),
134
    seticmprofilea(0x00000070, UnimplementedHemfRecord.class),
135
    seticmprofilew(0x00000071, UnimplementedHemfRecord.class),
136
    alphablend(0x00000072, UnimplementedHemfRecord.class),
137
    setlayout(0x00000073, UnimplementedHemfRecord.class),
138
    transparentblt(0x00000074, UnimplementedHemfRecord.class),
139
    gradientfill(0x00000076, UnimplementedHemfRecord.class), //no 75?!
140
    setlinkdufis(0x00000077, UnimplementedHemfRecord.class),
141
    settextjustification(0x00000078, HemfText.SetTextJustification.class),
142
    colormatchtargetw(0x00000079, UnimplementedHemfRecord.class),
143
    createcolorspacew(0x0000007A, UnimplementedHemfRecord.class);
144
145
    public final long id;
146
    public final Class<? extends HemfRecord> clazz;
147
148
    HemfRecordType(long id, Class<? extends HemfRecord> clazz) {
149
        this.id = id;
150
        this.clazz = clazz;
151
    }
152
153
    public static HemfRecordType getById(long id) {
154
        for (HemfRecordType wrt : values()) {
155
            if (wrt.id == id) return wrt;
156
        }
157
        return null;
158
    }
159
}
(-)src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentRecord.java (+121 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
package org.apache.poi.hemf.record;
19
20
21
import java.io.IOException;
22
23
import org.apache.poi.util.IOUtils;
24
import org.apache.poi.util.Internal;
25
import org.apache.poi.util.LittleEndian;
26
import org.apache.poi.util.LittleEndianInputStream;
27
28
/**
29
 * This is the outer comment record that is recognized
30
 * by the initial parse by {@link HemfRecordType#comment}.
31
 * However, there are four types of comment: EMR_COMMENT,
32
 * EMR_COMMENT_EMFPLUS, EMR_COMMENT_EMFSPOOL, and EMF_COMMENT_PUBLIC.
33
 * To get the underlying comment, call {@link #getComment()}.
34
 *
35
 */
36
@Internal
37
public class HemfCommentRecord implements HemfRecord {
38
39
    public final static long COMMENT_EMFSPOOL = 0x00000000;
40
    public final static long COMMENT_EMFPLUS = 0x2B464D45;
41
    public final static long COMMENT_PUBLIC = 0x43494447;
42
43
44
    private AbstractHemfComment comment;
45
    @Override
46
    public HemfRecordType getRecordType() {
47
        return HemfRecordType.comment;
48
    }
49
50
    @Override
51
    public long init(LittleEndianInputStream leis, long recordId, long recordSize) throws IOException {
52
        long dataSize = leis.readUInt();
53
54
        dataSize = dataSize-4; //size minus the first int which could be a comment identifier
55
56
        byte[] optionalCommentIndentifierBuffer = new byte[4];
57
        leis.readFully(optionalCommentIndentifierBuffer);
58
        long optionalCommentIdentifier = LittleEndian.getInt(optionalCommentIndentifierBuffer) & 0x00FFFFFFFFL;
59
        if (optionalCommentIdentifier == COMMENT_EMFSPOOL) {
60
            comment = new HemfCommentEMFSpool(readToByteArray(leis, dataSize));
61
        } else if (optionalCommentIdentifier == COMMENT_EMFPLUS) {
62
            comment = new HemfCommentEMFPlus(readToByteArray(leis, dataSize));
63
        } else if (optionalCommentIdentifier == COMMENT_PUBLIC) {
64
            comment = CommentPublicParser.parse(readToByteArray(leis, dataSize));
65
        } else {
66
            comment = new HemfComment(readToByteArray(optionalCommentIndentifierBuffer, leis, dataSize));
67
        }
68
69
        return recordSize;
70
    }
71
72
    //this prepends the initial "int" which turned out not to be
73
    //a signifier of emfplus, spool, public.
74
    private byte[] readToByteArray(byte[] initialBytes, LittleEndianInputStream leis,
75
                                   long dataSize) throws IOException {
76
        long actualDataSize = dataSize+initialBytes.length;
77
        assert actualDataSize < Integer.MAX_VALUE;
78
79
        byte[] arr = new byte[(int)actualDataSize];
80
        System.arraycopy(initialBytes,0,arr, 0, initialBytes.length);
81
        IOUtils.readFully(leis, arr, initialBytes.length, (int)dataSize-initialBytes.length);
82
        return arr;
83
    }
84
85
    private byte[] readToByteArray(LittleEndianInputStream leis, long dataSize) throws IOException {
86
        assert dataSize < Integer.MAX_VALUE;
87
88
        byte[] arr = new byte[(int)dataSize];
89
        IOUtils.readFully(leis, arr);
90
        return arr;
91
    }
92
93
    public AbstractHemfComment getComment() {
94
        return comment;
95
    }
96
97
    private static class CommentPublicParser {
98
        private static final long WINDOWS_METAFILE = 0x80000001; //wmf
99
        private static final long BEGINGROUP = 0x00000002; //beginning of a group of drawing records
100
        private static final long ENDGROUP = 0x00000003; //end of a group of drawing records
101
        private static final long MULTIFORMATS = 0x40000004; //allows multiple definitions of an image, including encapsulated postscript
102
        private static final long UNICODE_STRING = 0x00000040; //reserved. must not be used
103
        private static final long UNICODE_END = 0x00000080; //reserved, must not be used
104
105
        private static AbstractHemfComment parse(byte[] bytes) {
106
            long publicCommentIdentifier = LittleEndian.getUInt(bytes, 0);
107
            if (publicCommentIdentifier == WINDOWS_METAFILE) {
108
                return new HemfCommentPublic.WindowsMetafile(bytes);
109
            } else if (publicCommentIdentifier == BEGINGROUP) {
110
                return new HemfCommentPublic.BeginGroup(bytes);
111
            } else if (publicCommentIdentifier == ENDGROUP) {
112
                return new HemfCommentPublic.EndGroup(bytes);
113
            } else if (publicCommentIdentifier == MULTIFORMATS) {
114
                return new HemfCommentPublic.MultiFormats(bytes);
115
            } else if (publicCommentIdentifier == UNICODE_STRING || publicCommentIdentifier == UNICODE_END) {
116
                throw new RuntimeException("UNICODE_STRING/UNICODE_END values are reserved in CommentPublic records");
117
            }
118
            throw new RuntimeException("Unrecognized public comment type:" +publicCommentIdentifier);
119
        }
120
    }
121
}
(-)src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentEMFPlus.java (+107 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
package org.apache.poi.hemf.record;
19
20
import java.io.IOException;
21
import java.util.ArrayList;
22
import java.util.List;
23
24
import org.apache.poi.hemf.hemfplus.record.HemfPlusRecord;
25
import org.apache.poi.hemf.hemfplus.record.HemfPlusRecordType;
26
import org.apache.poi.util.Internal;
27
import org.apache.poi.util.LittleEndian;
28
import org.apache.poi.util.RecordFormatException;
29
30
/**
31
 * An HemfCommentEMFPlus may contain one or more EMFPlus records
32
 */
33
@Internal
34
public class HemfCommentEMFPlus extends AbstractHemfComment {
35
36
    long dataSize;
37
    public HemfCommentEMFPlus(byte[] rawBytes) {
38
        //these rawBytes contain only the EMFPlusRecord(s?)
39
        //the EmfComment type, size, datasize and comment identifier have all been stripped.
40
        //The EmfPlus type, flags, size, data size should start at rawBytes[0]
41
        super(rawBytes);
42
43
    }
44
45
    public List<HemfPlusRecord> getRecords() {
46
        return HemfPlusParser.parse(getRawBytes());
47
    }
48
49
    private static class HemfPlusParser {
50
51
        public static List<HemfPlusRecord> parse(byte[] bytes) {
52
            List<HemfPlusRecord> records = new ArrayList<HemfPlusRecord>();
53
            int offset = 0;
54
            while (offset < bytes.length) {
55
                if (offset + 12 > bytes.length) {
56
                    //if header will go beyond bytes, stop now
57
                    //TODO: log or throw
58
                    break;
59
                }
60
                int type = LittleEndian.getUShort(bytes, offset); offset += LittleEndian.SHORT_SIZE;
61
                int flags = LittleEndian.getUShort(bytes, offset); offset += LittleEndian.SHORT_SIZE;
62
                long sizeLong = LittleEndian.getUInt(bytes, offset); offset += LittleEndian.INT_SIZE;
63
                if (sizeLong >= Integer.MAX_VALUE) {
64
                    throw new RecordFormatException("size of emf record >= Integer.MAX_VALUE");
65
                }
66
                int size = (int)sizeLong;
67
                long dataSizeLong = LittleEndian.getUInt(bytes, offset); offset += LittleEndian.INT_SIZE;
68
                if (dataSizeLong >= Integer.MAX_VALUE) {
69
                    throw new RuntimeException("data size of emfplus record cannot be >= Integer.MAX_VALUE");
70
                }
71
                int dataSize = (int)dataSizeLong;
72
                if (dataSize + offset > bytes.length) {
73
                    //TODO: log or throw?
74
                    break;
75
                }
76
                HemfPlusRecord record = buildRecord(type, flags, dataSize, offset, bytes);
77
                records.add(record);
78
                offset += dataSize;
79
            }
80
            return records;
81
        }
82
83
        private static HemfPlusRecord buildRecord(int recordId, int flags, int size, int offset, byte[] bytes) {
84
            HemfPlusRecord record = null;
85
            HemfPlusRecordType type = HemfPlusRecordType.getById(recordId);
86
            if (type == null) {
87
                throw new RuntimeException("Undefined record of type:"+recordId);
88
            }
89
            try {
90
                record = type.clazz.newInstance();
91
            } catch (InstantiationException e) {
92
                throw new RuntimeException(e);
93
            } catch (IllegalAccessException e) {
94
                throw new RuntimeException(e);
95
            }
96
            byte[] dataBytes = new byte[size];
97
            System.arraycopy(bytes, offset, dataBytes, 0, size);
98
            try {
99
                record.init(dataBytes, recordId, flags);
100
            } catch (IOException e) {
101
                throw new RuntimeException(e);
102
            }
103
            return record;
104
105
        }
106
    }
107
}

Return to bug 60570