| /* ==================================================================== |
| 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.ByteArrayInputStream; |
| import java.io.InputStream; |
| 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 { |
| |
| private final byte[] wmfBytes; |
| public WindowsMetafile(byte[] rawBytes) { |
| super(rawBytes); |
| int offset = LittleEndian.INT_SIZE;//public comment identifier |
| int version = LittleEndian.getUShort(rawBytes, offset); offset += LittleEndian.SHORT_SIZE; |
| int reserved = LittleEndian.getUShort(rawBytes, offset); offset += LittleEndian.SHORT_SIZE; |
| offset += LittleEndian.INT_SIZE; //checksum |
| offset += LittleEndian.INT_SIZE; //flags |
| long winMetafileSizeLong = LittleEndian.getUInt(rawBytes, offset); offset += LittleEndian.INT_SIZE; |
| if (winMetafileSizeLong == 0L) { |
| wmfBytes = new byte[0]; |
| return; |
| } |
| if (winMetafileSizeLong > Integer.MAX_VALUE) { |
| throw new RecordFormatException("Metafile record length can't be > Integer.MAX_VALUE"); |
| } |
| int winMetafileSize = (int)winMetafileSizeLong; |
| wmfBytes = new byte[winMetafileSize]; |
| System.arraycopy(rawBytes, offset, wmfBytes, 0, winMetafileSize); |
| } |
| |
| /** |
| * |
| * @return an InputStream for the embedded WMF file |
| */ |
| public InputStream getWmfInputStream() { |
| return new ByteArrayInputStream(wmfBytes); |
| } |
| } |
| |
| /** |
| * 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; |
| } |
| } |
| } |