ASF Bugzilla – Attachment 34605 Details for
Bug 60570
Add rudimentary EMF read-only capability
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
initial patch
hemf_v1.patch (text/plain), 77.37 KB, created by
Tim Allison
on 2017-01-10 17:18:45 UTC
(
hide
)
Description:
initial patch
Filename:
MIME Type:
Creator:
Tim Allison
Created:
2017-01-10 17:18:45 UTC
Size:
77.37 KB
patch
obsolete
>Index: src/scratchpad/src/org/apache/poi/hemf/record/HemfComment.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- src/scratchpad/src/org/apache/poi/hemf/record/HemfComment.java (revision ) >+++ src/scratchpad/src/org/apache/poi/hemf/record/HemfComment.java (revision ) >@@ -0,0 +1,31 @@ >+/* ==================================================================== >+ Licensed to the Apache Software Foundation (ASF) under one or more >+ contributor license agreements. See the NOTICE file distributed with >+ this work for additional information regarding copyright ownership. >+ The ASF licenses this file to You under the Apache License, Version 2.0 >+ (the "License"); you may not use this file except in compliance with >+ the License. You may obtain a copy of the License at >+ >+ http://www.apache.org/licenses/LICENSE-2.0 >+ >+ Unless required by applicable law or agreed to in writing, software >+ distributed under the License is distributed on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ See the License for the specific language governing permissions and >+ limitations under the License. >+==================================================================== */ >+ >+package org.apache.poi.hemf.record; >+ >+import org.apache.poi.util.Internal; >+ >+/** >+ * Contains arbitrary data >+ */ >+@Internal >+public class HemfComment extends AbstractHemfComment { >+ >+ public HemfComment(byte[] rawBytes) { >+ super(rawBytes); >+ } >+} >Index: src/scratchpad/src/org/apache/poi/hemf/hemfplus/record/UnimplementedHemfPlusRecord.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- src/scratchpad/src/org/apache/poi/hemf/hemfplus/record/UnimplementedHemfPlusRecord.java (revision ) >+++ src/scratchpad/src/org/apache/poi/hemf/hemfplus/record/UnimplementedHemfPlusRecord.java (revision ) >@@ -0,0 +1,53 @@ >+/* ==================================================================== >+ Licensed to the Apache Software Foundation (ASF) under one or more >+ contributor license agreements. See the NOTICE file distributed with >+ this work for additional information regarding copyright ownership. >+ The ASF licenses this file to You under the Apache License, Version 2.0 >+ (the "License"); you may not use this file except in compliance with >+ the License. You may obtain a copy of the License at >+ >+ http://www.apache.org/licenses/LICENSE-2.0 >+ >+ Unless required by applicable law or agreed to in writing, software >+ distributed under the License is distributed on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ See the License for the specific language governing permissions and >+ limitations under the License. >+==================================================================== */ >+ >+package org.apache.poi.hemf.hemfplus.record; >+ >+ >+import java.io.IOException; >+ >+import org.apache.poi.util.Internal; >+ >+@Internal >+public class UnimplementedHemfPlusRecord implements HemfPlusRecord { >+ >+ private int recordId; >+ private int flags; >+ private byte[] recordBytes; >+ >+ @Override >+ public HemfPlusRecordType getRecordType() { >+ return HemfPlusRecordType.getById(recordId); >+ } >+ >+ @Override >+ public int getFlags() { >+ return flags; >+ } >+ >+ @Override >+ public void init(byte[] recordBytes, int recordId, int flags) throws IOException { >+ this.recordId = recordId; >+ this.flags = flags; >+ this.recordBytes = recordBytes; >+ } >+ >+ public byte[] getRecordBytes() { >+ //should probably defensively return a copy. >+ return recordBytes; >+ } >+} >Index: src/scratchpad/testcases/org/apache/poi/hemf/extractor/HemfExtractorTest.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- src/scratchpad/testcases/org/apache/poi/hemf/extractor/HemfExtractorTest.java (revision ) >+++ src/scratchpad/testcases/org/apache/poi/hemf/extractor/HemfExtractorTest.java (revision ) >@@ -0,0 +1,158 @@ >+/* ==================================================================== >+ Licensed to the Apache Software Foundation (ASF) under one or more >+ contributor license agreements. See the NOTICE file distributed with >+ this work for additional information regarding copyright ownership. >+ The ASF licenses this file to You under the Apache License, Version 2.0 >+ (the "License"); you may not use this file except in compliance with >+ the License. You may obtain a copy of the License at >+ >+ http://www.apache.org/licenses/LICENSE-2.0 >+ >+ Unless required by applicable law or agreed to in writing, software >+ distributed under the License is distributed on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ See the License for the specific language governing permissions and >+ limitations under the License. >+==================================================================== */ >+ >+ >+package org.apache.poi.hemf.extractor; >+ >+import static org.apache.poi.POITestCase.assertContains; >+import static org.junit.Assert.assertEquals; >+import static org.junit.Assert.assertTrue; >+ >+import java.io.InputStream; >+ >+import org.apache.poi.POIDataSamples; >+import org.apache.poi.hemf.record.AbstractHemfComment; >+import org.apache.poi.hemf.record.HemfCommentPublic; >+import org.apache.poi.hemf.record.HemfCommentRecord; >+import org.apache.poi.hemf.record.HemfRecord; >+import org.apache.poi.hemf.record.HemfRecordType; >+import org.apache.poi.hemf.record.HemfText; >+import org.apache.poi.hemf.record.HemfHeader; >+import org.junit.Test; >+ >+public class HemfExtractorTest { >+ static { >+ System.setProperty("POI.testdata.path", "C:/users/tallison/Idea Projects/poi-trunk/test-data"); >+ } >+ >+ @Test >+ public void testBasicWindows() throws Exception { >+ InputStream is = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SimpleEMF_windows.emf"); >+ HemfExtractor ex = new HemfExtractor(is); >+ HemfHeader header = ex.getHeader(); >+ assertEquals(27864, header.getBytes()); >+ assertEquals(31, header.getRecords()); >+ assertEquals(3, header.getHandles()); >+ assertEquals(346000, header.getMicrometersX()); >+ assertEquals(194000, header.getMicrometersY()); >+ >+ int records = 0; >+ for (HemfRecord record : ex) { >+ records++; >+ } >+ >+ assertEquals(header.getRecords() - 1, records); >+ } >+ >+ @Test >+ public void testBasicMac() throws Exception { >+ InputStream is = >+ POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SimpleEMF_mac.emf"); >+ HemfExtractor ex = new HemfExtractor(is); >+ HemfHeader header = ex.getHeader(); >+ >+ int records = 0; >+ boolean extractedData = false; >+ for (HemfRecord record : ex) { >+ if (record.getRecordType() == HemfRecordType.comment) { >+ AbstractHemfComment comment = ((HemfCommentRecord) record).getComment(); >+ if (comment instanceof HemfCommentPublic.MultiFormats) { >+ for (HemfCommentPublic.HemfMultiFormatsData d : ((HemfCommentPublic.MultiFormats) comment).getData()) { >+ byte[] data = d.getData(); >+ //make sure header starts at 0 >+ assertEquals('%', data[0]); >+ assertEquals('P', data[1]); >+ assertEquals('D', data[2]); >+ assertEquals('F', data[3]); >+ >+ //make sure byte array ends at EOF\n >+ assertEquals('E', data[data.length - 4]); >+ assertEquals('O', data[data.length - 3]); >+ assertEquals('F', data[data.length - 2]); >+ assertEquals('\n', data[data.length - 1]); >+ extractedData = true; >+ } >+ } >+ } >+ records++; >+ } >+ assertTrue(extractedData); >+ assertEquals(header.getRecords() - 1, records); >+ } >+ >+ @Test >+ public void testMacText() throws Exception { >+ InputStream is = >+ POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SimpleEMF_mac.emf"); >+ HemfExtractor ex = new HemfExtractor(is); >+ >+ long lastY = -1; >+ long lastX = -1; >+ long fudgeFactorX = 1000;//derive this from the font information! >+ StringBuilder sb = new StringBuilder(); >+ for (HemfRecord record : ex) { >+ if (record.getRecordType().equals(HemfRecordType.exttextoutw)) { >+ HemfText.ExtTextOutW extTextOutW = (HemfText.ExtTextOutW) record; >+ HemfText.EmrTextObject emrTextObject = extTextOutW.getTextObject(); >+ if (lastY > -1 && lastY != emrTextObject.getY()) { >+ sb.append("\n"); >+ lastX = -1; >+ } >+ if (lastX > -1 && emrTextObject.getX() - lastX > fudgeFactorX) { >+ sb.append(" "); >+ } >+ sb.append(emrTextObject.getText()); >+ lastY = emrTextObject.getY(); >+ lastX = emrTextObject.getX(); >+ } >+ } >+ String txt = sb.toString(); >+ assertContains(txt, "Tika http://incubator.apache.org"); >+ assertContains(txt, "Latest News\n"); >+ } >+ >+ @Test >+ public void testWindowsText() throws Exception { >+ InputStream is = POIDataSamples.getSpreadSheetInstance().openResourceAsStream("SimpleEMF_windows.emf"); >+ HemfExtractor ex = new HemfExtractor(is); >+ long lastY = -1; >+ long lastX = -1; >+ long fudgeFactorX = 1000;//derive this from the font information! >+ StringBuilder sb = new StringBuilder(); >+ for (HemfRecord record : ex) { >+ if (record.getRecordType().equals(HemfRecordType.exttextoutw)) { >+ HemfText.ExtTextOutW extTextOutW = (HemfText.ExtTextOutW) record; >+ HemfText.EmrTextObject emrTextObject = extTextOutW.getTextObject(); >+ if (lastY > -1 && lastY != emrTextObject.getY()) { >+ sb.append("\n"); >+ lastX = -1; >+ } >+ if (lastX > -1 && emrTextObject.getX() - lastX > fudgeFactorX) { >+ sb.append(" "); >+ } >+ sb.append(emrTextObject.getText()); >+ lastY = emrTextObject.getY(); >+ lastX = emrTextObject.getX(); >+ } >+ } >+ String txt = sb.toString(); >+ assertContains(txt, "C:\\Users\\tallison\\\n"); >+ assertContains(txt, "asf2-git-1.x\\tika-\n"); >+ } >+ >+ >+} >\ No newline at end of file >Index: src/scratchpad/src/org/apache/poi/hemf/record/UnimplementedHemfRecord.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- src/scratchpad/src/org/apache/poi/hemf/record/UnimplementedHemfRecord.java (revision ) >+++ src/scratchpad/src/org/apache/poi/hemf/record/UnimplementedHemfRecord.java (revision ) >@@ -0,0 +1,46 @@ >+/* ==================================================================== >+ Licensed to the Apache Software Foundation (ASF) under one or more >+ contributor license agreements. See the NOTICE file distributed with >+ this work for additional information regarding copyright ownership. >+ The ASF licenses this file to You under the Apache License, Version 2.0 >+ (the "License"); you may not use this file except in compliance with >+ the License. You may obtain a copy of the License at >+ >+ http://www.apache.org/licenses/LICENSE-2.0 >+ >+ Unless required by applicable law or agreed to in writing, software >+ distributed under the License is distributed on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ See the License for the specific language governing permissions and >+ limitations under the License. >+==================================================================== */ >+ >+package org.apache.poi.hemf.record; >+ >+ >+import java.io.IOException; >+ >+import org.apache.poi.util.IOUtils; >+import org.apache.poi.util.Internal; >+import org.apache.poi.util.LittleEndianInputStream; >+ >+@Internal >+public class UnimplementedHemfRecord implements HemfRecord { >+ >+ private long recordId; >+ >+ @Override >+ public HemfRecordType getRecordType() { >+ return HemfRecordType.getById(recordId); >+ } >+ >+ @Override >+ public long init(LittleEndianInputStream leis, long recordId, long recordSize) throws IOException { >+ this.recordId = recordId; >+ long skipped = IOUtils.skipFully(leis, recordSize); >+ if (skipped < 0) { >+ throw new IOException("End of stream reached before record read"); >+ } >+ return skipped; >+ } >+} >Index: src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentPublic.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentPublic.java (revision ) >+++ src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentPublic.java (revision ) >@@ -0,0 +1,149 @@ >+/* ==================================================================== >+ Licensed to the Apache Software Foundation (ASF) under one or more >+ contributor license agreements. See the NOTICE file distributed with >+ this work for additional information regarding copyright ownership. >+ The ASF licenses this file to You under the Apache License, Version 2.0 >+ (the "License"); you may not use this file except in compliance with >+ the License. You may obtain a copy of the License at >+ >+ http://www.apache.org/licenses/LICENSE-2.0 >+ >+ Unless required by applicable law or agreed to in writing, software >+ distributed under the License is distributed on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ See the License for the specific language governing permissions and >+ limitations under the License. >+==================================================================== */ >+ >+package org.apache.poi.hemf.record; >+ >+ >+import java.util.ArrayList; >+import java.util.List; >+ >+import org.apache.poi.util.Internal; >+import org.apache.poi.util.LittleEndian; >+import org.apache.poi.util.RecordFormatException; >+ >+/** >+ * Container class for four subtypes of HemfCommentPublic: BeginGroup, EndGroup, MultiFormats >+ * and Windows Metafile. >+ */ >+@Internal >+public class HemfCommentPublic { >+ >+ /** >+ * Stub, to be implemented >+ */ >+ public static class BeginGroup extends AbstractHemfComment { >+ >+ public BeginGroup(byte[] rawBytes) { >+ super(rawBytes); >+ } >+ >+ } >+ >+ /** >+ * Stub, to be implemented >+ */ >+ public static class EndGroup extends AbstractHemfComment { >+ >+ public EndGroup(byte[] rawBytes) { >+ super(rawBytes); >+ } >+ } >+ >+ public static class MultiFormats extends AbstractHemfComment { >+ >+ public MultiFormats(byte[] rawBytes) { >+ super(rawBytes); >+ } >+ >+ /** >+ * >+ * @return a list of HemfMultFormatsData >+ */ >+ public List<HemfMultiFormatsData> getData() { >+ >+ byte[] rawBytes = getRawBytes(); >+ //note that raw bytes includes the public comment identifier >+ int currentOffset = 4 + 16;//4 public comment identifier, 16 for outputrect >+ long countFormats = LittleEndian.getUInt(rawBytes, currentOffset); >+ currentOffset += LittleEndian.INT_SIZE; >+ List<EmrFormat> emrFormatList = new ArrayList<EmrFormat>(); >+ for (long i = 0; i < countFormats; i++) { >+ emrFormatList.add(new EmrFormat(rawBytes, currentOffset)); >+ currentOffset += 4 * LittleEndian.INT_SIZE; >+ } >+ List<HemfMultiFormatsData> list = new ArrayList<HemfMultiFormatsData>(); >+ for (EmrFormat emrFormat : emrFormatList) { >+ byte[] data = new byte[emrFormat.size]; >+ System.arraycopy(rawBytes, emrFormat.offset-4, data, 0, emrFormat.size); >+ list.add(new HemfMultiFormatsData(emrFormat.signature, emrFormat.version, data)); >+ } >+ return list; >+ } >+ >+ private class EmrFormat { >+ long signature; >+ long version; >+ int size; >+ int offset; >+ >+ public EmrFormat(byte[] rawBytes, int currentOffset) { >+ signature = LittleEndian.getUInt(rawBytes, currentOffset); currentOffset += LittleEndian.INT_SIZE; >+ version = LittleEndian.getUInt(rawBytes, currentOffset); currentOffset += LittleEndian.INT_SIZE; >+ //spec says this must be a 32bit "aligned" typo for "signed"? >+ //realistically, this has to be an int... >+ size = LittleEndian.getInt(rawBytes, currentOffset); currentOffset += LittleEndian.INT_SIZE; >+ //y, can be long, but realistically? >+ offset = LittleEndian.getInt(rawBytes, currentOffset); currentOffset += LittleEndian.INT_SIZE; >+ if (size < 0) { >+ throw new RecordFormatException("size for emrformat must be > 0"); >+ } >+ if (offset < 0) { >+ throw new RecordFormatException("offset for emrformat must be > 0"); >+ } >+ } >+ } >+ } >+ >+ /** >+ * Stub, to be implemented >+ */ >+ public static class WindowsMetafile extends AbstractHemfComment { >+ >+ public WindowsMetafile(byte[] rawBytes) { >+ super(rawBytes); >+ } >+ } >+ >+ /** >+ * This encapulates a single record stored within >+ * a HemfCommentPublic.MultiFormats record. >+ */ >+ public static class HemfMultiFormatsData { >+ >+ long signature; >+ long version; >+ byte[] data; >+ >+ public HemfMultiFormatsData(long signature, long version, byte[] data) { >+ this.signature = signature; >+ this.version = version; >+ this.data = data; >+ } >+ >+ public long getSignature() { >+ return signature; >+ } >+ >+ public long getVersion() { >+ return version; >+ } >+ >+ public byte[] getData() { >+ return data; >+ } >+ } >+} >Index: src/scratchpad/src/org/apache/poi/hemf/hemfplus/record/HemfPlusRecordType.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- src/scratchpad/src/org/apache/poi/hemf/hemfplus/record/HemfPlusRecordType.java (revision ) >+++ src/scratchpad/src/org/apache/poi/hemf/hemfplus/record/HemfPlusRecordType.java (revision ) >@@ -0,0 +1,97 @@ >+/* ==================================================================== >+ Licensed to the Apache Software Foundation (ASF) under one or more >+ contributor license agreements. See the NOTICE file distributed with >+ this work for additional information regarding copyright ownership. >+ The ASF licenses this file to You under the Apache License, Version 2.0 >+ (the "License"); you may not use this file except in compliance with >+ the License. You may obtain a copy of the License at >+ >+ http://www.apache.org/licenses/LICENSE-2.0 >+ >+ Unless required by applicable law or agreed to in writing, software >+ distributed under the License is distributed on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ See the License for the specific language governing permissions and >+ limitations under the License. >+==================================================================== */ >+ >+package org.apache.poi.hemf.hemfplus.record; >+ >+import org.apache.poi.util.Internal; >+ >+@Internal >+public enum HemfPlusRecordType { >+ header(0x4001, HemfPlusHeader.class), >+ endOfFile(0x4002, UnimplementedHemfPlusRecord.class), >+ comment(0x4003, UnimplementedHemfPlusRecord.class), >+ getDC(0x4004, UnimplementedHemfPlusRecord.class), >+ multiFormatStart(0x4005, UnimplementedHemfPlusRecord.class), >+ multiFormatSection(0x4006, UnimplementedHemfPlusRecord.class), >+ multiFormatEnd(0x4007, UnimplementedHemfPlusRecord.class), >+ object(0x4008, UnimplementedHemfPlusRecord.class), >+ clear(0x4009, UnimplementedHemfPlusRecord.class), >+ fillRects(0x400A, UnimplementedHemfPlusRecord.class), >+ drawRects(0x400B, UnimplementedHemfPlusRecord.class), >+ fillPolygon(0x400C, UnimplementedHemfPlusRecord.class), >+ drawLines(0x400D, UnimplementedHemfPlusRecord.class), >+ fillEllipse(0x400E, UnimplementedHemfPlusRecord.class), >+ drawEllipse(0x400F, UnimplementedHemfPlusRecord.class), >+ fillPie(0x4010, UnimplementedHemfPlusRecord.class), >+ drawPie(0x4011, UnimplementedHemfPlusRecord.class), >+ drawArc(0x4012, UnimplementedHemfPlusRecord.class), >+ fillRegion(0x4013, UnimplementedHemfPlusRecord.class), >+ fillPath(0x4014, UnimplementedHemfPlusRecord.class), >+ drawPath(0x4015, UnimplementedHemfPlusRecord.class), >+ fillClosedCurve(0x4016, UnimplementedHemfPlusRecord.class), >+ drawClosedCurve(0x4017, UnimplementedHemfPlusRecord.class), >+ drawCurve(0x4018, UnimplementedHemfPlusRecord.class), >+ drawBeziers(0x4019, UnimplementedHemfPlusRecord.class), >+ drawImage(0x401A, UnimplementedHemfPlusRecord.class), >+ drawImagePoints(0x401B, UnimplementedHemfPlusRecord.class), >+ drawString(0x401C, UnimplementedHemfPlusRecord.class), >+ setRenderingOrigin(0x401D, UnimplementedHemfPlusRecord.class), >+ setAntiAliasMode(0x401E, UnimplementedHemfPlusRecord.class), >+ setTextRenderingHint(0x401F, UnimplementedHemfPlusRecord.class), >+ setTextContrast(0x4020, UnimplementedHemfPlusRecord.class), >+ setInterpolationMode(0x4021, UnimplementedHemfPlusRecord.class), >+ setPixelOffsetMode(0x4022, UnimplementedHemfPlusRecord.class), >+ setComositingMode(0x4023, UnimplementedHemfPlusRecord.class), >+ setCompositingQuality(0x4024, UnimplementedHemfPlusRecord.class), >+ save(0x4025, UnimplementedHemfPlusRecord.class), >+ restore(0x4026, UnimplementedHemfPlusRecord.class), >+ beginContainer(0x4027, UnimplementedHemfPlusRecord.class), >+ beginContainerNoParams(0x428, UnimplementedHemfPlusRecord.class), >+ endContainer(0x4029, UnimplementedHemfPlusRecord.class), >+ setWorldTransform(0x402A, UnimplementedHemfPlusRecord.class), >+ resetWorldTransform(0x402B, UnimplementedHemfPlusRecord.class), >+ multiplyWorldTransform(0x402C, UnimplementedHemfPlusRecord.class), >+ translateWorldTransform(0x402D, UnimplementedHemfPlusRecord.class), >+ scaleWorldTransform(0x402E, UnimplementedHemfPlusRecord.class), >+ rotateWorldTransform(0x402F, UnimplementedHemfPlusRecord.class), >+ setPageTransform(0x4030, UnimplementedHemfPlusRecord.class), >+ resetClip(0x4031, UnimplementedHemfPlusRecord.class), >+ setClipRect(0x4032, UnimplementedHemfPlusRecord.class), >+ setClipRegion(0x4033, UnimplementedHemfPlusRecord.class), >+ setClipPath(0x4034, UnimplementedHemfPlusRecord.class), >+ offsetClip(0x4035, UnimplementedHemfPlusRecord.class), >+ drawDriverstring(0x4036, UnimplementedHemfPlusRecord.class), >+ strokeFillPath(0x4037, UnimplementedHemfPlusRecord.class), >+ serializableObject(0x4038, UnimplementedHemfPlusRecord.class), >+ setTSGraphics(0x4039, UnimplementedHemfPlusRecord.class), >+ setTSClip(0x403A, UnimplementedHemfPlusRecord.class); >+ >+ public final long id; >+ public final Class<? extends HemfPlusRecord> clazz; >+ >+ HemfPlusRecordType(long id, Class<? extends HemfPlusRecord> clazz) { >+ this.id = id; >+ this.clazz = clazz; >+ } >+ >+ public static HemfPlusRecordType getById(long id) { >+ for (HemfPlusRecordType wrt : values()) { >+ if (wrt.id == id) return wrt; >+ } >+ return null; >+ } >+} >Index: src/scratchpad/src/org/apache/poi/hemf/record/HemfHeader.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- src/scratchpad/src/org/apache/poi/hemf/record/HemfHeader.java (revision ) >+++ src/scratchpad/src/org/apache/poi/hemf/record/HemfHeader.java (revision ) >@@ -0,0 +1,260 @@ >+/* ==================================================================== >+ Licensed to the Apache Software Foundation (ASF) under one or more >+ contributor license agreements. See the NOTICE file distributed with >+ this work for additional information regarding copyright ownership. >+ The ASF licenses this file to You under the Apache License, Version 2.0 >+ (the "License"); you may not use this file except in compliance with >+ the License. You may obtain a copy of the License at >+ >+ http://www.apache.org/licenses/LICENSE-2.0 >+ >+ Unless required by applicable law or agreed to in writing, software >+ distributed under the License is distributed on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ See the License for the specific language governing permissions and >+ limitations under the License. >+==================================================================== */ >+ >+package org.apache.poi.hemf.record; >+ >+import java.awt.Rectangle; >+import java.io.IOException; >+ >+import org.apache.poi.util.Internal; >+import org.apache.poi.util.LittleEndianInputStream; >+ >+/** >+ * Extracts the full header from EMF files. >+ * @see org.apache.poi.sl.image.ImageHeaderEMF >+ */ >+@Internal >+public class HemfHeader { >+ >+ private Rectangle boundsRectangle; >+ private Rectangle frameRectangle; >+ private long bytes; >+ private long records; >+ private int handles; >+ private long nDescription; >+ private long offDescription; >+ private long nPalEntries; >+ private boolean hasExtension1; >+ private long cbPixelFormat; >+ private long offPixelFormat; >+ private long bOpenGL; >+ private boolean hasExtension2; >+ private long micrometersX; >+ private long micrometersY; >+ >+ /** >+ * Parses the EMF header from the InputStream and leaves the stream >+ * at the end of the header/beginning of the first record. >+ * >+ * @param is InputStream to read from >+ * @return header >+ * @throws IOException on exception >+ */ >+ public static HemfHeader parse(LittleEndianInputStream is) throws IOException { >+ HemfHeader header = new HemfHeader(); >+ long type = is.readUInt(); >+ if (type != 1L) { >+ throw new IOException("Not a valid EMF header"); >+ } >+ //if >= 108, extension2, if >=100, extension1, else EMFMetafileHeader >+ long headerSize = is.readUInt(); >+ >+ //bounds >+ int boundsLeft = is.readInt(); >+ int boundsTop = is.readInt(); >+ int boundsRight = is.readInt(); >+ int boundsBottom = is.readInt(); >+ header.setBoundsRectangle(new Rectangle(boundsLeft, boundsTop, >+ boundsRight - boundsLeft, boundsBottom - boundsTop)); >+ >+ int frameLeft = is.readInt(); >+ int frameTop = is.readInt(); >+ int frameRight = is.readInt(); >+ int frameBottom = is.readInt(); >+ header.setFrameRectangle(new Rectangle(frameLeft, frameTop, >+ frameRight - frameLeft, frameBottom - frameTop)); >+ >+ long recordSignature = is.readInt(); >+ if (recordSignature != 0x464D4520) { >+ throw new IOException("bad record signature: " + recordSignature); >+ } >+ >+ long version = is.readInt(); >+ if (version != 0x00010000) { >+ throw new IOException("bad version: " + version); >+ } >+ header.setBytes(is.readUInt()); >+ header.setRecords(is.readUInt()); >+ header.setHandles(is.readUShort()); >+ is.readUShort();//reserved >+ header.setnDescription(is.readUInt()); >+ header.setOffDescription(is.readUInt()); >+ header.setnPalEntries(is.readUInt()); >+ >+ //should be skips >+ is.readFully(new byte[8]); //device >+ is.readFully(new byte[8]); //millimeters >+ >+ if (headerSize >= 100) { >+ header.setHasExtension1(true); >+ header.setCbPixelFormat(is.readUInt()); >+ header.setOffPixelFormat(is.readUInt()); >+ header.setbOpenGL(is.readUInt()); >+ } >+ >+ if (headerSize >= 108) { >+ header.setHasExtension2(true); >+ header.setMicrometersX(is.readUInt()); >+ header.setMicrometersY(is.readUInt()); >+ } >+ >+ //should we keep track of bytes read and slurp >+ //whatever is left over headerSize? >+ return header; >+ } >+ >+ private void setBoundsRectangle(Rectangle boundsRectangle) { >+ this.boundsRectangle = boundsRectangle; >+ } >+ >+ private void setFrameRectangle(Rectangle frameRectangle) { >+ this.frameRectangle = frameRectangle; >+ } >+ >+ private void setBytes(long bytes) { >+ this.bytes = bytes; >+ } >+ >+ private void setRecords(long records) { >+ this.records = records; >+ } >+ >+ private void setHandles(int handles) { >+ this.handles = handles; >+ } >+ >+ private void setnDescription(long nDescription) { >+ this.nDescription = nDescription; >+ } >+ >+ private void setOffDescription(long offDescription) { >+ this.offDescription = offDescription; >+ } >+ >+ private void setnPalEntries(long nPalEntries) { >+ this.nPalEntries = nPalEntries; >+ } >+ >+ private void setHasExtension1(boolean hasExtension1) { >+ this.hasExtension1 = hasExtension1; >+ } >+ >+ private void setCbPixelFormat(long cbPixelFormat) { >+ this.cbPixelFormat = cbPixelFormat; >+ } >+ >+ private void setOffPixelFormat(long offPixelFormat) { >+ this.offPixelFormat = offPixelFormat; >+ } >+ >+ private void setbOpenGL(long bOpenGL) { >+ this.bOpenGL = bOpenGL; >+ } >+ >+ private void setHasExtension2(boolean hasExtension2) { >+ this.hasExtension2 = hasExtension2; >+ } >+ >+ private void setMicrometersX(long micrometersX) { >+ this.micrometersX = micrometersX; >+ } >+ >+ private void setMicrometersY(long micrometersY) { >+ this.micrometersY = micrometersY; >+ } >+ >+ public Rectangle getBoundsRectangle() { >+ return boundsRectangle; >+ } >+ >+ public Rectangle getFrameRectangle() { >+ return frameRectangle; >+ } >+ >+ public long getBytes() { >+ return bytes; >+ } >+ >+ public long getRecords() { >+ return records; >+ } >+ >+ public int getHandles() { >+ return handles; >+ } >+ >+ public long getnDescription() { >+ return nDescription; >+ } >+ >+ public long getOffDescription() { >+ return offDescription; >+ } >+ >+ public long getnPalEntries() { >+ return nPalEntries; >+ } >+ >+ public boolean isHasExtension1() { >+ return hasExtension1; >+ } >+ >+ public long getCbPixelFormat() { >+ return cbPixelFormat; >+ } >+ >+ public long getOffPixelFormat() { >+ return offPixelFormat; >+ } >+ >+ public long getbOpenGL() { >+ return bOpenGL; >+ } >+ >+ public boolean isHasExtension2() { >+ return hasExtension2; >+ } >+ >+ public long getMicrometersX() { >+ return micrometersX; >+ } >+ >+ public long getMicrometersY() { >+ return micrometersY; >+ } >+ >+ @Override >+ public String toString() { >+ return "HemfHeader{" + >+ "boundsRectangle=" + boundsRectangle + >+ ", frameRectangle=" + frameRectangle + >+ ", bytes=" + bytes + >+ ", records=" + records + >+ ", handles=" + handles + >+ ", nDescription=" + nDescription + >+ ", offDescription=" + offDescription + >+ ", nPalEntries=" + nPalEntries + >+ ", hasExtension1=" + hasExtension1 + >+ ", cbPixelFormat=" + cbPixelFormat + >+ ", offPixelFormat=" + offPixelFormat + >+ ", bOpenGL=" + bOpenGL + >+ ", hasExtension2=" + hasExtension2 + >+ ", micrometersX=" + micrometersX + >+ ", micrometersY=" + micrometersY + >+ '}'; >+ } >+} >Index: src/scratchpad/src/org/apache/poi/hemf/record/HemfText.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- src/scratchpad/src/org/apache/poi/hemf/record/HemfText.java (revision ) >+++ src/scratchpad/src/org/apache/poi/hemf/record/HemfText.java (revision ) >@@ -0,0 +1,146 @@ >+/* ==================================================================== >+ Licensed to the Apache Software Foundation (ASF) under one or more >+ contributor license agreements. See the NOTICE file distributed with >+ this work for additional information regarding copyright ownership. >+ The ASF licenses this file to You under the Apache License, Version 2.0 >+ (the "License"); you may not use this file except in compliance with >+ the License. You may obtain a copy of the License at >+ >+ http://www.apache.org/licenses/LICENSE-2.0 >+ >+ Unless required by applicable law or agreed to in writing, software >+ distributed under the License is distributed on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ See the License for the specific language governing permissions and >+ limitations under the License. >+==================================================================== */ >+ >+package org.apache.poi.hemf.record; >+ >+ >+import java.io.IOException; >+import java.nio.charset.Charset; >+ >+import org.apache.poi.util.IOUtils; >+import org.apache.poi.util.Internal; >+import org.apache.poi.util.LittleEndian; >+import org.apache.poi.util.LittleEndianInputStream; >+import org.apache.poi.util.RecordFormatException; >+import org.apache.poi.util.StringUtil; >+ >+/** >+ * Container class to gather all text-related commands >+ * This is starting out as read only, and very little is actually >+ * implemented at this point! >+ */ >+@Internal >+public class HemfText { >+ >+ private final static Charset UTF16LE = Charset.forName("UTF-16LE"); >+ >+ public static class ExtCreateFontIndirectW extends UnimplementedHemfRecord { >+ } >+ >+ public static class ExtTextOutA extends UnimplementedHemfRecord { >+ >+ } >+ >+ public static class ExtTextOutW implements HemfRecord { >+ >+ private long left,top,right,bottom; >+ >+ //TODO: translate this to a graphicsmode enum >+ private long graphicsMode; >+ >+ private long exScale; >+ private long eyScale; >+ EmrTextObject textObject; >+ >+ @Override >+ public HemfRecordType getRecordType() { >+ return HemfRecordType.exttextoutw; >+ } >+ >+ @Override >+ public long init(LittleEndianInputStream leis, long recordId, long recordSize) throws IOException { >+ //note that the first 2 uInts have been read off and the recordsize has >+ //been decreased by 8 >+ left = leis.readUInt(); >+ top = leis.readUInt(); >+ right = leis.readUInt(); >+ bottom = leis.readUInt(); >+ graphicsMode = leis.readUInt(); >+ exScale = leis.readUInt(); >+ eyScale = leis.readUInt(); >+ >+ int recordSizeInt = -1; >+ if (recordSize < Integer.MAX_VALUE) { >+ recordSizeInt = (int)recordSize; >+ } else { >+ throw new RecordFormatException("can't have text length > Integer.MAX_VALUE"); >+ } >+ //guarantee to read the rest of the EMRTextObjectRecord >+ //emrtextbytes start after 7*4 bytes read above >+ byte[] emrTextBytes = new byte[recordSizeInt-(7*LittleEndian.INT_SIZE)]; >+ IOUtils.readFully(leis, emrTextBytes); >+ textObject = new EmrTextObject(emrTextBytes, UTF16LE, 20);//should be 28, but recordSizeInt has already subtracted 8 >+ return recordSize; >+ } >+ >+ public EmrTextObject getTextObject() { >+ return textObject; >+ } >+ } >+ >+ public static class PolyTextOutA extends UnimplementedHemfRecord { >+ >+ } >+ >+ public static class PolyTextOutW extends UnimplementedHemfRecord { >+ >+ } >+ >+ public static class SetTextAlign extends UnimplementedHemfRecord { >+ } >+ >+ public static class SetTextColor extends UnimplementedHemfRecord { >+ } >+ >+ >+ public class SetTextJustification extends UnimplementedHemfRecord { >+ } >+ >+ public static class EmrTextObject { >+ long x; >+ long y; >+ >+ String text; >+ public EmrTextObject(byte[] emrTextObjBytes, Charset charset, int readSoFar) throws IOException { >+ >+ int offset = 0; >+ x = LittleEndian.getUInt(emrTextObjBytes, offset); offset+= LittleEndian.INT_SIZE; >+ y = LittleEndian.getUInt(emrTextObjBytes, offset); offset+= LittleEndian.INT_SIZE; >+ long numChars = LittleEndian.getUInt(emrTextObjBytes, offset); offset += LittleEndian.INT_SIZE; >+ long offString = LittleEndian.getUInt(emrTextObjBytes, offset); offset += LittleEndian.INT_SIZE; >+ int start = (int)offString-offset-readSoFar; >+ >+ if (charset.equals(UTF16LE)) { >+ text = StringUtil.getFromUnicodeLE(emrTextObjBytes, start, (int)numChars); >+ } >+ } >+ >+ public long getX() { >+ return x; >+ } >+ >+ public long getY() { >+ return y; >+ } >+ >+ public String getText() { >+ return text; >+ } >+ } >+ >+ >+} >Index: src/scratchpad/testcases/org/apache/poi/hemf/hemfplus/extractor/HemfPlusExtractorTest.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- src/scratchpad/testcases/org/apache/poi/hemf/hemfplus/extractor/HemfPlusExtractorTest.java (revision ) >+++ src/scratchpad/testcases/org/apache/poi/hemf/hemfplus/extractor/HemfPlusExtractorTest.java (revision ) >@@ -0,0 +1,100 @@ >+/* ==================================================================== >+ Licensed to the Apache Software Foundation (ASF) under one or more >+ contributor license agreements. See the NOTICE file distributed with >+ this work for additional information regarding copyright ownership. >+ The ASF licenses this file to You under the Apache License, Version 2.0 >+ (the "License"); you may not use this file except in compliance with >+ the License. You may obtain a copy of the License at >+ >+ http://www.apache.org/licenses/LICENSE-2.0 >+ >+ Unless required by applicable law or agreed to in writing, software >+ distributed under the License is distributed on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ See the License for the specific language governing permissions and >+ limitations under the License. >+==================================================================== */ >+ >+package org.apache.poi.hemf.hemfplus.extractor; >+ >+ >+import static org.junit.Assert.assertEquals; >+ >+import java.io.InputStream; >+import java.util.ArrayList; >+import java.util.List; >+ >+import org.apache.poi.POIDataSamples; >+import org.apache.poi.hemf.extractor.HemfExtractor; >+import org.apache.poi.hemf.hemfplus.record.HemfPlusHeader; >+import org.apache.poi.hemf.hemfplus.record.HemfPlusRecord; >+import org.apache.poi.hemf.hemfplus.record.HemfPlusRecordType; >+import org.apache.poi.hemf.record.HemfCommentEMFPlus; >+import org.apache.poi.hemf.record.HemfCommentRecord; >+import org.apache.poi.hemf.record.HemfRecord; >+import org.junit.Test; >+ >+public class HemfPlusExtractorTest { >+ >+ static { >+ System.setProperty("POI.testdata.path", "C:/users/tallison/Idea Projects/poi-trunk/test-data"); >+ } >+ >+ @Test >+ public void testBasic() throws Exception { >+ //test header >+ HemfCommentEMFPlus emfPlus = getCommentRecord("SimpleEMF_windows.emf", 0); >+ List<HemfPlusRecord> records = emfPlus.getRecords(); >+ assertEquals(1, records.size()); >+ assertEquals(HemfPlusRecordType.header, records.get(0).getRecordType()); >+ >+ HemfPlusHeader header = (HemfPlusHeader)records.get(0); >+ assertEquals(240, header.getLogicalDpiX()); >+ assertEquals(240, header.getLogicalDpiY()); >+ assertEquals(1, header.getFlags()); >+ assertEquals(1, header.getEmfPlusFlags()); >+ >+ >+ >+ //test that the HemfCommentEMFPlus record at offset 1 >+ //contains 6 HemfCommentEMFPlus records within it >+ List<HemfPlusRecordType> expected = new ArrayList<HemfPlusRecordType>(); >+ expected.add(HemfPlusRecordType.setPixelOffsetMode); >+ expected.add(HemfPlusRecordType.setAntiAliasMode); >+ expected.add(HemfPlusRecordType.setCompositingQuality); >+ expected.add(HemfPlusRecordType.setPageTransform); >+ expected.add(HemfPlusRecordType.setInterpolationMode); >+ expected.add(HemfPlusRecordType.getDC); >+ >+ emfPlus = getCommentRecord("SimpleEMF_windows.emf", 1); >+ records = emfPlus.getRecords(); >+ assertEquals(expected.size(), records.size()); >+ >+ for (int i = 0; i < expected.size(); i++) { >+ assertEquals(expected.get(i), records.get(i).getRecordType()); >+ } >+ } >+ >+ >+ private HemfCommentEMFPlus getCommentRecord(String testFileName, int recordIndex) throws Exception { >+ InputStream is = null; >+ HemfCommentEMFPlus returnRecord = null; >+ >+ try { >+ is = POIDataSamples.getSpreadSheetInstance().openResourceAsStream(testFileName); >+ HemfExtractor ex = new HemfExtractor(is); >+ int i = 0; >+ for (HemfRecord record : ex) { >+ if (i == recordIndex) { >+ HemfCommentRecord commentRecord = ((HemfCommentRecord) record); >+ returnRecord = (HemfCommentEMFPlus) commentRecord.getComment(); >+ break; >+ } >+ i++; >+ } >+ } finally { >+ is.close(); >+ } >+ return returnRecord; >+ } >+} >Index: src/java/org/apache/poi/util/IOUtils.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- src/java/org/apache/poi/util/IOUtils.java (revision 1778162) >+++ src/java/org/apache/poi/util/IOUtils.java (revision ) >@@ -251,4 +251,27 @@ > exc ); > } > } >+ >+ /** >+ * Skips bytes from a stream. Returns -1L if EOF was hit before >+ * the end of the stream. >+ * >+ * @param in inputstream >+ * @param len length to skip >+ * @return number of bytes skipped >+ * @throws IOException on IOException >+ */ >+ public static long skipFully(InputStream in, long len) throws IOException { >+ int total = 0; >+ while (true) { >+ long got = in.skip(len-total); >+ if (got < 0) { >+ return -1L; >+ } >+ total += got; >+ if (total == len) { >+ return total; >+ } >+ } >+ } > } >Index: src/scratchpad/src/org/apache/poi/hemf/hemfplus/record/HemfPlusHeader.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- src/scratchpad/src/org/apache/poi/hemf/hemfplus/record/HemfPlusHeader.java (revision ) >+++ src/scratchpad/src/org/apache/poi/hemf/hemfplus/record/HemfPlusHeader.java (revision ) >@@ -0,0 +1,82 @@ >+/* ==================================================================== >+ Licensed to the Apache Software Foundation (ASF) under one or more >+ contributor license agreements. See the NOTICE file distributed with >+ this work for additional information regarding copyright ownership. >+ The ASF licenses this file to You under the Apache License, Version 2.0 >+ (the "License"); you may not use this file except in compliance with >+ the License. You may obtain a copy of the License at >+ >+ http://www.apache.org/licenses/LICENSE-2.0 >+ >+ Unless required by applicable law or agreed to in writing, software >+ distributed under the License is distributed on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ See the License for the specific language governing permissions and >+ limitations under the License. >+==================================================================== */ >+ >+package org.apache.poi.hemf.hemfplus.record; >+ >+ >+import java.io.IOException; >+ >+import org.apache.poi.util.Internal; >+import org.apache.poi.util.LittleEndian; >+ >+@Internal >+public class HemfPlusHeader implements HemfPlusRecord { >+ >+ private int flags; >+ private long version; //hack for now; replace with EmfPlusGraphicsVersion object >+ private long emfPlusFlags; >+ private long logicalDpiX; >+ private long logicalDpiY; >+ >+ @Override >+ public HemfPlusRecordType getRecordType() { >+ return HemfPlusRecordType.header; >+ } >+ >+ public int getFlags() { >+ return flags; >+ } >+ >+ @Override >+ public void init(byte[] dataBytes, int recordId, int flags) throws IOException { >+ //assert record id == header >+ this.flags = flags; >+ int offset = 0; >+ this.version = LittleEndian.getUInt(dataBytes, offset); offset += LittleEndian.INT_SIZE; >+ this.emfPlusFlags = LittleEndian.getUInt(dataBytes, offset); offset += LittleEndian.INT_SIZE; >+ this.logicalDpiX = LittleEndian.getUInt(dataBytes, offset); offset += LittleEndian.INT_SIZE; >+ this.logicalDpiY = LittleEndian.getUInt(dataBytes, offset); >+ >+ } >+ >+ public long getVersion() { >+ return version; >+ } >+ >+ public long getEmfPlusFlags() { >+ return emfPlusFlags; >+ } >+ >+ public long getLogicalDpiX() { >+ return logicalDpiX; >+ } >+ >+ public long getLogicalDpiY() { >+ return logicalDpiY; >+ } >+ >+ @Override >+ public String toString() { >+ return "HemfPlusHeader{" + >+ "flags=" + flags + >+ ", version=" + version + >+ ", emfPlusFlags=" + emfPlusFlags + >+ ", logicalDpiX=" + logicalDpiX + >+ ", logicalDpiY=" + logicalDpiY + >+ '}'; >+ } >+} >Index: src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentEMFSpool.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentEMFSpool.java (revision ) >+++ src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentEMFSpool.java (revision ) >@@ -0,0 +1,31 @@ >+/* ==================================================================== >+ Licensed to the Apache Software Foundation (ASF) under one or more >+ contributor license agreements. See the NOTICE file distributed with >+ this work for additional information regarding copyright ownership. >+ The ASF licenses this file to You under the Apache License, Version 2.0 >+ (the "License"); you may not use this file except in compliance with >+ the License. You may obtain a copy of the License at >+ >+ http://www.apache.org/licenses/LICENSE-2.0 >+ >+ Unless required by applicable law or agreed to in writing, software >+ distributed under the License is distributed on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ See the License for the specific language governing permissions and >+ limitations under the License. >+==================================================================== */ >+ >+package org.apache.poi.hemf.record; >+ >+import org.apache.poi.util.Internal; >+ >+/** >+ * Not yet implemented >+ */ >+@Internal >+public class HemfCommentEMFSpool extends AbstractHemfComment { >+ >+ public HemfCommentEMFSpool(byte[] rawBytes) { >+ super(rawBytes); >+ } >+} >Index: src/scratchpad/src/org/apache/poi/hemf/record/HemfRecord.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- src/scratchpad/src/org/apache/poi/hemf/record/HemfRecord.java (revision ) >+++ src/scratchpad/src/org/apache/poi/hemf/record/HemfRecord.java (revision ) >@@ -0,0 +1,41 @@ >+/* ==================================================================== >+ Licensed to the Apache Software Foundation (ASF) under one or more >+ contributor license agreements. See the NOTICE file distributed with >+ this work for additional information regarding copyright ownership. >+ The ASF licenses this file to You under the Apache License, Version 2.0 >+ (the "License"); you may not use this file except in compliance with >+ the License. You may obtain a copy of the License at >+ >+ http://www.apache.org/licenses/LICENSE-2.0 >+ >+ Unless required by applicable law or agreed to in writing, software >+ distributed under the License is distributed on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ See the License for the specific language governing permissions and >+ limitations under the License. >+==================================================================== */ >+ >+package org.apache.poi.hemf.record; >+ >+ >+import java.io.IOException; >+ >+import org.apache.poi.util.Internal; >+import org.apache.poi.util.LittleEndianInputStream; >+ >+@Internal >+public interface HemfRecord { >+ >+ HemfRecordType getRecordType(); >+ >+ /** >+ * Init record from stream >+ * >+ * @param leis the little endian input stream >+ * @return count of processed bytes >+ * @throws IOException >+ */ >+ long init(LittleEndianInputStream leis, long recordId, long recordSize) throws IOException; >+ >+ >+} >Index: src/scratchpad/src/org/apache/poi/hemf/hemfplus/record/HemfPlusRecord.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- src/scratchpad/src/org/apache/poi/hemf/hemfplus/record/HemfPlusRecord.java (revision ) >+++ src/scratchpad/src/org/apache/poi/hemf/hemfplus/record/HemfPlusRecord.java (revision ) >@@ -0,0 +1,45 @@ >+/* ==================================================================== >+ Licensed to the Apache Software Foundation (ASF) under one or more >+ contributor license agreements. See the NOTICE file distributed with >+ this work for additional information regarding copyright ownership. >+ The ASF licenses this file to You under the Apache License, Version 2.0 >+ (the "License"); you may not use this file except in compliance with >+ the License. You may obtain a copy of the License at >+ >+ http://www.apache.org/licenses/LICENSE-2.0 >+ >+ Unless required by applicable law or agreed to in writing, software >+ distributed under the License is distributed on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ See the License for the specific language governing permissions and >+ limitations under the License. >+==================================================================== */ >+ >+package org.apache.poi.hemf.hemfplus.record; >+ >+ >+import java.io.IOException; >+ >+import org.apache.poi.util.Internal; >+ >+@Internal >+public interface HemfPlusRecord { >+ >+ HemfPlusRecordType getRecordType(); >+ >+ int getFlags(); >+ >+ /** >+ * >+ * @param dataBytes these are the bytes that start after the id, flags, record size >+ * and go to the end of the record; they do not include any required padding >+ * at the end. >+ * @param recordId record type id >+ * @param flags flags >+ * @return >+ * @throws IOException, RecordFormatException >+ */ >+ void init(byte[] dataBytes, int recordId, int flags) throws IOException; >+ >+ >+} >Index: src/scratchpad/src/org/apache/poi/hemf/record/AbstractHemfComment.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- src/scratchpad/src/org/apache/poi/hemf/record/AbstractHemfComment.java (revision ) >+++ src/scratchpad/src/org/apache/poi/hemf/record/AbstractHemfComment.java (revision ) >@@ -0,0 +1,39 @@ >+/* ==================================================================== >+ Licensed to the Apache Software Foundation (ASF) under one or more >+ contributor license agreements. See the NOTICE file distributed with >+ this work for additional information regarding copyright ownership. >+ The ASF licenses this file to You under the Apache License, Version 2.0 >+ (the "License"); you may not use this file except in compliance with >+ the License. You may obtain a copy of the License at >+ >+ http://www.apache.org/licenses/LICENSE-2.0 >+ >+ Unless required by applicable law or agreed to in writing, software >+ distributed under the License is distributed on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ See the License for the specific language governing permissions and >+ limitations under the License. >+==================================================================== */ >+ >+package org.apache.poi.hemf.record; >+ >+import org.apache.poi.util.Internal; >+ >+/** >+ * Syntactic utility to allow for four different >+ * comment classes >+ */ >+@Internal >+public abstract class AbstractHemfComment { >+ >+ private final byte[] rawBytes; >+ >+ public AbstractHemfComment(byte[] rawBytes) { >+ this.rawBytes = rawBytes; >+ } >+ >+ public byte[] getRawBytes() { >+ return rawBytes; >+ } >+ >+} >Index: src/scratchpad/src/org/apache/poi/hemf/extractor/HemfExtractor.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- src/scratchpad/src/org/apache/poi/hemf/extractor/HemfExtractor.java (revision ) >+++ src/scratchpad/src/org/apache/poi/hemf/extractor/HemfExtractor.java (revision ) >@@ -0,0 +1,109 @@ >+/* ==================================================================== >+ Licensed to the Apache Software Foundation (ASF) under one or more >+ contributor license agreements. See the NOTICE file distributed with >+ this work for additional information regarding copyright ownership. >+ The ASF licenses this file to You under the Apache License, Version 2.0 >+ (the "License"); you may not use this file except in compliance with >+ the License. You may obtain a copy of the License at >+ >+ http://www.apache.org/licenses/LICENSE-2.0 >+ >+ Unless required by applicable law or agreed to in writing, software >+ distributed under the License is distributed on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ See the License for the specific language governing permissions and >+ limitations under the License. >+==================================================================== */ >+ >+package org.apache.poi.hemf.extractor; >+ >+ >+import java.io.IOException; >+import java.io.InputStream; >+import java.util.Iterator; >+ >+import org.apache.poi.hemf.record.HemfRecord; >+import org.apache.poi.hemf.record.HemfRecordType; >+import org.apache.poi.hemf.record.HemfHeader; >+import org.apache.poi.util.Internal; >+import org.apache.poi.util.LittleEndianInputStream; >+ >+/** >+ * Read-only EMF extractor. Lots remain >+ */ >+@Internal >+public class HemfExtractor implements Iterable<HemfRecord> { >+ >+ private final HemfHeader header; >+ private final LittleEndianInputStream stream; >+ >+ public HemfExtractor(InputStream is) throws IOException { >+ stream = new LittleEndianInputStream(is); >+ header = HemfHeader.parse(stream); >+ } >+ >+ public HemfHeader getHeader() { >+ return header; >+ } >+ >+ @Override >+ public Iterator<HemfRecord> iterator() { >+ return new HemfRecordIterator(); >+ } >+ >+ private class HemfRecordIterator implements Iterator<HemfRecord> { >+ >+ private HemfRecord currentRecord = null; >+ private long recordsRead = 1;//header is the first record, and that was already read! >+ >+ HemfRecordIterator() { >+ //queue the first non-header record >+ currentRecord = _next(); >+ } >+ >+ @Override >+ public boolean hasNext() { >+ return currentRecord != null; >+ } >+ >+ @Override >+ public HemfRecord next() { >+ HemfRecord toReturn = currentRecord; >+ currentRecord = _next(); >+ return toReturn; >+ } >+ >+ private HemfRecord _next() { >+ recordsRead++; >+ if (recordsRead > header.getRecords()) { >+ return null; >+ } >+ long recordId = stream.readUInt(); >+ long recordSize = stream.readUInt(); >+ HemfRecord record = null; >+ HemfRecordType type = HemfRecordType.getById(recordId); >+ if (type == null) { >+ throw new RuntimeException("Undefined record of type:"+recordId); >+ } >+ try { >+ record = type.clazz.newInstance(); >+ } catch (InstantiationException e) { >+ throw new RuntimeException(e); >+ } catch (IllegalAccessException e) { >+ throw new RuntimeException(e); >+ } >+ try { >+ record.init(stream, recordId, recordSize-8); >+ } catch (IOException e) { >+ throw new RuntimeException(e); >+ } >+ return record; >+ } >+ >+ @Override >+ public void remove() { >+ throw new UnsupportedOperationException("Remove not supported"); >+ } >+ >+ } >+} >Index: src/scratchpad/src/org/apache/poi/hemf/record/HemfRecordType.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- src/scratchpad/src/org/apache/poi/hemf/record/HemfRecordType.java (revision ) >+++ src/scratchpad/src/org/apache/poi/hemf/record/HemfRecordType.java (revision ) >@@ -0,0 +1,159 @@ >+/* ==================================================================== >+ Licensed to the Apache Software Foundation (ASF) under one or more >+ contributor license agreements. See the NOTICE file distributed with >+ this work for additional information regarding copyright ownership. >+ The ASF licenses this file to You under the Apache License, Version 2.0 >+ (the "License"); you may not use this file except in compliance with >+ the License. You may obtain a copy of the License at >+ >+ http://www.apache.org/licenses/LICENSE-2.0 >+ >+ Unless required by applicable law or agreed to in writing, software >+ distributed under the License is distributed on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ See the License for the specific language governing permissions and >+ limitations under the License. >+==================================================================== */ >+ >+package org.apache.poi.hemf.record; >+ >+import org.apache.poi.util.Internal; >+ >+@Internal >+public enum HemfRecordType { >+ >+ header(0x00000001, UnimplementedHemfRecord.class), >+ polybeizer(0x00000002, UnimplementedHemfRecord.class), >+ polygon(0x00000003, UnimplementedHemfRecord.class), >+ polyline(0x00000004, UnimplementedHemfRecord.class), >+ polybezierto(0x00000005, UnimplementedHemfRecord.class), >+ polylineto(0x00000006, UnimplementedHemfRecord.class), >+ polypolyline(0x00000007, UnimplementedHemfRecord.class), >+ polypolygon(0x00000008, UnimplementedHemfRecord.class), >+ setwindowextex(0x00000009, UnimplementedHemfRecord.class), >+ setwindoworgex(0x0000000A, UnimplementedHemfRecord.class), >+ setviewportextex(0x0000000B, UnimplementedHemfRecord.class), >+ setviewportorgex(0x0000000C, UnimplementedHemfRecord.class), >+ setbrushorgex(0x0000000D, UnimplementedHemfRecord.class), >+ eof(0x0000000E, UnimplementedHemfRecord.class), >+ setpixelv(0x0000000F, UnimplementedHemfRecord.class), >+ setmapperflags(0x00000010, UnimplementedHemfRecord.class), >+ setmapmode(0x00000011, UnimplementedHemfRecord.class), >+ setbkmode(0x00000012, UnimplementedHemfRecord.class), >+ setpolyfillmode(0x00000013, UnimplementedHemfRecord.class), >+ setrop2(0x00000014, UnimplementedHemfRecord.class), >+ setstretchbltmode(0x00000015, UnimplementedHemfRecord.class), >+ settextalign(0x00000016, HemfText.SetTextAlign.class), >+ setcoloradjustment(0x00000017, UnimplementedHemfRecord.class), >+ settextcolor(0x00000018, HemfText.SetTextColor.class), >+ setbkcolor(0x00000019, UnimplementedHemfRecord.class), >+ setoffsetcliprgn(0x0000001A, UnimplementedHemfRecord.class), >+ setmovetoex(0x0000001B, UnimplementedHemfRecord.class), >+ setmetargn(0x0000001C, UnimplementedHemfRecord.class), >+ setexcludecliprect(0x0000001D, UnimplementedHemfRecord.class), >+ setintersectcliprect(0x0000001E, UnimplementedHemfRecord.class), >+ scaleviewportextex(0x0000001F, UnimplementedHemfRecord.class), >+ scalewindowextex(0x00000020, UnimplementedHemfRecord.class), >+ savedc(0x00000021, UnimplementedHemfRecord.class), >+ restoredc(0x00000022, UnimplementedHemfRecord.class), >+ setworldtransform(0x00000023, UnimplementedHemfRecord.class), >+ modifyworldtransform(0x00000024, UnimplementedHemfRecord.class), >+ selectobject(0x00000025, UnimplementedHemfRecord.class), >+ createpen(0x00000026, UnimplementedHemfRecord.class), >+ createbrushindirect(0x00000027, UnimplementedHemfRecord.class), >+ deleteobject(0x00000028, UnimplementedHemfRecord.class), >+ anglearc(0x00000029, UnimplementedHemfRecord.class), >+ ellipse(0x0000002A, UnimplementedHemfRecord.class), >+ rectangle(0x0000002B, UnimplementedHemfRecord.class), >+ roundirect(0x0000002C, UnimplementedHemfRecord.class), >+ arc(0x0000002D, UnimplementedHemfRecord.class), >+ chord(0x0000002E, UnimplementedHemfRecord.class), >+ pie(0x0000002F, UnimplementedHemfRecord.class), >+ selectpalette(0x00000030, UnimplementedHemfRecord.class), >+ createpalette(0x00000031, UnimplementedHemfRecord.class), >+ setpaletteentries(0x00000032, UnimplementedHemfRecord.class), >+ resizepalette(0x00000033, UnimplementedHemfRecord.class), >+ realizepalette(0x0000034, UnimplementedHemfRecord.class), >+ extfloodfill(0x00000035, UnimplementedHemfRecord.class), >+ lineto(0x00000036, UnimplementedHemfRecord.class), >+ arcto(0x00000037, UnimplementedHemfRecord.class), >+ polydraw(0x00000038, UnimplementedHemfRecord.class), >+ setarcdirection(0x00000039, UnimplementedHemfRecord.class), >+ setmiterlimit(0x0000003A, UnimplementedHemfRecord.class), >+ beginpath(0x0000003B, UnimplementedHemfRecord.class), >+ endpath(0x0000003C, UnimplementedHemfRecord.class), >+ closefigure(0x0000003D, UnimplementedHemfRecord.class), >+ fillpath(0x0000003E, UnimplementedHemfRecord.class), >+ strokeandfillpath(0x0000003F, UnimplementedHemfRecord.class), >+ strokepath(0x00000040, UnimplementedHemfRecord.class), >+ flattenpath(0x00000041, UnimplementedHemfRecord.class), >+ widenpath(0x00000042, UnimplementedHemfRecord.class), >+ selectclippath(0x00000043, UnimplementedHemfRecord.class), >+ abortpath(0x00000044, UnimplementedHemfRecord.class), //no 45?! >+ comment(0x00000046, HemfCommentRecord.class), >+ fillrgn(0x00000047, UnimplementedHemfRecord.class), >+ framergn(0x00000048, UnimplementedHemfRecord.class), >+ invertrgn(0x00000049, UnimplementedHemfRecord.class), >+ paintrgn(0x0000004A, UnimplementedHemfRecord.class), >+ extselectciprrgn(0x0000004B, UnimplementedHemfRecord.class), >+ bitblt(0x0000004C, UnimplementedHemfRecord.class), >+ stretchblt(0x0000004D, UnimplementedHemfRecord.class), >+ maskblt(0x0000004E, UnimplementedHemfRecord.class), >+ plgblt(0x0000004F, UnimplementedHemfRecord.class), >+ setbitstodevice(0x00000050, UnimplementedHemfRecord.class), >+ stretchdibits(0x00000051, UnimplementedHemfRecord.class), >+ extcreatefontindirectw(0x00000052, HemfText.ExtCreateFontIndirectW.class), >+ exttextouta(0x00000053, HemfText.ExtTextOutA.class), >+ exttextoutw(0x00000054, HemfText.ExtTextOutW.class), >+ polybezier16(0x00000055, UnimplementedHemfRecord.class), >+ polygon16(0x00000056, UnimplementedHemfRecord.class), >+ polyline16(0x00000057, UnimplementedHemfRecord.class), >+ polybezierto16(0x00000058, UnimplementedHemfRecord.class), >+ polylineto16(0x00000059, UnimplementedHemfRecord.class), >+ polypolyline16(0x0000005A, UnimplementedHemfRecord.class), >+ polypolygon16(0x0000005B, UnimplementedHemfRecord.class), >+ polydraw16(0x0000005C, UnimplementedHemfRecord.class), >+ createmonobrush16(0x0000005D, UnimplementedHemfRecord.class), >+ createdibpatternbrushpt(0x0000005E, UnimplementedHemfRecord.class), >+ extcreatepen(0x0000005F, UnimplementedHemfRecord.class), >+ polytextouta(0x00000060, HemfText.PolyTextOutA.class), >+ polytextoutw(0x00000061, HemfText.PolyTextOutW.class), >+ seticmmode(0x00000062, UnimplementedHemfRecord.class), >+ createcolorspace(0x00000063, UnimplementedHemfRecord.class), >+ setcolorspace(0x00000064, UnimplementedHemfRecord.class), >+ deletecolorspace(0x00000065, UnimplementedHemfRecord.class), >+ glsrecord(0x00000066, UnimplementedHemfRecord.class), >+ glsboundedrecord(0x00000067, UnimplementedHemfRecord.class), >+ pixelformat(0x00000068, UnimplementedHemfRecord.class), >+ drawescape(0x00000069, UnimplementedHemfRecord.class), >+ extescape(0x0000006A, UnimplementedHemfRecord.class),//no 6b?! >+ smalltextout(0x0000006C, UnimplementedHemfRecord.class), >+ forceufimapping(0x0000006D, UnimplementedHemfRecord.class), >+ namedescape(0x0000006E, UnimplementedHemfRecord.class), >+ colorcorrectpalette(0x0000006F, UnimplementedHemfRecord.class), >+ seticmprofilea(0x00000070, UnimplementedHemfRecord.class), >+ seticmprofilew(0x00000071, UnimplementedHemfRecord.class), >+ alphablend(0x00000072, UnimplementedHemfRecord.class), >+ setlayout(0x00000073, UnimplementedHemfRecord.class), >+ transparentblt(0x00000074, UnimplementedHemfRecord.class), >+ gradientfill(0x00000076, UnimplementedHemfRecord.class), //no 75?! >+ setlinkdufis(0x00000077, UnimplementedHemfRecord.class), >+ settextjustification(0x00000078, HemfText.SetTextJustification.class), >+ colormatchtargetw(0x00000079, UnimplementedHemfRecord.class), >+ createcolorspacew(0x0000007A, UnimplementedHemfRecord.class); >+ >+ public final long id; >+ public final Class<? extends HemfRecord> clazz; >+ >+ HemfRecordType(long id, Class<? extends HemfRecord> clazz) { >+ this.id = id; >+ this.clazz = clazz; >+ } >+ >+ public static HemfRecordType getById(long id) { >+ for (HemfRecordType wrt : values()) { >+ if (wrt.id == id) return wrt; >+ } >+ return null; >+ } >+} >Index: src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentRecord.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentRecord.java (revision ) >+++ src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentRecord.java (revision ) >@@ -0,0 +1,121 @@ >+/* ==================================================================== >+ Licensed to the Apache Software Foundation (ASF) under one or more >+ contributor license agreements. See the NOTICE file distributed with >+ this work for additional information regarding copyright ownership. >+ The ASF licenses this file to You under the Apache License, Version 2.0 >+ (the "License"); you may not use this file except in compliance with >+ the License. You may obtain a copy of the License at >+ >+ http://www.apache.org/licenses/LICENSE-2.0 >+ >+ Unless required by applicable law or agreed to in writing, software >+ distributed under the License is distributed on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ See the License for the specific language governing permissions and >+ limitations under the License. >+==================================================================== */ >+ >+package org.apache.poi.hemf.record; >+ >+ >+import java.io.IOException; >+ >+import org.apache.poi.util.IOUtils; >+import org.apache.poi.util.Internal; >+import org.apache.poi.util.LittleEndian; >+import org.apache.poi.util.LittleEndianInputStream; >+ >+/** >+ * This is the outer comment record that is recognized >+ * by the initial parse by {@link HemfRecordType#comment}. >+ * However, there are four types of comment: EMR_COMMENT, >+ * EMR_COMMENT_EMFPLUS, EMR_COMMENT_EMFSPOOL, and EMF_COMMENT_PUBLIC. >+ * To get the underlying comment, call {@link #getComment()}. >+ * >+ */ >+@Internal >+public class HemfCommentRecord implements HemfRecord { >+ >+ public final static long COMMENT_EMFSPOOL = 0x00000000; >+ public final static long COMMENT_EMFPLUS = 0x2B464D45; >+ public final static long COMMENT_PUBLIC = 0x43494447; >+ >+ >+ private AbstractHemfComment comment; >+ @Override >+ public HemfRecordType getRecordType() { >+ return HemfRecordType.comment; >+ } >+ >+ @Override >+ public long init(LittleEndianInputStream leis, long recordId, long recordSize) throws IOException { >+ long dataSize = leis.readUInt(); >+ >+ dataSize = dataSize-4; //size minus the first int which could be a comment identifier >+ >+ byte[] optionalCommentIndentifierBuffer = new byte[4]; >+ leis.readFully(optionalCommentIndentifierBuffer); >+ long optionalCommentIdentifier = LittleEndian.getInt(optionalCommentIndentifierBuffer) & 0x00FFFFFFFFL; >+ if (optionalCommentIdentifier == COMMENT_EMFSPOOL) { >+ comment = new HemfCommentEMFSpool(readToByteArray(leis, dataSize)); >+ } else if (optionalCommentIdentifier == COMMENT_EMFPLUS) { >+ comment = new HemfCommentEMFPlus(readToByteArray(leis, dataSize)); >+ } else if (optionalCommentIdentifier == COMMENT_PUBLIC) { >+ comment = CommentPublicParser.parse(readToByteArray(leis, dataSize)); >+ } else { >+ comment = new HemfComment(readToByteArray(optionalCommentIndentifierBuffer, leis, dataSize)); >+ } >+ >+ return recordSize; >+ } >+ >+ //this prepends the initial "int" which turned out not to be >+ //a signifier of emfplus, spool, public. >+ private byte[] readToByteArray(byte[] initialBytes, LittleEndianInputStream leis, >+ long dataSize) throws IOException { >+ long actualDataSize = dataSize+initialBytes.length; >+ assert actualDataSize < Integer.MAX_VALUE; >+ >+ byte[] arr = new byte[(int)actualDataSize]; >+ System.arraycopy(initialBytes,0,arr, 0, initialBytes.length); >+ IOUtils.readFully(leis, arr, initialBytes.length, (int)dataSize-initialBytes.length); >+ return arr; >+ } >+ >+ private byte[] readToByteArray(LittleEndianInputStream leis, long dataSize) throws IOException { >+ assert dataSize < Integer.MAX_VALUE; >+ >+ byte[] arr = new byte[(int)dataSize]; >+ IOUtils.readFully(leis, arr); >+ return arr; >+ } >+ >+ public AbstractHemfComment getComment() { >+ return comment; >+ } >+ >+ private static class CommentPublicParser { >+ private static final long WINDOWS_METAFILE = 0x80000001; //wmf >+ private static final long BEGINGROUP = 0x00000002; //beginning of a group of drawing records >+ private static final long ENDGROUP = 0x00000003; //end of a group of drawing records >+ private static final long MULTIFORMATS = 0x40000004; //allows multiple definitions of an image, including encapsulated postscript >+ private static final long UNICODE_STRING = 0x00000040; //reserved. must not be used >+ private static final long UNICODE_END = 0x00000080; //reserved, must not be used >+ >+ private static AbstractHemfComment parse(byte[] bytes) { >+ long publicCommentIdentifier = LittleEndian.getUInt(bytes, 0); >+ if (publicCommentIdentifier == WINDOWS_METAFILE) { >+ return new HemfCommentPublic.WindowsMetafile(bytes); >+ } else if (publicCommentIdentifier == BEGINGROUP) { >+ return new HemfCommentPublic.BeginGroup(bytes); >+ } else if (publicCommentIdentifier == ENDGROUP) { >+ return new HemfCommentPublic.EndGroup(bytes); >+ } else if (publicCommentIdentifier == MULTIFORMATS) { >+ return new HemfCommentPublic.MultiFormats(bytes); >+ } else if (publicCommentIdentifier == UNICODE_STRING || publicCommentIdentifier == UNICODE_END) { >+ throw new RuntimeException("UNICODE_STRING/UNICODE_END values are reserved in CommentPublic records"); >+ } >+ throw new RuntimeException("Unrecognized public comment type:" +publicCommentIdentifier); >+ } >+ } >+} >Index: src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentEMFPlus.java >IDEA additional info: >Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP ><+>UTF-8 >=================================================================== >--- src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentEMFPlus.java (revision ) >+++ src/scratchpad/src/org/apache/poi/hemf/record/HemfCommentEMFPlus.java (revision ) >@@ -0,0 +1,107 @@ >+/* ==================================================================== >+ Licensed to the Apache Software Foundation (ASF) under one or more >+ contributor license agreements. See the NOTICE file distributed with >+ this work for additional information regarding copyright ownership. >+ The ASF licenses this file to You under the Apache License, Version 2.0 >+ (the "License"); you may not use this file except in compliance with >+ the License. You may obtain a copy of the License at >+ >+ http://www.apache.org/licenses/LICENSE-2.0 >+ >+ Unless required by applicable law or agreed to in writing, software >+ distributed under the License is distributed on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ See the License for the specific language governing permissions and >+ limitations under the License. >+==================================================================== */ >+ >+package org.apache.poi.hemf.record; >+ >+import java.io.IOException; >+import java.util.ArrayList; >+import java.util.List; >+ >+import org.apache.poi.hemf.hemfplus.record.HemfPlusRecord; >+import org.apache.poi.hemf.hemfplus.record.HemfPlusRecordType; >+import org.apache.poi.util.Internal; >+import org.apache.poi.util.LittleEndian; >+import org.apache.poi.util.RecordFormatException; >+ >+/** >+ * An HemfCommentEMFPlus may contain one or more EMFPlus records >+ */ >+@Internal >+public class HemfCommentEMFPlus extends AbstractHemfComment { >+ >+ long dataSize; >+ public HemfCommentEMFPlus(byte[] rawBytes) { >+ //these rawBytes contain only the EMFPlusRecord(s?) >+ //the EmfComment type, size, datasize and comment identifier have all been stripped. >+ //The EmfPlus type, flags, size, data size should start at rawBytes[0] >+ super(rawBytes); >+ >+ } >+ >+ public List<HemfPlusRecord> getRecords() { >+ return HemfPlusParser.parse(getRawBytes()); >+ } >+ >+ private static class HemfPlusParser { >+ >+ public static List<HemfPlusRecord> parse(byte[] bytes) { >+ List<HemfPlusRecord> records = new ArrayList<HemfPlusRecord>(); >+ int offset = 0; >+ while (offset < bytes.length) { >+ if (offset + 12 > bytes.length) { >+ //if header will go beyond bytes, stop now >+ //TODO: log or throw >+ break; >+ } >+ int type = LittleEndian.getUShort(bytes, offset); offset += LittleEndian.SHORT_SIZE; >+ int flags = LittleEndian.getUShort(bytes, offset); offset += LittleEndian.SHORT_SIZE; >+ long sizeLong = LittleEndian.getUInt(bytes, offset); offset += LittleEndian.INT_SIZE; >+ if (sizeLong >= Integer.MAX_VALUE) { >+ throw new RecordFormatException("size of emf record >= Integer.MAX_VALUE"); >+ } >+ int size = (int)sizeLong; >+ long dataSizeLong = LittleEndian.getUInt(bytes, offset); offset += LittleEndian.INT_SIZE; >+ if (dataSizeLong >= Integer.MAX_VALUE) { >+ throw new RuntimeException("data size of emfplus record cannot be >= Integer.MAX_VALUE"); >+ } >+ int dataSize = (int)dataSizeLong; >+ if (dataSize + offset > bytes.length) { >+ //TODO: log or throw? >+ break; >+ } >+ HemfPlusRecord record = buildRecord(type, flags, dataSize, offset, bytes); >+ records.add(record); >+ offset += dataSize; >+ } >+ return records; >+ } >+ >+ private static HemfPlusRecord buildRecord(int recordId, int flags, int size, int offset, byte[] bytes) { >+ HemfPlusRecord record = null; >+ HemfPlusRecordType type = HemfPlusRecordType.getById(recordId); >+ if (type == null) { >+ throw new RuntimeException("Undefined record of type:"+recordId); >+ } >+ try { >+ record = type.clazz.newInstance(); >+ } catch (InstantiationException e) { >+ throw new RuntimeException(e); >+ } catch (IllegalAccessException e) { >+ throw new RuntimeException(e); >+ } >+ byte[] dataBytes = new byte[size]; >+ System.arraycopy(bytes, offset, dataBytes, 0, size); >+ try { >+ record.init(dataBytes, recordId, flags); >+ } catch (IOException e) { >+ throw new RuntimeException(e); >+ } >+ return record; >+ >+ } >+ } >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 60570
: 34605 |
34606
|
34607