#63745 - Add traversing and debugging interface

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1866808 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2019-09-11 21:24:06 +00:00
parent f31281f18f
commit 1d4b05ff60
165 changed files with 6101 additions and 1651 deletions

View File

@ -0,0 +1,32 @@
/*
* ====================================================================
* 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.common.usermodel;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
public interface GenericRecord {
default Enum getGenericRecordType() { return null; }
Map<String, Supplier<?>> getGenericProperties();
default List<? extends GenericRecord> getGenericChildren() { return null; }
}

View File

@ -17,10 +17,18 @@
package org.apache.poi.common.usermodel.fonts;
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import static org.apache.poi.util.GenericRecordUtil.safeEnum;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndianByteArrayInputStream;
import org.apache.poi.util.LittleEndianInput;
@ -34,8 +42,76 @@ import org.apache.poi.util.LittleEndianInputStream;
*
* @see <a href="http://www.w3.org/Submission/EOT">Embedded OpenType (EOT) File Format</a>
*/
@SuppressWarnings({"FieldCanBeLocal", "unused", "Duplicates"})
public class FontHeader implements FontInfo {
@SuppressWarnings({"FieldCanBeLocal", "unused", "Duplicates", "WeakerAccess"})
public class FontHeader implements FontInfo, GenericRecord {
public enum PanoseFamily {
ANY, NO_FIT, TEXT_DISPLAY, SCRIPT, DECORATIVE, PICTORIAL
}
public enum PanoseSerif {
ANY, NO_FIT, COVE, OBTUSE_COVE, SQUARE_COVE, OBTUSE_SQUARE_COVE, SQUARE, THIN, BONE,
EXAGGERATED, TRIANGLE, NORMAL_SANS, OBTUSE_SANS, PERP_SANS, FLARED, ROUNDED
}
public enum PanoseWeight {
ANY, NO_FIT, VERY_LIGHT, LIGHT, THIN, BOOK, MEDIUM, DEMI, BOLD, HEAVY, BLACK, NORD
}
public enum PanoseProportion {
ANY, NO_FIT, OLD_STYLE, MODERN, EVEN_WIDTH, EXPANDED, CONDENSED, VERY_EXPANDED, VERY_CONDENSED, MONOSPACED
}
public enum PanoseContrast {
ANY, NO_FIT, NONE, VERY_LOW, LOW, MEDIUM_LOW, MEDIUM, MEDIUM_HIGH, HIGH, VERY_HIGH
}
public enum PanoseStroke {
ANY, NO_FIT, GRADUAL_DIAG, GRADUAL_TRAN, GRADUAL_VERT, GRADUAL_HORZ, RAPID_VERT, RAPID_HORZ, INSTANT_VERT
}
public enum PanoseArmStyle {
ANY, NO_FIT, STRAIGHT_ARMS_HORZ, STRAIGHT_ARMS_WEDGE, STRAIGHT_ARMS_VERT, STRAIGHT_ARMS_SINGLE_SERIF,
STRAIGHT_ARMS_DOUBLE_SERIF, BENT_ARMS_HORZ, BENT_ARMS_WEDGE, BENT_ARMS_VERT, BENT_ARMS_SINGLE_SERIF,
BENT_ARMS_DOUBLE_SERIF,
}
public enum PanoseLetterForm {
ANY, NO_FIT, NORMAL_CONTACT, NORMAL_WEIGHTED, NORMAL_BOXED, NORMAL_FLATTENED, NORMAL_ROUNDED,
NORMAL_OFF_CENTER, NORMAL_SQUARE, OBLIQUE_CONTACT, OBLIQUE_WEIGHTED, OBLIQUE_BOXED, OBLIQUE_FLATTENED,
OBLIQUE_ROUNDED, OBLIQUE_OFF_CENTER, OBLIQUE_SQUARE
}
public enum PanoseMidLine {
ANY, NO_FIT, STANDARD_TRIMMED, STANDARD_POINTED, STANDARD_SERIFED, HIGH_TRIMMED, HIGH_POINTED, HIGH_SERIFED,
CONSTANT_TRIMMED, CONSTANT_POINTED, CONSTANT_SERIFED, LOW_TRIMMED, LOW_POINTED, LOW_SERIFED
}
public enum PanoseXHeight {
ANY, NO_FIT, CONSTANT_SMALL, CONSTANT_STD, CONSTANT_LARGE, DUCKING_SMALL, DUCKING_STD, DUCKING_LARGE
}
private static final int[] FLAGS_MASKS = {
0x00000001, 0x00000004, 0x00000010, 0x00000020, 0x00000040, 0x00000080, 0x10000000
};
private static final String[] FLAGS_NAMES = {
"SUBSET", "TTCOMPRESSED", "FAILIFVARIATIONSIMULATED", "EMBEDEUDC", "VALIDATIONTESTS", "WEBOBJECT", "XORENCRYPTDATA"
};
private static final int[] FSTYPE_MASKS = {
0x0000, 0x0002, 0x0004, 0x0008, 0x0100, 0x0200
};
private static final String[] FSTYPE_NAMES = {
"INSTALLABLE_EMBEDDING",
"RESTRICTED_LICENSE_EMBEDDING",
"PREVIEW_PRINT_EMBEDDING",
"EDITABLE_EMBEDDING",
"NO_SUBSETTING",
"BITMAP_EMBEDDING_ONLY"
};
/**
* Fonts with a font weight of 400 are regarded as regular weighted.
* Higher font weights (up to 1000) are bold - lower weights are thin.
@ -142,53 +218,54 @@ public class FontHeader implements FontInfo {
}
public FontPitch getPitch() {
byte familyKind = panose[0];
switch (familyKind) {
switch (getPanoseFamily()) {
default:
// Any
case 0:
// No Fit
case 1:
case ANY:
case NO_FIT:
return FontPitch.VARIABLE;
// Latin Text
case 2:
// Latin Decorative
case 4:
byte proportion = panose[3];
return proportion == 9 ? FontPitch.FIXED : FontPitch.VARIABLE;
case TEXT_DISPLAY:
// Latin Decorative
case DECORATIVE:
return (getPanoseProportion() == PanoseProportion.MONOSPACED) ? FontPitch.FIXED : FontPitch.VARIABLE;
// Latin Hand Written
case 3:
// Latin Symbol
case 5:
byte spacing = panose[3];
return spacing == 3 ? FontPitch.FIXED : FontPitch.VARIABLE;
case SCRIPT:
// Latin Symbol
case PICTORIAL:
return (getPanoseProportion() == PanoseProportion.MODERN) ? FontPitch.FIXED : FontPitch.VARIABLE;
}
}
public FontFamily getFamily() {
switch (panose[0]) {
// Any
case 0:
// No Fit
case 1:
switch (getPanoseFamily()) {
case ANY:
case NO_FIT:
return FontFamily.FF_DONTCARE;
// Latin Text
case 2:
byte serifStyle = panose[1];
return (10 <= serifStyle && serifStyle <= 15)
? FontFamily.FF_SWISS : FontFamily.FF_ROMAN;
case TEXT_DISPLAY:
switch (getPanoseSerif()) {
case TRIANGLE:
case NORMAL_SANS:
case OBTUSE_SANS:
case PERP_SANS:
case FLARED:
case ROUNDED:
return FontFamily.FF_SWISS;
default:
return FontFamily.FF_ROMAN;
}
// Latin Hand Written
case 3:
case SCRIPT:
return FontFamily.FF_SCRIPT;
// Latin Decorative
default:
case 4:
case DECORATIVE:
return FontFamily.FF_DECORATIVE;
// Latin Symbol
case 5:
case PICTORIAL:
return FontFamily.FF_MODERN;
}
}
@ -221,7 +298,79 @@ public class FontHeader implements FontInfo {
public int getFlags() {
return flags;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String,Supplier<?>> m = new LinkedHashMap<>();
m.put("eotSize", () -> eotSize);
m.put("fontDataSize", () -> fontDataSize);
m.put("version", () -> version);
m.put("flags", getBitsAsString(this::getFlags, FLAGS_MASKS, FLAGS_NAMES));
m.put("panose.familyType", this::getPanoseFamily);
m.put("panose.serifType", this::getPanoseSerif);
m.put("panose.weight", this::getPanoseWeight);
m.put("panose.proportion", this::getPanoseProportion);
m.put("panose.contrast", this::getPanoseContrast);
m.put("panose.stroke", this::getPanoseStroke);
m.put("panose.armStyle", this::getPanoseArmStyle);
m.put("panose.letterForm", this::getPanoseLetterForm);
m.put("panose.midLine", this::getPanoseMidLine);
m.put("panose.xHeight", this::getPanoseXHeight);
m.put("charset", this::getCharset);
m.put("italic", this::isItalic);
m.put("weight", this::getWeight);
m.put("fsType", getBitsAsString(() -> fsType, FSTYPE_MASKS, FSTYPE_NAMES));
m.put("unicodeRange1", () -> unicodeRange1);
m.put("unicodeRange2", () -> unicodeRange2);
m.put("unicodeRange3", () -> unicodeRange3);
m.put("unicodeRange4", () -> unicodeRange4);
m.put("codePageRange1", () -> codePageRange1);
m.put("codePageRange2", () -> codePageRange2);
m.put("checkSumAdjustment", () -> checkSumAdjustment);
m.put("familyName", this::getFamilyName);
m.put("styleName", this::getStyleName);
m.put("versionName", this::getVersionName);
m.put("fullName", this::getFullName);
return Collections.unmodifiableMap(m);
}
public PanoseFamily getPanoseFamily() {
return safeEnum(PanoseFamily.values(), () -> panose[0]).get();
}
public PanoseSerif getPanoseSerif() {
return safeEnum(PanoseSerif.values(), () -> panose[1]).get();
}
public PanoseWeight getPanoseWeight() {
return safeEnum(PanoseWeight.values(), () -> panose[2]).get();
}
public PanoseProportion getPanoseProportion() {
return safeEnum(PanoseProportion.values(), () -> panose[3]).get();
}
public PanoseContrast getPanoseContrast() {
return safeEnum(PanoseContrast.values(), () -> panose[4]).get();
}
public PanoseStroke getPanoseStroke() {
return safeEnum(PanoseStroke.values(), () -> panose[5]).get();
}
public PanoseArmStyle getPanoseArmStyle() {
return safeEnum(PanoseArmStyle.values(), () -> panose[6]).get();
}
public PanoseLetterForm getPanoseLetterForm() {
return safeEnum(PanoseLetterForm.values(), () -> panose[7]).get();
}
public PanoseMidLine getPanoseMidLine() {
return safeEnum(PanoseMidLine.values(), () -> panose[8]).get();
}
public PanoseXHeight getPanoseXHeight() {
return safeEnum(PanoseXHeight.values(), () -> panose[9]).get();
}
}

View File

@ -18,9 +18,11 @@ package org.apache.poi.ddf;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndian;
/**
@ -29,7 +31,7 @@ import org.apache.poi.util.LittleEndian;
*/
public abstract class AbstractEscherOptRecord extends EscherRecord
{
private List<EscherProperty> properties = new ArrayList<>();
private final List<EscherProperty> properties = new ArrayList<>();
/**
* Add a property to this record.
@ -50,7 +52,8 @@ public abstract class AbstractEscherOptRecord extends EscherRecord
int pos = offset + 8;
EscherPropertyFactory f = new EscherPropertyFactory();
properties = f.createProperties( data, pos, propertiesCount );
properties.clear();
properties.addAll( f.createProperties( data, pos, propertiesCount ) );
return bytesRemaining + 8;
}
@ -132,16 +135,8 @@ public abstract class AbstractEscherOptRecord extends EscherRecord
/**
* Records should be sorted by property number before being stored.
*/
public void sortProperties()
{
properties.sort(new Comparator<EscherProperty>() {
@Override
public int compare(EscherProperty p1, EscherProperty p2) {
short s1 = p1.getPropertyNumber();
short s2 = p2.getPropertyNumber();
return Short.compare(s1, s2);
}
});
public void sortProperties() {
properties.sort(Comparator.comparingInt(EscherProperty::getPropertyNumber));
}
/**
@ -151,24 +146,13 @@ public abstract class AbstractEscherOptRecord extends EscherRecord
* @param value the property to set.
*/
public void setEscherProperty(EscherProperty value){
for ( Iterator<EscherProperty> iterator =
properties.iterator(); iterator.hasNext(); ) {
EscherProperty prop = iterator.next();
if (prop.getId() == value.getId()){
iterator.remove();
}
}
properties.removeIf(prop -> prop.getId() == value.getId());
properties.add( value );
sortProperties();
}
public void removeEscherProperty(int num){
for ( Iterator<EscherProperty> iterator = getEscherProperties().iterator(); iterator.hasNext(); ) {
EscherProperty prop = iterator.next();
if (prop.getPropertyNumber() == num){
iterator.remove();
}
}
properties.removeIf(prop -> prop.getPropertyNumber() == num);
}
@Override
@ -187,4 +171,12 @@ public abstract class AbstractEscherOptRecord extends EscherRecord
attrList.toArray()
};
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"isContainer", this::isContainerRecord
);
}
}

View File

@ -17,6 +17,11 @@
package org.apache.poi.ddf;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
@ -32,8 +37,7 @@ public final class EscherBSERecord extends EscherRecord {
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000;
public static final short RECORD_ID = (short) 0xF007;
public static final String RECORD_DESCRIPTION = "MsofbtBSE";
public static final short RECORD_ID = EscherRecordTypes.BSE.typeID;
public static final byte BT_ERROR = 0;
public static final byte BT_UNKNOWN = 1;
@ -147,7 +151,7 @@ public final class EscherBSERecord extends EscherRecord {
@Override
public String getRecordName() {
return "BSE";
return EscherRecordTypes.BSE.recordName;
}
/**
@ -401,4 +405,28 @@ public final class EscherBSERecord extends EscherRecord {
{ "Extra Data", _remainingData }
};
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String, Supplier<?>> m = new LinkedHashMap<>(super.getGenericProperties());
m.put("blipTypeWin32", this::getBlipTypeWin32);
m.put("blipTypeMacOS", this::getBlipTypeMacOS);
m.put("suid", this::getUid);
m.put("tag", this::getTag);
m.put("size", this::getSize);
m.put("ref", this::getRef);
m.put("offset", this::getOffset);
m.put("usage", this::getUsage);
m.put("name", this::getName);
m.put("unused2", this::getUnused2);
m.put("unused3", this::getUnused3);
m.put("blipRecord", this::getBlipRecord);
m.put("remainingData", this::getRemainingData);
return Collections.unmodifiableMap(m);
}
@Override
public Enum getGenericRecordType() {
return EscherRecordTypes.BSE;
}
}

View File

@ -17,12 +17,17 @@
package org.apache.poi.ddf;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.LittleEndian;
public class EscherBitmapBlip extends EscherBlipRecord {
public static final short RECORD_ID_JPEG = (short) 0xF018 + 5;
public static final short RECORD_ID_PNG = (short) 0xF018 + 6;
public static final short RECORD_ID_DIB = (short) 0xF018 + 7;
public static final short RECORD_ID_JPEG = EscherRecordTypes.BLIP_JPEG.typeID;
public static final short RECORD_ID_PNG = EscherRecordTypes.BLIP_PNG.typeID;
public static final short RECORD_ID_DIB = EscherRecordTypes.BLIP_DIB.typeID;
private static final int HEADER_SIZE = 8;
@ -115,4 +120,14 @@ public class EscherBitmapBlip extends EscherBlipRecord {
{ "Extra Data", getPicturedata() }
};
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String, Supplier<?>> m = new LinkedHashMap<>(super.getGenericProperties());
m.put("uid", this::getUID);
m.put("marker", this::getMarker);
return Collections.unmodifiableMap(m);
}
}

View File

@ -17,6 +17,10 @@
package org.apache.poi.ddf;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
@ -25,9 +29,8 @@ public class EscherBlipRecord extends EscherRecord {
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 104_857_600;
public static final short RECORD_ID_START = (short) 0xF018;
public static final short RECORD_ID_END = (short) 0xF117;
public static final String RECORD_DESCRIPTION = "msofbtBlip";
public static final short RECORD_ID_START = EscherRecordTypes.BLIP_START.typeID;
public static final short RECORD_ID_END = EscherRecordTypes.BLIP_END.typeID;
private static final int HEADER_SIZE = 8;
@ -67,7 +70,8 @@ public class EscherBlipRecord extends EscherRecord {
@Override
public String getRecordName() {
return "Blip";
EscherRecordTypes t = EscherRecordTypes.forTypeID(getRecordId());
return (t != EscherRecordTypes.UNKNOWN ? t : EscherRecordTypes.BLIP_START).recordName;
}
/**
@ -109,4 +113,18 @@ public class EscherBlipRecord extends EscherRecord {
{ "Extra Data", getPicturedata() }
};
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"pictureData", this::getPicturedata
);
}
@Override
public Enum getGenericRecordType() {
EscherRecordTypes t = EscherRecordTypes.forTypeID(getRecordId());
return (t != EscherRecordTypes.UNKNOWN) ? t : EscherRecordTypes.BLIP_START;
}
}

View File

@ -18,6 +18,10 @@
package org.apache.poi.ddf;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndian;
/**
@ -26,11 +30,8 @@ import org.apache.poi.util.LittleEndian;
*
* @see EscherChildAnchorRecord
*/
public class EscherChildAnchorRecord
extends EscherRecord
{
public static final short RECORD_ID = (short) 0xF00F;
public static final String RECORD_DESCRIPTION = "MsofbtChildAnchor";
public class EscherChildAnchorRecord extends EscherRecord {
public static final short RECORD_ID = EscherRecordTypes.CHILD_ANCHOR.typeID;
private int field_1_dx1;
private int field_2_dy1;
@ -91,7 +92,7 @@ public class EscherChildAnchorRecord
@Override
public String getRecordName() {
return "ChildAnchor";
return EscherRecordTypes.CHILD_ANCHOR.recordName;
}
@ -184,4 +185,20 @@ public class EscherChildAnchorRecord
{ "Y2", field_4_dy2 }
};
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"x1", this::getDx1,
"y1", this::getDy1,
"x2", this::getDx2,
"y2", this::getDy2
);
}
@Override
public Enum getGenericRecordType() {
return EscherRecordTypes.CHILD_ANCHOR;
}
}

View File

@ -17,6 +17,11 @@
package org.apache.poi.ddf;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
@ -28,14 +33,11 @@ import org.apache.poi.util.LittleEndian;
*
* @see EscherChildAnchorRecord
*/
public class EscherClientAnchorRecord
extends EscherRecord
{
public class EscherClientAnchorRecord extends EscherRecord {
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000;
public static final short RECORD_ID = (short) 0xF010;
public static final String RECORD_DESCRIPTION = "MsofbtClientAnchor";
public static final short RECORD_ID = EscherRecordTypes.CLIENT_ANCHOR.typeID;
/**
* bit[0] - fMove (1 bit): A bit that specifies whether the shape will be kept intact when the cells are moved.
@ -135,7 +137,7 @@ public class EscherClientAnchorRecord
@Override
public String getRecordName() {
return "ClientAnchor";
return EscherRecordTypes.CLIENT_ANCHOR.recordName;
}
/**
@ -361,4 +363,25 @@ public class EscherClientAnchorRecord
{ "Extra Data", remainingData }
};
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String,Supplier<?>> m = new LinkedHashMap<>(super.getGenericProperties());
m.put("flag", this::getFlag);
m.put("col1", this::getCol1);
m.put("dx1", this::getDx1);
m.put("row1", this::getRow1);
m.put("dy1", this::getDy1);
m.put("col2", this::getCol2);
m.put("dx2", this::getDx2);
m.put("row2", this::getRow2);
m.put("dy2", this::getDy2);
m.put("remainingData", this::getRemainingData);
return Collections.unmodifiableMap(m);
}
@Override
public Enum getGenericRecordType() {
return EscherRecordTypes.CLIENT_ANCHOR;
}
}

View File

@ -18,6 +18,10 @@
package org.apache.poi.ddf;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
@ -31,8 +35,7 @@ public class EscherClientDataRecord
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000;
public static final short RECORD_ID = (short) 0xF011;
public static final String RECORD_DESCRIPTION = "MsofbtClientData";
public static final short RECORD_ID = EscherRecordTypes.CLIENT_DATA.typeID;
private byte[] remainingData;
@ -75,7 +78,7 @@ public class EscherClientDataRecord
@Override
public String getRecordName() {
return "ClientData";
return EscherRecordTypes.CLIENT_DATA.recordName;
}
/**
@ -105,4 +108,17 @@ public class EscherClientDataRecord
{ "Extra Data", getRemainingData() }
};
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"remainingData", this::getRemainingData
);
}
@Override
public Enum getGenericRecordType() {
return EscherRecordTypes.CLIENT_DATA;
}
}

View File

@ -22,7 +22,10 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogFactory;
@ -35,12 +38,12 @@ import org.apache.poi.util.POILogger;
* used to represent many different types of records.
*/
public final class EscherContainerRecord extends EscherRecord implements Iterable<EscherRecord> {
public static final short DGG_CONTAINER = (short)0xF000;
public static final short BSTORE_CONTAINER = (short)0xF001;
public static final short DG_CONTAINER = (short)0xF002;
public static final short SPGR_CONTAINER = (short)0xF003;
public static final short SP_CONTAINER = (short)0xF004;
public static final short SOLVER_CONTAINER = (short)0xF005;
public static final short DGG_CONTAINER = EscherRecordTypes.DGG_CONTAINER.typeID;
public static final short BSTORE_CONTAINER = EscherRecordTypes.BSTORE_CONTAINER.typeID;
public static final short DG_CONTAINER = EscherRecordTypes.DG_CONTAINER.typeID;
public static final short SPGR_CONTAINER = EscherRecordTypes.SPGR_CONTAINER.typeID;
public static final short SP_CONTAINER = EscherRecordTypes.SP_CONTAINER.typeID;
public static final short SOLVER_CONTAINER = EscherRecordTypes.SOLVER_CONTAINER.typeID;
private static final POILogger log = POILogFactory.getLogger(EscherContainerRecord.class);
@ -201,22 +204,9 @@ public final class EscherContainerRecord extends EscherRecord implements Iterabl
@Override
public String getRecordName() {
switch (getRecordId()) {
case DGG_CONTAINER:
return "DggContainer";
case BSTORE_CONTAINER:
return "BStoreContainer";
case DG_CONTAINER:
return "DgContainer";
case SPGR_CONTAINER:
return "SpgrContainer";
case SP_CONTAINER:
return "SpContainer";
case SOLVER_CONTAINER:
return "SolverContainer";
default:
return "Container 0x" + HexDump.toHex(getRecordId());
}
final short id = getRecordId();
EscherRecordTypes t = EscherRecordTypes.forTypeID(id);
return (t != EscherRecordTypes.UNKNOWN) ? t.recordName : "Container 0x" + HexDump.toHex(id);
}
@Override
@ -298,4 +288,17 @@ public final class EscherContainerRecord extends EscherRecord implements Iterabl
chList.toArray()
};
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"isContainer", this::isContainerRecord
);
}
@Override
public Enum getGenericRecordType() {
return EscherRecordTypes.forTypeID(getRecordId());
}
}

View File

@ -18,17 +18,18 @@
package org.apache.poi.ddf;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndian;
/**
* This record simply holds the number of shapes in the drawing group and the
* last shape id used for this drawing group.
*/
public class EscherDgRecord
extends EscherRecord
{
public static final short RECORD_ID = (short) 0xF008;
public static final String RECORD_DESCRIPTION = "MsofbtDg";
public class EscherDgRecord extends EscherRecord {
public static final short RECORD_ID = EscherRecordTypes.DG.typeID;
private int field_1_numShapes;
private int field_2_lastMSOSPID;
@ -81,7 +82,7 @@ public class EscherDgRecord
@Override
public String getRecordName() {
return "Dg";
return EscherRecordTypes.DG.recordName;
}
/**
@ -150,4 +151,19 @@ public class EscherDgRecord
{ "LastMSOSPID", field_2_lastMSOSPID }
};
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"numShapes", this::getNumShapes,
"lastMSOSPID", this::getLastMSOSPID,
"drawingGroupId", this::getDrawingGroupId
);
}
@Override
public Enum getGenericRecordType() {
return EscherRecordTypes.DG;
}
}

View File

@ -22,7 +22,11 @@ import java.util.Arrays;
import java.util.BitSet;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.RecordFormatException;
@ -30,9 +34,8 @@ import org.apache.poi.util.RecordFormatException;
* This record defines the drawing groups used for a particular sheet.
*/
public final class EscherDggRecord extends EscherRecord {
public static final short RECORD_ID = (short) 0xF006;
public static final String RECORD_DESCRIPTION = "MsofbtDgg";
public static final short RECORD_ID = EscherRecordTypes.DGG.typeID;
private int field_1_shapeIdMax;
// for some reason the number of clusters is actually the real number + 1
// private int field_2_numIdClusters;
@ -41,7 +44,7 @@ public final class EscherDggRecord extends EscherRecord {
private final List<FileIdCluster> field_5_fileIdClusters = new ArrayList<>();
private int maxDgId;
public static class FileIdCluster {
public static class FileIdCluster implements GenericRecord {
private int field_1_drawingGroupId;
private int field_2_numShapeIdsUsed;
@ -61,6 +64,14 @@ public final class EscherDggRecord extends EscherRecord {
private void incrementUsedShapeId() {
field_2_numShapeIdsUsed++;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"drawingGroupId", this::getDrawingGroupId,
"numShapeIdUsed", this::getNumShapeIdsUsed
);
}
}
@Override
@ -129,7 +140,7 @@ public final class EscherDggRecord extends EscherRecord {
@Override
public String getRecordName() {
return "Dgg";
return EscherRecordTypes.DGG.recordName;
}
/**
@ -344,4 +355,21 @@ public final class EscherDggRecord extends EscherRecord {
fldIds.toArray()
};
}
@Override
public Enum getGenericRecordType() {
return EscherRecordTypes.DGG;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"fileIdClusters", () -> field_5_fileIdClusters,
"shapeIdMax", this::getShapeIdMax,
"numIdClusters", this::getNumIdClusters,
"numShapesSaved", this::getNumShapesSaved,
"drawingsSaved", this::getDrawingsSaved
);
}
}

View File

@ -22,6 +22,10 @@ import java.awt.Rectangle;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
@ -36,9 +40,9 @@ public final class EscherMetafileBlip extends EscherBlipRecord {
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000_000;
public static final short RECORD_ID_EMF = (short) 0xF018 + 2;
public static final short RECORD_ID_WMF = (short) 0xF018 + 3;
public static final short RECORD_ID_PICT = (short) 0xF018 + 4;
public static final short RECORD_ID_EMF = EscherRecordTypes.BLIP_EMF.typeID;
public static final short RECORD_ID_WMF = EscherRecordTypes.BLIP_WMF.typeID;
public static final short RECORD_ID_PICT = EscherRecordTypes.BLIP_PICT.typeID;
private static final int HEADER_SIZE = 8;
@ -348,10 +352,10 @@ public final class EscherMetafileBlip extends EscherBlipRecord {
* @return the blip signature
*/
public short getSignature() {
switch (getRecordId()) {
case RECORD_ID_EMF: return HSSFPictureData.MSOBI_EMF;
case RECORD_ID_WMF: return HSSFPictureData.MSOBI_WMF;
case RECORD_ID_PICT: return HSSFPictureData.MSOBI_PICT;
switch (EscherRecordTypes.forTypeID(getRecordId())) {
case BLIP_EMF: return HSSFPictureData.MSOBI_EMF;
case BLIP_WMF: return HSSFPictureData.MSOBI_WMF;
case BLIP_PICT: return HSSFPictureData.MSOBI_PICT;
}
if (log.check(POILogger.WARN)) {
log.log(POILogger.WARN, "Unknown metafile: " + getRecordId());
@ -397,4 +401,17 @@ public final class EscherMetafileBlip extends EscherBlipRecord {
{ "Remaining Data", remainingData }
};
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String, Supplier<?>> m = new LinkedHashMap<>(super.getGenericProperties());
m.put("uid", this::getUID);
m.put("uncompressedSize", this::getUncompressedSize);
m.put("bounds", this::getBounds);
m.put("sizeInEMU", this::getSizeEMU);
m.put("compressedSize", this::getCompressedSize);
m.put("isCompressed", this::isCompressed);
m.put("filter", this::getFilter);
return Collections.unmodifiableMap(m);
}
}

View File

@ -26,8 +26,8 @@ import org.apache.poi.util.Internal;
*/
public class EscherOptRecord extends AbstractEscherOptRecord
{
public static final String RECORD_DESCRIPTION = "msofbtOPT";
public static final short RECORD_ID = (short) 0xF00B;
public static final short RECORD_ID = EscherRecordTypes.OPT.typeID;
public static final String RECORD_DESCRIPTION = EscherRecordTypes.OPT.description;
@Override
public short getInstance()
@ -50,9 +50,8 @@ public class EscherOptRecord extends AbstractEscherOptRecord
}
@Override
public String getRecordName()
{
return "Opt";
public String getRecordName() {
return EscherRecordTypes.OPT.recordName;
}
@Override
@ -72,4 +71,9 @@ public class EscherOptRecord extends AbstractEscherOptRecord
super.setVersion( value );
}
@Override
public Enum getGenericRecordType() {
return EscherRecordTypes.OPT;
}
}

View File

@ -22,6 +22,10 @@ import java.awt.Rectangle;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import java.util.zip.InflaterInputStream;
import org.apache.poi.util.IOUtils;
@ -34,9 +38,9 @@ public final class EscherPictBlip extends EscherBlipRecord {
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000;
public static final short RECORD_ID_EMF = (short) 0xF018 + 2;
public static final short RECORD_ID_WMF = (short) 0xF018 + 3;
public static final short RECORD_ID_PICT = (short) 0xF018 + 4;
public static final short RECORD_ID_EMF = EscherRecordTypes.BLIP_EMF.typeID;
public static final short RECORD_ID_WMF = EscherRecordTypes.BLIP_WMF.typeID;
public static final short RECORD_ID_PICT = EscherRecordTypes.BLIP_PICT.typeID;
private static final int HEADER_SIZE = 8;
@ -293,4 +297,17 @@ public final class EscherPictBlip extends EscherBlipRecord {
{ "Extra Data", getPicturedata() },
};
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String, Supplier<?>> m = new LinkedHashMap<>(super.getGenericProperties());
m.put("uid", this::getUID);
m.put("uncompressedSize", this::getUncompressedSize);
m.put("bounds", this::getBounds);
m.put("sizeInEMU", this::getSizeEMU);
m.put("compressedSize", this::getCompressedSize);
m.put("isCompressed", this::isCompressed);
m.put("filter", this::getFilter);
return Collections.unmodifiableMap(m);
}
}

View File

@ -21,9 +21,13 @@ package org.apache.poi.ddf;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndian;
@ -32,7 +36,7 @@ import org.apache.poi.util.LittleEndian;
* The base abstract record from which all escher records are defined. Subclasses will need
* to define methods for serialization/deserialization and for determining the record size.
*/
public abstract class EscherRecord implements Cloneable {
public abstract class EscherRecord implements Cloneable, GenericRecord {
private static final BitField fInstance = BitFieldFactory.getInstance(0xfff0);
private static final BitField fVersion = BitFieldFactory.getInstance(0x000f);
@ -500,4 +504,20 @@ public abstract class EscherRecord implements Cloneable {
}
}
}
@Override
public List<? extends GenericRecord> getGenericChildren() {
return getChildRecords();
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"recordId", this::getRecordId,
"version", this::getVersion,
"instance", this::getInstance,
"options", this::getOptions,
"recordSize", this::getRecordSize
);
}
}

View File

@ -0,0 +1,92 @@
/* ====================================================================
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.ddf;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public enum EscherRecordTypes {
// records greater then 0xF000 belong to with Microsoft Office Drawing format also known as Escher
DGG_CONTAINER(0xF000, "DggContainer", null),
BSTORE_CONTAINER(0xf001, "BStoreContainer", null),
DG_CONTAINER(0xf002, "DgContainer", null),
SPGR_CONTAINER(0xf003, "SpgrContainer", null),
SP_CONTAINER(0xf004, "SpContainer", null),
SOLVER_CONTAINER(0xf005, "SolverContainer", null),
DGG(0xf006, "Dgg", "MsofbtDgg"),
BSE(0xf007, "BSE", "MsofbtBSE"),
DG(0xf008, "Dg", "MsofbtDg"),
SPGR(0xf009, "Spgr", "MsofbtSpgr"),
SP(0xf00a, "Sp", "MsofbtSp"),
OPT(0xf00b, "Opt", "msofbtOPT"),
TEXTBOX(0xf00c, null, null),
CLIENT_TEXTBOX(0xf00d, "ClientTextbox", "msofbtClientTextbox"),
ANCHOR(0xf00e, null, null),
CHILD_ANCHOR(0xf00f, "ChildAnchor", "MsofbtChildAnchor"),
CLIENT_ANCHOR(0xf010, "ClientAnchor", "MsofbtClientAnchor"),
CLIENT_DATA(0xf011, "ClientData", "MsofbtClientData"),
CONNECTOR_RULE(0xf012, null, null),
ALIGN_RULE(0xf013, null, null),
ARC_RULE(0xf014, null, null),
CLIENT_RULE(0xf015, null, null),
CLSID(0xf016, null, null),
CALLOUT_RULE(0xf017, null, null),
BLIP_START(0xf018, "Blip", "msofbtBlip"),
BLIP_EMF(0xf018 + 2, "BlipEmf", null),
BLIP_WMF(0xf018 + 3, "BlipWmf", null),
BLIP_PICT(0xf018 + 4, "BlipPict", null),
BLIP_JPEG(0xf018 + 5, "BlipJpeg", null),
BLIP_PNG(0xf018 + 6, "BlipPng", null),
BLIP_DIB(0xf018 + 7, "BlipDib", null),
BLIP_END(0xf117, "Blip", "msofbtBlip"),
REGROUP_ITEMS(0xf118, null, null),
SELECTION(0xf119, null, null),
COLOR_MRU(0xf11a, null, null),
DELETED_PSPL(0xf11d, null, null),
SPLIT_MENU_COLORS(0xf11e, "SplitMenuColors", "MsofbtSplitMenuColors"),
OLE_OBJECT(0xf11f, null, null),
COLOR_SCHEME(0xf120, null, null),
// same as EscherTertiaryOptRecord.RECORD_ID
USER_DEFINED(0xf122, "TertiaryOpt", null),
UNKNOWN(0xffff, "unknown", "unknown");
public final short typeID;
public final String recordName;
public final String description;
EscherRecordTypes(int typeID, String recordName, String description) {
this.typeID = (short) typeID;
this.recordName = recordName;
this.description = description;
}
private Short getTypeId() {
return typeID;
}
private static final Map<Short, EscherRecordTypes> LOOKUP =
Stream.of(values()).collect(Collectors.toMap(EscherRecordTypes::getTypeId, Function.identity()));
public static EscherRecordTypes forTypeID(int typeID) {
EscherRecordTypes rt = LOOKUP.get((short)typeID);
return (rt != null) ? rt : EscherRecordTypes.UNKNOWN;
}
}

View File

@ -17,6 +17,12 @@
package org.apache.poi.ddf;
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
@ -24,11 +30,8 @@ import org.apache.poi.util.LittleEndian;
* Together the the EscherOptRecord this record defines some of the basic
* properties of a shape.
*/
public class EscherSpRecord
extends EscherRecord
{
public static final short RECORD_ID = (short) 0xF00A;
public static final String RECORD_DESCRIPTION = "MsofbtSp";
public class EscherSpRecord extends EscherRecord {
public static final short RECORD_ID = EscherRecordTypes.SP.typeID;
public static final int FLAG_GROUP = 0x0001;
public static final int FLAG_CHILD = 0x0002;
@ -43,6 +46,36 @@ public class EscherSpRecord
public static final int FLAG_BACKGROUND = 0x0400;
public static final int FLAG_HASSHAPETYPE = 0x0800;
private static final int[] FLAGS_MASKS = {
FLAG_GROUP,
FLAG_CHILD,
FLAG_PATRIARCH,
FLAG_DELETED,
FLAG_OLESHAPE,
FLAG_HAVEMASTER,
FLAG_FLIPHORIZ,
FLAG_FLIPVERT,
FLAG_CONNECTOR,
FLAG_HAVEANCHOR,
FLAG_BACKGROUND,
FLAG_HASSHAPETYPE
};
private static final String[] FLAGS_NAMES = {
"GROUP",
"CHILD",
"PATRIARCH",
"DELETED",
"OLESHAPE",
"HAVEMASTER",
"FLIPHORIZ",
"FLIPVERT",
"CONNECTOR",
"HAVEANCHOR",
"BACKGROUND",
"HASSHAPETYPE"
};
private int field_1_shapeId;
private int field_2_flags;
@ -98,7 +131,7 @@ public class EscherSpRecord
@Override
public String getRecordName() {
return "Sp";
return EscherRecordTypes.SP.recordName;
}
/**
@ -106,7 +139,7 @@ public class EscherSpRecord
*/
private String decodeFlags( int flags )
{
StringBuffer result = new StringBuffer();
StringBuilder result = new StringBuilder();
result.append( ( flags & FLAG_GROUP ) != 0 ? "|GROUP" : "" );
result.append( ( flags & FLAG_CHILD ) != 0 ? "|CHILD" : "" );
result.append( ( flags & FLAG_PATRIARCH ) != 0 ? "|PATRIARCH" : "" );
@ -222,4 +255,19 @@ public class EscherSpRecord
{ "Flags", decodeFlags(field_2_flags)+" (0x"+HexDump.toHex(field_2_flags)+")" }
};
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"shapeType", this::getShapeType,
"shapeId", this::getShapeId,
"flags", getBitsAsString(this::getFlags, FLAGS_MASKS, FLAGS_NAMES)
);
}
@Override
public Enum getGenericRecordType() {
return EscherRecordTypes.SP;
}
}

View File

@ -17,6 +17,10 @@
package org.apache.poi.ddf;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.RecordFormatException;
@ -24,11 +28,8 @@ import org.apache.poi.util.RecordFormatException;
* The spgr record defines information about a shape group. Groups in escher
* are simply another form of shape that you can't physically see.
*/
public class EscherSpgrRecord
extends EscherRecord
{
public static final short RECORD_ID = (short) 0xF009;
public static final String RECORD_DESCRIPTION = "MsofbtSpgr";
public class EscherSpgrRecord extends EscherRecord {
public static final short RECORD_ID = EscherRecordTypes.SPGR.typeID;
private int field_1_rectX1;
private int field_2_rectY1;
@ -84,7 +85,7 @@ public class EscherSpgrRecord
@Override
public String getRecordName() {
return "Spgr";
return EscherRecordTypes.SPGR.recordName;
}
/**
@ -175,4 +176,20 @@ public class EscherSpgrRecord
{ "RectHeight", field_4_rectY2 }
};
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"rectX1", this::getRectX1,
"rectY1", this::getRectY1,
"rectX2", this::getRectX2,
"rectY2", this::getRectY2
);
}
@Override
public Enum getGenericRecordType() {
return EscherRecordTypes.SPGR;
}
}

View File

@ -17,6 +17,10 @@
package org.apache.poi.ddf;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.RecordFormatException;
@ -24,11 +28,8 @@ import org.apache.poi.util.RecordFormatException;
* A list of the most recently used colours for the drawings contained in
* this document.
*/
public class EscherSplitMenuColorsRecord
extends EscherRecord
{
public static final short RECORD_ID = (short) 0xF11E;
public static final String RECORD_DESCRIPTION = "MsofbtSplitMenuColors";
public class EscherSplitMenuColorsRecord extends EscherRecord {
public static final short RECORD_ID = EscherRecordTypes.SPLIT_MENU_COLORS.typeID;
private int field_1_color1;
private int field_2_color2;
@ -82,7 +83,7 @@ public class EscherSplitMenuColorsRecord
@Override
public String getRecordName() {
return "SplitMenuColors";
return EscherRecordTypes.SPLIT_MENU_COLORS.recordName;
}
/**
@ -166,4 +167,20 @@ public class EscherSplitMenuColorsRecord
{ "Color4", field_4_color4 }
};
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"color1", this::getColor1,
"color2", this::getColor2,
"color3", this::getColor3,
"color4", this::getColor4
);
}
@Override
public Enum getGenericRecordType() {
return EscherRecordTypes.SPLIT_MENU_COLORS;
}
}

View File

@ -22,11 +22,15 @@ package org.apache.poi.ddf;
*/
public class EscherTertiaryOptRecord extends AbstractEscherOptRecord
{
public static final short RECORD_ID = (short) 0xF122;
public static final short RECORD_ID = EscherRecordTypes.USER_DEFINED.typeID;
@Override
public String getRecordName()
{
return "TertiaryOpt";
public String getRecordName() {
return EscherRecordTypes.USER_DEFINED.recordName;
}
@Override
public Enum getGenericRecordType() {
return EscherRecordTypes.USER_DEFINED;
}
}

View File

@ -19,7 +19,10 @@ package org.apache.poi.ddf;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.RecordFormatException;
@ -35,8 +38,7 @@ public final class EscherTextboxRecord extends EscherRecord implements Cloneable
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000;
public static final short RECORD_ID = (short)0xF00D;
public static final String RECORD_DESCRIPTION = "msofbtClientTextbox";
public static final short RECORD_ID = EscherRecordTypes.CLIENT_TEXTBOX.typeID;
private static final byte[] NO_BYTES = new byte[0];
@ -134,7 +136,7 @@ public final class EscherTextboxRecord extends EscherRecord implements Cloneable
@Override
public String getRecordName() {
return "ClientTextbox";
return EscherRecordTypes.CLIENT_TEXTBOX.recordName;
}
@Override
@ -154,4 +156,18 @@ public final class EscherTextboxRecord extends EscherRecord implements Cloneable
{ "Extra Data", thedata }
};
}
@Override
public Enum getGenericRecordType() {
return EscherRecordTypes.CLIENT_TEXTBOX;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"isContainer", this::isContainerRecord,
"extraData", this::getData
);
}
}

View File

@ -19,7 +19,10 @@ package org.apache.poi.ddf;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
@ -158,4 +161,17 @@ public final class UnknownEscherRecord extends EscherRecord implements Cloneable
{ "Extra Data", thedata }
};
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"data", this::getData
);
}
@Override
public Enum getGenericRecordType() {
return EscherRecordTypes.UNKNOWN;
}
}

View File

@ -26,7 +26,7 @@ import org.apache.poi.ddf.EscherOptRecord;
import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.ddf.EscherProperty;
import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.ddf.EscherTextboxRecord;
import org.apache.poi.ddf.EscherRecordTypes;
import org.apache.poi.hssf.record.CommonObjectDataSubRecord;
import org.apache.poi.hssf.record.EmbeddedObjectRefSubRecord;
import org.apache.poi.hssf.record.EscherAggregate;
@ -71,11 +71,11 @@ public class HSSFShapeFactory {
TextObjectRecord txtRecord = null;
for (EscherRecord record : container) {
switch (record.getRecordId()) {
case EscherClientDataRecord.RECORD_ID:
switch (EscherRecordTypes.forTypeID(record.getRecordId())) {
case CLIENT_DATA:
objRecord = (ObjRecord) shapeToObj.get(record);
break;
case EscherTextboxRecord.RECORD_ID:
case CLIENT_TEXTBOX:
txtRecord = (TextObjectRecord) shapeToObj.get(record);
break;
default:

View File

@ -17,13 +17,28 @@
package org.apache.poi.hssf.usermodel;
import org.apache.poi.ddf.*;
import org.apache.poi.hssf.record.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Iterator;
import java.util.List;
import org.apache.poi.ddf.DefaultEscherRecordFactory;
import org.apache.poi.ddf.EscherBoolProperty;
import org.apache.poi.ddf.EscherChildAnchorRecord;
import org.apache.poi.ddf.EscherClientAnchorRecord;
import org.apache.poi.ddf.EscherClientDataRecord;
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherOptRecord;
import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.ddf.EscherRecordTypes;
import org.apache.poi.ddf.EscherSpRecord;
import org.apache.poi.ddf.EscherSpgrRecord;
import org.apache.poi.hssf.record.CommonObjectDataSubRecord;
import org.apache.poi.hssf.record.EndSubRecord;
import org.apache.poi.hssf.record.EscherAggregate;
import org.apache.poi.hssf.record.GroupMarkerSubRecord;
import org.apache.poi.hssf.record.ObjRecord;
/**
* A shape group may contain other shapes. It was no actual form on the
@ -40,13 +55,13 @@ public class HSSFShapeGroup extends HSSFShape implements HSSFShapeContainer {
EscherContainerRecord spContainer = spgrContainer.getChildContainers().get(0);
_spgrRecord = (EscherSpgrRecord) spContainer.getChild(0);
for (EscherRecord ch : spContainer.getChildRecords()) {
switch (ch.getRecordId()) {
case EscherSpgrRecord.RECORD_ID:
switch (EscherRecordTypes.forTypeID(ch.getRecordId())) {
case SPGR:
break;
case EscherClientAnchorRecord.RECORD_ID:
case CLIENT_ANCHOR:
anchor = new HSSFClientAnchor((EscherClientAnchorRecord) ch);
break;
case EscherChildAnchorRecord.RECORD_ID:
case CHILD_ANCHOR:
anchor = new HSSFChildAnchor((EscherChildAnchorRecord) ch);
break;
default:
@ -307,8 +322,7 @@ public class HSSFShapeGroup extends HSSFShape implements HSSFShapeContainer {
*/
public int countOfAllChildren() {
int count = shapes.size();
for (Iterator<HSSFShape> iterator = shapes.iterator(); iterator.hasNext(); ) {
HSSFShape shape = iterator.next();
for (HSSFShape shape : shapes) {
count += shape.countOfAllChildren();
}
return count;

View File

@ -19,16 +19,20 @@ package org.apache.poi.poifs.crypt;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.util.Map;
import java.util.function.Supplier;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.GenericRecordUtil;
public abstract class Decryptor implements Cloneable {
public abstract class Decryptor implements Cloneable, GenericRecord {
public static final String DEFAULT_PASSWORD="VelvetSweatshop";
public static final String DEFAULT_POIFS_ENTRY="EncryptedPackage";
@ -185,4 +189,14 @@ public abstract class Decryptor implements Cloneable {
// encryptionInfo is set from outside
return other;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"secretKey", secretKey::getEncoded,
"verifier", this::getVerifier,
"integrityHmacKey", this::getIntegrityHmacKey,
"integrityHmacValue", this::getIntegrityHmacValue
);
}
}

View File

@ -16,13 +16,19 @@
==================================================================== */
package org.apache.poi.poifs.crypt;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.common.usermodel.GenericRecord;
/**
* Reads and processes OOXML Encryption Headers
* The constants are largely based on ZIP constants.
*/
public abstract class EncryptionHeader implements Cloneable {
public abstract class EncryptionHeader implements Cloneable, GenericRecord {
public static final int ALGORITHM_RC4 = CipherAlgorithm.rc4.ecmaId;
public static final int ALGORITHM_AES_128 = CipherAlgorithm.aes128.ecmaId;
public static final int ALGORITHM_AES_192 = CipherAlgorithm.aes192.ecmaId;
@ -156,4 +162,20 @@ public abstract class EncryptionHeader implements Cloneable {
other.keySalt = (keySalt == null) ? null : keySalt.clone();
return other;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String,Supplier<?>> m = new LinkedHashMap<>();
m.put("flags", this::getFlags);
m.put("sizeExtra", this::getSizeExtra);
m.put("cipherAlgorithm", this::getCipherAlgorithm);
m.put("hashAlgorithm", this::getHashAlgorithm);
m.put("keyBits", this::getKeySize);
m.put("blockSize", this::getBlockSize);
m.put("providerType", this::getCipherProvider);
m.put("chainingMode", this::getChainingMode);
m.put("keySalt", this::getKeySalt);
m.put("cspName", this::getCspName);
return Collections.unmodifiableMap(m);
}
}

View File

@ -21,10 +21,16 @@ import static org.apache.poi.poifs.crypt.EncryptionMode.binaryRC4;
import static org.apache.poi.poifs.crypt.EncryptionMode.cryptoAPI;
import static org.apache.poi.poifs.crypt.EncryptionMode.standard;
import static org.apache.poi.poifs.crypt.EncryptionMode.xor;
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.BitField;
@ -36,7 +42,7 @@ import org.apache.poi.util.LittleEndianInput;
* some {@link EncryptionMode}s.
* @see #getBuilder(EncryptionMode)
*/
public class EncryptionInfo implements Cloneable {
public class EncryptionInfo implements Cloneable, GenericRecord {
private final EncryptionMode encryptionMode;
private final int versionMajor;
private final int versionMinor;
@ -72,8 +78,15 @@ public class EncryptionInfo implements Cloneable {
* ECMA-376. If the fAES bit is 1, the fCryptoAPI bit MUST also be 1.
*/
public static final BitField flagAES = BitFieldFactory.getInstance(0x20);
private static final int[] FLAGS_MASKS = {
0x04, 0x08, 0x10, 0x20
};
private static final String[] FLAGS_NAMES = {
"CRYPTO_API", "DOC_PROPS", "EXTERNAL", "AES"
};
/**
* Opens for decryption
*/
@ -277,4 +290,18 @@ public class EncryptionInfo implements Cloneable {
other.encryptor.setEncryptionInfo(other);
return other;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String,Supplier<?>> m = new LinkedHashMap<>();
m.put("encryptionMode", this::getEncryptionMode);
m.put("versionMajor", this::getVersionMajor);
m.put("versionMinor", this::getVersionMinor);
m.put("encryptionFlags", getBitsAsString(this::getEncryptionFlags, FLAGS_MASKS, FLAGS_NAMES));
m.put("header", this::getHeader);
m.put("verifier", this::getVerifier);
m.put("decryptor", this::getDecryptor);
m.put("encryptor", this::getEncryptor);
return Collections.unmodifiableMap(m);
}
}

View File

@ -16,10 +16,17 @@
==================================================================== */
package org.apache.poi.poifs.crypt;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.GenericRecord;
/**
* Used when checking if a key is valid for a document
*/
public abstract class EncryptionVerifier implements Cloneable {
public abstract class EncryptionVerifier implements Cloneable, GenericRecord {
private byte[] salt;
private byte[] encryptedVerifier;
private byte[] encryptedVerifierHash;
@ -105,4 +112,18 @@ public abstract class EncryptionVerifier implements Cloneable {
other.encryptedKey = (encryptedKey == null) ? null : encryptedKey.clone();
return other;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String,Supplier<?>> m = new LinkedHashMap<>();
m.put("salt", this::getSalt);
m.put("encryptedVerifier", this::getEncryptedVerifier);
m.put("encryptedVerifierHash", this::getEncryptedVerifierHash);
m.put("encryptedKey", this::getEncryptedKey);
m.put("spinCount", this::getSpinCount);
m.put("cipherAlgorithm", this::getCipherAlgorithm);
m.put("chainingMode", this::getChainingMode);
m.put("hashAlgorithm", this::getHashAlgorithm);
return Collections.unmodifiableMap(m);
}
}

View File

@ -19,15 +19,19 @@ package org.apache.poi.poifs.crypt;
import java.io.IOException;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.util.Map;
import java.util.function.Supplier;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.GenericRecordUtil;
public abstract class Encryptor implements Cloneable {
public abstract class Encryptor implements Cloneable, GenericRecord {
protected static final String DEFAULT_POIFS_ENTRY = Decryptor.DEFAULT_POIFS_ENTRY;
private EncryptionInfo encryptionInfo;
private SecretKey secretKey;
@ -93,4 +97,11 @@ public abstract class Encryptor implements Cloneable {
// encryptionInfo is set from outside
return other;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"secretKey", secretKey::getEncoded
);
}
}

View File

@ -76,9 +76,9 @@ public class DrawPictureShape extends DrawSimpleShape {
* @param graphics the graphics context
* @return the image renderer
*/
@SuppressWarnings({"WeakerAccess", "unchecked"})
@SuppressWarnings({"unchecked"})
public static ImageRenderer getImageRenderer(Graphics2D graphics, String contentType) {
final ImageRenderer renderer = (ImageRenderer)graphics.getRenderingHint(Drawable.IMAGE_RENDERER);
final ImageRenderer renderer = (graphics != null) ? (ImageRenderer)graphics.getRenderingHint(Drawable.IMAGE_RENDERER) : null;
if (renderer != null && renderer.canRender(contentType)) {
return renderer;
}

View File

@ -23,8 +23,8 @@ import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
@ -62,6 +62,10 @@ public class DrawSimpleShape extends DrawShape {
return;
}
Paint oldPaint = graphics.getPaint();
Stroke oldStroke = graphics.getStroke();
Color oldColor = graphics.getColor();
Paint fill = getFillPaint(graphics);
Paint line = getLinePaint(graphics);
BasicStroke stroke = getStroke(); // the stroke applies both to the shadow and the shape
@ -115,8 +119,12 @@ public class DrawSimpleShape extends DrawShape {
}
}
// draw line decorations
// draw line decorations
drawDecoration(graphics, line, stroke);
graphics.setColor(oldColor);
graphics.setPaint(oldPaint);
graphics.setStroke(oldStroke);
}
private void fillArea(Graphics2D graphics, PaintModifier pm, Path2D area) {

View File

@ -26,6 +26,8 @@ import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import org.apache.poi.common.usermodel.GenericRecord;
/**
* Classes can implement this interfaces to support other formats, for
* example, use Apache Batik to render WMF, PICT can be rendered using Apple QuickTime API for Java:
@ -134,4 +136,7 @@ public interface ImageRenderer {
* @return true if the picture data was successfully rendered
*/
boolean drawImage(Graphics2D graphics, Rectangle2D anchor, Insets clip);
default GenericRecord getGenericRecord() { return null; }
}

View File

@ -105,21 +105,38 @@ public interface TextShape<
*/
enum TextPlaceholder {
/** Title placeholder shape text */
TITLE,
TITLE(0),
/** Body placeholder shape text */
BODY,
BODY(1),
/** Center title placeholder shape text */
CENTER_TITLE,
CENTER_TITLE(6),
/** Center body placeholder shape text */
CENTER_BODY,
CENTER_BODY(5),
/** Half-sized body placeholder shape text */
HALF_BODY,
HALF_BODY(7),
/** Quarter-sized body placeholder shape text */
QUARTER_BODY,
QUARTER_BODY(8),
/** Notes placeholder shape text */
NOTES,
NOTES(2),
/** Any other text */
OTHER
OTHER(4);
public final int nativeId;
TextPlaceholder(int nativeId) {
this.nativeId = nativeId;
}
public static TextPlaceholder fromNativeId(int nativeId) {
for (TextPlaceholder ld : values()) {
if (ld.nativeId == nativeId) return ld;
}
return null;
}
public static boolean isTitle(int nativeId) {
return (nativeId == TITLE.nativeId || nativeId == CENTER_TITLE.nativeId);
}
}
/**

View File

@ -0,0 +1,455 @@
/*
* ====================================================================
* 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.util;
import java.awt.Color;
import java.awt.geom.AffineTransform;
import java.awt.geom.Dimension2D;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.Flushable;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.lang.reflect.Array;
import java.nio.charset.StandardCharsets;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.bind.DatatypeConverter;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.util.GenericRecordUtil.AnnotatedFlag;
@Beta
public class GenericRecordJsonWriter implements Closeable {
private static final String TABS;
private static final String ZEROS = "0000000000000000";
private static final Pattern ESC_CHARS = Pattern.compile("[\"\\p{Cntrl}\\\\]");
private static final List<Map.Entry<Class,BiConsumer<GenericRecordJsonWriter,Object>>> handler = new ArrayList<>();
static {
char[] t = new char[255];
Arrays.fill(t, '\t');
TABS = new String(t);
handler(String.class, GenericRecordJsonWriter::printObject);
handler(Number.class, GenericRecordJsonWriter::printNumber);
handler(Boolean.class, GenericRecordJsonWriter::printBoolean);
handler(List.class, GenericRecordJsonWriter::printList);
handler(GenericRecord.class, GenericRecordJsonWriter::printGenericRecord);
handler(AnnotatedFlag.class, GenericRecordJsonWriter::printAnnotatedFlag);
handler(byte[].class, GenericRecordJsonWriter::printBytes);
handler(Point2D.class, GenericRecordJsonWriter::printPoint);
handler(Dimension2D.class, GenericRecordJsonWriter::printDimension);
handler(Rectangle2D.class, GenericRecordJsonWriter::printRectangle);
handler(Path2D.class, GenericRecordJsonWriter::printPath);
handler(AffineTransform.class, GenericRecordJsonWriter::printAffineTransform);
handler(Color.class, GenericRecordJsonWriter::printColor);
handler(Array.class, GenericRecordJsonWriter::printArray);
handler(Object.class, GenericRecordJsonWriter::printObject);
}
private static void handler(Class c, BiConsumer<GenericRecordJsonWriter,Object> printer) {
handler.add(new AbstractMap.SimpleEntry<>(c,printer));
}
private final PrintWriter fw;
private int indent = 0;
private boolean withComments = true;
private int childIndex = 0;
public GenericRecordJsonWriter(File fileName) throws IOException {
OutputStream os = ("null".equals(fileName.getName())) ? new NullOutputStream() : new FileOutputStream(fileName);
fw = new PrintWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8));
}
public GenericRecordJsonWriter(Appendable buffer) {
fw = new PrintWriter(new Writer(){
@Override
public void write(char[] cbuf, int off, int len) throws IOException {
buffer.append(String.valueOf(cbuf), off, len);
}
@Override
public void flush() throws IOException {
if (buffer instanceof Flushable) {
((Flushable)buffer).flush();
}
}
@Override
public void close() throws IOException {
flush();
if (buffer instanceof Closeable) {
((Closeable)buffer).close();
}
}
});
}
public static String marshal(GenericRecord record) {
return marshal(record, true);
}
public static String marshal(GenericRecord record, boolean withComments) {
final StringBuilder sb = new StringBuilder();
try (GenericRecordJsonWriter w = new GenericRecordJsonWriter(sb)) {
w.setWithComments(withComments);
w.write(record);
return sb.toString();
} catch (IOException e) {
return "{}";
}
}
public void setWithComments(boolean withComments) {
this.withComments = withComments;
}
@Override
public void close() throws IOException {
fw.close();
}
private String tabs() {
return TABS.substring(0, Math.min(indent, TABS.length()));
}
public void write(GenericRecord record) {
final String tabs = tabs();
Enum type = record.getGenericRecordType();
String recordName = (type != null) ? type.name() : record.getClass().getSimpleName();
fw.append(tabs);
fw.append("{");
if (withComments) {
fw.append(" /* ");
fw.append(recordName);
if (childIndex > 0) {
fw.append(" - index: ");
fw.print(childIndex);
}
fw.append(" */");
}
fw.println();
Map<String, Supplier<?>> prop = record.getGenericProperties();
if (prop != null) {
final int oldChildIndex = childIndex;
childIndex = 0;
prop.forEach(this::writeProp);
childIndex = oldChildIndex;
}
fw.println();
List<? extends GenericRecord> list = record.getGenericChildren();
if (list != null && !list.isEmpty()) {
indent++;
fw.append(tabs());
if (prop != null && !prop.isEmpty()) {
fw.append(", ");
}
fw.append("children: [");
final int oldChildIndex = childIndex;
childIndex = 0;
list.forEach(l -> { writeValue(l); childIndex++; });
childIndex = oldChildIndex;
fw.println();
fw.append(tabs());
fw.append("]");
fw.println();
indent--;
}
fw.append(tabs);
fw.append("}");
}
public void writeError(String errorMsg) {
fw.append("{ error: ");
printObject(errorMsg);
fw.append(" }");
}
private void writeProp(String k, Supplier<?> v) {
final boolean isNext = (childIndex++>0);
if (isNext) {
fw.println();
}
fw.write(tabs());
fw.write('\t');
fw.write(isNext ? ", " : " ");
fw.write(k);
fw.write(": ");
final int oldChildIndex = childIndex;
childIndex = 0;
writeValue(v.get());
childIndex = oldChildIndex;
}
private void writeValue(Object o) {
if (childIndex > 0) {
fw.println(',');
}
if (o == null) {
fw.write("null");
} else {
handler.stream().
filter(h -> matchInstanceOrArray(h.getKey(), o)).
findFirst().
ifPresent(h -> h.getValue().accept(this, o));
}
}
private static boolean matchInstanceOrArray(Class key, Object instance) {
return key.isInstance(instance) || (Array.class.equals(key) && instance.getClass().isArray());
}
private void printNumber(Object o) {
Number n = (Number)o;
fw.print(n.toString());
final int size;
if (n instanceof Byte) {
size = 2;
} else if (n instanceof Short) {
size = 4;
} else if (n instanceof Integer) {
size = 8;
} else if (n instanceof Long) {
size = 16;
} else {
size = -1;
}
long l = n.longValue();
if (withComments && size > 0 && (l < 0 || l > 9)) {
fw.write(" /* 0x");
fw.write(trimHex(l, size));
fw.write(" */");
}
}
private void printBoolean(Object o) {
fw.write(((Boolean)o).toString());
}
private void printList(Object o) {
fw.println('[');
final int[] c = new int[1];
//noinspection unchecked
int oldChildIndex = childIndex;
childIndex = 0;
((List)o).forEach(e -> { writeValue(e); childIndex++; });
childIndex = oldChildIndex;
fw.write(']');
}
private void printGenericRecord(Object o) {
fw.println();
this.indent++;
write((GenericRecord) o);
this.indent--;
}
private void printAnnotatedFlag(Object o) {
AnnotatedFlag af = (AnnotatedFlag) o;
fw.write("0x");
fw.write(Long.toHexString(af.getValue().get().longValue()));
if (withComments) {
fw.write(" /* ");
fw.write(af.getDescription());
fw.write(" */ ");
}
}
private void printBytes(Object o) {
fw.write('"');
fw.write(DatatypeConverter.printBase64Binary((byte[]) o));
fw.write('"');
}
private void printPoint(Object o) {
Point2D p = (Point2D)o;
fw.write("{ x: "+p.getX()+", y: "+p.getY()+" }");
}
private void printDimension(Object o) {
Dimension2D p = (Dimension2D)o;
fw.write("{ width: "+p.getWidth()+", height: "+p.getHeight()+" }");
}
private void printRectangle(Object o) {
Rectangle2D p = (Rectangle2D)o;
fw.write("{ x: "+p.getX()+", y: "+p.getY()+", width: "+p.getWidth()+", height: "+p.getHeight()+" }");
}
private void printPath(Object o) {
final PathIterator iter = ((Path2D)o).getPathIterator(null);
final double[] pnts = new double[6];
fw.print("[");
indent += 2;
String t = tabs();
indent -= 2;
boolean isNext = false;
while (!iter.isDone()) {
fw.println(isNext ? ", " : "");
fw.print(t);
isNext = true;
final int segType = iter.currentSegment(pnts);
fw.append("{ type: ");
switch (segType) {
case PathIterator.SEG_MOVETO:
fw.write("'move', x: "+pnts[0]+", y: "+pnts[1]);
break;
case PathIterator.SEG_LINETO:
fw.write("'lineto', x: "+pnts[0]+", y: "+pnts[1]);
break;
case PathIterator.SEG_QUADTO:
fw.write("'quad', x1: "+pnts[0]+", y1: "+pnts[1]+", x2: "+pnts[2]+", y2: "+pnts[3]);
break;
case PathIterator.SEG_CUBICTO:
fw.write("'cubic', x1: "+pnts[0]+", y1: "+pnts[1]+", x2: "+pnts[2]+", y2: "+pnts[3]+", x3: "+pnts[4]+", y3: "+pnts[5]);
break;
case PathIterator.SEG_CLOSE:
fw.write("'close'");
break;
}
fw.append(" }");
iter.next();
}
fw.write("]");
}
private void printObject(Object o) {
fw.write('"');
final Matcher m = ESC_CHARS.matcher(o.toString());
final StringBuffer sb = new StringBuffer();
while (m.find()) {
String repl;
String match = m.group();
switch (match) {
case "\n":
repl = "\\\\n";
break;
case "\r":
repl = "\\\\r";
break;
case "\t":
repl = "\\\\t";
break;
case "\b":
repl = "\\\\b";
break;
case "\f":
repl = "\\\\f";
break;
case "\\":
repl = "\\\\\\\\";
break;
case "\"":
repl = "\\\\\"";
break;
default:
repl = "\\\\u" + trimHex(match.charAt(0), 4);
break;
}
m.appendReplacement(sb, repl);
}
m.appendTail(sb);
fw.write(sb.toString());
fw.write('"');
}
private void printAffineTransform(Object o) {
AffineTransform xForm = (AffineTransform)o;
fw.write(
"{ scaleX: "+xForm.getScaleX()+
", shearX: "+xForm.getShearX()+
", transX: "+xForm.getTranslateX()+
", scaleY: "+xForm.getScaleY()+
", shearY: "+xForm.getShearY()+
", transY: "+xForm.getTranslateY()+" }");
}
private void printColor(Object o) {
final int rgb = ((Color)o).getRGB();
fw.print(rgb);
if (withComments) {
fw.write(" /* 0x");
fw.write(trimHex(rgb, 8));
fw.write(" */");
}
}
private void printArray(Object o) {
fw.println('[');
int length = Array.getLength(o);
final int oldChildIndex = childIndex;
for (childIndex=0; childIndex<length; childIndex++) {
writeValue(Array.get(o, childIndex));
}
childIndex = oldChildIndex;
fw.write(']');
}
private String trimHex(final long l, final int size) {
final String b = Long.toHexString(l);
int len = b.length();
return ZEROS.substring(0, Math.max(0,size-len)) + b.substring(Math.max(0,len-size), len);
}
private static class NullOutputStream extends OutputStream {
private NullOutputStream() {
}
@Override
public void write(byte[] b, int off, int len) {
}
@Override
public void write(int b) {
}
@Override
public void write(byte[] b) {
}
}
}

View File

@ -0,0 +1,142 @@
/*
* ====================================================================
* 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.util;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@Internal
public final class GenericRecordUtil {
private GenericRecordUtil() {}
public static Map<String, Supplier<?>>
getGenericProperties(String val1, Supplier<?> sup1) {
return Collections.unmodifiableMap(Collections.singletonMap(val1, sup1));
}
public static Map<String, Supplier<?>> getGenericProperties(
String val1, Supplier<?> sup1,
String val2, Supplier<?> sup2
) {
return getGenericProperties(val1, sup1, val2, sup2, null, null, null, null, null, null, null, null);
}
public static Map<String, Supplier<?>> getGenericProperties(
String val1, Supplier<?> sup1,
String val2, Supplier<?> sup2,
String val3, Supplier<?> sup3
) {
return getGenericProperties(val1, sup1, val2, sup2, val3, sup3, null, null, null, null, null, null);
}
public static Map<String, Supplier<?>> getGenericProperties(
String val1, Supplier<?> sup1,
String val2, Supplier<?> sup2,
String val3, Supplier<?> sup3,
String val4, Supplier<?> sup4
) {
return getGenericProperties(val1, sup1, val2, sup2, val3, sup3, val4, sup4, null, null, null, null);
}
public static Map<String, Supplier<?>> getGenericProperties(
String val1, Supplier<?> sup1,
String val2, Supplier<?> sup2,
String val3, Supplier<?> sup3,
String val4, Supplier<?> sup4,
String val5, Supplier<?> sup5
) {
return getGenericProperties(val1, sup1, val2, sup2, val3, sup3, val4, sup4, val5, sup5, null, null);
}
public static Map<String, Supplier<?>> getGenericProperties(
String val1, Supplier<?> sup1,
String val2, Supplier<?> sup2,
String val3, Supplier<?> sup3,
String val4, Supplier<?> sup4,
String val5, Supplier<?> sup5,
String val6, Supplier<?> sup6
) {
final Map<String,Supplier<?>> m = new LinkedHashMap<>();
final String[] vals = { val1, val2, val3, val4, val5, val6 };
final Supplier<?>[] sups = { sup1, sup2, sup3, sup4, sup5, sup6 };
for (int i=0; i<vals.length && vals[i] != null; i++) {
assert(sups[i] != null);
if ("base".equals(vals[i])) {
Object baseMap = sups[i].get();
assert(baseMap instanceof Map);
//noinspection unchecked
m.putAll((Map<String,Supplier<?>>)baseMap);
} else {
m.put(vals[i], sups[i]);
}
}
return Collections.unmodifiableMap(m);
}
public static <T extends Enum> Supplier<T> safeEnum(T[] values, Supplier<Number> ordinal) {
return safeEnum(values, ordinal, null);
}
public static <T extends Enum> Supplier<T> safeEnum(T[] values, Supplier<Number> ordinal, T defaultVal) {
int ord = ordinal.get().intValue();
return () -> (0 <= ord && ord < values.length) ? values[ord] : defaultVal;
}
public static Supplier<AnnotatedFlag> getBitsAsString(Supplier<Number> flags, final int[] masks, final String[] names) {
return () -> new AnnotatedFlag(flags, masks, names);
}
public static class AnnotatedFlag {
private final Supplier<Number> value;
private final Map<Integer,String> masks = new LinkedHashMap<>();
AnnotatedFlag(Supplier<Number> value, int[] masks, String[] names) {
assert(masks.length == names.length);
this.value = value;
for (int i=0; i<masks.length; i++) {
this.masks.put(masks[i], names[i]);
}
}
public Supplier<Number> getValue() {
return value;
}
public String getDescription() {
final int val = value.get().intValue();
return masks.entrySet().stream().
filter(e -> match(val, e.getKey())).
map(Map.Entry::getValue).
collect(Collectors.joining(" | "));
}
private static boolean match(final int val, int mask) {
return (val & mask) == mask;
}
}
}

View File

@ -16,16 +16,19 @@
==================================================================== */
package org.apache.poi.poifs.crypt.agile;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.poifs.crypt.ChainingMode;
import org.apache.poi.poifs.crypt.CipherAlgorithm;
import org.apache.poi.poifs.crypt.EncryptionHeader;
import org.apache.poi.poifs.crypt.HashAlgorithm;
import java.util.Map;
import java.util.function.Supplier;
import com.microsoft.schemas.office.x2006.encryption.CTDataIntegrity;
import com.microsoft.schemas.office.x2006.encryption.CTKeyData;
import com.microsoft.schemas.office.x2006.encryption.EncryptionDocument;
import com.microsoft.schemas.office.x2006.encryption.STCipherChaining;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.poifs.crypt.ChainingMode;
import org.apache.poi.poifs.crypt.CipherAlgorithm;
import org.apache.poi.poifs.crypt.EncryptionHeader;
import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.poi.util.GenericRecordUtil;
public class AgileEncryptionHeader extends EncryptionHeader implements Cloneable {
private byte[] encryptedHmacKey;
@ -132,4 +135,12 @@ public class AgileEncryptionHeader extends EncryptionHeader implements Cloneable
return other;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"encryptedHmacKey", this::getEncryptedHmacKey,
"encryptedHmacValue", this::getEncryptedHmacValue
);
}
}

View File

@ -19,24 +19,45 @@
package org.apache.poi.xslf.util;
import java.awt.Dimension;
import static java.util.Spliterator.NONNULL;
import static java.util.Spliterator.ORDERED;
import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Dimension2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.Collections;
import java.util.Locale;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators.AbstractSpliterator;
import java.util.TreeSet;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import javax.imageio.ImageIO;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.sl.draw.DrawPictureShape;
import org.apache.poi.sl.draw.Drawable;
import org.apache.poi.sl.draw.ImageRenderer;
import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.sl.usermodel.Slide;
import org.apache.poi.sl.usermodel.SlideShow;
import org.apache.poi.sl.usermodel.SlideShowFactory;
import org.apache.poi.util.GenericRecordJsonWriter;
/**
* An utility to convert slides of a .pptx slide show to a PNG image
@ -57,12 +78,14 @@ public class PPTX2PNG {
(error == null ? "" : ("Error: "+error+"\n")) +
"Options:\n" +
" -scale <float> scale factor\n" +
" -fixSide <side> specify side (long,short,width,height) to fix - use <scale> as amount of pixels\n" +
" -slide <integer> 1-based index of a slide to render\n" +
" -format <type> png,gif,jpg (,null for testing)\n" +
" -outdir <dir> output directory, defaults to origin of the ppt/pptx file\n" +
" -outfile <file> output filename, defaults to '"+OUTPUT_PAT_REGEX+"'\n" +
" -outpat <pattern> output filename pattern, defaults to '"+OUTPUT_PAT_REGEX+"'\n" +
" patterns: basename, slideno, format, ext\n" +
" -dump <file> dump the annotated records to a file\n" +
" -quiet do not write to console (for normal processing)";
System.out.println(msg);
@ -82,7 +105,10 @@ public class PPTX2PNG {
File outdir = null;
String outfile = null;
boolean quiet = false;
String outpattern = OUTPUT_PAT_REGEX;
String outPattern = OUTPUT_PAT_REGEX;
File dumpfile = null;
String fixSide = "scale";
for (int i = 0; i < args.length; i++) {
String opt = (i+1 < args.length) ? args[i+1] : null;
@ -108,12 +134,20 @@ public class PPTX2PNG {
i++;
break;
case "-outpat":
outpattern = opt;
outPattern = opt;
i++;
break;
case "-quiet":
quiet = true;
break;
case "-dump":
dumpfile = new File(opt);
i++;
break;
case "-fixside":
fixSide = opt.toLowerCase(Locale.ROOT);
i++;
break;
default:
file = new File(args[i]);
break;
@ -144,28 +178,64 @@ public class PPTX2PNG {
return;
}
if (!"long,short,width,height,scale".contains(fixSide)) {
usage("<fixside> must be one of long / short / width / height");
return;
}
if (!quiet) {
System.out.println("Processing " + file);
}
try (SlideShow<?, ?> ss = SlideShowFactory.create(file, null, true)) {
List<? extends Slide<?, ?>> slides = ss.getSlides();
Set<Integer> slidenum = slideIndexes(slides.size(), slidenumStr);
try (MFProxy proxy = initProxy(file)) {
final Set<Integer> slidenum = proxy.slideIndexes(slidenumStr);
if (slidenum.isEmpty()) {
usage("slidenum must be either -1 (for all) or within range: [1.." + slides.size() + "] for " + file);
usage("slidenum must be either -1 (for all) or within range: [1.." + proxy.getSlideCount() + "] for " + file);
return;
}
Dimension pgsize = ss.getPageSize();
int width = (int) (pgsize.width * scale);
int height = (int) (pgsize.height * scale);
final Dimension2D pgsize = proxy.getSize();
final double lenSide;
switch (fixSide) {
default:
case "scale":
lenSide = 1;
break;
case "long":
lenSide = Math.max(pgsize.getWidth(), pgsize.getHeight());
break;
case "short":
lenSide = Math.min(pgsize.getWidth(), pgsize.getHeight());
break;
case "width":
lenSide = pgsize.getWidth();
break;
case "height":
lenSide = pgsize.getHeight();
break;
}
for (Integer slideNo : slidenum) {
Slide<?, ?> slide = slides.get(slideNo);
String title = slide.getTitle();
final int width = (int) Math.rint(pgsize.getWidth() * scale / lenSide);
final int height = (int) Math.rint(pgsize.getHeight() * scale / lenSide);
for (int slideNo : slidenum) {
proxy.setSlideNo(slideNo);
if (!quiet) {
System.out.println("Rendering slide " + (slideNo+1) + (title == null ? "" : ": " + title.trim()));
String title = proxy.getTitle();
System.out.println("Rendering slide " + (slideNo + 1) + (title == null ? "" : ": " + title.trim()));
}
GenericRecord gr = proxy.getRoot();
if (dumpfile != null) {
try (GenericRecordJsonWriter fw = new GenericRecordJsonWriter(dumpfile)) {
if (gr == null) {
fw.writeError(file.getName()+" doesn't support GenericRecord interface and can't be dumped to a file.");
} else {
fw.write(gr);
}
}
}
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
@ -174,19 +244,25 @@ public class PPTX2PNG {
// default rendering options
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
graphics.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_SPEED);
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
graphics.setRenderingHint(Drawable.BUFFERED_IMAGE, new WeakReference<>(img));
graphics.scale(scale, scale);
graphics.scale(scale / lenSide, scale / lenSide);
graphics.setComposite(AlphaComposite.Clear);
graphics.fillRect(0, 0, (int)width, (int)height);
graphics.setComposite(AlphaComposite.SrcOver);
// draw stuff
slide.draw(graphics);
proxy.draw(graphics);
// save the result
if (!"null".equals(format)) {
String inname = String.format(Locale.ROOT, "%04d|%s|%s", slideNo+1, format, file.getName());
String outname = (outfile != null) ? outfile : INPUT_PATTERN.matcher(inname).replaceAll(outpattern);
String inname = String.format(Locale.ROOT, "%04d|%s|%s", slideNo, format, file.getName());
String outpat = (proxy.getSlideCount() > 1 ? outPattern : outPattern.replaceAll("-?\\$\\{slideno\\}", ""));
String outname = (outfile != null) ? outfile : INPUT_PATTERN.matcher(inname).replaceAll(outpat);
ImageIO.write(img, format, new File(outdir, outname));
}
@ -200,42 +276,181 @@ public class PPTX2PNG {
}
}
private static Set<Integer> slideIndexes(final int slideCount, String range) {
Set<Integer> slideIdx = new TreeSet<>();
if ("-1".equals(range)) {
for (int i=0; i<slideCount; i++) {
slideIdx.add(i);
private static MFProxy initProxy(File file) throws IOException {
MFProxy proxy;
final String fileName = file.getName().toLowerCase(Locale.ROOT);
switch (fileName.contains(".") ? fileName.substring(fileName.lastIndexOf('.')) : "") {
case ".emf":
proxy = new EMFHandler();
break;
case ".wmf":
proxy = new WMFHandler();
break;
default:
proxy = new PPTHandler();
break;
}
proxy.parse(file);
return proxy;
}
private interface MFProxy extends Closeable {
void parse(File file) throws IOException;
// boolean isEmpty();
// void dumpRecords(Writer writer) throws IOException;
// Iterable<HwmfEmbedded> getEmbeddings();
Dimension2D getSize();
default void setSlideNo(int slideNo) {}
String getTitle();
void draw(Graphics2D ctx);
default int getSlideCount() { return 1; }
default Set<Integer> slideIndexes(String range) {
return Collections.singleton(1);
}
GenericRecord getRoot();
}
/** Handler for ppt and pptx files */
private static class PPTHandler implements MFProxy {
SlideShow<?,?> ppt;
Slide<?,?> slide;
@Override
public void parse(File file) throws IOException {
ppt = SlideShowFactory.create(file, null, true);
slide = ppt.getSlides().get(0);
}
@Override
public Dimension2D getSize() {
return ppt.getPageSize();
}
@Override
public int getSlideCount() {
return ppt.getSlides().size();
}
@Override
public void setSlideNo(int slideNo) {
slide = ppt.getSlides().get(slideNo-1);
}
@Override
public String getTitle() {
return slide.getTitle();
}
private static final String RANGE_PATTERN = "(^|,)(?<from>\\d+)?(-(?<to>\\d+))?";
@Override
public Set<Integer> slideIndexes(String range) {
final Matcher matcher = Pattern.compile(RANGE_PATTERN).matcher(range);
Spliterator<Matcher> sp = new AbstractSpliterator<Matcher>(range.length(), ORDERED|NONNULL){
@Override
public boolean tryAdvance(Consumer<? super Matcher> action) {
boolean b = matcher.find();
if (b) {
action.accept(matcher);
}
return b;
}
};
return StreamSupport.stream(sp, false).
flatMap(this::range).
collect(Collectors.toCollection(TreeSet::new));
}
@Override
public void draw(Graphics2D ctx) {
slide.draw(ctx);
}
@Override
public void close() throws IOException {
if (ppt != null) {
ppt.close();
}
} else {
for (String subrange : range.split(",")) {
String[] idx = subrange.split("-");
switch (idx.length) {
default:
case 0: break;
case 1: {
int subidx = Integer.parseInt(idx[0]);
if (subrange.contains("-")) {
int startIdx = subrange.startsWith("-") ? 0 : subidx;
int endIdx = subrange.endsWith("-") ? slideCount : Math.min(subidx,slideCount);
for (int i=Math.max(startIdx,1); i<endIdx; i++) {
slideIdx.add(i-1);
}
} else {
slideIdx.add(Math.max(subidx,1)-1);
}
break;
}
case 2: {
int startIdx = Math.min(Integer.parseInt(idx[0]), slideCount);
int endIdx = Math.min(Integer.parseInt(idx[1]), slideCount);
for (int i=Math.max(startIdx,1); i<endIdx; i++) {
slideIdx.add(i-1);
}
break;
}
}
@Override
public GenericRecord getRoot() {
return (ppt instanceof GenericRecord) ? (GenericRecord)ppt : null;
}
private Stream<Integer> range(Matcher m) {
final int slideCount = ppt.getSlides().size();
String fromStr = m.group("from");
String toStr = m.group("to");
int from = (fromStr == null || fromStr.isEmpty() ? 1 : Integer.parseInt(fromStr));
int to = (toStr == null) ? from
: (toStr.isEmpty() || ((fromStr == null || fromStr.isEmpty()) && "1".equals(toStr))) ? slideCount
: Integer.parseInt(toStr);
return IntStream.rangeClosed(from, to).filter(i -> i <= slideCount).boxed();
}
}
private static class EMFHandler implements MFProxy {
private ImageRenderer imgr = null;
private InputStream is;
@Override
public void parse(File file) throws IOException {
imgr = DrawPictureShape.getImageRenderer(null, getContentType());
// stream needs to be kept open
is = file.toURI().toURL().openStream();
imgr.loadImage(is, getContentType());
}
protected String getContentType() {
return PictureData.PictureType.EMF.contentType;
}
@Override
public Dimension2D getSize() {
return imgr.getDimension();
}
@Override
public String getTitle() {
return "";
}
@Override
public void draw(Graphics2D ctx) {
Dimension2D dim = getSize();
imgr.drawImage(ctx, new Rectangle2D.Double(0, 0, dim.getWidth(), dim.getHeight()));
}
@Override
public void close() throws IOException {
if (is != null) {
try {
is.close();
} finally {
is = null;
}
}
}
return slideIdx;
@Override
public GenericRecord getRoot() {
return imgr.getGenericRecord();
}
}
private static class WMFHandler extends EMFHandler {
@Override
protected String getContentType() {
return PictureData.PictureType.WMF.contentType;
}
}
}

View File

@ -48,7 +48,7 @@ public class TestPPTX2PNG {
private static final String files =
"53446.ppt, alterman_security.ppt, alterman_security.pptx, KEY02.pptx, themes.pptx, " +
"backgrounds.pptx, layouts.pptx, sample.pptx, shapes.pptx, 54880_chinese.ppt, keyframes.pptx," +
"customGeo.pptx, customGeo.ppt";
"customGeo.pptx, customGeo.ppt, wrench.emf, santa.wmf";
@ -83,8 +83,12 @@ public class TestPPTX2PNG {
"-slide", "-1", // -1 for all
"-outdir", new File("build/tmp/").getCanonicalPath(),
"-outpat", "${basename}-${slideno}-${ext}.${format}",
"-scale", "1.333333333",
// "-dump", new File("build/tmp/", pptFile+".dump").getCanonicalPath(),
"-dump", "null",
"-quiet",
"-fixside", "long",
"-scale", "800",
// "-scale", "1.333333333",
(basedir == null ? samples.getFile(pptFile) : new File(basedir, pptFile)).getAbsolutePath()
};
PPTX2PNG.main(args);

View File

@ -24,11 +24,11 @@ import java.awt.RenderingHints;
import java.awt.geom.Dimension2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hemf.usermodel.HemfPicture;
import org.apache.poi.sl.draw.BitmapImageRenderer;
import org.apache.poi.sl.draw.ImageRenderer;
@ -109,4 +109,8 @@ public class HemfImageRenderer implements ImageRenderer {
}
}
@Override
public GenericRecord getGenericRecord() {
return image;
}
}

View File

@ -24,12 +24,16 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hemf.draw.HemfGraphics;
import org.apache.poi.hemf.record.emfplus.HemfPlusRecord;
import org.apache.poi.hemf.record.emfplus.HemfPlusRecordIterator;
import org.apache.poi.hwmf.usermodel.HwmfPicture;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndianConsts;
@ -78,10 +82,15 @@ public class HemfComment {
}
}
public interface EmfCommentData {
public interface EmfCommentData extends GenericRecord {
HemfCommentRecordType getCommentRecordType();
long init(LittleEndianInputStream leis, long dataSize) throws IOException;
@Override
default Enum getGenericRecordType() {
return getCommentRecordType();
}
}
public static class EmfComment implements HemfRecord {
@ -116,7 +125,12 @@ public class HemfComment {
@Override
public String toString() {
return "{ data: "+data+" }";
return GenericRecordJsonWriter.marshal(this);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties("data", this::getCommentData);
}
}
@ -241,7 +255,19 @@ public class HemfComment {
@Override
public String toString() {
return "\""+new String(privateData, LocaleUtil.CHARSET_1252).replaceAll("\\p{Cntrl}", ".")+"\"";
return GenericRecordJsonWriter.marshal(this);
}
public String getPrivateDataAsString() {
return new String(privateData, LocaleUtil.CHARSET_1252);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"privateData", this::getPrivateData,
"privateDataAsString", this::getPrivateDataAsString
);
}
}
@ -271,6 +297,16 @@ public class HemfComment {
public void draw(HemfGraphics ctx) {
records.forEach(ctx::draw);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return null;
}
@Override
public List<HemfPlusRecord> getGenericChildren() {
return getRecords();
}
}
public static class EmfCommentDataBeginGroup implements EmfCommentData {
@ -301,6 +337,22 @@ public class HemfComment {
return leis.getReadIndex()-startIdx;
}
public Rectangle2D getBounds() {
return bounds;
}
public String getDescription() {
return description;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"bounds", this::getBounds,
"description", this::getDescription
);
}
}
public static class EmfCommentDataEndGroup implements EmfCommentData {
@ -319,6 +371,11 @@ public class HemfComment {
assert(publicCommentIdentifier == HemfCommentRecordType.emfEndGroup.id);
return leis.getReadIndex()-startIdx;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return null;
}
}
public static class EmfCommentDataMultiformats implements EmfCommentData {
@ -369,6 +426,20 @@ public class HemfComment {
public List<EmfCommentDataFormat> getFormats() {
return Collections.unmodifiableList(formats);
}
public Rectangle2D getBounds() {
return bounds;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties("bounds", this::getBounds);
}
@Override
public List<EmfCommentDataFormat> getGenericChildren() {
return getFormats();
}
}
public enum EmfFormatSignature {
@ -400,7 +471,7 @@ public class HemfComment {
}
public static class EmfCommentDataFormat {
public static class EmfCommentDataFormat implements GenericRecord {
private EmfFormatSignature signature;
private int version;
private int sizeData;
@ -439,11 +510,20 @@ public class HemfComment {
public EmfFormatSignature getSignature() {
return signature;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"signature", this::getSignature,
"version", () -> version,
"sizeData", () -> sizeData,
"offData", () -> offData
);
}
}
public static class EmfCommentDataWMF implements EmfCommentData {
private final Rectangle2D bounds = new Rectangle2D.Double();
private final List<EmfCommentDataFormat> formats = new ArrayList<>();
private byte[] wmfData;
@Override
public HemfCommentRecordType getCommentRecordType() {
@ -485,12 +565,21 @@ public class HemfComment {
public byte[] getWMFData() {
return wmfData;
}
public Rectangle2D getBounds() {
return bounds;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"bounds", this::getBounds,
"wmfData", this::getWMFData
);
}
}
public static class EmfCommentDataUnicode implements EmfCommentData {
private final Rectangle2D bounds = new Rectangle2D.Double();
private final List<EmfCommentDataFormat> formats = new ArrayList<>();
@Override
public HemfCommentRecordType getCommentRecordType() {
return HemfCommentRecordType.emfUnicodeString;
@ -501,5 +590,10 @@ public class HemfComment {
throws IOException {
throw new RecordFormatException("UNICODE_STRING/UNICODE_END values are reserved in CommentPublic records");
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return null;
}
}
}

View File

@ -17,11 +17,10 @@
package org.apache.poi.hemf.record.emf;
import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
import static org.apache.poi.hwmf.record.HwmfDraw.normalizeBounds;
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Dimension2D;
import java.awt.geom.Path2D;
@ -29,13 +28,17 @@ import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.IntStream;
import org.apache.poi.hemf.draw.HemfDrawProperties;
import org.apache.poi.hemf.draw.HemfGraphics;
import org.apache.poi.hwmf.draw.HwmfGraphics.FillDrawStyle;
import org.apache.poi.hwmf.record.HwmfDraw;
import org.apache.poi.hwmf.record.HwmfDraw.WmfSelectObject;
import org.apache.poi.util.Internal;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
@ -47,26 +50,30 @@ public class HemfDraw {
*/
public static class EmfSelectObject extends WmfSelectObject implements HemfRecord {
private static final String[] STOCK_IDS = {
"0x80000000 /* WHITE_BRUSH */",
"0x80000001 /* LTGRAY_BRUSH */",
"0x80000002 /* GRAY_BRUSH */",
"0x80000003 /* DKGRAY_BRUSH */",
"0x80000004 /* BLACK_BRUSH */",
"0x80000005 /* NULL_BRUSH */",
"0x80000006 /* WHITE_PEN */",
"0x80000007 /* BLACK_PEN */",
"0x80000008 /* NULL_PEN */",
"0x8000000A /* OEM_FIXED_FONT */",
"0x8000000B /* ANSI_FIXED_FONT */",
"0x8000000C /* ANSI_VAR_FONT */",
"0x8000000D /* SYSTEM_FONT */",
"0x8000000E /* DEVICE_DEFAULT_FONT */",
"0x8000000F /* DEFAULT_PALETTE */",
"0x80000010 /* SYSTEM_FIXED_FONT */",
"0x80000011 /* DEFAULT_GUI_FONT */",
"0x80000012 /* DC_BRUSH */",
"0x80000013 /* DC_PEN */"
private static final int[] IDX_MASKS = IntStream.rangeClosed(0x80000000,0x80000013).toArray();
private static final String[] IDX_NAMES = {
"WHITE_BRUSH",
"LTGRAY_BRUSH",
"GRAY_BRUSH",
"DKGRAY_BRUSH",
"BLACK_BRUSH",
"NULL_BRUSH",
"WHITE_PEN",
"BLACK_PEN",
"NULL_PEN",
// 0x80000009 is not a valid stock object
"INVALID",
"OEM_FIXED_FONT",
"ANSI_FIXED_FONT",
"ANSI_VAR_FONT",
"SYSTEM_FONT",
"DEVICE_DEFAULT_FONT",
"DEFAULT_PALETTE",
"SYSTEM_FIXED_FONT",
"DEFAULT_GUI_FONT",
"DC_BRUSH",
"DC_PEN"
};
@Override
@ -84,12 +91,20 @@ public class HemfDraw {
@Override
public String toString() {
return "{ index: "+
(((objectIndex & 0x80000000) != 0 && (objectIndex & 0x3FFFFFFF) <= 13 )
? STOCK_IDS[objectIndex & 0x3FFFFFFF]
: objectIndex)+" }";
return GenericRecordJsonWriter.marshal(this);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"objectIndex", getBitsAsString(this::getObjectIndex, IDX_MASKS, IDX_NAMES)
);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
@ -183,6 +198,23 @@ public class HemfDraw {
public void draw(HemfGraphics ctx) {
ctx.draw(path -> path.append(poly, !hasStartPoint()), getFillDrawStyle());
}
public Rectangle2D getBounds() {
return bounds;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"bounds", this::getBounds
);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -267,6 +299,23 @@ public class HemfDraw {
public void draw(HemfGraphics ctx) {
ctx.draw(path -> path.append(poly, false), getFillDrawStyle());
}
public Rectangle2D getBounds() {
return bounds;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"bounds", this::getBounds
);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -429,10 +478,8 @@ public class HemfDraw {
Point2D pnt = new Point2D.Double();
for (long nPoints : polygonPointCount) {
/**
* An array of WMF PointL objects that specifies the points for all polygons in logical units.
* The number of points is specified by the Count field value.
*/
// An array of WMF PointL objects that specifies the points for all polygons in logical units.
// The number of points is specified by the Count field value.
Path2D poly = new Path2D.Double(Path2D.WIND_EVEN_ODD, (int)nPoints);
for (int i=0; i<nPoints; i++) {
size += readPoint(leis, pnt);
@ -460,6 +507,23 @@ public class HemfDraw {
ctx.draw(path -> path.append(shape, false), getFillDrawStyle());
}
public Rectangle2D getBounds() {
return bounds;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"bounds", this::getBounds
);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -527,6 +591,11 @@ public class HemfDraw {
size += colorRef.init(leis);
return size;
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -547,6 +616,11 @@ public class HemfDraw {
public void draw(final HemfGraphics ctx) {
ctx.draw((path) -> path.moveTo(point.getX(), point.getY()), FillDrawStyle.NONE);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -571,6 +645,11 @@ public class HemfDraw {
public void draw(HemfGraphics ctx) {
ctx.draw(path -> path.append(getShape(), false), getFillDrawStyle());
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -596,6 +675,11 @@ public class HemfDraw {
public void draw(HemfGraphics ctx) {
ctx.draw(path -> path.append(getShape(), false), getFillDrawStyle());
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -620,6 +704,11 @@ public class HemfDraw {
public void draw(HemfGraphics ctx) {
ctx.draw(path -> path.append(getShape(), false), getFillDrawStyle());
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -642,6 +731,11 @@ public class HemfDraw {
public void draw(HemfGraphics ctx) {
ctx.draw(path -> path.append(getShape(), false), FillDrawStyle.FILL_DRAW);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -663,6 +757,11 @@ public class HemfDraw {
public void draw(HemfGraphics ctx) {
ctx.draw(path -> path.append(normalizeBounds(bounds), false), FillDrawStyle.FILL_DRAW);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -680,8 +779,9 @@ public class HemfDraw {
long size = readRectL(leis, bounds);
// A 32-bit unsigned integer that defines the x-coordinate of the point.
width = (int)leis.readUInt();
height = (int)leis.readUInt();
int width = (int)leis.readUInt();
int height = (int)leis.readUInt();
corners.setSize(width, height);
return size + 2*LittleEndianConsts.INT_SIZE;
}
@ -690,6 +790,11 @@ public class HemfDraw {
public void draw(HemfGraphics ctx) {
ctx.draw(path -> path.append(getShape(), false), FillDrawStyle.FILL_DRAW);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -711,6 +816,11 @@ public class HemfDraw {
public void draw(final HemfGraphics ctx) {
ctx.draw((path) -> path.lineTo(point.getX(), point.getY()), FillDrawStyle.DRAW);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -736,6 +846,11 @@ public class HemfDraw {
final Arc2D arc = getShape();
ctx.draw((path) -> path.append(arc, true), getFillDrawStyle());
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/** The EMR_POLYDRAW record specifies a set of line segments and Bezier curves. */
@ -829,6 +944,23 @@ public class HemfDraw {
public void draw(HemfGraphics ctx) {
ctx.draw(path -> path.append(poly, false), getFillDrawStyle());
}
public Rectangle2D getBounds() {
return bounds;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"bounds", this::getBounds
);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
public static class EmfPolyDraw16 extends EmfPolyDraw {
@ -852,7 +984,7 @@ public class HemfDraw {
* When an application processes the EMR_BEGINPATH record, all previous paths
* MUST be discarded from the playback device context.
*/
public static class EmfBeginPath implements HemfRecord {
public static class EmfBeginPath implements HemfRecordWithoutProperties {
@Override
public HemfRecordType getEmfRecordType() {
return HemfRecordType.beginPath;
@ -880,7 +1012,7 @@ public class HemfDraw {
* This record closes a path bracket and selects the path defined by the bracket into
* the playback device context.
*/
public static class EmfEndPath implements HemfRecord {
public static class EmfEndPath implements HemfRecordWithoutProperties {
@Override
public HemfRecordType getEmfRecordType() {
return HemfRecordType.endPath;
@ -906,7 +1038,7 @@ public class HemfDraw {
/**
* This record aborts a path bracket or discards the path from a closed path bracket.
*/
public static class EmfAbortPath implements HemfRecord {
public static class EmfAbortPath implements HemfRecordWithoutProperties {
@Override
public HemfRecordType getEmfRecordType() {
return HemfRecordType.abortPath;
@ -949,7 +1081,7 @@ public class HemfDraw {
* After processing the EMR_CLOSEFIGURE record, adding a line or curve to the path
* MUST start a new figure.
*/
public static class EmfCloseFigure implements HemfRecord {
public static class EmfCloseFigure implements HemfRecordWithoutProperties {
@Override
public HemfRecordType getEmfRecordType() {
return HemfRecordType.closeFigure;
@ -980,7 +1112,7 @@ public class HemfDraw {
* This record transforms any curves in the selected path into the playback device
* context; each curve MUST be turned into a sequence of lines.
*/
public static class EmfFlattenPath implements HemfRecord {
public static class EmfFlattenPath implements HemfRecordWithoutProperties {
@Override
public HemfRecordType getEmfRecordType() {
return HemfRecordType.flattenPath;
@ -996,7 +1128,7 @@ public class HemfDraw {
* This record redefines the current path as the area that would be painted if the path
* were drawn using the pen currently selected into the playback device context.
*/
public static class EmfWidenPath implements HemfRecord {
public static class EmfWidenPath implements HemfRecordWithoutProperties {
@Override
public HemfRecordType getEmfRecordType() {
return HemfRecordType.widenPath;
@ -1040,7 +1172,16 @@ public class HemfDraw {
@Override
public String toString() {
return boundsToString(bounds);
return GenericRecordJsonWriter.marshal(this);
}
public Rectangle2D getBounds() {
return bounds;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties("bounds", this::getBounds);
}
}
@ -1155,16 +1296,4 @@ public class HemfDraw {
ctx.draw((path) -> path.append(pi, true), fillDrawStyle);
}
@Internal
public static String xformToString(AffineTransform xForm) {
return (xForm == null) ? "null" :
"{ scaleX: "+xForm.getScaleX()+
", shearX: "+xForm.getShearX()+
", transX: "+xForm.getTranslateX()+
", scaleY: "+xForm.getScaleY()+
", shearY: "+xForm.getShearY()+
", transY: "+xForm.getTranslateY()+" }";
}
}

View File

@ -19,10 +19,7 @@ package org.apache.poi.hemf.record.emf;
import static org.apache.poi.hemf.record.emf.HemfDraw.readPointL;
import static org.apache.poi.hemf.record.emf.HemfDraw.readRectL;
import static org.apache.poi.hemf.record.emf.HemfDraw.xformToString;
import static org.apache.poi.hemf.record.emf.HemfRecordIterator.HEADER_SIZE;
import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
import static org.apache.poi.hwmf.record.HwmfDraw.pointToString;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
@ -33,7 +30,11 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.hemf.draw.HemfDrawProperties;
import org.apache.poi.hemf.draw.HemfGraphics;
@ -45,6 +46,8 @@ import org.apache.poi.hwmf.record.HwmfFill;
import org.apache.poi.hwmf.record.HwmfFill.ColorUsage;
import org.apache.poi.hwmf.record.HwmfRegionMode;
import org.apache.poi.hwmf.record.HwmfTernaryRasterOp;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianConsts;
@ -70,6 +73,11 @@ public class HemfFill {
polyFillMode = HwmfPolyfillMode.valueOf((int)leis.readUInt());
return LittleEndianConsts.INT_SIZE;
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
public static class EmfExtFloodFill extends HwmfFill.WmfExtFloodFill implements HemfRecord {
@ -85,9 +93,14 @@ public class HemfFill {
size += colorRef.init(leis);
// A 32-bit unsigned integer that specifies how to use the Color value to determine the area for
// the flood fill operation. The value MUST be in the FloodFill enumeration
mode = (int)leis.readUInt();
mode = HwmfFloodFillMode.values()[(int)leis.readUInt()];
return size + LittleEndianConsts.INT_SIZE;
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -185,11 +198,34 @@ public class HemfFill {
@Override
public String toString() {
return
"{ bounds: "+boundsToString(bounds)+
", xFormSrc: " + xformToString(xFormSrc) +
", bkColorSrc: "+bkColorSrc+
","+super.toString().substring(1);
return GenericRecordJsonWriter.marshal(this);
}
public Rectangle2D getBounds() {
return bounds;
}
public AffineTransform getXFormSrc() {
return xFormSrc;
}
public HwmfColorRef getBkColorSrc() {
return bkColorSrc;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"bounds", this::getBounds,
"xFormSrc", this::getXFormSrc,
"bkColorSrc", this::getBkColorSrc
);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
@ -259,6 +295,23 @@ public class HemfFill {
return size;
}
public Rectangle2D getBounds() {
return bounds;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"bounds", this::getBounds
);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -296,9 +349,10 @@ public class HemfFill {
// A 32-bit unsigned integer that specifies the brush EMF Object Table index.
brushIndex = (int)leis.readUInt();
// A 32-bit signed integer that specifies the width of the vertical brush stroke, in logical units.
width = leis.readInt();
int width = leis.readInt();
// A 32-bit signed integer that specifies the height of the horizontal brush stroke, in logical units.
height = leis.readInt();
int height = leis.readInt();
frame.setSize(width,height);
size += 4*LittleEndianConsts.INT_SIZE;
size += readRgnData(leis, rgnRects);
return size;
@ -313,6 +367,28 @@ public class HemfFill {
protected Shape getShape() {
return getRgnShape(rgnRects);
}
public Rectangle2D getBounds() {
return bounds;
}
public List<Rectangle2D> getRgnRects() {
return rgnRects;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"bounds", this::getBounds,
"rgnRects", this::getRgnRects
);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/** The EMR_INVERTRGN record inverts the colors in the specified region. */
@ -338,6 +414,22 @@ public class HemfFill {
protected Shape getShape() {
return getRgnShape(rgnRects);
}
public Rectangle2D getBounds() {
return bounds;
}
public List<Rectangle2D> getRgnRects() {
return rgnRects;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"bounds", this::getBounds,
"rgnRects", this::getRgnRects
);
}
}
/**
@ -375,6 +467,28 @@ public class HemfFill {
protected Shape getShape() {
return getRgnShape(rgnRects);
}
public Rectangle2D getBounds() {
return bounds;
}
public List<Rectangle2D> getRgnRects() {
return rgnRects;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"bounds", this::getBounds,
"rgnRects", this::getRgnRects
);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
public static class EmfExtSelectClipRgn implements HemfRecord {
@ -414,19 +528,23 @@ public class HemfFill {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{ regionMode: '"+regionMode+"'");
sb.append(", regions: [");
boolean isFirst = true;
for (Rectangle2D r : rgnRects) {
if (!isFirst) {
sb.append(",");
}
isFirst = false;
sb.append(boundsToString(r));
}
sb.append("]}");
return sb.toString();
return GenericRecordJsonWriter.marshal(this);
}
public HwmfRegionMode getRegionMode() {
return regionMode;
}
public List<Rectangle2D> getRgnRects() {
return rgnRects;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"regionMode", this::getRegionMode,
"rgnRects", this::getRgnRects
);
}
}
@ -539,6 +657,23 @@ public class HemfFill {
return size;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String,Supplier<?>> m = new LinkedHashMap<>();
m.put("bounds", () -> bounds);
m.put("destRect", () -> destRect);
m.put("srcRect", () -> srcRect);
m.put("blendOperation", () -> blendOperation);
m.put("blendFlags", () -> blendFlags);
m.put("srcConstantAlpha", () -> srcConstantAlpha);
m.put("alphaFormat", () -> alphaFormat);
m.put("xFormSrc", () -> xFormSrc);
m.put("bkColorSrc", () -> bkColorSrc);
m.put("usageSrc", () -> usageSrc);
m.put("bitmap", () -> bitmap);
return Collections.unmodifiableMap(m);
}
}
/**
@ -591,15 +726,40 @@ public class HemfFill {
return size;
}
public Rectangle2D getBounds() {
return bounds;
}
public Point2D getDest() {
return dest;
}
public Rectangle2D getSrc() {
return src;
}
public ColorUsage getUsageSrc() {
return usageSrc;
}
public HwmfBitmapDib getBitmap() {
return bitmap;
}
@Override
public String toString() {
return
"{ bounds: " + boundsToString(bounds) +
", dest: " + pointToString(dest) +
", src: " + boundsToString(src) +
", usageSrc: '" + usageSrc + "'" +
", bitmap: " + bitmap +
"}";
return GenericRecordJsonWriter.marshal(this);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"bounds", this::getBounds,
"dest", this::getDest,
"src", this::getSrc,
"usageSrc", this::getUsageSrc,
"bitmap", this::getBitmap
);
}
}
@ -670,9 +830,7 @@ public class HemfFill {
static int readBounds2(LittleEndianInputStream leis, Rectangle2D bounds) {
/**
* The 32-bit signed integers that defines the corners of the bounding rectangle.
*/
// The 32-bit signed integers that defines the corners of the bounding rectangle.
int x = leis.readInt();
int y = leis.readInt();
int w = leis.readInt();

View File

@ -19,10 +19,17 @@ package org.apache.poi.hemf.record.emf;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.IOUtils;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.common.usermodel.fonts.FontCharset;
import org.apache.poi.hwmf.record.HwmfFont;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
@ -41,7 +48,7 @@ public class HemfFont extends HwmfFont {
}
}
protected static class LogFontPanose implements LogFontDetails {
protected static class LogFontPanose implements LogFontDetails, GenericRecord {
enum FamilyType {
PAN_ANY,
PAN_NO_FIT,
@ -201,21 +208,26 @@ public class HemfFont extends HwmfFont {
@Override
public String toString() {
return
"{ styleSize: " + styleSize +
", vendorId: " + vendorId +
", culture: " + culture +
", familyType: '" + familyType + "'" +
", serifStyle: '" + serifStyle + "'" +
", weight: '" + weight + "'" +
", proportion: '" + proportion + "'" +
", contrast: '" + contrast + "'" +
", strokeVariation: '" + strokeVariation + "'" +
", armStyle: '" + armStyle + "'" +
", letterform: '" + letterform + "'" +
", midLine: '" + midLine + "'" +
", xHeight: '" + xHeight + "'" +
"}";
return GenericRecordJsonWriter.marshal(this);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String,Supplier<?>> m = new LinkedHashMap<>();
m.put("styleSize", () -> styleSize);
m.put("vendorId", () -> vendorId);
m.put("culture", () -> culture);
m.put("familyType", () -> familyType);
m.put("serifStyle", () -> serifStyle);
m.put("weight", () -> weight);
m.put("proportion", () -> proportion);
m.put("contrast", () -> contrast);
m.put("strokeVariation", () -> strokeVariation);
m.put("armStyle", () -> armStyle);
m.put("letterform", () -> letterform);
m.put("midLine", () -> midLine);
m.put("xHeight", () -> xHeight);
return Collections.unmodifiableMap(m);
}
}
@ -466,12 +478,18 @@ public class HemfFont extends HwmfFont {
@Override
public String toString() {
return
"{ fullname: '" + (fullname == null ? "" : fullname) + "'" +
", style: '" + (style == null ? "" : style) + "'" +
", script: '" + (script == null ? "" : script) + "'" +
", details: " + details +
"," + super.toString().substring(1);
return GenericRecordJsonWriter.marshal(this);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"fullname", () -> fullname,
"style", () -> style,
"script", () -> script,
"details", () -> details
);
}
@Override

View File

@ -20,15 +20,18 @@ package org.apache.poi.hemf.record.emf;
import static org.apache.poi.hemf.record.emf.HemfDraw.readDimensionInt;
import static org.apache.poi.hemf.record.emf.HemfDraw.readRectL;
import static org.apache.poi.hemf.record.emf.HemfRecordIterator.HEADER_SIZE;
import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
import static org.apache.poi.hwmf.record.HwmfDraw.dimToString;
import java.awt.geom.Dimension2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.Dimension2DDouble;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
@ -82,7 +85,7 @@ public class HemfHeader implements HemfRecord {
public String getDescription() { return description; }
public long getnPalEntries() {
public long getNPalEntries() {
return nPalEntries;
}
@ -120,23 +123,7 @@ public class HemfHeader implements HemfRecord {
@Override
public String toString() {
return "HemfHeader{" +
"boundsRectangle: " + boundsToString(boundsRectangle) +
", frameRectangle: " + boundsToString(frameRectangle) +
", bytes: " + bytes +
", records: " + records +
", handles: " + handles +
", description: '" + (description == null ? "" : description) + "'" +
", nPalEntries: " + nPalEntries +
", hasExtension1: " + hasExtension1 +
", cbPixelFormat: " + cbPixelFormat +
", offPixelFormat: " + offPixelFormat +
", bOpenGL: " + bOpenGL +
", hasExtension2: " + hasExtension2 +
", deviceDimension: " + dimToString(deviceDimension) +
", microDimension: " + dimToString(microDimension) +
", milliDimension: " + dimToString(milliDimension) +
'}';
return GenericRecordJsonWriter.marshal(this);
}
@Override
@ -204,4 +191,25 @@ public class HemfHeader implements HemfRecord {
return size;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String,Supplier<?>> m = new LinkedHashMap<>();
m.put("boundsRectangle", this::getBoundsRectangle);
m.put("frameRectangle", this::getFrameRectangle);
m.put("bytes", this::getBytes);
m.put("records", this::getRecords);
m.put("handles", this::getHandles);
m.put("description", this::getDescription);
m.put("nPalEntries", this::getNPalEntries);
m.put("hasExtension1", this::isHasExtension1);
m.put("cbPixelFormat", this::getCbPixelFormat);
m.put("offPixelFormat", this::getOffPixelFormat);
m.put("bOpenGL", this::getbOpenGL);
m.put("hasExtension2", this::isHasExtension2);
m.put("deviceDimension", this::getDeviceDimension);
m.put("milliDimension", this::getMilliDimension);
m.put("microDimension", this::getMicroDimension);
return Collections.unmodifiableMap(m);
}
}

View File

@ -18,7 +18,6 @@
package org.apache.poi.hemf.record.emf;
import static org.apache.poi.hemf.record.emf.HemfDraw.readPointL;
import static org.apache.poi.hemf.record.emf.HemfDraw.xformToString;
import static org.apache.poi.hemf.record.emf.HemfFill.readBitmap;
import static org.apache.poi.hemf.record.emf.HemfFill.readXForm;
import static org.apache.poi.hemf.record.emf.HemfRecordIterator.HEADER_SIZE;
@ -28,9 +27,10 @@ import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
import org.apache.poi.hemf.draw.HemfDrawProperties;
import org.apache.poi.hemf.draw.HemfGraphics;
@ -49,9 +49,12 @@ import org.apache.poi.hwmf.record.HwmfObjectTableEntry;
import org.apache.poi.hwmf.record.HwmfPalette.PaletteEntry;
import org.apache.poi.hwmf.record.HwmfPenStyle;
import org.apache.poi.hwmf.record.HwmfPenStyle.HwmfLineDash;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
@SuppressWarnings("WeakerAccess")
public class HemfMisc {
public enum HemfModifyWorldTransformMode {
@ -138,12 +141,21 @@ public class HemfMisc {
return size;
}
public List<PaletteEntry> getPalette() {
return palette;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties("palette", this::getPalette);
}
}
/**
* The EMF_SAVEDC record saves the playback device context for later retrieval.
*/
public static class EmfSaveDc extends HwmfMisc.WmfSaveDc implements HemfRecord {
public static class EmfSaveDc extends HwmfMisc.WmfSaveDc implements HemfRecordWithoutProperties {
@Override
public HemfRecordType getEmfRecordType() {
return HemfRecordType.saveDc;
@ -153,6 +165,11 @@ public class HemfMisc {
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return 0;
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -174,6 +191,11 @@ public class HemfMisc {
nSavedDC = leis.readInt();
return LittleEndianConsts.INT_SIZE;
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -191,6 +213,11 @@ public class HemfMisc {
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return colorRef.init(leis);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
@ -213,6 +240,11 @@ public class HemfMisc {
bkMode = HwmfBkMode.valueOf((int) leis.readUInt());
return LittleEndianConsts.INT_SIZE;
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -228,6 +260,11 @@ public class HemfMisc {
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return super.init(leis, recordSize, (int) recordId);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -246,6 +283,11 @@ public class HemfMisc {
mapMode = HwmfMapMode.valueOf((int) leis.readUInt());
return LittleEndianConsts.INT_SIZE;
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -264,6 +306,11 @@ public class HemfMisc {
drawMode = HwmfBinaryRasterOp.valueOf((int) leis.readUInt());
return LittleEndianConsts.INT_SIZE;
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
@ -284,6 +331,11 @@ public class HemfMisc {
stretchBltMode = StretchBltMode.valueOf((int) leis.readUInt());
return LittleEndianConsts.INT_SIZE;
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -317,14 +369,26 @@ public class HemfMisc {
ctx.addObjectTableEntry(this, brushIdx);
}
public int getBrushIdx() {
return brushIdx;
}
@Override
public String toString() {
return
"{ brushIndex: "+brushIdx+
", brushStyle: '"+brushStyle+"'"+
", colorRef: "+colorRef+
", brushHatch: '"+brushHatch+"' }";
return GenericRecordJsonWriter.marshal(this);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"brushIdx", this::getBrushIdx
);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
@ -379,6 +443,22 @@ public class HemfMisc {
ctx.addObjectTableEntry(this, brushIdx);
}
public int getBrushIdx() {
return brushIdx;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"brushIdx", this::getBrushIdx
);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -397,6 +477,11 @@ public class HemfMisc {
objectIndex = (int) leis.readUInt();
return LittleEndianConsts.INT_SIZE;
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -439,7 +524,24 @@ public class HemfMisc {
@Override
public String toString() {
return super.toString().replaceFirst("\\{", "{ penIndex: "+penIndex+", ");
return GenericRecordJsonWriter.marshal(this);
}
public int getPenIndex() {
return penIndex;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"penIndex", this::getPenIndex
);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
@ -539,12 +641,34 @@ public class HemfMisc {
@Override
public String toString() {
// TODO: add style entries + bmp
return
"{ brushStyle: '"+brushStyle+"'"+
", hatchStyle: '"+hatchStyle+"'"+
", dashPattern: "+ Arrays.toString(penStyle.getLineDashes())+
", "+super.toString().substring(1);
return GenericRecordJsonWriter.marshal(this);
}
public HwmfBrushStyle getBrushStyle() {
return brushStyle;
}
public HwmfHatchStyle getHatchStyle() {
return hatchStyle;
}
public HwmfBitmapDib getBitmap() {
return bitmap;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"brushStyle", this::getBrushStyle,
"hatchStyle", this::getHatchStyle,
"bitmap", this::getBitmap
);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
@ -573,7 +697,16 @@ public class HemfMisc {
@Override
public String toString() {
return "{ miterLimit: "+miterLimit+" }";
return GenericRecordJsonWriter.marshal(this);
}
public int getMiterLimit() {
return miterLimit;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties("miterLimit", this::getMiterLimit);
}
}
@ -593,7 +726,16 @@ public class HemfMisc {
@Override
public String toString() {
return "{ x: "+origin.getX()+", y: "+origin.getY()+" }";
return GenericRecordJsonWriter.marshal(this);
}
public Point2D getOrigin() {
return origin;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties("origin", this::getOrigin);
}
}
@ -620,7 +762,16 @@ public class HemfMisc {
@Override
public String toString() {
return "{ xForm: " + xformToString(xForm)+" }";
return GenericRecordJsonWriter.marshal(this);
}
public AffineTransform getXForm() {
return xForm;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties("xForm", this::getXForm);
}
}
@ -687,9 +838,23 @@ public class HemfMisc {
@Override
public String toString() {
return
"{ xForm: " + xformToString(xForm) +
", modifyWorldTransformMode: '"+modifyWorldTransformMode+"' }";
return GenericRecordJsonWriter.marshal(this);
}
public AffineTransform getXForm() {
return xForm;
}
public HemfModifyWorldTransformMode getModifyWorldTransformMode() {
return modifyWorldTransformMode;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"xForm", this::getXForm,
"modifyWorldTransformMode", this::getModifyWorldTransformMode
);
}
}
@ -760,11 +925,28 @@ public class HemfMisc {
@Override
public String toString() {
return
"{ penIndex: " + penIndex +
", colorUsage: " + colorUsage +
", bitmap: " + bitmap +
"}";
return GenericRecordJsonWriter.marshal(this);
}
public int getPenIndex() {
return penIndex;
}
public HwmfFill.ColorUsage getColorUsage() {
return colorUsage;
}
public HwmfBitmapDib getBitmap() {
return bitmap;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"penIndex", this::getPenIndex,
"colorUsage", this::getColorUsage,
"bitmap", this::getBitmap
);
}
}

View File

@ -18,12 +18,16 @@
package org.apache.poi.hemf.record.emf;
import java.io.IOException;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.hemf.draw.HemfGraphics;
import org.apache.poi.hwmf.record.HwmfPalette;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
@SuppressWarnings("WeakerAccess")
public class HemfPalette {
/** The EMR_SELECTPALETTE record specifies a logical palette for the playback device context. */
public static class EmfSelectPalette extends HwmfPalette.WmfSelectPalette implements HemfRecord {
@ -42,6 +46,11 @@ public class HemfPalette {
paletteIndex = (int)leis.readUInt();
return LittleEndianConsts.INT_SIZE;
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/** The EMR_CREATEPALETTE record defines a logical palette for graphics operations. */
@ -73,6 +82,23 @@ public class HemfPalette {
public void draw(HemfGraphics ctx) {
ctx.addObjectTableEntry(this, paletteIndex);
}
public int getPaletteIndex() {
return paletteIndex;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"paletteIndex", this::getPaletteIndex
);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -104,6 +130,23 @@ public class HemfPalette {
public void draw(HemfGraphics ctx) {
ctx.addObjectTableEntry(this, paletteIndex);
}
public int getPaletteIndex() {
return paletteIndex;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"paletteIndex", this::getPaletteIndex
);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -134,6 +177,23 @@ public class HemfPalette {
public void draw(HemfGraphics ctx) {
ctx.addObjectTableEntry(this, paletteIndex);
}
public int getPaletteIndex() {
return paletteIndex;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"paletteIndex", this::getPaletteIndex
);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -150,6 +210,11 @@ public class HemfPalette {
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return 0;
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -205,5 +270,14 @@ public class HemfPalette {
icmMode = ICMMode.valueOf(leis.readInt());
return LittleEndianConsts.INT_SIZE;
}
public ICMMode getIcmMode() {
return icmMode;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties("icmMode", this::getIcmMode);
}
}
}

View File

@ -19,14 +19,17 @@ package org.apache.poi.hemf.record.emf;
import java.io.IOException;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hemf.draw.HemfGraphics;
import org.apache.poi.hwmf.record.HwmfRecord;
import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndianInputStream;
@Internal
public interface HemfRecord {
public interface HemfRecord extends GenericRecord {
HemfRecordType getEmfRecordType();
@ -58,4 +61,16 @@ public interface HemfRecord {
* @param header the emf header
*/
default void setHeader(HemfHeader header) {}
@Override
default Enum getGenericRecordType() {
return getEmfRecordType();
}
}
interface HemfRecordWithoutProperties extends HemfRecord {
default Map<String, Supplier<?>> getGenericProperties() {
return null;
}
}

View File

@ -27,12 +27,16 @@ import java.awt.geom.Dimension2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.hemf.draw.HemfGraphics;
import org.apache.poi.hwmf.draw.HwmfGraphics;
import org.apache.poi.hwmf.record.HwmfText;
import org.apache.poi.hwmf.record.HwmfText.WmfSetTextAlign;
import org.apache.poi.util.Dimension2DDouble;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndianConsts;
@ -45,6 +49,7 @@ import org.apache.poi.util.RecordFormatException;
* implemented at this point!
*/
@Internal
@SuppressWarnings("WeakerAccess")
public class HemfText {
private static final int MAX_RECORD_LENGTH = 1_000_000;
@ -181,7 +186,7 @@ public class HemfText {
*
* @param charset the charset to be used to decode the character bytes
* @return text from this text element
* @throws IOException
* @throws IOException if the charset is not compatible to the underlying bytes
*/
public String getText(Charset charset) throws IOException {
return super.getText(charset);
@ -206,10 +211,21 @@ public class HemfText {
@Override
public String toString() {
return
"{ graphicsMode: '"+graphicsMode+"'"+
", scale: { w: "+scale.getWidth()+", h: "+scale.getHeight()+" },"+
super.toString().substring(1);
return GenericRecordJsonWriter.marshal(this);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"boundsIgnored", () -> boundsIgnored,
"graphicsMode", this::getGraphicsMode
);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
@ -240,15 +256,18 @@ public class HemfText {
@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
/**
* A 32-bit unsigned integer that specifies text alignment by using a mask of text alignment flags.
* These are either WMF TextAlignmentMode Flags for text with a horizontal baseline,
* or WMF VerticalTextAlignmentMode Flags for text with a vertical baseline.
* Only one value can be chosen from those that affect horizontal and vertical alignment.
*/
// A 32-bit unsigned integer that specifies text alignment by using a mask of text alignment flags.
// These are either WMF TextAlignmentMode Flags for text with a horizontal baseline,
// or WMF VerticalTextAlignmentMode Flags for text with a vertical baseline.
// Only one value can be chosen from those that affect horizontal and vertical alignment.
textAlignmentMode = (int)leis.readUInt();
return LittleEndianConsts.INT_SIZE;
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -264,6 +283,11 @@ public class HemfText {
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return colorRef.init(leis);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
@ -297,7 +321,24 @@ public class HemfText {
@Override
public String toString() {
return "{ index: "+fontIdx+", font: "+font+" } ";
return GenericRecordJsonWriter.marshal(this);
}
public int getFontIdx() {
return fontIdx;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"fontIdx", this::getFontIdx
);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
@ -306,7 +347,7 @@ public class HemfText {
public int init(LittleEndianInputStream leis) {
// A 32-bit unsigned integer that specifies how to use the rectangle specified in the Rectangle field.
// This field can be a combination of more than one ExtTextOutOptions enumeration
flag = (int)leis.readUInt();
flags = (int)leis.readUInt();
return LittleEndianConsts.INT_SIZE;
}
}

View File

@ -21,15 +21,21 @@ import static org.apache.poi.hemf.record.emf.HemfDraw.readDimensionInt;
import static org.apache.poi.hemf.record.emf.HemfDraw.readPointL;
import static org.apache.poi.hwmf.record.HwmfDraw.normalizeBounds;
import java.awt.geom.Dimension2D;
import java.io.IOException;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.hemf.draw.HemfDrawProperties;
import org.apache.poi.hemf.draw.HemfGraphics;
import org.apache.poi.hwmf.record.HwmfRegionMode;
import org.apache.poi.hwmf.record.HwmfWindowing;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
@SuppressWarnings("WeakerAccess")
public class HemfWindowing {
/**
@ -45,6 +51,11 @@ public class HemfWindowing {
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return readDimensionInt(leis, size);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -60,6 +71,11 @@ public class HemfWindowing {
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return readPointL(leis, origin);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -75,6 +91,11 @@ public class HemfWindowing {
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return readDimensionInt(leis, extents);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -90,6 +111,11 @@ public class HemfWindowing {
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return readPointL(leis, origin);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -106,6 +132,11 @@ public class HemfWindowing {
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return readPointL(leis, offset);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -122,6 +153,11 @@ public class HemfWindowing {
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return HemfDraw.readRectL(leis, bounds);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -138,6 +174,11 @@ public class HemfWindowing {
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return HemfDraw.readRectL(leis, normalizeBounds(bounds));
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
/**
@ -152,12 +193,12 @@ public class HemfWindowing {
@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
double xNum = leis.readInt();
double xDenom = leis.readInt();
double yNum = leis.readInt();
double yDenom = leis.readInt();
scale.setSize(xNum / xDenom, yNum / yDenom);
return 4*LittleEndianConsts.INT_SIZE;
return readScale(leis, scale);
}
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
@ -173,14 +214,12 @@ public class HemfWindowing {
@Override
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
double xNum = leis.readInt();
double xDenom = leis.readInt();
double yNum = leis.readInt();
double yDenom = leis.readInt();
return readScale(leis, scale);
}
scale.setSize(xNum / xDenom, yNum / yDenom);
return 4*LittleEndianConsts.INT_SIZE;
@Override
public Enum getGenericRecordType() {
return getEmfRecordType();
}
}
@ -213,8 +252,25 @@ public class HemfWindowing {
@Override
public String toString() {
return "{ regionMode: '"+regionMode+"' }";
return GenericRecordJsonWriter.marshal(this);
}
public HwmfRegionMode getRegionMode() {
return regionMode;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties("regionMode", this::getRegionMode);
}
}
private static int readScale(LittleEndianInputStream leis, Dimension2D scale) {
double xNum = leis.readInt();
double xDenom = leis.readInt();
double yNum = leis.readInt();
double yDenom = leis.readInt();
scale.setSize(xNum / xDenom, yNum / yDenom);
return 4*LittleEndianConsts.INT_SIZE;
}
}

View File

@ -25,7 +25,7 @@ import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndianInputStream;
@Internal
public class UnimplementedHemfRecord implements HemfRecord {
public class UnimplementedHemfRecord implements HemfRecordWithoutProperties {
private HemfRecordType recordType;

View File

@ -17,26 +17,24 @@
package org.apache.poi.hemf.record.emfplus;
import static java.util.stream.Collectors.joining;
import static org.apache.poi.hemf.record.emf.HemfDraw.xformToString;
import static org.apache.poi.hemf.record.emf.HemfFill.readXForm;
import static org.apache.poi.hemf.record.emfplus.HemfPlusDraw.readARGB;
import static org.apache.poi.hemf.record.emfplus.HemfPlusDraw.readPointF;
import static org.apache.poi.hemf.record.emfplus.HemfPlusDraw.readRectF;
import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
import static org.apache.poi.hwmf.record.HwmfDraw.pointToString;
import java.awt.Color;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hemf.draw.HemfDrawProperties;
import org.apache.poi.hemf.draw.HemfGraphics;
import org.apache.poi.hemf.record.emfplus.HemfPlusHeader.EmfPlusGraphicsVersion;
@ -47,10 +45,10 @@ import org.apache.poi.hemf.record.emfplus.HemfPlusObject.EmfPlusObjectType;
import org.apache.poi.hemf.record.emfplus.HemfPlusPath.EmfPlusPath;
import org.apache.poi.hwmf.record.HwmfBrushStyle;
import org.apache.poi.hwmf.record.HwmfColorRef;
import org.apache.poi.hwmf.record.HwmfDraw;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.Internal;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
@ -243,7 +241,7 @@ public class HemfPlusBrush {
}
public interface EmfPlusBrushData {
public interface EmfPlusBrushData extends GenericRecord {
/**
* This flag is meaningful in EmfPlusPathGradientBrushData objects.
*
@ -343,9 +341,24 @@ public class HemfPlusBrush {
@Override
public String toString() {
return
"{ brushType: '"+brushType+"'" +
", brushData: "+brushData+" }";
return GenericRecordJsonWriter.marshal(this);
}
public EmfPlusBrushData getBrushData() {
return brushData;
}
@Override
public EmfPlusBrushType getGenericRecordType() {
return brushType;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"graphicsVersion", this::getGraphicsVersion,
"brushData", this::getBrushData
);
}
}
@ -366,7 +379,17 @@ public class HemfPlusBrush {
@Override
public String toString() {
return "{ solidColor: "+new HwmfColorRef(solidColor)+" }";
return GenericRecordJsonWriter.marshal(this);
}
@Override
public Enum getGenericRecordType() {
return EmfPlusBrushType.SOLID_COLOR;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties("solidColor", () -> solidColor);
}
}
@ -392,10 +415,21 @@ public class HemfPlusBrush {
@Override
public String toString() {
return
"{ style: '"+style+"'" +
", foreColor: "+new HwmfColorRef(foreColor) +
", backColor: "+new HwmfColorRef(backColor) + " }";
return GenericRecordJsonWriter.marshal(this);
}
@Override
public Enum getGenericRecordType() {
return EmfPlusBrushType.HATCH_FILL;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"style", () -> style,
"foreColor", () -> foreColor,
"backColor", () -> backColor
);
}
}
@ -462,23 +496,31 @@ public class HemfPlusBrush {
@Override
public String toString() {
return
"{ flags: "+dataFlags+
", wrapMode: '"+wrapMode+"'"+
", rect: "+boundsToString(rect)+
", startColor: "+new HwmfColorRef(startColor)+
", endColor: "+new HwmfColorRef(endColor)+
", transform: "+xformToString(transform)+
", positions: "+ Arrays.toString(positions)+
", blendColors: "+ colorsToString(blendColors)+
", positionsV: "+ Arrays.toString(positionsV)+
", blendFactorsV: "+ Arrays.toString(blendFactorsV)+
", positionsH: "+ Arrays.toString(positionsH)+
", blendFactorsH: "+ Arrays.toString(blendFactorsH)+
"}";
return GenericRecordJsonWriter.marshal(this);
}
@Override
public Enum getGenericRecordType() {
return EmfPlusBrushType.LINEAR_GRADIENT;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String,Supplier<?>> m = new LinkedHashMap<>();
m.put("flags", () -> dataFlags);
m.put("wrapMode", () -> wrapMode);
m.put("rect", () -> rect);
m.put("startColor", () -> startColor);
m.put("endColor", () -> endColor);
m.put("transform", () -> transform);
m.put("positions", () -> positions);
m.put("blendColors", () -> blendColors);
m.put("positionsV", () -> positionsV);
m.put("blendFactorsV", () -> blendFactorsV);
m.put("positionsH", () -> positionsH);
m.put("blendFactorsH", () -> blendFactorsH);
return Collections.unmodifiableMap(m);
}
}
/** The EmfPlusPathGradientBrushData object specifies a path gradient for a graphics brush. */
@ -593,22 +635,32 @@ public class HemfPlusBrush {
@Override
public String toString() {
return
"{ flags: "+dataFlags+
", wrapMode: '"+wrapMode+"'"+
", centerColor: "+new HwmfColorRef(centerColor)+
", centerPoint: "+pointToString(centerPoint)+
", surroundingColor: "+colorsToString(surroundingColor)+
", boundaryPath: "+(boundaryPath == null ? "null" : boundaryPath)+
", boundaryPoints: "+pointsToString(boundaryPoints)+
", transform: "+xformToString(transform)+
", positions: "+Arrays.toString(positions)+
", blendColors: "+colorsToString(blendColors)+
", blendFactorsH: "+Arrays.toString(blendFactorsH)+
", focusScaleX: "+focusScaleX+
", focusScaleY: "+focusScaleY+
"}"
;
return GenericRecordJsonWriter.marshal(this);
}
@Override
public Enum getGenericRecordType() {
return EmfPlusBrushType.PATH_GRADIENT;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String,Supplier<?>> m = new LinkedHashMap<>();
m.put("flags", () -> dataFlags);
m.put("wrapMode", () -> wrapMode);
m.put("centerColor", () -> centerColor);
m.put("centerPoint", () -> centerPoint);
m.put("surroundingColor", () -> surroundingColor);
m.put("boundaryPath", () -> boundaryPath);
m.put("boundaryPoints", () -> boundaryPoints);
m.put("transform", () -> transform);
m.put("positions", () -> positions);
m.put("blendColors", () -> blendColors);
m.put("blendFactorsH", () -> blendFactorsH);
m.put("focusScaleX", () -> focusScaleX);
m.put("focusScaleY", () -> focusScaleY);
return Collections.unmodifiableMap(m);
}
}
@ -652,12 +704,22 @@ public class HemfPlusBrush {
@Override
public String toString() {
return
"{ flags: "+dataFlags+
", wrapMode: '"+wrapMode+"'"+
", transform: "+xformToString(transform)+
", image: "+image+
"]";
return GenericRecordJsonWriter.marshal(this);
}
@Override
public Enum getGenericRecordType() {
return EmfPlusBrushType.TEXTURE_FILL;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"dataFlags", () -> dataFlags,
"wrapMode", () -> wrapMode,
"transform", () -> transform,
"image", () -> image
);
}
}
@ -696,18 +758,4 @@ public class HemfPlusBrush {
facs.accept(factors);
return size + factors.length * LittleEndianConsts.INT_SIZE;
}
@Internal
public static String colorsToString(Color[] colors) {
return (colors == null ? "null" :
Stream.of(colors).map(HwmfColorRef::new).map(Object::toString).
collect(joining(",", "{", "}")));
}
@Internal
public static String pointsToString(Point2D[] points) {
return (points == null ? "null" :
Stream.of(points).map(HwmfDraw::pointToString).
collect(joining(",", "{", "}")));
}
}

View File

@ -17,10 +17,7 @@
package org.apache.poi.hemf.record.emfplus;
import static java.util.stream.Collectors.joining;
import static org.apache.poi.hemf.record.emf.HemfDraw.xformToString;
import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
import static org.apache.poi.hwmf.record.HwmfDraw.pointToString;
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import java.awt.Color;
import java.awt.geom.AffineTransform;
@ -32,8 +29,12 @@ import java.awt.image.BufferedImage;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import org.apache.commons.math3.linear.LUDecomposition;
import org.apache.commons.math3.linear.MatrixUtils;
@ -46,16 +47,18 @@ import org.apache.poi.hemf.record.emfplus.HemfPlusMisc.EmfPlusObjectId;
import org.apache.poi.hemf.record.emfplus.HemfPlusObject.EmfPlusObject;
import org.apache.poi.hwmf.record.HwmfBrushStyle;
import org.apache.poi.hwmf.record.HwmfColorRef;
import org.apache.poi.hwmf.record.HwmfDraw;
import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode.HwmfBkMode;
import org.apache.poi.hwmf.record.HwmfTernaryRasterOp;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
import org.apache.poi.util.StringUtil;
@SuppressWarnings("WeakerAccess")
public class HemfPlusDraw {
private static final int MAX_OBJECT_SIZE = 1_000_000;
@ -185,6 +188,10 @@ public class HemfPlusDraw {
return flags;
}
public int getPenId() {
return penId;
}
@Override
public long init(LittleEndianInputStream leis, long dataSize, long recordId, int flags) throws IOException {
this.flags = flags;
@ -213,9 +220,20 @@ public class HemfPlusDraw {
@Override
public String toString() {
return
"{ flags: "+flags+
", penId: "+penId+" }";
return GenericRecordJsonWriter.marshal(this);
}
@Override
public HemfPlusRecordType getGenericRecordType() {
return getEmfPlusRecordType();
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"flags", this::getFlags,
"penId", this::getPenId
);
}
}
@ -278,11 +296,25 @@ public class HemfPlusDraw {
@Override
public String toString() {
return
"{ flags: "+flags+
", brushId: "+brushId+
", rectData: "+rectData.stream().map(HwmfDraw::boundsToString).collect(joining(",", "{", "}"))+
"}";
return GenericRecordJsonWriter.marshal(this);
}
@Override
public HemfPlusRecordType getGenericRecordType() {
return getEmfPlusRecordType();
}
public List<Rectangle2D> getRectData() {
return rectData;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"flags", this::getFlags,
"brushId", this::getBrushId,
"rectData", this::getRectData
);
}
}
@ -428,17 +460,21 @@ public class HemfPlusDraw {
@Override
public String toString() {
return
"{ flags: "+flags+
", imageAttributesID: "+imageAttributesID+
", srcUnit: '"+srcUnit+"'"+
", srcRect: "+boundsToString(srcRect)+
", upperLeft: "+pointToString(upperLeft)+
", lowerLeft: "+pointToString(lowerLeft)+
", lowerRight: "+pointToString(lowerRight)+
", transform: "+xformToString(trans)+
"}"
;
return GenericRecordJsonWriter.marshal(this);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String,Supplier<?>> m = new LinkedHashMap<>();
m.put("flags", this::getFlags);
m.put("imageAttributesID", () -> imageAttributesID);
m.put("srcUnit", () -> srcUnit);
m.put("srcRect", () -> srcRect);
m.put("upperLeft", () -> upperLeft);
m.put("lowerLeft", () -> lowerLeft);
m.put("lowerRight", () -> lowerRight);
m.put("transform", () -> trans);
return Collections.unmodifiableMap(m);
}
}
@ -500,14 +536,18 @@ public class HemfPlusDraw {
@Override
public String toString() {
return
"{ flags: "+flags+
", imageAttributesID: "+imageAttributesID+
", srcUnit: '"+srcUnit+"'"+
", srcRect: "+boundsToString(srcRect)+
", rectData: "+boundsToString(rectData)+
"}"
;
return GenericRecordJsonWriter.marshal(this);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"flags", this::getFlags,
"imageAttributesID", () -> imageAttributesID,
"srcUnit", () -> srcUnit,
"srcRect", () -> srcRect,
"rectData", () -> rectData
);
}
}
@ -554,9 +594,15 @@ public class HemfPlusDraw {
@Override
public String toString() {
return
"{ flags: "+flags+
", brushId: "+brushId+" }";
return GenericRecordJsonWriter.marshal(this);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"flags", this::getFlags,
"brushId", () -> brushId
);
}
}
@ -596,7 +642,11 @@ public class HemfPlusDraw {
*/
private static final BitField LIMIT_SUBPIXEL = BitFieldFactory.getInstance(0x0008);
private static final int[] OPTIONS_MASK = { 0x0001, 0x0002, 0x0004, 0x0008 };
private static final String[] OPTIONS_NAMES = {
"CMAP_LOOKUP", "VERTICAL", "REALIZED_ADVANCE", "LIMIT_SUBPIXEL"
};
private int flags;
private int brushId;
@ -671,6 +721,23 @@ public class HemfPlusDraw {
return size;
}
@Override
public String toString() {
return GenericRecordJsonWriter.marshal(this);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"flags", this::getFlags,
"brushId", this::getBrushId,
"optionsFlags", getBitsAsString(() -> optionsFlags, OPTIONS_MASK, OPTIONS_NAMES),
"glyphs", () -> glyphs,
"glyphPos", () -> glpyhPos,
"transform", () -> transformMatrix
);
}
}
/** The EmfPlusDrawRects record specifies drawing a series of rectangles. */
@ -705,6 +772,19 @@ public class HemfPlusDraw {
return size;
}
@Override
public String toString() {
return GenericRecordJsonWriter.marshal(this);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"flags", this::getFlags,
"rectData", () -> rectData
);
}
}

View File

@ -19,13 +19,18 @@ package org.apache.poi.hemf.record.emfplus;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.hemf.draw.HemfGraphics;
import org.apache.poi.hemf.record.emfplus.HemfPlusDraw.EmfPlusUnitType;
import org.apache.poi.hemf.record.emfplus.HemfPlusHeader.EmfPlusGraphicsVersion;
import org.apache.poi.hemf.record.emfplus.HemfPlusObject.EmfPlusObjectData;
import org.apache.poi.hemf.record.emfplus.HemfPlusObject.EmfPlusObjectType;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
import org.apache.poi.util.StringUtil;
@ -69,7 +74,7 @@ public class HemfPlusFont {
private String family;
@Override
public long init(LittleEndianInputStream leis, long dataSize, HemfPlusObject.EmfPlusObjectType objectType, int flags) throws IOException {
public long init(LittleEndianInputStream leis, long dataSize, EmfPlusObjectType objectType, int flags) throws IOException {
// An EmfPlusGraphicsVersion object that specifies the version of operating system graphics that was used
// to create this object.
long size = graphicsVersion.init(leis);
@ -108,5 +113,26 @@ public class HemfPlusFont {
public EmfPlusGraphicsVersion getGraphicsVersion() {
return graphicsVersion;
}
@Override
public String toString() {
return GenericRecordJsonWriter.marshal(this);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"graphicsVersion", () -> graphicsVersion,
"emSize", () -> emSize,
"sizeUnit", () -> sizeUnit,
"styleFlags", () -> styleFlags,
"family", () -> family
);
}
@Override
public EmfPlusObjectType getGenericRecordType() {
return EmfPlusObjectType.FONT;
}
}
}

View File

@ -18,12 +18,18 @@
package org.apache.poi.hemf.record.emfplus;
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import java.io.IOException;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.hemf.draw.HemfGraphics;
import org.apache.poi.hemf.draw.HemfGraphics.EmfRenderState;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
@ -53,6 +59,8 @@ public class HemfPlusHeader implements HemfPlusRecord {
}
}
private static final int[] FLAGS_MASK = { 0x0001 };
private static final String[] FLAGS_NAMES = { "DUAL_MODE" };
private int flags;
private final EmfPlusGraphicsVersion version = new EmfPlusGraphicsVersion();
@ -121,13 +129,18 @@ public class HemfPlusHeader implements HemfPlusRecord {
@Override
public String toString() {
return "HemfPlusHeader{" +
"flags=" + flags +
", version=" + version +
", emfPlusFlags=" + emfPlusFlags +
", logicalDpiX=" + logicalDpiX +
", logicalDpiY=" + logicalDpiY +
'}';
return GenericRecordJsonWriter.marshal(this);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"flags", this::getFlags,
"version", this::getVersion,
"emfPlusFlags", getBitsAsString(this::getEmfPlusFlags, FLAGS_MASK, FLAGS_NAMES),
"logicalDpiX", this::getLogicalDpiX,
"logicalDpiY", this::getLogicalDpiY
);
}
public static class EmfPlusGraphicsVersion {

View File

@ -36,8 +36,12 @@ import java.awt.image.WritableRaster;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
import javax.imageio.ImageIO;
@ -50,6 +54,8 @@ import org.apache.poi.hemf.usermodel.HemfPicture;
import org.apache.poi.hwmf.usermodel.HwmfPicture;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
@ -280,7 +286,6 @@ public class HemfPlusImage {
public static class EmfPlusImage implements EmfPlusObjectData {
private static final int MAX_OBJECT_SIZE = 50_000_000;
private final EmfPlusGraphicsVersion graphicsVersion = new EmfPlusGraphicsVersion();
private EmfPlusImageDataType imageDataType;
private int bitmapWidth;
@ -595,10 +600,36 @@ public class HemfPlusImage {
return bufImg;
}
@Override
public String toString() {
return GenericRecordJsonWriter.marshal(this);
}
@Override
public EmfPlusObjectType getGenericRecordType() {
return EmfPlusObjectType.IMAGE;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String,Supplier<?>> m = new LinkedHashMap<>();
m.put("graphicsVersion", this::getGraphicsVersion);
m.put("imageDataType", this::getImageDataType);
m.put("bitmapWidth", this::getBitmapWidth);
m.put("bitmapHeight", this::getBitmapHeight);
m.put("bitmapStride", this::getBitmapStride);
m.put("pixelFormat", this::getPixelFormat);
m.put("bitmapType", this::getBitmapType);
m.put("imageData", this::getImageData);
m.put("metafileType", this::getMetafileType);
m.put("metafileDataSize", () -> metafileDataSize);
return Collections.unmodifiableMap(m);
}
}
public static class EmfPlusImageAttributes implements EmfPlusObjectData {
private final EmfPlusGraphicsVersion graphicsVersion = new EmfPlusGraphicsVersion();
private EmfPlusWrapMode wrapMode;
@ -650,6 +681,26 @@ public class HemfPlusImage {
@Override
public void applyObject(HemfGraphics ctx, List<? extends EmfPlusObjectData> continuedObjectData) {
}
@Override
public String toString() {
return GenericRecordJsonWriter.marshal(this);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"graphicsVersion", this::getGraphicsVersion,
"wrapMode", this::getWrapMode,
"clampColor", this::getClampColor,
"objectClamp", this::getObjectClamp
);
}
@Override
public EmfPlusObjectType getGenericRecordType() {
return EmfPlusObjectType.IMAGE_ATTRIBUTES;
}
}
}

View File

@ -19,19 +19,24 @@ package org.apache.poi.hemf.record.emfplus;
import static org.apache.poi.hemf.record.emf.HemfMisc.adaptXForm;
import static org.apache.poi.hemf.record.emfplus.HemfPlusDraw.readRectF;
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.hemf.draw.HemfGraphics;
import org.apache.poi.hemf.record.emf.HemfFill;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
@SuppressWarnings("WeakerAccess")
public class HemfPlusMisc {
public interface EmfPlusObjectId {
BitField OBJECT_ID = BitFieldFactory.getInstance(0x00FF);
@ -75,6 +80,9 @@ public class HemfPlusMisc {
private int flags;
private HemfPlusRecordType recordType;
private static final int[] FLAGS_MASK = { 0x0F00 };
private static final String[] FLAGS_NAMES = { "COMBINE_MODE" };
@Override
public int getFlags() {
return flags;
@ -92,6 +100,18 @@ public class HemfPlusMisc {
recordType = HemfPlusRecordType.getById(recordId);
return 0;
}
@Override
public HemfPlusRecordType getGenericRecordType() {
return getEmfPlusRecordType();
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"flags", getBitsAsString(this::getFlags,FLAGS_MASK,FLAGS_NAMES)
);
}
}
public static class EmfPlusEOF extends EmfPlusFlagOnly {
@ -193,6 +213,14 @@ public class HemfPlusMisc {
tx.concatenate(getMatrixData());
ctx.setTransform(tx);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"flags", this::getFlags,
"matrixData", this::getMatrixData
);
}
}
/**
@ -239,6 +267,18 @@ public class HemfPlusMisc {
pageScale = leis.readFloat();
return LittleEndianConsts.INT_SIZE;
}
public double getPageScale() {
return pageScale;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"flags", this::getFlags,
"pageScale", this::getPageScale
);
}
}
/**
@ -264,6 +304,9 @@ public class HemfPlusMisc {
public static class EmfPlusSetClipRect implements HemfPlusRecord {
private static final BitField COMBINE_MODE = BitFieldFactory.getInstance(0x0F00);
private static final int[] FLAGS_MASK = { 0x0F00 };
private static final String[] FLAGS_NAMES = { "COMBINE_MODE" };
private int flags;
private final Rectangle2D clipRect = new Rectangle2D.Double();
@ -288,6 +331,18 @@ public class HemfPlusMisc {
// An EmfPlusRectF object that defines the rectangle to use in the CombineMode operation.
return readRectF(leis, clipRect);
}
public Rectangle2D getClipRect() {
return clipRect;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"flags", getBitsAsString(this::getFlags, FLAGS_MASK, FLAGS_NAMES),
"clipRect", this::getClipRect
);
}
}
@ -314,6 +369,10 @@ public class HemfPlusMisc {
return flags;
}
public int getStackIndex() {
return stackIndex;
}
@Override
public long init(LittleEndianInputStream leis, long dataSize, long recordId, int flags) throws IOException {
this.flags = flags;
@ -324,6 +383,14 @@ public class HemfPlusMisc {
return LittleEndianConsts.INT_SIZE;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"flags", this::getFlags,
"stackIndex", this::getStackIndex
);
}
}
/**
@ -369,6 +436,14 @@ public class HemfPlusMisc {
return LittleEndianConsts.INT_SIZE*2;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"flags", this::getFlags,
"origin", this::getOrigin
);
}
}
}

View File

@ -17,11 +17,15 @@
package org.apache.poi.hemf.record.emfplus;
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hemf.draw.HemfGraphics;
import org.apache.poi.hemf.record.emfplus.HemfPlusBrush.EmfPlusBrush;
import org.apache.poi.hemf.record.emfplus.HemfPlusFont.EmfPlusFont;
@ -36,6 +40,7 @@ import org.apache.poi.hwmf.draw.HwmfGraphics;
import org.apache.poi.hwmf.record.HwmfObjectTableEntry;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
@ -113,8 +118,6 @@ public class HemfPlusObject {
* can span multiple records), which is indicated by the value of the Flags field.
*/
public static class EmfPlusObject implements HemfPlusRecord, EmfPlusObjectId, HwmfObjectTableEntry {
/**
* Indicates that the object definition continues on in the next EmfPlusObject
* record. This flag is never set in the final record that defines the object.
@ -127,6 +130,10 @@ public class HemfPlusObject {
*/
private static final BitField OBJECT_TYPE = BitFieldFactory.getInstance(0x7F00);
private static final int[] FLAGS_MASKS = { 0x7F00, 0x8000 };
private static final String[] FLAGS_NAMES = { "OBJECT_TYPE", "CONTINUABLE" };
private int flags;
// for debugging
private int objectId;
@ -211,9 +218,20 @@ public class HemfPlusObject {
List<EmfPlusObjectData> getContinuedObject() {
return continuedObjectData;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"flags", getBitsAsString(this::getFlags, FLAGS_MASKS, FLAGS_NAMES),
"objectId", this::getObjectId,
"continuedObjectData", this::getContinuedObject,
"totalObjectSize", () -> totalObjectSize
);
}
}
public interface EmfPlusObjectData {
public interface EmfPlusObjectData extends GenericRecord {
long init(LittleEndianInputStream leis, long dataSize, EmfPlusObjectType objectType, int flags) throws IOException;
void applyObject(HemfGraphics ctx, List<? extends EmfPlusObjectData> continuedObjectData);
@ -251,5 +269,18 @@ public class HemfPlusObject {
public EmfPlusGraphicsVersion getGraphicsVersion() {
return graphicsVersion;
}
@Override
public EmfPlusObjectType getGenericRecordType() {
return objectType;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"graphicsVersion", this::getGraphicsVersion,
"objectDataBytes", () -> objectDataBytes
);
}
}
}

View File

@ -17,13 +17,20 @@
package org.apache.poi.hemf.record.emfplus;
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hemf.draw.HemfDrawProperties;
import org.apache.poi.hemf.draw.HemfGraphics;
import org.apache.poi.hemf.record.emfplus.HemfPlusDraw.EmfPlusCompressed;
@ -32,6 +39,7 @@ import org.apache.poi.hemf.record.emfplus.HemfPlusObject.EmfPlusObjectData;
import org.apache.poi.hemf.record.emfplus.HemfPlusObject.EmfPlusObjectType;
import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
@ -73,6 +81,12 @@ public class HemfPlusPath {
private static final BitField POINT_RLE_COUNT = BitFieldFactory.getInstance(0x3F);
private static final int[] FLAGS_MASKS = { 0x0800, 0x1000, 0x4000 };
private static final String[] FLAGS_NAMES = { "RELATIVE_POSITION", "RLE_COMPRESSED", "FORMAT_COMPRESSED" };
private static final int[] TYPE_MASKS = { 0x10, 0x20, 0x80 };
private static final String[] TYPE_NAMES = { "DASHED", "MARKER", "CLOSE" };
private final HemfPlusHeader.EmfPlusGraphicsVersion graphicsVersion = new HemfPlusHeader.EmfPlusGraphicsVersion();
private int pointFlags;
private Point2D[] pathPoints;
@ -154,7 +168,9 @@ public class HemfPlusPath {
return pointFlags;
}
public Point2D getPoint(int index) {
return pathPoints[index];
}
@Override
public void applyObject(HemfGraphics ctx, List<? extends EmfPlusObjectData> continuedObjectData) {
@ -184,8 +200,32 @@ public class HemfPlusPath {
}
}
@Override
public EmfPlusObjectType getGenericRecordType() {
return EmfPlusObjectType.PATH;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"graphicsVersion", this::getGraphicsVersion,
"flags", getBitsAsString(this::getFlags, FLAGS_MASKS, FLAGS_NAMES),
"points", this::getGenericPoints
);
}
private List<GenericRecord> getGenericPoints() {
return IntStream.range(0, pathPoints.length).
mapToObj(this::getGenericPoint).
collect(Collectors.toList());
}
private GenericRecord getGenericPoint(final int idx) {
return () -> GenericRecordUtil.getGenericProperties(
"flags", getBitsAsString(() -> pointTypes[idx], TYPE_MASKS, TYPE_NAMES),
"type", () -> getPointType(idx),
"point", () -> getPoint(idx)
);
}
}
}

View File

@ -19,13 +19,19 @@ package org.apache.poi.hemf.record.emfplus;
import static org.apache.poi.hemf.record.emf.HemfFill.readXForm;
import static org.apache.poi.hemf.record.emfplus.HemfPlusDraw.readPointF;
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hemf.draw.HemfDrawProperties;
import org.apache.poi.hemf.draw.HemfGraphics;
import org.apache.poi.hemf.record.emfplus.HemfPlusDraw.EmfPlusUnitType;
@ -40,6 +46,7 @@ import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
@SuppressWarnings("WeakerAccess")
public class HemfPlusPen {
/**
* The LineCapType enumeration defines types of line caps to use at the ends of lines that are drawn
@ -222,7 +229,7 @@ public class HemfPlusPen {
@Internal
public interface EmfPlusCustomLineCap {
public interface EmfPlusCustomLineCap extends GenericRecord {
long init(LittleEndianInputStream leis) throws IOException;
}
@ -290,6 +297,18 @@ public class HemfPlusPen {
*/
private final static BitField CUSTOM_END_CAP = BitFieldFactory.getInstance(0x00001000);
private static final int[] FLAGS_MASKS = {
0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010,
0x00000020, 0x00000040, 0x00000080, 0x00000100, 0x00000200,
0x00000400, 0x00000800, 0x00001000
};
private static final String[] FLAGS_NAMES = {
"TRANSFORM", "START_CAP", "END_CAP", "JOIN", "MITER_LIMIT",
"LINE_STYLE", "DASHED_LINE_CAP", "DASHED_LINE_OFFSET", "DASHED_LINE", "NON_CENTER",
"COMPOUND_LINE", "CUSTOM_START_CAP", "CUSTOM_END_CAP"
};
private final EmfPlusGraphicsVersion graphicsVersion = new EmfPlusGraphicsVersion();
@ -528,6 +547,34 @@ public class HemfPlusPen {
}
});
}
@Override
public EmfPlusObjectType getGenericRecordType() {
return EmfPlusObjectType.PEN;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String,Supplier<?>> m = new LinkedHashMap<>();
m.put("type", () -> type);
m.put("flags", getBitsAsString(() -> penDataFlags, FLAGS_MASKS, FLAGS_NAMES));
m.put("unitType", () -> unitType);
m.put("penWidth", () -> penWidth);
m.put("trans", () -> trans);
m.put("startCap", () -> startCap);
m.put("endCap", () -> endCap);
m.put("join", () -> join);
m.put("miterLimit", () -> miterLimit);
m.put("style", () -> style);
m.put("dashedLineCapType", () -> dashedLineCapType);
m.put("dashOffset", () -> dashOffset);
m.put("dashedLineData", () -> dashedLineData);
m.put("penAlignment", () -> penAlignment);
m.put("compoundLineData", () -> compoundLineData);
m.put("customStartCap", () -> customStartCap);
m.put("customEndCap", () -> customEndCap);
return Collections.unmodifiableMap(m);
}
}
public static class EmfPlusPathArrowCap implements EmfPlusCustomLineCap {
@ -542,6 +589,9 @@ public class HemfPlusPen {
*/
private static final BitField LINE_PATH = BitFieldFactory.getInstance(0x00000002);
private static final int[] FLAGS_MASKS = { 0x00000001, 0x00000002 };
private static final String[] FLAGS_NAMES = { "FILL_PATH", "LINE_PATH" };
private int dataFlags;
private EmfPlusLineCapType baseCap;
@ -549,7 +599,7 @@ public class HemfPlusPen {
private EmfPlusLineCapType startCap;
private EmfPlusLineCapType endCap;
private EmfPlusLineJoin join;
private double mitterLimit;
private double miterLimit;
private double widthScale;
private final Point2D fillHotSpot = new Point2D.Double();
private final Point2D lineHotSpot = new Point2D.Double();
@ -582,7 +632,7 @@ public class HemfPlusPen {
// A 32-bit floating-point value that contains the limit of the thickness of the join on a mitered corner
// by setting the maximum allowed ratio of miter length to line width.
mitterLimit = leis.readFloat();
miterLimit = leis.readFloat();
// A 32-bit floating-point value that specifies the amount by which to scale the custom line cap with
// respect to the width of the EmfPlusPen object that is used to draw the lines.
@ -606,6 +656,24 @@ public class HemfPlusPen {
return size;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String,Supplier<?>> m = new LinkedHashMap<>();
m.put("flags", getBitsAsString(() -> dataFlags, FLAGS_MASKS, FLAGS_NAMES));
m.put("baseCap", () -> baseCap);
m.put("baseInset", () -> baseInset);
m.put("startCap", () -> startCap);
m.put("endCap", () -> endCap);
m.put("join", () -> join);
m.put("miterLimit", () -> miterLimit);
m.put("widthScale", () -> widthScale);
m.put("fillHotSpot", () -> fillHotSpot);
m.put("lineHotSpot", () -> lineHotSpot);
m.put("fillPath", () -> fillPath);
m.put("outlinePath", () -> outlinePath);
return Collections.unmodifiableMap(m);
}
}
public static class EmfPlusAdjustableArrowCap implements EmfPlusCustomLineCap {
@ -616,7 +684,7 @@ public class HemfPlusPen {
private EmfPlusLineCapType startCap;
private EmfPlusLineCapType endCap;
private EmfPlusLineJoin join;
private double mitterLimit;
private double miterLimit;
private double widthScale;
private final Point2D fillHotSpot = new Point2D.Double();
private final Point2D lineHotSpot = new Point2D.Double();
@ -655,7 +723,7 @@ public class HemfPlusPen {
// A 32-bit floating-point value that specifies the limit of the thickness of the join on a mitered
// corner by setting the maximum allowed ratio of miter length to line width.
mitterLimit = leis.readFloat();
miterLimit = leis.readFloat();
// A 32-bit floating-point value that specifies the amount by which to scale an EmfPlusCustomLineCap
// object with respect to the width of the graphics pen that is used to draw the lines.
@ -671,5 +739,23 @@ public class HemfPlusPen {
return size;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String,Supplier<?>> m = new LinkedHashMap<>();
m.put("width", () -> width);
m.put("height", () -> height);
m.put("middleInset", () -> middleInset);
m.put("isFilled", () -> isFilled);
m.put("startCap", () -> startCap);
m.put("endCap", () -> endCap);
m.put("join", () -> join);
m.put("miterLimit", () -> miterLimit);
m.put("widthScale", () -> widthScale);
m.put("fillHotSpot", () -> fillHotSpot);
m.put("lineHotSpot", () -> lineHotSpot);
return Collections.unmodifiableMap(m);
}
}
}

View File

@ -20,12 +20,13 @@ package org.apache.poi.hemf.record.emfplus;
import java.io.IOException;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hemf.draw.HemfGraphics;
import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndianInputStream;
@Internal
public interface HemfPlusRecord {
public interface HemfPlusRecord extends GenericRecord {
HemfPlusRecordType getEmfPlusRecordType();

View File

@ -22,14 +22,17 @@ import static org.apache.poi.hemf.record.emfplus.HemfPlusDraw.readRectF;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hemf.draw.HemfGraphics;
import org.apache.poi.hemf.record.emfplus.HemfPlusHeader.EmfPlusGraphicsVersion;
import org.apache.poi.hemf.record.emfplus.HemfPlusObject.EmfPlusObjectData;
import org.apache.poi.hemf.record.emfplus.HemfPlusObject.EmfPlusObjectType;
import org.apache.poi.hemf.record.emfplus.HemfPlusPath.EmfPlusPath;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
@ -122,10 +125,23 @@ public class HemfPlusRegion {
public EmfPlusGraphicsVersion getGraphicsVersion() {
return graphicsVersion;
}
@Override
public EmfPlusObjectType getGenericRecordType() {
return EmfPlusObjectType.REGION;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"graphicsVersion", this::getGraphicsVersion,
"regionNode", () -> regionNode
);
}
}
public interface EmfPlusRegionNodeData {
public interface EmfPlusRegionNodeData extends GenericRecord {
long init(LittleEndianInputStream leis) throws IOException;
}
@ -141,6 +157,11 @@ public class HemfPlusRegion {
public long init(LittleEndianInputStream leis) throws IOException {
return 0;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return null;
}
}
public static class EmfPlusRegionEmpty implements EmfPlusRegionNodeData {
@ -148,6 +169,11 @@ public class HemfPlusRegion {
public long init(LittleEndianInputStream leis) throws IOException {
return 0;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return null;
}
}
public static class EmfPlusRegionRect implements EmfPlusRegionNodeData {
@ -157,6 +183,11 @@ public class HemfPlusRegion {
public long init(LittleEndianInputStream leis) {
return readRectF(leis, rect);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties("rect", () -> rect);
}
}
public static class EmfPlusRegionNode implements EmfPlusRegionNodeData {
@ -168,8 +199,15 @@ public class HemfPlusRegion {
size += readNode(leis, n -> right = n);
return size;
}
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"left", () -> left,
"right", () -> right
);
}
}
private static long readNode(LittleEndianInputStream leis, Consumer<EmfPlusRegionNodeData> con) throws IOException {
// A 32-bit unsigned integer that specifies the type of data in the RegionNodeData field.

View File

@ -19,7 +19,10 @@ package org.apache.poi.hemf.record.emfplus;
import java.io.IOException;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndianInputStream;
@ -56,4 +59,12 @@ public class UnimplementedHemfPlusRecord implements HemfPlusRecord {
//should probably defensively return a copy.
return recordBytes;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"flags", this::getFlags,
"recordBytes", () -> recordBytes
);
}
}

View File

@ -30,9 +30,12 @@ import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hemf.draw.HemfDrawProperties;
import org.apache.poi.hemf.draw.HemfGraphics;
import org.apache.poi.hemf.record.emf.HemfHeader;
@ -49,7 +52,7 @@ import org.apache.poi.util.Units;
* Read-only EMF extractor. Lots remain
*/
@Internal
public class HemfPicture implements Iterable<HemfRecord> {
public class HemfPicture implements Iterable<HemfRecord>, GenericRecord {
private final LittleEndianInputStream stream;
private final List<HemfRecord> records = new ArrayList<>();
private boolean isParsed = false;
@ -179,4 +182,14 @@ public class HemfPicture implements Iterable<HemfRecord> {
public Iterable<HwmfEmbedded> getEmbeddings() {
return () -> new HemfEmbeddedIterator(HemfPicture.this);
}
@Override
public List<? extends GenericRecord> getGenericChildren() {
return getRecords();
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return null;
}
}

View File

@ -17,6 +17,12 @@
package org.apache.poi.hslf.model.textproperties;
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
@ -178,5 +184,13 @@ public abstract class BitMaskTextProp extends TextProp implements Cloneable {
public BitMaskTextProp cloneAll(){
return (BitMaskTextProp)super.clone();
}
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"flags", getBitsAsString(this::getValue, subPropMasks, subPropNames)
);
}
}

View File

@ -17,6 +17,12 @@
package org.apache.poi.hslf.model.textproperties;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.sl.usermodel.TextParagraph.FontAlign;
import org.apache.poi.util.GenericRecordUtil;
/**
* Definition for the font alignment property.
*/
@ -30,4 +36,27 @@ public class FontAlignmentProp extends TextProp {
public FontAlignmentProp() {
super(2, 0x10000, NAME);
}
public FontAlign getFontAlign() {
switch (getValue()) {
default:
return FontAlign.AUTO;
case BASELINE:
return FontAlign.BASELINE;
case TOP:
return FontAlign.TOP;
case CENTER:
return FontAlign.CENTER;
case BOTTOM:
return FontAlign.BOTTOM;
}
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"fontAlign", this::getFontAlign
);
}
}

View File

@ -17,12 +17,17 @@
package org.apache.poi.hslf.model.textproperties;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.sl.usermodel.TabStop;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.Internal;
import org.apache.poi.util.Units;
@Internal
public class HSLFTabStop implements TabStop, Cloneable {
public class HSLFTabStop implements TabStop, Cloneable, GenericRecord {
/**
* A signed integer that specifies an offset, in master units, of the tab stop.
*
@ -113,4 +118,12 @@ public class HSLFTabStop implements TabStop, Cloneable {
public String toString() {
return type + " @ " + position;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"type", this::getType,
"position", this::getPosition
);
}
}

View File

@ -20,8 +20,11 @@ package org.apache.poi.hslf.model.textproperties;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.sl.usermodel.TabStop.TabStopType;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndianByteArrayInputStream;
import org.apache.poi.util.LittleEndianConsts;
@ -150,5 +153,13 @@ public class HSLFTabStopPropCollection extends TextProp {
return sb.toString();
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"tabStops", this::getTabStops
);
}
}

View File

@ -17,7 +17,12 @@
package org.apache.poi.hslf.model.textproperties;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hslf.record.TxMasterStyleAtom;
import org.apache.poi.util.GenericRecordUtil;
/**
* Definition of the indent level of some text. Defines how many
@ -25,7 +30,7 @@ import org.apache.poi.hslf.record.TxMasterStyleAtom;
*
* This is defined by the slightly confusingly named MasterTextPropRun
*/
public class IndentProp {
public class IndentProp implements GenericRecord {
private int charactersCovered;
private short indentLevel;
@ -62,4 +67,12 @@ public class IndentProp {
public void updateTextSize(int textSize) {
charactersCovered = textSize;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"charactersCovered", this::getCharactersCovered,
"indentLevel", this::getIndentLevel
);
}
}

View File

@ -17,6 +17,12 @@
package org.apache.poi.hslf.model.textproperties;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
import org.apache.poi.util.GenericRecordUtil;
/**
* Definition for the text alignment property.
*/
@ -63,4 +69,30 @@ public class TextAlignmentProp extends TextProp {
public TextAlignmentProp() {
super(2, 0x800, "alignment");
}
public TextAlign getTextAlign() {
switch (getValue()) {
default:
case LEFT:
return TextAlign.LEFT;
case CENTER:
return TextAlign.CENTER;
case RIGHT:
return TextAlign.RIGHT;
case JUSTIFY:
return TextAlign.JUSTIFY;
case DISTRIBUTED:
return TextAlign.DIST;
case THAIDISTRIBUTED:
return TextAlign.THAI_DIST;
}
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"textAlign", this::getTextAlign
);
}
}

View File

@ -21,7 +21,12 @@
*/
package org.apache.poi.hslf.model.textproperties;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.sl.usermodel.AutoNumberingScheme;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndian;
/**
@ -34,7 +39,11 @@ import org.apache.poi.util.LittleEndian;
* @author Alex Nikiforov [mailto:anikif@gmail.com]
*
*/
public class TextPFException9 {
public class TextPFException9 implements GenericRecord {
private final static AutoNumberingScheme DEFAULT_AUTONUMBER_SCHEME = AutoNumberingScheme.arabicPeriod;
private final static Short DEFAULT_START_NUMBER = 1;
//private final byte mask1;
//private final byte mask2;
private final byte mask3;
@ -42,9 +51,7 @@ public class TextPFException9 {
private final Short bulletBlipRef;
private final Short fBulletHasAutoNumber;
private final AutoNumberingScheme autoNumberScheme;
private final static AutoNumberingScheme DEFAULT_AUTONUMBER_SHEME = AutoNumberingScheme.arabicPeriod;
private final Short autoNumberStartNumber;
private final static Short DEFAULT_START_NUMBER = 1;
private final int recordLength;
public TextPFException9(final byte[] source, final int startIndex) { // NOSONAR
//this.mask1 = source[startIndex];
@ -86,23 +93,24 @@ public class TextPFException9 {
return fBulletHasAutoNumber;
}
public AutoNumberingScheme getAutoNumberScheme() {
if (null != this.autoNumberScheme) {
return this.autoNumberScheme;
if (autoNumberScheme != null) {
return autoNumberScheme;
}
if (null != this.fBulletHasAutoNumber && 1 == this.fBulletHasAutoNumber.shortValue()) {
return DEFAULT_AUTONUMBER_SHEME;
}
return null;
return hasBulletAutoNumber() ? DEFAULT_AUTONUMBER_SCHEME : null;
}
public Short getAutoNumberStartNumber() {
if (null != this.autoNumberStartNumber) {
return this.autoNumberStartNumber;
if (autoNumberStartNumber != null) {
return autoNumberStartNumber;
}
if (null != this.fBulletHasAutoNumber && 1 == this.fBulletHasAutoNumber.shortValue()) {
return DEFAULT_START_NUMBER;
}
return null;
return hasBulletAutoNumber() ? DEFAULT_START_NUMBER : null;
}
private boolean hasBulletAutoNumber() {
final Short one = 1;
return one.equals(fBulletHasAutoNumber);
}
public int getRecordLength() {
return recordLength;
}
@ -115,4 +123,14 @@ public class TextPFException9 {
sb.append("autoNumberStartNumber: ").append(this.autoNumberStartNumber).append("\n");
return sb.toString();
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"bulletBlipRef", this::getBulletBlipRef,
"bulletHasAutoNumber", this::hasBulletAutoNumber,
"autoNumberScheme", this::getAutoNumberScheme,
"autoNumberStartNumber", this::getAutoNumberStartNumber
);
}
}

View File

@ -18,6 +18,11 @@
package org.apache.poi.hslf.model.textproperties;
import java.util.Locale;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.util.GenericRecordUtil;
/**
* Definition of a property of some text, or its paragraph. Defines
@ -30,7 +35,7 @@ import java.util.Locale;
* TxMasterTextProps, the definitions of the standard
* TextProps is stored in the different record classes
*/
public class TextProp implements Cloneable {
public class TextProp implements Cloneable, GenericRecord {
private int sizeOfDataBlock; // Number of bytes the data part uses
private String propName;
private int dataValue;
@ -152,4 +157,14 @@ public class TextProp implements Cloneable {
}
return String.format(Locale.ROOT, "%s = %d (%0#"+len+"X mask / %d bytes)", getName(), getValue(), getMask(), getSize());
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"sizeOfDataBlock", this::getSize,
"propName", this::getName,
"dataValue", this::getValue,
"maskInHeader", this::getMask
);
}
}

View File

@ -21,10 +21,14 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.record.StyleTextPropAtom;
import org.apache.poi.util.HexDump;
@ -38,7 +42,7 @@ import org.apache.poi.util.POILogger;
* Used to hold the number of characters affected, the list of active
* properties, and the indent level if required.
*/
public class TextPropCollection {
public class TextPropCollection implements GenericRecord {
private static final POILogger LOG = POILogFactory.getLogger(TextPropCollection.class);
/** All the different kinds of paragraph properties we might handle */
@ -393,4 +397,15 @@ public class TextPropCollection {
return out.toString();
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
Map<String,Supplier<?>> m = new LinkedHashMap<>();
m.put("charactersCovered", this::getCharactersCovered);
m.put("indentLevel", this::getIndentLevel);
textProps.forEach((s,t) -> m.put(s, () -> t));
m.put("maskSpecial", this::getSpecialMask);
m.put("textPropType", this::getTextPropType);
return Collections.unmodifiableMap(m);
}
}

View File

@ -17,9 +17,14 @@
package org.apache.poi.hslf.record;
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
@ -36,35 +41,57 @@ public final class AnimationInfoAtom extends RecordAtom {
/**
* whether the animation plays in the reverse direction
*/
public static final int Reverse = 1;
public static final int Reverse = 0x0001;
/**
* whether the animation starts automatically
*/
public static final int Automatic = 4;
public static final int Automatic = 0x0004;
/**
* whether the animation has an associated sound
*/
public static final int Sound = 16;
public static final int Sound = 0x0010;
/**
* whether all playing sounds are stopped when this animation begins
*/
public static final int StopSound = 64;
public static final int StopSound = 0x0040;
/**
* whether an associated sound, media or action verb is activated when the shape is clicked.
*/
public static final int Play = 256;
public static final int Play = 0x0100;
/**
* specifies that the animation, while playing, stops other slide show actions.
*/
public static final int Synchronous = 1024;
public static final int Synchronous = 0x0400;
/**
* whether the shape is hidden while the animation is not playing
*/
public static final int Hide = 4096;
public static final int Hide = 0x1000;
/**
* whether the background of the shape is animated
*/
public static final int AnimateBg = 16384;
public static final int AnimateBg = 0x4000;
private static final int[] FLAGS_MASKS = {
Reverse,
Automatic,
Sound,
StopSound,
Play,
Synchronous,
Hide,
AnimateBg
};
private static final String[] FLAGS_NAMES = {
"REVERSE",
"AUTOMATIC",
"SOUND",
"STOP_SOUND",
"PLAY",
"SYNCHRONOUS",
"HIDE",
"ANIMATE_BG"
};
/**
* Record header.
@ -275,4 +302,15 @@ public final class AnimationInfoAtom extends RecordAtom {
return buf.toString();
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"dimColor", this::getDimColor,
"flags", getBitsAsString(this::getMask, FLAGS_MASKS, FLAGS_NAMES),
"soundIdRef", this::getSoundIdRef,
"delayTime", this::getDelayTime,
"orderID", this::getOrderID,
"slideCount", this::getSlideCount
);
}
}

View File

@ -19,7 +19,10 @@ package org.apache.poi.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.StringUtil;
@ -38,7 +41,6 @@ public final class CString extends RecordAtom {
private static final int MAX_RECORD_LENGTH = 1_000_000;
private byte[] _header;
private static long _type = 4026l;
/** The bytes that make up the text */
private byte[] _text;
@ -104,7 +106,9 @@ public final class CString extends RecordAtom {
/**
* We are of type 4026
*/
public long getRecordType() { return _type; }
public long getRecordType() {
return RecordTypes.CString.typeID;
}
/**
* Write the contents of the record back, so it can be written
@ -125,4 +129,9 @@ public final class CString extends RecordAtom {
public String toString() {
return getText();
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties("text", this::getText);
}
}

View File

@ -20,6 +20,10 @@ package org.apache.poi.hslf.record;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.util.LittleEndian;
@ -217,4 +221,18 @@ public final class ColorSchemeAtom extends RecordAtom {
fillsColourRGB, accentColourRGB, accentAndHyperlinkColourRGB, accentAndFollowingHyperlinkColourRGB};
return clr[idx];
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String, Supplier<?>> m = new LinkedHashMap<>();
m.put("backgroundColourRGB", this::getBackgroundColourRGB);
m.put("textAndLinesColourRGB", this::getTextAndLinesColourRGB);
m.put("shadowsColourRGB", this::getShadowsColourRGB);
m.put("titleTextColourRGB", this::getTitleTextColourRGB);
m.put("fillsColourRGB", this::getFillsColourRGB);
m.put("accentColourRGB", this::getAccentColourRGB);
m.put("accentAndHyperlinkColourRGB", this::getAccentAndHyperlinkColourRGB);
m.put("accentAndFollowingHyperlinkColourRGB", this::getAccentAndFollowingHyperlinkColourRGB);
return Collections.unmodifiableMap(m);
}
}

View File

@ -30,7 +30,7 @@ import org.apache.poi.util.POILogger;
*/
public final class Comment2000 extends RecordContainer {
private byte[] _header;
private static long _type = 12000;
private static final long _type = RecordTypes.Comment2000.typeID;
// Links to our more interesting children
@ -172,5 +172,4 @@ public final class Comment2000 extends RecordContainer {
public void writeOut(OutputStream out) throws IOException {
writeOut(_header[0],_header[1],_type,_children,out);
}
}

View File

@ -20,8 +20,11 @@ package org.apache.poi.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.hslf.util.SystemTimeUtils;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
@ -158,4 +161,14 @@ public final class Comment2000Atom extends RecordAtom
out.write(_header);
out.write(_data);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"number", this::getNumber,
"date", this::getDate,
"xOffset", this::getXOffset,
"yOffset", this::getYOffset
);
}
}

View File

@ -19,6 +19,8 @@ package org.apache.poi.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.LittleEndian;
@ -27,7 +29,7 @@ import org.apache.poi.util.LittleEndian;
*/
public final class DocInfoListContainer extends RecordContainer {
private byte[] _header;
private static long _type = RecordTypes.List.typeID;
private static final long _type = RecordTypes.List.typeID;
// Links to our more interesting children
@ -81,4 +83,8 @@ public final class DocInfoListContainer extends RecordContainer {
writeOut(_header[0],_header[1],_type,_children,out);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return null;
}
}

View File

@ -19,9 +19,14 @@ package org.apache.poi.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndianByteArrayInputStream;
import org.apache.poi.util.Removal;
/**
* A Document Atom (type 1001). Holds misc information on the PowerPoint
@ -29,11 +34,37 @@ import org.apache.poi.util.LittleEndianByteArrayInputStream;
*/
@SuppressWarnings({"WeakerAccess", "unused"})
public final class DocumentAtom extends RecordAtom
{
public final class DocumentAtom extends RecordAtom {
/**
* Holds the different Slide Size values
*/
public enum SlideSize {
/** Slide size ratio is consistent with a computer screen. */
ON_SCREEN,
/** Slide size ratio is consistent with letter paper. */
LETTER_SIZED_PAPER,
/** Slide size ratio is consistent with A4 paper. */
A4_SIZED_PAPER,
/** Slide size ratio is consistent with 35mm photo slides. */
ON_35MM,
/** Slide size ratio is consistent with overhead projector slides. */
OVERHEAD,
/** Slide size ratio is consistent with a banner. */
BANNER,
/**
* Slide size ratio that is not consistent with any of the other specified slide sizes in
* this enumeration.
*/
CUSTOM
}
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 1_000_000;
private final byte[] _header = new byte[8];
private static long _type = RecordTypes.DocumentAtom.typeID;
@ -79,9 +110,22 @@ public final class DocumentAtom extends RecordAtom
public int getFirstSlideNum() { return firstSlideNum; }
/** The Size of the Document's slides, @see DocumentAtom.SlideSize for values */
/**
* The Size of the Document's slides, @see DocumentAtom.SlideSize for values
* @deprecated to be replaced by enum
*/
@Deprecated
@Removal(version = "5.0.0")
public int getSlideSizeType() { return slideSizeType; }
public SlideSize getSlideSizeTypeEnum() {
return SlideSize.values()[slideSizeType];
}
public void setSlideSize(SlideSize size) {
slideSizeType = size.ordinal();
}
/** Was the document saved with True Type fonts embeded? */
public boolean getSaveWithFonts() {
return saveWithFonts != 0;
@ -191,16 +235,23 @@ public final class DocumentAtom extends RecordAtom
out.write(reserved);
}
/**
* Holds the different Slide Size values
*/
public static final class SlideSize {
public static final int ON_SCREEN = 0;
public static final int LETTER_SIZED_PAPER = 1;
public static final int A4_SIZED_PAPER = 2;
public static final int ON_35MM = 3;
public static final int OVERHEAD = 4;
public static final int BANNER = 5;
public static final int CUSTOM = 6;
@Override
public Map<String, Supplier<?>> getGenericProperties() {
final Map<String, Supplier<?>> m = new LinkedHashMap<>();
m.put("slideSizeX", this::getSlideSizeX);
m.put("slideSizeY", this::getSlideSizeY);
m.put("notesSizeX", this::getNotesSizeX);
m.put("notesSizeY", this::getNotesSizeY);
m.put("serverZoomFrom", this::getServerZoomFrom);
m.put("serverZoomTo", this::getServerZoomTo);
m.put("notesMasterPersist", this::getNotesMasterPersist);
m.put("handoutMasterPersist", this::getHandoutMasterPersist);
m.put("firstSlideNum", this::getFirstSlideNum);
m.put("slideSize", this::getSlideSizeTypeEnum);
m.put("saveWithFonts", this::getSaveWithFonts);
m.put("omitTitlePlace", this::getOmitTitlePlace);
m.put("rightToLeft", this::getRightToLeft);
m.put("showComments", this::getShowComments);
return Collections.unmodifiableMap(m);
}
}

View File

@ -21,6 +21,7 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.poifs.crypt.CipherAlgorithm;
@ -29,6 +30,7 @@ import org.apache.poi.poifs.crypt.EncryptionMode;
import org.apache.poi.poifs.crypt.HashAlgorithm;
import org.apache.poi.poifs.crypt.cryptoapi.CryptoAPIEncryptionHeader;
import org.apache.poi.poifs.crypt.cryptoapi.CryptoAPIEncryptionVerifier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianByteArrayOutputStream;
import org.apache.poi.util.LittleEndianInputStream;
@ -40,7 +42,7 @@ import org.apache.poi.util.LittleEndianInputStream;
* @author Nick Burch
*/
public final class DocumentEncryptionAtom extends PositionDependentRecordAtom {
private static final long _type = 12052l;
private static final long _type = RecordTypes.DocumentEncryptionAtom.typeID;
private final byte[] _header;
private EncryptionInfo ei;
@ -132,4 +134,11 @@ public final class DocumentEncryptionAtom extends PositionDependentRecordAtom {
public void updateOtherRecordReferences(Map<Integer,Integer> oldToNewReferencesLookup) {
// nothing to update
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"encryptionInfo", this::getEncryptionInfo
);
}
}

View File

@ -17,9 +17,13 @@
package org.apache.poi.hslf.record;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.ddf.EscherRecordFactory;
import org.apache.poi.ddf.EscherSerializationListener;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndian;
/**
@ -77,6 +81,18 @@ public class EscherPlaceholder extends EscherRecord {
return "ClientTextboxPlaceholder";
}
public int getPosition() {
return position;
}
public byte getPlacementId() {
return placementId;
}
public byte getSize() {
return size;
}
@Override
protected Object[][] getAttributeMap() {
return new Object[][] {
@ -86,4 +102,19 @@ public class EscherPlaceholder extends EscherRecord {
{ "unused", unused }
};
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"base", super::getGenericProperties,
"position", this::getPosition,
"placementId", this::getPlacementId,
"size", this::getSize
);
}
@Override
public Enum getGenericRecordType() {
return RecordTypes.OEPlaceholderAtom;
}
}

View File

@ -17,11 +17,14 @@
package org.apache.poi.hslf.record;
import org.apache.poi.ddf.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.ByteArrayOutputStream;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.ddf.EscherTextboxRecord;
import org.apache.poi.util.GenericRecordUtil;
/**
* A wrapper around a DDF (Escher) EscherTextbox Record. Causes the DDF
@ -118,4 +121,12 @@ public final class EscherTextboxWrapper extends RecordContainer {
public StyleTextProp9Atom getStyleTextProp9Atom() {
return this.styleTextProp9Atom;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"shapeId", this::getShapeId,
"escherRecord", this::getEscherRecord
);
}
}

View File

@ -19,7 +19,10 @@ package org.apache.poi.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndian;
/**
@ -114,4 +117,8 @@ public final class ExControlAtom extends RecordAtom {
out.write(data);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties("slideId", this::getSlideId);
}
}

View File

@ -19,7 +19,10 @@ package org.apache.poi.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
@ -166,4 +169,25 @@ public class ExEmbedAtom extends RecordAtom {
out.write(_data);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"followColorScheme", this::getFollowColorSchemeString,
"cantLockServer", this::getCantLockServerB,
"noSizeToServer", this::getNoSizeToServerB,
"isTable", this::getIsTable
);
}
private String getFollowColorSchemeString() {
switch (getFollowColorScheme()) {
default:
case DOES_NOT_FOLLOW_COLOR_SCHEME:
return "DOES_NOT_FOLLOW_COLOR_SCHEME";
case FOLLOWS_ENTIRE_COLOR_SCHEME:
return "FOLLOWS_ENTIRE_COLOR_SCHEME";
case FOLLOWS_TEXT_AND_BACKGROUND_SCHEME:
return "FOLLOWS_TEXT_AND_BACKGROUND_SCHEME";
}
}
}

View File

@ -27,9 +27,10 @@ import org.apache.poi.util.POILogger;
* @author Nick Burch
*/
public class ExHyperlink extends RecordContainer {
private static final long _type = RecordTypes.ExHyperlink.typeID;
private byte[] _header;
private static long _type = 4055;
// Links to our more interesting children
private ExHyperlinkAtom linkAtom;
private CString linkDetailsA;

View File

@ -19,7 +19,10 @@ package org.apache.poi.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
@ -114,4 +117,9 @@ public final class ExHyperlinkAtom extends RecordAtom {
out.write(_header);
out.write(_data);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties("number", this::getNumber);
}
}

View File

@ -17,9 +17,14 @@
package org.apache.poi.hslf.record;
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
@ -46,6 +51,12 @@ public final class ExMediaAtom extends RecordAtom
*/
public static final int fNarration = 4;
private static final int[] FLAG_MASKS = { fLoop, fRewind, fNarration };
private static final String[] FLAG_NAMES = { "LOOP", "REWIND", "NARRATION" };
/**
* Record header.
*/
@ -169,4 +180,11 @@ public final class ExMediaAtom extends RecordAtom
return buf.toString();
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"objectId", this::getObjectId,
"flags", getBitsAsString(this::getMask, FLAG_MASKS, FLAG_NAMES)
);
}
}

View File

@ -29,7 +29,7 @@ import org.apache.poi.util.LittleEndian;
*/
public class ExObjList extends RecordContainer {
private byte[] _header;
private static long _type = 1033;
private static final long _type = RecordTypes.ExObjList.typeID;
// Links to our more interesting children
private ExObjListAtom exObjListAtom;

View File

@ -20,7 +20,10 @@ package org.apache.poi.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
@ -116,4 +119,11 @@ public class ExObjListAtom extends RecordAtom
out.write(_header);
out.write(_data);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"objectIDSeed", this::getObjectIDSeed
);
}
}

View File

@ -17,9 +17,13 @@
package org.apache.poi.hslf.record;
import org.apache.poi.util.LittleEndian;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndian;
/**
* ExObjRefAtom (3009).
@ -91,4 +95,9 @@ public final class ExObjRefAtom extends RecordAtom {
out.write(recdata);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties("exObjIdRef", this::getExObjIdRef);
}
}

View File

@ -17,16 +17,21 @@
package org.apache.poi.hslf.record;
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import static org.apache.poi.util.GenericRecordUtil.safeEnum;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
/**
* Atom storing information for an OLE object.
*
* <!--
* offset type name description
*
* 0 uint4 drawAspect Stores whether the object can be completely seen
@ -60,12 +65,45 @@ import org.apache.poi.util.LittleEndian;
*
* 20 bool1 isBlank Set if the object's image is blank
* (note: KOffice has this as an int.)
* -->
*
* @author Daniel Noll
*/
public class ExOleObjAtom extends RecordAtom {
public enum OleType {
/** An embedded OLE object; the object is serialized and saved within the file. */
EMBEDDED,
/** A linked OLE object; the object is saved outside of the file. */
LINKED,
/** The OLE object is an ActiveX control. */
CONTROL
}
public enum Subtype {
DEFAULT,
CLIPART_GALLERY,
WORD_TABLE,
EXCEL,
GRAPH,
ORGANIZATION_CHART,
EQUATION,
WORDART,
SOUND,
IMAGE,
POWERPOINT_PRESENTATION,
POWERPOINT_SLIDE,
PROJECT,
NOTEIT,
EXCEL_CHART,
MEDIA_PLAYER
}
private static final int[] DRAWASPECT_MASKS = {
0x0001, 0x0002, 0x0004, 0x0008
};
private static final String[] DRAWASPECT_NAMES = {
"CONTENT", "THUMBNAIL", "ICON", "DOCPRINT"
};
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 10_485_760;
@ -314,4 +352,16 @@ public class ExOleObjAtom extends RecordAtom {
buf.append(" options: " + getOptions() + "\n");
return buf.toString();
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"drawAspect", getBitsAsString(this::getDrawAspect, DRAWASPECT_MASKS, DRAWASPECT_NAMES),
"type", safeEnum(OleType.values(), this::getType),
"objID", this::getObjID,
"subType", safeEnum(Subtype.values(), this::getSubType),
"objStgDataRef", this::getObjStgDataRef,
"options", this::getOptions
);
}
}

View File

@ -23,10 +23,12 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import java.util.function.Supplier;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
import org.apache.poi.util.BoundedInputStream;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
@ -185,4 +187,14 @@ public class ExOleObjStg extends PositionDependentRecordAtom implements PersistR
public void updateOtherRecordReferences(Map<Integer,Integer> oldToNewReferencesLookup) {
// nothing to update
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"compressed", this::isCompressed,
"persistId", this::getPersistId,
"dataLength", this::getDataLength,
"data", this::getData
);
}
}

View File

@ -24,6 +24,7 @@ import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.fonts.FontHeader;
import org.apache.poi.common.usermodel.fonts.FontInfo;
@ -200,4 +201,9 @@ public final class FontCollection extends RecordContainer {
public List<HSLFFontInfo> getFonts() {
return new ArrayList<>(fonts.values());
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return null;
}
}

View File

@ -19,9 +19,12 @@ package org.apache.poi.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.fonts.FontFacet;
import org.apache.poi.common.usermodel.fonts.FontHeader;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
@ -113,4 +116,9 @@ public class FontEmbeddedData extends RecordAtom implements FontFacet {
public Object getFontData() {
return this;
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties("fontHeader", this::getFontHeader);
}
}

View File

@ -17,11 +17,18 @@
package org.apache.poi.hslf.record;
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.common.usermodel.fonts.FontFamily;
import org.apache.poi.common.usermodel.fonts.FontPitch;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.StringUtil;
@ -40,6 +47,18 @@ public final class FontEntityAtom extends RecordAtom {
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 1_000_000;
private static final int[] FLAGS_MASKS = {
0x0001, 0x0100, 0x0200, 0x0400, 0x0800
};
private static final String[] FLAGS_NAMES = {
"EMBED_SUBSETTED",
"RASTER_FONT",
"DEVICE_FONT",
"TRUETYPE_FONT",
"NO_FONT_SUBSTITUTION"
};
/**
* record header
*/
@ -210,4 +229,16 @@ public final class FontEntityAtom extends RecordAtom {
out.write(_header);
out.write(_recdata);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"fontName", this::getFontName,
"fontIndex", this::getFontIndex,
"charset", this::getCharSet,
"fontFlags", getBitsAsString(this::getFontFlags, FLAGS_MASKS, FLAGS_NAMES),
"fontPitch", () -> FontPitch.valueOfPitchFamily((byte)getPitchAndFamily()),
"fontFamily", () -> FontFamily.valueOfPitchFamily((byte)getPitchAndFamily())
);
}
}

View File

@ -17,10 +17,17 @@
package org.apache.poi.hslf.record;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import static org.apache.poi.util.GenericRecordUtil.safeEnum;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
/**
* An atom record that specifies options for displaying headers and footers
@ -31,10 +38,33 @@ import java.io.OutputStream;
public final class HeadersFootersAtom extends RecordAtom {
/** FormatIndex enum without LCID mapping */
public enum FormatIndex {
SHORT_DATE,
LONG_DATE,
LONG_DATE_WITHOUT_WEEKDAY,
ALTERNATE_SHORT_DATE,
ISO_STANDARD_DATE,
SHORT_DATE_WITH_ABBREVIATED_MONTH,
SHORT_DATE_WITH_SLASHES,
ALTERNATE_SHORT_DATE_WITH_ABBREVIATED_MONTH,
ENGLISH_DATE,
MONTH_AND_YEAR,
ABBREVIATED_MONTH_AND_YEAR,
DATE_AND_HOUR12_TIME,
DATE_AND_HOUR12_TIME_WITH_SECONDS,
HOUR12_TIME,
HOUR12_TIME_WITH_SECONDS,
HOUR24_TIME,
HOUR24_TIME_WITH_SECONDS,
CHINESE1,
CHINESE2,
CHINESE3
}
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000;
/**
* A bit that specifies whether the date is displayed in the footer.
* @see #getMask()
@ -82,6 +112,21 @@ public final class HeadersFootersAtom extends RecordAtom {
*/
public static final int fHasFooter = 32;
private static final int[] PLACEHOLDER_MASKS = {
fHasDate,
fHasTodayDate,
fHasUserDate,
fHasSlideNumber,
fHasHeader,
fHasFooter
};
private static final String[] PLACEHOLDER_NAMES = {
"DATE", "TODAY_DATE", "USER_DATE", "SLIDE_NUMBER", "HEADER", "FOOTER"
};
/**
* record header
*/
@ -213,4 +258,12 @@ public final class HeadersFootersAtom extends RecordAtom {
buf.append("\t fHasFooter : " + getFlag(fHasFooter) + "\n");
return buf.toString();
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"formatIndex", safeEnum(FormatIndex.values(), this::getFormatId),
"flags", getBitsAsString(this::getMask, PLACEHOLDER_MASKS, PLACEHOLDER_NAMES)
);
}
}

View File

@ -17,12 +17,12 @@
package org.apache.poi.hslf.record;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogger;
import java.io.OutputStream;
import java.io.IOException;
/**
* A container record that specifies information about the footers on a presentation slide.
* <p>
@ -63,24 +63,39 @@ public final class HeadersFootersContainer extends RecordContainer {
System.arraycopy(source,start,_header,0,8);
_children = Record.findChildRecords(source,start+8,len-8);
for(int i=0; i < _children.length; i++){
if(_children[i] instanceof HeadersFootersAtom) hdAtom = (HeadersFootersAtom)_children[i];
else if(_children[i] instanceof CString) {
CString cs = (CString)_children[i];
findInterestingChildren();
}
/**
* Go through our child records, picking out the ones that are
* interesting, and saving those for use by the easy helper
* methods.
*/
private void findInterestingChildren() {
for (Record child : _children) {
if (child instanceof HeadersFootersAtom) {
hdAtom = (HeadersFootersAtom) child;
} else if (child instanceof CString) {
CString cs = (CString) child;
int opts = cs.getOptions() >> 4;
switch(opts){
case USERDATEATOM: csDate = cs; break;
case HEADERATOM: csHeader = cs; break;
case FOOTERATOM: csFooter = cs; break;
switch (opts) {
case USERDATEATOM:
csDate = cs;
break;
case HEADERATOM:
csHeader = cs;
break;
case FOOTERATOM:
csFooter = cs;
break;
default:
logger.log(POILogger.WARN, "Unexpected CString.Options in HeadersFootersContainer: " + opts);
break;
}
} else {
logger.log(POILogger.WARN, "Unexpected record in HeadersFootersContainer: " + _children[i]);
logger.log(POILogger.WARN, "Unexpected record in HeadersFootersContainer: " + child);
}
}
}
public HeadersFootersContainer(short options) {

View File

@ -30,7 +30,7 @@ import org.apache.poi.util.POILogger;
*/
public class InteractiveInfo extends RecordContainer {
private byte[] _header;
private static long _type = 4082;
private static final long _type = RecordTypes.InteractiveInfo.typeID;
// Links to our more interesting children
private InteractiveInfoAtom infoAtom;

View File

@ -17,9 +17,15 @@
package org.apache.poi.hslf.record;
import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import static org.apache.poi.util.GenericRecordUtil.safeEnum;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
@ -35,6 +41,39 @@ public class InteractiveInfoAtom extends RecordAtom {
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 100_000;
public enum Action {
NONE,
MACRO,
RUN_PROGRAM,
JUMP,
HYPERLINK,
OLE,
MEDIA,
CUSTOM_SHOW
}
public enum Jump {
NONE,
NEXT_SLIDE,
PREVIOUS_SLIDE,
FIRST_SLIDE,
LAST_SLIDE,
LAST_SLIDE_VIEWED,
END_SHOW
}
public enum Link {
NEXT_SLIDE,
PREVIOUS_SLIDE,
FIRST_SLIDE,
LAST_SLIDE,
CUSTOM_SHOW,
SLIDE_NUMBER,
URL,
OTHER_PRESENTATION,
OTHER_FILE,
NULL
}
/**
* Action Table
@ -73,6 +112,14 @@ public class InteractiveInfoAtom extends RecordAtom {
public static final byte LINK_OtherFile = 0x0A;
public static final byte LINK_NULL = (byte)0xFF;
private static final int[] FLAGS_MASKS = {
0x0001, 0x0002, 0x0004, 0x0008
};
private static final String[] FLAGS_NAMES = {
"ANIMATED", "STOP_SOUND", "CUSTOM_SHOW_RETURN", "VISITED"
};
/**
* Record header.
*/
@ -280,4 +327,16 @@ public class InteractiveInfoAtom extends RecordAtom {
out.write(_header);
out.write(_data);
}
@Override
public Map<String, Supplier<?>> getGenericProperties() {
return GenericRecordUtil.getGenericProperties(
"hyperlinkID", this::getHyperlinkID,
"soundRef", this::getSoundRef,
"action", safeEnum(Action.values(), this::getAction),
"jump", safeEnum(Jump.values(), this::getJump),
"hyperlinkType", safeEnum(Link.values(), this::getHyperlinkType, Link.NULL),
"flags", getBitsAsString(this::getFlags, FLAGS_MASKS, FLAGS_NAMES)
);
}
}

Some files were not shown because too many files have changed in this diff Show More