--- /dev/null
+/*
+ * ====================================================================
+ * 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; }
+}
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;
*
* @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.
}
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;
}
}
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();
+ }
+}
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;
/**
*/
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.
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;
}
/**
* 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));
}
/**
* @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
attrList.toArray()
};
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "base", super::getGenericProperties,
+ "isContainer", this::isContainerRecord
+ );
+ }
}
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;
//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;
@Override
public String getRecordName() {
- return "BSE";
+ return EscherRecordTypes.BSE.recordName;
}
/**
{ "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;
+ }
}
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;
{ "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);
+ }
+
}
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;
//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;
@Override
public String getRecordName() {
- return "Blip";
+ EscherRecordTypes t = EscherRecordTypes.forTypeID(getRecordId());
+ return (t != EscherRecordTypes.UNKNOWN ? t : EscherRecordTypes.BLIP_START).recordName;
}
/**
{ "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;
+ }
}
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;
/**
*
* @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;
@Override
public String getRecordName() {
- return "ChildAnchor";
+ return EscherRecordTypes.CHILD_ANCHOR.recordName;
}
{ "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;
+ }
}
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;
*
* @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.
@Override
public String getRecordName() {
- return "ClientAnchor";
+ return EscherRecordTypes.CLIENT_ANCHOR.recordName;
}
/**
{ "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;
+ }
}
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;
//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;
@Override
public String getRecordName() {
- return "ClientData";
+ return EscherRecordTypes.CLIENT_DATA.recordName;
}
/**
{ "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;
+ }
}
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;
* 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);
@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
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());
+ }
}
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;
@Override
public String getRecordName() {
- return "Dg";
+ return EscherRecordTypes.DG.recordName;
}
/**
{ "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;
+ }
}
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;
* 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;
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;
private void incrementUsedShapeId() {
field_2_numShapeIdsUsed++;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "drawingGroupId", this::getDrawingGroupId,
+ "numShapeIdUsed", this::getNumShapeIdsUsed
+ );
+ }
}
@Override
@Override
public String getRecordName() {
- return "Dgg";
+ return EscherRecordTypes.DGG.recordName;
}
/**
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
+ );
+ }
}
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;
//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;
* @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());
{ "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);
+ }
}
*/
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()
}
@Override
- public String getRecordName()
- {
- return "Opt";
+ public String getRecordName() {
+ return EscherRecordTypes.OPT.recordName;
}
@Override
super.setVersion( value );
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return EscherRecordTypes.OPT;
+ }
}
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;
//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;
{ "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);
+ }
}
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;
* 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);
}
}
}
+
+ @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
+ );
+ }
}
\ No newline at end of file
--- /dev/null
+/* ====================================================================
+ 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;
+ }
+
+}
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;
* 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;
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;
@Override
public String getRecordName() {
- return "Sp";
+ return EscherRecordTypes.SP.recordName;
}
/**
*/
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" : "" );
{ "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;
+ }
}
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;
* 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;
@Override
public String getRecordName() {
- return "Spgr";
+ return EscherRecordTypes.SPGR.recordName;
}
/**
{ "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;
+ }
}
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;
* 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;
@Override
public String getRecordName() {
- return "SplitMenuColors";
+ return EscherRecordTypes.SPLIT_MENU_COLORS.recordName;
}
/**
{ "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;
+ }
}
*/
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;
}
}
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;
//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];
@Override
public String getRecordName() {
- return "ClientTextbox";
+ return EscherRecordTypes.CLIENT_TEXTBOX.recordName;
}
@Override
{ "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
+ );
+ }
}
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;
{ "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;
+ }
}
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;
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:
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
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:
*/
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;
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";
// 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
+ );
+ }
}
\ No newline at end of file
==================================================================== */
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;
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);
+ }
}
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;
* 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;
* 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
*/
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);
+ }
}
\ No newline at end of file
==================================================================== */
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;
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);
+ }
}
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;
// encryptionInfo is set from outside
return other;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "secretKey", secretKey::getEncoded
+ );
+ }
}
* @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;
}
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;
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
}
}
- // 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) {
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:
* @return true if the picture data was successfully rendered
*/
boolean drawImage(Graphics2D graphics, Rectangle2D anchor, Insets clip);
+
+ default GenericRecord getGenericRecord() { return null; }
+
}
\ No newline at end of file
*/
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);
+ }
}
/**
--- /dev/null
+/*
+ * ====================================================================
+ * 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) {
+ }
+ }
+}
--- /dev/null
+/*
+ * ====================================================================
+ * 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;
+ }
+ }
+}
==================================================================== */
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;
return other;
}
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "base", super::getGenericProperties,
+ "encryptedHmacKey", this::getEncryptedHmacKey,
+ "encryptedHmacValue", this::getEncryptedHmacValue
+ );
+ }
}
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
(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);
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;
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;
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);
// 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));
}
}
}
- 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);
- }
- } 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);
+ 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);
}
- break;
+ 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();
+ }
+ }
+
+ @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;
+ }
+ }
+
}
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";
"-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);
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;
}
}
+ @Override
+ public GenericRecord getGenericRecord() {
+ return image;
+ }
}
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;
}
}
- 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 {
@Override
public String toString() {
- return "{ data: "+data+" }";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("data", this::getCommentData);
}
}
@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
+ );
}
}
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 {
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 {
assert(publicCommentIdentifier == HemfCommentRecordType.emfEndGroup.id);
return leis.getReadIndex()-startIdx;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return null;
+ }
}
public static class EmfCommentDataMultiformats implements EmfCommentData {
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 {
}
- public static class EmfCommentDataFormat {
+ public static class EmfCommentDataFormat implements GenericRecord {
private EmfFormatSignature signature;
private int version;
private int sizeData;
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() {
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;
throws IOException {
throw new RecordFormatException("UNICODE_STRING/UNICODE_END values are reserved in CommentPublic records");
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return null;
+ }
}
}
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;
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;
*/
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
@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();
+ }
}
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();
+ }
}
/**
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();
+ }
}
/**
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);
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();
+ }
}
/**
size += colorRef.init(leis);
return size;
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
public void draw(final HemfGraphics ctx) {
ctx.draw((path) -> path.moveTo(point.getX(), point.getY()), FillDrawStyle.NONE);
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
public void draw(HemfGraphics ctx) {
ctx.draw(path -> path.append(getShape(), false), getFillDrawStyle());
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
public void draw(HemfGraphics ctx) {
ctx.draw(path -> path.append(getShape(), false), getFillDrawStyle());
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
public void draw(HemfGraphics ctx) {
ctx.draw(path -> path.append(getShape(), false), getFillDrawStyle());
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
public void draw(HemfGraphics ctx) {
ctx.draw(path -> path.append(getShape(), false), FillDrawStyle.FILL_DRAW);
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
public void draw(HemfGraphics ctx) {
ctx.draw(path -> path.append(normalizeBounds(bounds), false), FillDrawStyle.FILL_DRAW);
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
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;
}
public void draw(HemfGraphics ctx) {
ctx.draw(path -> path.append(getShape(), false), FillDrawStyle.FILL_DRAW);
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
public void draw(final HemfGraphics ctx) {
ctx.draw((path) -> path.lineTo(point.getX(), point.getY()), FillDrawStyle.DRAW);
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
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. */
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 {
* 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;
* 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;
/**
* 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;
* 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;
* 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;
* 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;
@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);
}
}
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()+" }";
- }
}
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;
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;
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;
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 {
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();
+ }
}
/**
@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();
}
}
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();
+ }
}
/**
// 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;
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. */
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
+ );
+ }
}
/**
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 {
@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
+ );
}
}
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);
+ }
}
/**
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
+ );
}
}
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();
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;
}
}
- protected static class LogFontPanose implements LogFontDetails {
+ protected static class LogFontPanose implements LogFontDetails, GenericRecord {
enum FamilyType {
PAN_ANY,
PAN_NO_FIT,
@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);
}
}
@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
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;
public String getDescription() { return description; }
- public long getnPalEntries() {
+ public long getNPalEntries() {
return nPalEntries;
}
@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
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);
+ }
}
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;
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;
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 {
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;
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return 0;
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
nSavedDC = leis.readInt();
return LittleEndianConsts.INT_SIZE;
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return colorRef.init(leis);
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
bkMode = HwmfBkMode.valueOf((int) leis.readUInt());
return LittleEndianConsts.INT_SIZE;
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return super.init(leis, recordSize, (int) recordId);
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
mapMode = HwmfMapMode.valueOf((int) leis.readUInt());
return LittleEndianConsts.INT_SIZE;
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
drawMode = HwmfBinaryRasterOp.valueOf((int) leis.readUInt());
return LittleEndianConsts.INT_SIZE;
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
stretchBltMode = StretchBltMode.valueOf((int) leis.readUInt());
return LittleEndianConsts.INT_SIZE;
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
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();
}
}
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();
+ }
}
/**
objectIndex = (int) leis.readUInt();
return LittleEndianConsts.INT_SIZE;
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
@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();
}
}
@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();
}
}
@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);
}
}
@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);
}
}
@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);
}
}
@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
+ );
}
}
@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
+ );
}
}
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 {
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. */
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();
+ }
}
/**
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();
+ }
}
/**
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();
+ }
}
/**
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return 0;
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
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);
+ }
}
}
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();
* @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;
+ }
+
}
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;
* implemented at this point!
*/
@Internal
+@SuppressWarnings("WeakerAccess")
public class HemfText {
private static final int MAX_RECORD_LENGTH = 1_000_000;
*
* @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);
@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();
}
}
@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();
+ }
}
/**
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return colorRef.init(leis);
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
@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();
}
}
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;
}
}
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 {
/**
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return readDimensionInt(leis, size);
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return readPointL(leis, origin);
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return readDimensionInt(leis, extents);
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return readPointL(leis, origin);
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return readPointL(leis, offset);
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return HemfDraw.readRectL(leis, bounds);
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
public long init(LittleEndianInputStream leis, long recordSize, long recordId) throws IOException {
return HemfDraw.readRectL(leis, normalizeBounds(bounds));
}
+
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
+ }
}
/**
@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();
}
}
@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 readScale(leis, scale);
+ }
- return 4*LittleEndianConsts.INT_SIZE;
+ @Override
+ public Enum getGenericRecordType() {
+ return getEmfRecordType();
}
}
@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;
+ }
}
\ No newline at end of file
import org.apache.poi.util.LittleEndianInputStream;
@Internal
-public class UnimplementedHemfRecord implements HemfRecord {
+public class UnimplementedHemfRecord implements HemfRecordWithoutProperties {
private HemfRecordType recordType;
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;
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;
}
- public interface EmfPlusBrushData {
+ public interface EmfPlusBrushData extends GenericRecord {
/**
* This flag is meaningful in EmfPlusPathGradientBrushData objects.
*
@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
+ );
}
}
@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);
}
}
@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
+ );
}
}
@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. */
@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);
}
}
@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
+ );
}
}
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(",", "{", "}")));
- }
}
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;
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;
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;
return flags;
}
+ public int getPenId() {
+ return penId;
+ }
+
@Override
public long init(LittleEndianInputStream leis, long dataSize, long recordId, int flags) throws IOException {
this.flags = flags;
@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
+ );
}
}
@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
+ );
}
}
@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);
}
}
@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
+ );
}
}
@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
+ );
}
}
*/
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;
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. */
return size;
}
+
+ @Override
+ public String toString() {
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "flags", this::getFlags,
+ "rectData", () -> rectData
+ );
+ }
}
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;
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);
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;
+ }
}
}
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;
}
}
+ private static final int[] FLAGS_MASK = { 0x0001 };
+ private static final String[] FLAGS_NAMES = { "DUAL_MODE" };
private int flags;
private final EmfPlusGraphicsVersion version = new EmfPlusGraphicsVersion();
@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 {
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;
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;
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;
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();
@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;
+ }
}
}
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);
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;
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 {
tx.concatenate(getMatrixData());
ctx.setTransform(tx);
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "flags", this::getFlags,
+ "matrixData", this::getMatrixData
+ );
+ }
}
/**
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
+ );
+ }
}
/**
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();
// 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
+ );
+ }
}
return flags;
}
+ public int getStackIndex() {
+ return stackIndex;
+ }
+
@Override
public long init(LittleEndianInputStream leis, long dataSize, long recordId, int flags) throws IOException {
this.flags = flags;
return LittleEndianConsts.INT_SIZE;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "flags", this::getFlags,
+ "stackIndex", this::getStackIndex
+ );
+ }
}
/**
return LittleEndianConsts.INT_SIZE*2;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "flags", this::getFlags,
+ "origin", this::getOrigin
+ );
+ }
}
}
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;
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;
* 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.
*/
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;
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);
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
+ );
+ }
}
}
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;
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;
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;
return pointFlags;
}
-
+ public Point2D getPoint(int index) {
+ return pathPoints[index];
+ }
@Override
public void applyObject(HemfGraphics ctx, List<? extends EmfPlusObjectData> continuedObjectData) {
}
}
+ @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)
+ );
+ }
+ }
}
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;
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
@Internal
- public interface EmfPlusCustomLineCap {
+ public interface EmfPlusCustomLineCap extends GenericRecord {
long init(LittleEndianInputStream leis) throws IOException;
}
*/
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();
}
});
}
+
+ @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 {
*/
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;
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();
// 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.
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 {
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();
// 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.
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);
+ }
}
}
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();
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;
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;
}
public long init(LittleEndianInputStream leis) throws IOException {
return 0;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return null;
+ }
}
public static class EmfPlusRegionEmpty implements EmfPlusRegionNodeData {
public long init(LittleEndianInputStream leis) throws IOException {
return 0;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return null;
+ }
}
public static class EmfPlusRegionRect implements EmfPlusRegionNodeData {
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 {
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.
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;
//should probably defensively return a copy.
return recordBytes;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "flags", this::getFlags,
+ "recordBytes", () -> recordBytes
+ );
+ }
}
\ No newline at end of file
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;
* 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;
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;
+ }
}
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;
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)
+ );
+ }
}
\ No newline at end of file
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.
*/
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
+ );
+ }
}
\ No newline at end of file
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.
*
public String toString() {
return type + " @ " + position;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "type", this::getType,
+ "position", this::getPosition
+ );
+ }
}
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;
return sb.toString();
}
-
+
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "base", super::getGenericProperties,
+ "tabStops", this::getTabStops
+ );
+ }
}
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
*
* This is defined by the slightly confusingly named MasterTextPropRun
*/
-public class IndentProp {
+public class IndentProp implements GenericRecord {
private int charactersCovered;
private short indentLevel;
public void updateTextSize(int textSize) {
charactersCovered = textSize;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "charactersCovered", this::getCharactersCovered,
+ "indentLevel", this::getIndentLevel
+ );
+ }
}
\ No newline at end of file
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.
*/
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
+ );
+ }
}
\ No newline at end of file
*/
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;
/**
* @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;
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];
return fBulletHasAutoNumber;
}
public AutoNumberingScheme getAutoNumberScheme() {
- if (null != this.autoNumberScheme) {
- return this.autoNumberScheme;
- }
- if (null != this.fBulletHasAutoNumber && 1 == this.fBulletHasAutoNumber.shortValue()) {
- return DEFAULT_AUTONUMBER_SHEME;
+ if (autoNumberScheme != null) {
+ return autoNumberScheme;
}
- 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;
}
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
+ );
+ }
}
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
* 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;
}
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
+ );
+ }
}
\ No newline at end of file
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;
* 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 */
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);
+ }
}
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;
/**
* 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.
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
+ );
+ }
}
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;
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;
/**
* 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
public String toString() {
return getText();
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("text", this::getText);
+ }
}
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;
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);
+ }
}
*/
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
public void writeOut(OutputStream out) throws IOException {
writeOut(_header[0],_header[1],_type,_children,out);
}
-
}
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;
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
+ );
+ }
}
import java.io.IOException;
import java.io.OutputStream;
+import java.util.Map;
+import java.util.function.Supplier;
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
writeOut(_header[0],_header[1],_type,_children,out);
}
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return null;
+ }
}
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
*/
@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;
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;
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);
}
}
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;
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;
* @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;
public void updateOtherRecordReferences(Map<Integer,Integer> oldToNewReferencesLookup) {
// nothing to update
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "encryptionInfo", this::getEncryptionInfo
+ );
+ }
}
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;
/**
return "ClientTextboxPlaceholder";
}
+ public int getPosition() {
+ return position;
+ }
+
+ public byte getPlacementId() {
+ return placementId;
+ }
+
+ public byte getSize() {
+ return size;
+ }
+
@Override
protected Object[][] getAttributeMap() {
return new Object[][] {
{ "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;
+ }
}
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
public StyleTextProp9Atom getStyleTextProp9Atom() {
return this.styleTextProp9Atom;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "shapeId", this::getShapeId,
+ "escherRecord", this::getEscherRecord
+ );
+ }
}
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;
/**
out.write(data);
}
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("slideId", this::getSlideId);
+ }
}
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;
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";
+ }
+ }
}
* @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;
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;
out.write(_header);
out.write(_data);
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("number", this::getNumber);
+ }
}
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;
*/
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.
*/
return buf.toString();
}
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "objectId", this::getObjectId,
+ "flags", getBitsAsString(this::getMask, FLAG_MASKS, FLAG_NAMES)
+ );
+ }
}
*/
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;
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;
out.write(_header);
out.write(_data);
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "objectIDSeed", this::getObjectIDSeed
+ );
+ }
}
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).
out.write(recdata);
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("exObjIdRef", this::getExObjIdRef);
+ }
}
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
*
* 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;
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
+ );
+ }
}
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;
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
+ );
+ }
}
\ No newline at end of file
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;
public List<HSLFFontInfo> getFonts() {
return new ArrayList<>(fonts.values());
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return null;
+ }
}
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;
public Object getFontData() {
return this;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("fontHeader", this::getFontHeader);
+ }
}
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;
//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
*/
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())
+ );
+ }
}
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
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()
*/
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
*/
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)
+ );
+ }
}
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>
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) {
*/
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;
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;
//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
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.
*/
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)
+ );
+ }
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.function.Supplier;
import org.apache.commons.math3.util.ArithmeticUtils;
import org.apache.poi.hslf.model.textproperties.IndentProp;
+import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogger;
public List<IndentProp> getIndents() {
return Collections.unmodifiableList(indents);
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "indents", this::getIndents
+ );
+ }
}
package org.apache.poi.hslf.record;
-import org.apache.poi.util.IOUtils;
-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.IOUtils;
+import org.apache.poi.util.LittleEndian;
/**
* A Notes Atom (type 1009). Holds information on the parent Notes, such
// Reserved fields
out.write(reserved);
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "slideId", this::getSlideID,
+ "followMasterObjects", this::getFollowMasterObjects,
+ "followMasterScheme", this::getFollowMasterScheme,
+ "followMasterBackground", this::getFollowMasterBackground
+ );
+ }
}
import java.io.IOException;
import java.io.OutputStream;
+import java.util.Map;
+import java.util.function.Supplier;
import org.apache.poi.sl.usermodel.Placeholder;
+import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndian;
/**
out.write(recdata);
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "placementId", this::getPlacementId,
+ "placeholderId", this::getPlaceholderId,
+ "placeholderSize", this::getPlaceholderSize
+ );
+ }
}
package org.apache.poi.hslf.record;
-import org.apache.poi.util.LittleEndian;
-
-import java.io.OutputStream;
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;
/**
* OEPlaceholderAtom (3998).
return _index;
}
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "textIndex", this::getTextIndex
+ );
+ }
}
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
-import java.util.LinkedList;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
import org.apache.poi.ddf.DefaultEscherRecordFactory;
import org.apache.poi.ddf.EscherBoolProperty;
import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.ddf.EscherRGBProperty;
import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.ddf.EscherRecordTypes;
import org.apache.poi.ddf.EscherSimpleProperty;
import org.apache.poi.ddf.EscherSpRecord;
import org.apache.poi.ddf.EscherSpgrRecord;
import org.apache.poi.ddf.EscherTextboxRecord;
import org.apache.poi.sl.usermodel.ShapeType;
+import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogger;
// For now, pretending to be an atom. Might not always be, but that
// would require a wrapping class
-public final class PPDrawing extends RecordAtom {
+public final class PPDrawing extends RecordAtom implements Iterable<EscherRecord> {
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 10_485_760;
/**
* Get access to the underlying Escher Records
*/
+ @SuppressWarnings("WeakerAccess")
public List<EscherRecord> getEscherRecords() { return childRecords; }
+ @Override
+ public Iterator<EscherRecord> iterator() {
+ return childRecords.iterator();
+ }
+
/**
* Get access to the atoms inside Textboxes
*/
/**
* Sets everything up, groks the escher etc
*/
- protected PPDrawing(byte[] source, int start, int len) {
+ PPDrawing(byte[] source, int start, int len) {
// Get the header
_header = new byte[8];
System.arraycopy(source,start,_header,0,8);
EscherContainerRecord dgContainer = getDgContainer();
if (dgContainer != null) {
- textboxWrappers = findInDgContainer(dgContainer);
+ textboxWrappers = Stream.of(dgContainer).
+ flatMap(findEscherContainer(EscherRecordTypes.SPGR_CONTAINER)).
+ flatMap(findEscherContainer(EscherRecordTypes.SP_CONTAINER)).
+ flatMap(PPDrawing::getTextboxHelper).
+ toArray(EscherTextboxWrapper[]::new);
} else {
// Find and EscherTextboxRecord's, and wrap them up
final List<EscherTextboxWrapper> textboxes = new ArrayList<>();
findEscherTextboxRecord(childRecords, textboxes);
- this.textboxWrappers = textboxes.toArray(new EscherTextboxWrapper[textboxes.size()]);
+ this.textboxWrappers = textboxes.toArray(new EscherTextboxWrapper[0]);
}
}
- private EscherTextboxWrapper[] findInDgContainer(final EscherContainerRecord dgContainer) {
- final List<EscherTextboxWrapper> found = new LinkedList<>();
- final EscherContainerRecord spgrContainer = findFirstEscherContainerRecordOfType(RecordTypes.EscherSpgrContainer, dgContainer);
- final EscherContainerRecord[] spContainers = findAllEscherContainerRecordOfType(RecordTypes.EscherSpContainer, spgrContainer);
- for (EscherContainerRecord spContainer : spContainers) {
- EscherSpRecord sp = (EscherSpRecord)findFirstEscherRecordOfType(RecordTypes.EscherSp, spContainer);
- EscherTextboxRecord clientTextbox = (EscherTextboxRecord)findFirstEscherRecordOfType(RecordTypes.EscherClientTextbox, spContainer);
- if (null == clientTextbox) { continue; }
-
- EscherTextboxWrapper w = new EscherTextboxWrapper(clientTextbox);
- StyleTextProp9Atom nineAtom = findInSpContainer(spContainer);
- w.setStyleTextProp9Atom(nineAtom);
- if (null != sp) {
- w.setShapeId(sp.getShapeId());
- }
- found.add(w);
+
+ private static Stream<EscherTextboxWrapper> getTextboxHelper(EscherContainerRecord spContainer) {
+ Optional<EscherTextboxRecord> oTB = firstEscherRecord(spContainer, EscherRecordTypes.CLIENT_TEXTBOX);
+ if (!oTB.isPresent()) {
+ return Stream.empty();
}
- return found.toArray(new EscherTextboxWrapper[found.size()]);
+
+ EscherTextboxWrapper tbw = new EscherTextboxWrapper(oTB.get());
+ findInSpContainer(spContainer).ifPresent(tbw::setStyleTextProp9Atom);
+
+ Optional<EscherSpRecord> oSP = firstEscherRecord(spContainer, EscherRecordTypes.SP);
+ oSP.map(EscherSpRecord::getShapeId).ifPresent(tbw::setShapeId);
+
+ return Stream.of(tbw);
}
-
- private StyleTextProp9Atom findInSpContainer(final EscherContainerRecord spContainer) {
- HSLFEscherClientDataRecord cldata = spContainer.getChildById(RecordTypes.EscherClientData.typeID);
- if (cldata == null) {
- return null;
- }
- DummyPositionSensitiveRecordWithChildren progTags =
- getChildRecord(cldata.getHSLFChildRecords(), RecordTypes.ProgTags);
- if (progTags == null) {
- return null;
- }
- DummyPositionSensitiveRecordWithChildren progBinaryTag =
- (DummyPositionSensitiveRecordWithChildren)progTags.findFirstOfType(RecordTypes.ProgBinaryTag.typeID);
- if (progBinaryTag == null) {
- return null;
- }
- int size = progBinaryTag.getChildRecords().length;
- if (2 != size) { return null; }
-
- final Record r0 = progBinaryTag.getChildRecords()[0];
- final Record r1 = progBinaryTag.getChildRecords()[1];
-
- if (!(r0 instanceof CString)) { return null; }
- if (!("___PPT9".equals(((CString) r0).getText()))) { return null; }
- if (!(r1 instanceof BinaryTagDataBlob )) { return null; }
- final BinaryTagDataBlob blob = (BinaryTagDataBlob) r1;
- if (1 != blob.getChildRecords().length) { return null; }
- return (StyleTextProp9Atom) blob.findFirstOfType(RecordTypes.StyleTextProp9Atom.typeID);
+
+ private static Optional<StyleTextProp9Atom> findInSpContainer(final EscherContainerRecord spContainer) {
+ Optional<HSLFEscherClientDataRecord> oCD = firstEscherRecord(spContainer, EscherRecordTypes.CLIENT_DATA);
+ return oCD.map(HSLFEscherClientDataRecord::getHSLFChildRecords).map(List::stream).orElseGet(Stream::empty).
+ filter(sameHSLF(RecordTypes.ProgTags)).
+ flatMap(r -> Stream.of(r.getChildRecords())).
+ filter(sameHSLF(RecordTypes.ProgBinaryTag)).
+ flatMap(PPDrawing::findInProgBinaryTag).
+ findFirst();
+ }
+
+ private static Stream<StyleTextProp9Atom> findInProgBinaryTag(Record r) {
+ Record[] ch = r.getChildRecords();
+ if (ch != null &&
+ ch.length == 2 &&
+ ch[0] instanceof CString &&
+ ch[1] instanceof BinaryTagDataBlob &&
+ "___PPT9".equals(((CString)ch[0]).getText())
+ ) {
+ BinaryTagDataBlob blob = (BinaryTagDataBlob) ch[1];
+ StyleTextProp9Atom prop9 = (StyleTextProp9Atom) blob.findFirstOfType(RecordTypes.StyleTextProp9Atom.typeID);
+ if (prop9 != null) {
+ return Stream.of(prop9);
+ }
+ }
+ return Stream.empty();
}
/**
logger.log(POILogger.WARN, "Hit short DDF record at " + startPos + " - " + size);
}
- /**
+ /*
* Sanity check. Always advance the cursor by the correct value.
*
* getRecordSize() must return exactly the same number of bytes that was written in fillFields.
* @since POI 3.14-Beta2
*/
public EscherContainerRecord getDgContainer() {
- if (childRecords.isEmpty()) {
- return null;
- }
- EscherRecord r = childRecords.get(0);
- if (r instanceof EscherContainerRecord && r.getRecordId() == RecordTypes.EscherDgContainer.typeID) {
- return (EscherContainerRecord)r;
- } else {
- return null;
- }
+ return (EscherContainerRecord)firstEscherRecord(this, EscherRecordTypes.DG_CONTAINER).orElse(null);
}
/**
*/
public EscherDgRecord getEscherDgRecord(){
if (dg == null) {
- EscherContainerRecord dgr = getDgContainer();
- if (dgr != null) {
- for(EscherRecord r : dgr.getChildRecords()){
- if(r instanceof EscherDgRecord){
- dg = (EscherDgRecord)r;
- break;
- }
- }
- }
+ firstEscherRecord(this, EscherRecordTypes.DG_CONTAINER).
+ flatMap(c -> firstEscherRecord((EscherContainerRecord)c, EscherRecordTypes.DG)).
+ ifPresent(c -> dg = (EscherDgRecord)c);
}
return dg;
}
- protected EscherContainerRecord findFirstEscherContainerRecordOfType(RecordTypes type, EscherContainerRecord parent) {
- if (null == parent) { return null; }
- final List<EscherContainerRecord> children = parent.getChildContainers();
- for (EscherContainerRecord child : children) {
- if (type.typeID == child.getRecordId()) {
- return child;
- }
- }
- return null;
- }
- protected EscherRecord findFirstEscherRecordOfType(RecordTypes type, EscherContainerRecord parent) {
- if (null == parent) { return null; }
- final List<EscherRecord> children = parent.getChildRecords();
- for (EscherRecord child : children) {
- if (type.typeID == child.getRecordId()) {
- return child;
- }
- }
- return null;
- }
- protected EscherContainerRecord[] findAllEscherContainerRecordOfType(RecordTypes type, EscherContainerRecord parent) {
- if (null == parent) { return new EscherContainerRecord[0]; }
- final List<EscherContainerRecord> children = parent.getChildContainers();
- final List<EscherContainerRecord> result = new LinkedList<>();
- for (EscherContainerRecord child : children) {
- if (type.typeID == child.getRecordId()) {
- result.add(child);
- }
- }
- return result.toArray(new EscherContainerRecord[result.size()]);
+ public StyleTextProp9Atom[] getNumberedListInfo() {
+ EscherContainerRecord dgContainer = getDgContainer();
+
+ return (dgContainer == null) ? new StyleTextProp9Atom[0] : Stream.of(dgContainer).
+ flatMap(findEscherContainer(EscherRecordTypes.SPGR_CONTAINER)).
+ flatMap(findEscherContainer(EscherRecordTypes.SP_CONTAINER)).
+ map(PPDrawing::findInSpContainer).
+ filter(Optional::isPresent).
+ map(Optional::get).
+ toArray(StyleTextProp9Atom[]::new);
}
- public StyleTextProp9Atom[] getNumberedListInfo() {
- final List<StyleTextProp9Atom> result = new LinkedList<>();
- EscherContainerRecord dgContainer = getDgContainer();
- final EscherContainerRecord spgrContainer = findFirstEscherContainerRecordOfType(RecordTypes.EscherSpgrContainer, dgContainer);
- final EscherContainerRecord[] spContainers = findAllEscherContainerRecordOfType(RecordTypes.EscherSpContainer, spgrContainer);
- for (EscherContainerRecord spContainer : spContainers) {
- StyleTextProp9Atom prop9 = findInSpContainer(spContainer);
- if (prop9 != null) {
- result.add(prop9);
- }
- }
- return result.toArray(new StyleTextProp9Atom[result.size()]);
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("escherRecords", this::getEscherRecords);
}
-
- @SuppressWarnings("unchecked")
- private static <T extends Record> T getChildRecord(List<? extends Record> children, RecordTypes type) {
- for (Record r : children) {
- if (r.getRecordType() == type.typeID) {
- return (T)r;
- }
- }
- return null;
- }
+
+ private static Predicate<Record> sameHSLF(RecordTypes type) {
+ return (p) -> p.getRecordType() == type.typeID;
+ }
+
+ private static Predicate<EscherRecord> sameEscher(EscherRecordTypes type) {
+ return (p) -> p.getRecordId() == type.typeID;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T extends EscherRecord> Optional<T> firstEscherRecord(Iterable<EscherRecord> container, EscherRecordTypes type) {
+ return StreamSupport.stream(container.spliterator(), false).filter(sameEscher(type)).map(o -> (T)o).findFirst();
+ }
+
+ private static Function<EscherContainerRecord,Stream<EscherContainerRecord>> findEscherContainer(EscherRecordTypes type) {
+ return (r) -> r.getChildContainers().stream().filter(sameEscher(type));
+ }
+
}
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.util.Map;
+import java.util.function.Supplier;
+
+import org.apache.poi.ddf.DefaultEscherRecordFactory;
+import org.apache.poi.ddf.EscherContainerRecord;
+import org.apache.poi.ddf.EscherDggRecord;
+import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
-import java.io.OutputStream;
-import java.io.IOException;
-import java.io.ByteArrayOutputStream;
-import java.util.Iterator;
-
/**
* Container records which always exists inside Document.
* It always acts as a holder for escher DGG container
* which may contain which Escher BStore container information
* about pictures containes in the presentation (if any).
- *
- * @author Yegor Kozlov
*/
public final class PPDrawingGroup extends RecordAtom {
}
return dgg;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "dggContainer", this::getDggContainer
+ );
+ }
}
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
+import java.util.function.Supplier;
import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
import org.apache.poi.hslf.exceptions.HSLFException;
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.LittleEndian;
import org.apache.poi.util.POILogger;
* moves, then we have update all of these. If we come up with a new version
* of a slide, then we have to add one of these to the end of the chain
* (via CurrentUserAtom and UserEditAtom) pointing to the new slide location
- *
- * @author Nick Burch
*/
public final class PersistPtrHolder extends PositionDependentRecordAtom
*/
private Map<Integer,Integer> _slideLocations;
- private static final BitField persistIdFld = new BitField(0X000FFFFF);
- private static final BitField cntPersistFld = new BitField(0XFFF00000);
+ private static final BitField persistIdFld = BitFieldFactory.getInstance(0X000FFFFF);
+ private static final BitField cntPersistFld = BitFieldFactory.getInstance(0XFFF00000);
/**
* Return the value we were given at creation, be it 6001 or 6002
return buf;
}
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "slideLocations", this::getSlideLocationsLookup
+ );
+ }
}
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.record.RecordTypes.RecordConstructor;
* @author Nick Burch
*/
-public abstract class Record
+public abstract class Record implements GenericRecord
{
// For logging
protected static final POILogger logger = POILogFactory.getLogger(Record.class);
*/
public abstract void writeOut(OutputStream o) throws IOException;
+ @Override
+ public Enum getGenericRecordType() {
+ return RecordTypes.forTypeID((int)getRecordType());
+ }
+
+ @Override
+ public List<Record> getGenericChildren() {
+ Record[] recs = getChildRecords();
+ return (recs == null) ? null : Arrays.asList(recs);
+ }
+
/**
* When writing out, write out a signed int (32bit) in Little Endian format
*/
// Return the created record
return toReturn;
}
+
+
}
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
+import java.util.Map;
+import java.util.function.Supplier;
import org.apache.poi.hslf.util.MutableByteArrayOutputStream;
import org.apache.poi.util.ArrayUtil;
}
}
-
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return null;
+ }
}
// Records ~12050 seem to be related to Document Encryption
DocumentEncryptionAtom(12052,DocumentEncryptionAtom::new),
-
- // records greater then 0xF000 belong to with Microsoft Office Drawing format also known as Escher
- EscherDggContainer(0xF000,null),
- EscherDgg(0xf006,null),
- EscherCLSID(0xf016,null),
- EscherOPT(0xf00b,null),
- EscherBStoreContainer(0xf001,null),
- EscherBSE(0xf007,null),
- EscherBlip_START(0xf018,null),
- EscherBlip_END(0xf117,null),
- EscherDgContainer(0xf002,null),
- EscherDg(0xf008,null),
- EscherRegroupItems(0xf118,null),
- EscherColorScheme(0xf120,null),
- EscherSpgrContainer(0xf003,null),
- EscherSpContainer(0xf004,null),
- EscherSpgr(0xf009,null),
- EscherSp(0xf00a,null),
- EscherTextbox(0xf00c,null),
- EscherClientTextbox(0xf00d,null),
- EscherAnchor(0xf00e,null),
- EscherChildAnchor(0xf00f,null),
- EscherClientAnchor(0xf010,null),
- EscherClientData(0xf011,null),
- EscherSolverContainer(0xf005,null),
- EscherConnectorRule(0xf012,null),
- EscherAlignRule(0xf013,null),
- EscherArcRule(0xf014,null),
- EscherClientRule(0xf015,null),
- EscherCalloutRule(0xf017,null),
- EscherSelection(0xf119,null),
- EscherColorMRU(0xf11a,null),
- EscherDeletedPspl(0xf11d,null),
- EscherSplitMenuColors(0xf11e,null),
- EscherOleObject(0xf11f,null),
- // same as EscherTertiaryOptRecord.RECORD_ID
- EscherUserDefined(0xf122,null);
+ ;
@FunctionalInterface
public interface RecordConstructor<T extends 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;
/**
out.write(_header);
out.write(_placeholderId);
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("placeholderId", this::getPlaceholderId );
+ }
}
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.LittleEndian;
import org.apache.poi.util.LittleEndianConsts;
// public static int RESERVED5_BIT = 1 << 9;
// public static int RESERVED6_BIT = 1 << 11;
// public static int RESERVED7_BIT = 1 << 13 | 1 << 14 | 1 << 15;
-
+
+ private static final int[] EFFECT_MASKS = {
+ MANUAL_ADVANCE_BIT,
+ HIDDEN_BIT,
+ SOUND_BIT,
+ LOOP_SOUND_BIT,
+ STOP_SOUND_BIT,
+ AUTO_ADVANCE_BIT,
+ CURSOR_VISIBLE_BIT
+ };
+
+ private static final String[] EFFECT_NAMES = {
+ "MANUAL_ADVANCE",
+ "HIDDEN",
+ "SOUND",
+ "LOOP_SOUND",
+ "STOP_SOUND",
+ "AUTO_ADVANCE",
+ "CURSOR_VISIBLE"
+ };
+
private static final long _type = RecordTypes.SSSlideInfoAtom.typeID;
private byte[] _header;
public void setSpeed(short speed) {
this._speed = speed;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "effectTransitionFlags", getBitsAsString(this::getEffectTransitionFlags, EFFECT_MASKS, EFFECT_NAMES),
+ "slideTime", this::getSlideTime,
+ "soundIdRef", this::getSoundIdRef,
+ "effectDirection", this::getEffectDirection,
+ "effectType", this::getEffectType,
+ "speed", this::getSpeed
+ );
+ }
}
import java.io.IOException;
import java.io.OutputStream;
+import java.util.Map;
+import java.util.function.Supplier;
import org.apache.poi.hslf.record.SlideAtomLayout.SlideLayoutType;
+import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
// Reserved data
out.write(reserved);
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "masterID", this::getMasterID,
+ "notesID", this::getNotesID,
+ "followMasterObjects", this::getFollowMasterObjects,
+ "followMasterScheme", this::getFollowMasterScheme,
+ "followMasterBackground", this::getFollowMasterBackground,
+ "layoutAtom", this::getSSlideLayoutAtom
+ );
+ }
}
import java.io.IOException;
import java.io.OutputStream;
+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.util.GenericRecordUtil;
import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndian;
* This might eventually merged with the XSLF counterpart
*/
@Internal
-public class SlideAtomLayout {
+public class SlideAtomLayout implements GenericRecord {
// The different kinds of geometry
public enum SlideLayoutType {
/** One title and one subtitle placeholder shapes. */
out.write(placeholderIDs);
}
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "geometry", this::getGeometryType,
+ "placeholderIDs", () -> placeholderIDs
+ );
+ }
}
// For now, pretend to be an atom
public final class SlideListWithText extends RecordContainer {
+ private static final long _type = RecordTypes.SlideListWithText.typeID;
/**
* Instance filed of the record header indicates that this SlideListWithText stores
public static final int NOTES = 2;
private byte[] _header;
- private static long _type = 4080;
private SlideAtomsSet[] slideAtomsSets;
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 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;
/**
* A SlidePersist Atom (type 1011). Holds information on the text of a
* given slide, which are stored in the same SlideListWithText
- *
- * @author Nick Burch
*/
public final class SlidePersistAtom extends RecordAtom {
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 32;
- private byte[] _header;
- private static long _type = 1011l;
+ private static final long _type = 1011l;
+ private static final int HAS_SHAPES_OTHER_THAN_PLACEHOLDERS = 4;
- /**
- * Slide reference ID. Should correspond to the PersistPtr
- * "sheet ID" of the matching slide/notes record
- */
+ private static final int[] FLAGS_MASKS = { HAS_SHAPES_OTHER_THAN_PLACEHOLDERS };
+ private static final String[] FLAGS_NAMES = { "HAS_SHAPES_OTHER_THAN_PLACEHOLDERS" };
+
+
+ private final byte[] _header = new byte[8];
+
+ /** Slide reference ID. Should correspond to the PersistPtr "sheet ID" of the matching slide/notes record */
private int refID;
- private boolean hasShapesOtherThanPlaceholders;
+ private int flags;
+
/** Number of placeholder texts that will follow in the SlideListWithText */
private int numPlaceholderTexts;
- /**
- * The internal identifier (256+), which is used to tie slides
- * and notes together
- */
+ /** The internal identifier (256+), which is used to tie slides and notes together */
private int slideIdentifier;
/** Reserved fields. Who knows what they do */
private byte[] reservedFields;
- public int getRefID() { return refID; }
- public int getSlideIdentifier() { return slideIdentifier; }
- public int getNumPlaceholderTexts() { return numPlaceholderTexts; }
- public boolean getHasShapesOtherThanPlaceholders() { return hasShapesOtherThanPlaceholders; }
+ public int getRefID() {
+ return refID;
+ }
+
+ public int getSlideIdentifier() {
+ return slideIdentifier;
+ }
+
+ public int getNumPlaceholderTexts() {
+ return numPlaceholderTexts;
+ }
+
+ public boolean getHasShapesOtherThanPlaceholders() {
+ return (flags & HAS_SHAPES_OTHER_THAN_PLACEHOLDERS) != 0;
+ }
// Only set these if you know what you're doing!
public void setRefID(int id) {
if(len < 8) { len = 8; }
// Get the header
- _header = new byte[8];
System.arraycopy(source,start,_header,0,8);
// Grab the reference ID
refID = LittleEndian.getInt(source,start+8);
// Next up is a set of flags, but only bit 3 is used!
- int flags = LittleEndian.getInt(source,start+12);
- if(flags == 4) {
- hasShapesOtherThanPlaceholders = true;
- } else {
- hasShapesOtherThanPlaceholders = false;
- }
+ flags = LittleEndian.getInt(source,start+12);
// Now the number of Placeholder Texts
numPlaceholderTexts = LittleEndian.getInt(source,start+16);
/**
* Create a new SlidePersistAtom, for use with a new Slide
*/
- public SlidePersistAtom(){
- _header = new byte[8];
+ public SlidePersistAtom() {
LittleEndian.putUShort(_header, 0, 0);
LittleEndian.putUShort(_header, 2, (int)_type);
LittleEndian.putInt(_header, 4, 20);
- hasShapesOtherThanPlaceholders = true;
+ flags = HAS_SHAPES_OTHER_THAN_PLACEHOLDERS;
reservedFields = new byte[4];
}
// Header - size or type unchanged
out.write(_header);
- // Compute the flags part - only bit 3 is used
- int flags = 0;
- if(hasShapesOtherThanPlaceholders) {
- flags = 4;
- }
-
// Write out our fields
writeLittleEndian(refID,out);
writeLittleEndian(flags,out);
writeLittleEndian(slideIdentifier,out);
out.write(reservedFields);
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "refID", this::getRefID,
+ "flags", getBitsAsString(() -> flags, FLAGS_MASKS, FLAGS_NAMES),
+ "numPlaceholderTexts", this::getNumPlaceholderTexts,
+ "slideIdentifier", this::getSlideIdentifier
+ );
+ }
}
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;
out.write(_header);
out.write(_data);
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("data", this::getData);
+ }
}
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
+import java.util.function.Supplier;
import org.apache.poi.hslf.model.textproperties.TextPFException9;
+import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
// Update the size (header bytes 5-8)
LittleEndian.putInt(header, 4, data.length);
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "autoNumberSchemes", this::getAutoNumberTypes
+ );
+ }
}
\ No newline at end of file
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.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
import org.apache.poi.hslf.model.textproperties.TextPropCollection.TextPropType;
+import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
return getCharactersCovered(charStyles);
}
private int getCharactersCovered(List<TextPropCollection> styles) {
- int length = 0;
- for(TextPropCollection tpc : styles) {
- length += tpc.getCharactersCovered();
- }
- return length;
+ return styles.stream().mapToInt(TextPropCollection::getCharactersCovered).sum();
}
/* *************** record code follows ********************** */
return out.toString();
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return !initialised ? null : GenericRecordUtil.getGenericProperties(
+ "paragraphStyles", this::getParagraphStyles,
+ "characterStyles", this::getCharacterStyles
+ );
+ }
}
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.HexDump;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
out.append( HexDump.dump(_text, 0, 0) );
return out.toString();
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "text", this::getText
+ );
+ }
}
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.HexDump;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
out.append( HexDump.dump(_text, 0, 0) );
return out.toString();
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "text", this::getText
+ );
+ }
}
import java.io.IOException;
import java.io.OutputStream;
+import java.util.Map;
+import java.util.function.Supplier;
import org.apache.poi.hslf.exceptions.HSLFException;
+import org.apache.poi.sl.usermodel.TextShape.TextPlaceholder;
+import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndian;
/**
private byte[] _header;
private RecordContainer parentRecord;
- public static final int TITLE_TYPE = 0;
- public static final int BODY_TYPE = 1;
- public static final int NOTES_TYPE = 2;
- public static final int OTHER_TYPE = 4;
- public static final int CENTRE_BODY_TYPE = 5;
- public static final int CENTER_TITLE_TYPE = 6;
- public static final int HALF_BODY_TYPE = 7;
- public static final int QUARTER_BODY_TYPE = 8;
-
/** The kind of text it is */
private int textType;
/** position in the owning SlideListWithText */
public int getTextType() { return textType; }
public void setTextType(int type) { textType = type; }
-
+
+ public TextPlaceholder getTextTypeEnum() {
+ return TextPlaceholder.fromNativeId(textType);
+ }
+
+ public void setTextTypeEnum(TextPlaceholder placeholder) {
+ textType = placeholder.nativeId;
+ }
+
/**
* @return 0-based index of the text run in the SLWT container
*/
LittleEndian.putUShort(_header, 2, (int)_type);
LittleEndian.putInt(_header, 4, 4);
- textType = OTHER_TYPE;
+ textType = TextPlaceholder.OTHER.nativeId;
}
/**
// Write out our type
writeLittleEndian(textType,out);
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "index", this::getIndex,
+ "textType", this::getTextTypeEnum
+ );
+ }
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
+import java.util.function.Supplier;
import org.apache.poi.hslf.model.textproperties.HSLFTabStop;
import org.apache.poi.hslf.model.textproperties.HSLFTabStopPropCollection;
import org.apache.poi.util.BitField;
+import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianByteArrayInputStream;
this.indent[0] = (int)indent;
this.indent[1] = (int)indent;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "defaultTabSize", this::getDefaultTabSize,
+ "numLevels", this::getNumberOfLevels,
+ "tabStops", this::getTabStops,
+ "leftMargins", () -> leftMargin,
+ "indents", () -> indent
+ );
+ }
}
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.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.LittleEndianByteArrayInputStream;
return lst.toArray(new TextSpecInfoRun[lst.size()]);
}
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "charactersCovered", this::getCharactersCovered,
+ "textSpecInfoRuns", this::getTextSpecInfoRuns
+ );
+ }
}
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.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.BitField;
+import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianByteArrayInputStream;
-public class TextSpecInfoRun {
+public class TextSpecInfoRun implements GenericRecord {
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 1_000_000;
}
/** A bit that specifies whether the spellInfo field exists. */
- private static final BitField spellFld = new BitField(0X00000001);
+ private static final BitField spellFld = BitFieldFactory.getInstance(0X00000001);
/** A bit that specifies whether the lid field exists. */
- private static final BitField langFld = new BitField(0X00000002);
+ private static final BitField langFld = BitFieldFactory.getInstance(0X00000002);
/** A bit that specifies whether the altLid field exists. */
- private static final BitField altLangFld = new BitField(0X00000004);
+ private static final BitField altLangFld = BitFieldFactory.getInstance(0X00000004);
// unused1, unused2 - Undefined and MUST be ignored.
/** A bit that specifies whether the pp10runid, reserved3, and grammarError fields exist. */
- private static final BitField pp10extFld = new BitField(0X00000020);
+ private static final BitField pp10extFld = BitFieldFactory.getInstance(0X00000020);
/** A bit that specifies whether the bidi field exists. */
- private static final BitField bidiFld = new BitField(0X00000040);
+ private static final BitField bidiFld = BitFieldFactory.getInstance(0X00000040);
// unused3 - Undefined and MUST be ignored.
// reserved1 - MUST be zero and MUST be ignored.
/** A bit that specifies whether the smartTags field exists. */
- private static final BitField smartTagFld = new BitField(0X00000200);
+ private static final BitField smartTagFld = BitFieldFactory.getInstance(0X00000200);
// reserved2 - MUST be zero and MUST be ignored.
/**
* An optional unsigned integer that specifies an identifier for a character
* run that contains StyleTextProp11 data. It MUST exist if and only if pp10ext is TRUE.
**/
- private static final BitField pp10runidFld = new BitField(0X0000000F);
+ private static final BitField pp10runidFld = BitFieldFactory.getInstance(0X0000000F);
// reserved3 - An optional unsigned integer that MUST be zero, and MUST be ignored. It
// MUST exist if and only if fPp10ext is TRUE.
/**
* An optional bit that specifies a grammar error. It MUST exist if and
* only if fPp10ext is TRUE.
**/
- private static final BitField grammarErrorFld = new BitField(0X80000000);
+ private static final BitField grammarErrorFld = BitFieldFactory.getInstance(0X80000000);
+
+ private static final int[] FLAGS_MASKS = {
+ 0X00000001, 0X00000002, 0X00000004, 0X00000020, 0X00000040, 0X00000200,
+ };
+
+ private static final String[] FLAGS_NAMES = {
+ "SPELL", "LANG", "ALT_LANG", "PP10_EXT", "BIDI", "SMART_TAG"
+ };
//Length of special info run.
private int length;
// if both parameters are invalid, remove the extension mask
mask = pp10extFld.setBoolean(mask, pp10extMask != -1);
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ final Map<String,Supplier<?>> m = new LinkedHashMap<>();
+ m.put("flags", getBitsAsString(() -> mask, FLAGS_MASKS, FLAGS_NAMES));
+ m.put("spellInfo", this::getSpellInfo);
+ m.put("langId", this::getLangId);
+ m.put("altLangId", this::getAltLangId);
+ m.put("bidi", this::getBidi);
+ m.put("pp10RunId", this::getPP10RunId);
+ m.put("grammarError", this::getGrammarError);
+ m.put("smartTags", this::getSmartTagsBytes);
+ return Collections.unmodifiableMap(m);
+ }
}
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 java.io.OutputStream;
-import java.io.IOException;
-
/**
* Tne atom that holds starting and ending character positions of a hyperlink
*
out.write(_header);
out.write(_data);
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "startIndex", this::getStartIndex,
+ "endIndex", this::getEndIndex
+ );
+ }
}
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.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
import org.apache.poi.hslf.model.textproperties.TextPropCollection.TextPropType;
+import org.apache.poi.sl.usermodel.TextShape.TextPlaceholder;
+import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianOutputStream;
* each pair describes an indent level. The first pair describes
* first-level paragraph with no indentation.
* </p>
- *
- * @author Yegor Kozlov
*/
public final class TxMasterStyleAtom extends RecordAtom {
private static final POILogger LOG = POILogFactory.getLogger(TxMasterStyleAtom.class);
*/
public static final int MAX_INDENT = 5;
+ private static final long _type = RecordTypes.TxMasterStyleAtom.typeID;
+
private byte[] _header;
- private static long _type = 4003;
private byte[] _data;
private List<TextPropCollection> paragraphStyles;
for(short i = 0; i < levels; i++) {
TextPropCollection prprops = new TextPropCollection(0, TextPropType.paragraph);
- if (type >= TextHeaderAtom.CENTRE_BODY_TYPE) {
+ if (type >= TextPlaceholder.CENTER_BODY.nativeId) {
// Fetch the 2 byte value, that is safe to ignore for some types of text
short indentLevel = LittleEndian.getShort(_data, pos);
prprops.setIndentLevel(indentLevel);
for (int i=0; i<levels; i++) {
prdummy.copy(paragraphStyles.get(i));
chdummy.copy(charStyles.get(i));
- if (type >= TextHeaderAtom.CENTRE_BODY_TYPE) {
+ if (type >= TextPlaceholder.CENTER_BODY.nativeId) {
leos.writeShort(prdummy.getIndentLevel());
}
throw new HSLFException("error in updating master style properties", e);
}
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "paragraphStyles", this::getParagraphStyles,
+ "charStyles", this::getCharacterStyles
+ );
+ }
}
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;
public void writeOut(OutputStream out) throws IOException {
out.write(_contents);
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("contents", () -> _contents);
+ }
}
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;
* ** WARNING ** stores byte offsets from the start of the PPT stream to
* other records! If you change the size of any elements before one of
* these, you'll need to update the offsets!
- *
- * @author Nick Burch
*/
public final class UserEditAtom extends PositionDependentRecordAtom
public static final int LAST_VIEW_NOTES = 3;
private byte[] _header;
- private static long _type = 4085l;
+ private static final long _type = RecordTypes.UserEditAtom.typeID;
private short unused;
private int lastViewedSlideID;
writeLittleEndian(encryptSessionPersistIdRef,out);
}
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ final Map<String, Supplier<?>> m = new LinkedHashMap<>();
+ m.put("lastViewedSlideID", this::getLastViewedSlideID);
+ m.put("pptVersion", () -> pptVersion);
+ m.put("lastUserEditAtomOffset", this::getLastUserEditAtomOffset);
+ m.put("persistPointersOffset", this::getPersistPointersOffset);
+ m.put("docPersistRef", this::getDocPersistRef);
+ m.put("maxPersistWritten", this::getMaxPersistWritten);
+ m.put("lastViewType", this::getLastViewType);
+ m.put("encryptSessionPersistIdRef", this::getEncryptSessionPersistIdRef);
+ return Collections.unmodifiableMap(m);
+ }
}
package org.apache.poi.hslf.record;
-import java.io.ByteArrayOutputStream;
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;
/**
this.version = version;
}
-
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "persistIdRef", this::getPersistIdRef,
+ "hasMacros", this::isHasMacros,
+ "version", this::getVersion
+ );
+ }
}
*/
public final class VBAInfoContainer extends RecordContainer {
private byte[] _header;
- private static long _type = RecordTypes.VBAInfo.typeID;
+ private static final long _type = RecordTypes.VBAInfo.typeID;
// Links to our more interesting children
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.ddf.EscherRecordTypes;
import org.apache.poi.ddf.EscherSimpleProperty;
import org.apache.poi.hslf.record.Document;
-import org.apache.poi.hslf.record.RecordTypes;
import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.usermodel.ColorStyle;
import org.apache.poi.sl.usermodel.FillStyle;
private boolean isRotatedWithShape() {
// NOFILLHITTEST can be in the normal escher opt record but also in the tertiary record
// the extended bit fields seem to be in the second
- AbstractEscherOptRecord opt = shape.getEscherChild(RecordTypes.EscherUserDefined);
+ AbstractEscherOptRecord opt = shape.getEscherChild(EscherRecordTypes.USER_DEFINED);
EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST);
int propVal = (p == null) ? 0 : p.getPropertyValue();
return FILL_USE_USE_SHAPE_ANCHOR.isSet(propVal) && FILL_USE_SHAPE_ANCHOR.isSet(propVal);
import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.ddf.EscherProperty;
import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.ddf.EscherRecordTypes;
import org.apache.poi.ddf.EscherSimpleProperty;
import org.apache.poi.ddf.EscherSpRecord;
import org.apache.poi.ddf.EscherTextboxRecord;
import org.apache.poi.hslf.record.ColorSchemeAtom;
import org.apache.poi.hslf.record.HSLFEscherClientDataRecord;
import org.apache.poi.hslf.record.Record;
-import org.apache.poi.hslf.record.RecordTypes;
import org.apache.poi.sl.draw.DrawFactory;
import org.apache.poi.sl.usermodel.FillStyle;
import org.apache.poi.sl.usermodel.PresetColor;
/**
* @since POI 3.14-Beta2
*/
- public static <T extends EscherRecord> T getEscherChild(EscherContainerRecord owner, RecordTypes recordId){
+ public static <T extends EscherRecord> T getEscherChild(EscherContainerRecord owner, EscherRecordTypes recordId){
return getEscherChild(owner, recordId.typeID);
}
/**
* @since POI 3.14-Beta2
*/
- public <T extends EscherRecord> T getEscherChild(RecordTypes recordId){
+ public <T extends EscherRecord> T getEscherChild(EscherRecordTypes recordId){
return getEscherChild(recordId.typeID);
}
}
public AbstractEscherOptRecord getEscherOptRecord() {
- AbstractEscherOptRecord opt = getEscherChild(RecordTypes.EscherOPT);
+ AbstractEscherOptRecord opt = getEscherChild(EscherRecordTypes.OPT);
if (opt == null) {
- opt = getEscherChild(RecordTypes.EscherUserDefined);
+ opt = getEscherChild(EscherRecordTypes.USER_DEFINED);
}
return opt;
}
import org.apache.poi.ddf.EscherProperty;
import org.apache.poi.ddf.EscherPropertyFactory;
import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.ddf.EscherRecordTypes;
import org.apache.poi.ddf.EscherSimpleProperty;
import org.apache.poi.ddf.EscherSpRecord;
import org.apache.poi.ddf.EscherTextboxRecord;
public static HSLFGroupShape createShapeGroup(EscherContainerRecord spContainer, ShapeContainer<HSLFShape,HSLFTextParagraph> parent){
boolean isTable = false;
EscherContainerRecord ecr = (EscherContainerRecord)spContainer.getChild(0);
- EscherRecord opt = HSLFShape.getEscherChild(ecr, RecordTypes.EscherUserDefined);
+ EscherRecord opt = HSLFShape.getEscherChild(ecr, EscherRecordTypes.USER_DEFINED);
if (opt != null) {
EscherPropertyFactory f = new EscherPropertyFactory();
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherDgRecord;
import org.apache.poi.ddf.EscherDggRecord;
+import org.apache.poi.ddf.EscherRecordTypes;
import org.apache.poi.ddf.EscherSpRecord;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.model.HeadersFooters;
import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.sl.usermodel.ShapeType;
import org.apache.poi.sl.usermodel.Slide;
+import org.apache.poi.sl.usermodel.TextShape.TextPlaceholder;
/**
* This class represents a slide in a PowerPoint Document. It allows
for (EscherContainerRecord c : dgContainer.getChildContainers()) {
EscherSpRecord spr = null;
- switch(c.getRecordId()){
- case EscherContainerRecord.SPGR_CONTAINER:
+ switch(EscherRecordTypes.forTypeID(c.getRecordId())){
+ case SPGR_CONTAINER:
EscherContainerRecord dc = (EscherContainerRecord)c.getChild(0);
spr = dc.getChildById(EscherSpRecord.RECORD_ID);
break;
- case EscherContainerRecord.SP_CONTAINER:
+ case SP_CONTAINER:
spr = c.getChildById(EscherSpRecord.RECORD_ID);
break;
default:
HSLFPlaceholder pl = new HSLFPlaceholder();
pl.setShapeType(ShapeType.RECT);
pl.setPlaceholder(Placeholder.TITLE);
- pl.setRunType(TextHeaderAtom.TITLE_TYPE);
+ pl.setRunType(TextPlaceholder.TITLE.nativeId);
pl.setText("Click to edit title");
pl.setAnchor(new java.awt.Rectangle(54, 48, 612, 90));
addShape(pl);
continue;
}
int type = tp.get(0).getRunType();
- switch (type) {
- case TextHeaderAtom.CENTER_TITLE_TYPE:
- case TextHeaderAtom.TITLE_TYPE:
- String str = HSLFTextParagraph.getRawText(tp);
- return HSLFTextParagraph.toExternalString(str, type);
- }
+ if (TextPlaceholder.isTitle(type)) {
+ String str = HSLFTextParagraph.getRawText(tp);
+ return HSLFTextParagraph.toExternalString(str, type);
+ }
}
return null;
}
import org.apache.poi.hslf.record.MainMaster;
import org.apache.poi.hslf.record.TextHeaderAtom;
import org.apache.poi.hslf.record.TxMasterStyleAtom;
+import org.apache.poi.sl.usermodel.TextShape.TextPlaceholder;
import org.apache.poi.util.Internal;
/**
}
}
- switch (txtype) {
- case TextHeaderAtom.CENTRE_BODY_TYPE:
- case TextHeaderAtom.HALF_BODY_TYPE:
- case TextHeaderAtom.QUARTER_BODY_TYPE:
- return getPropCollection(TextHeaderAtom.BODY_TYPE, level, name, isCharacter);
- case TextHeaderAtom.CENTER_TITLE_TYPE:
- return getPropCollection(TextHeaderAtom.TITLE_TYPE, level, name, isCharacter);
+ switch (TextPlaceholder.fromNativeId(txtype)) {
+ case BODY:
+ case CENTER_BODY:
+ case HALF_BODY:
+ case QUARTER_BODY:
+ return getPropCollection(TextPlaceholder.BODY.nativeId, level, name, isCharacter);
+ case TITLE:
+ case CENTER_TITLE:
+ return getPropCollection(TextPlaceholder.TITLE.nativeId, level, name, isCharacter);
default:
return null;
}
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.function.Supplier;
+import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.common.usermodel.fonts.FontInfo;
import org.apache.poi.ddf.EscherBSERecord;
import org.apache.poi.ddf.EscherContainerRecord;
* TODO: - figure out how to match notes to their correct sheet (will involve
* understanding DocSlideList and DocNotesList) - handle Slide creation cleaner
*/
-public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagraph>, Closeable {
+public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagraph>, Closeable, GenericRecord {
//arbitrarily selected; may need to increase
private static final int MAX_RECORD_LENGTH = 10_000_000;
public Object getPersistDocument() {
return getSlideShowImpl();
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return null;
+ }
+
+ @Override
+ public List<? extends GenericRecord> getGenericChildren() {
+ return Arrays.asList(_hslfSlideShow.getRecords());
+ }
}
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherOptRecord;
import org.apache.poi.ddf.EscherProperties;
+import org.apache.poi.ddf.EscherRecordTypes;
import org.apache.poi.ddf.EscherSimpleProperty;
-import org.apache.poi.hslf.record.RecordTypes;
import org.apache.poi.sl.usermodel.ShapeContainer;
import org.apache.poi.sl.usermodel.TableShape;
import org.apache.poi.util.LittleEndian;
EscherContainerRecord spCont = (EscherContainerRecord) getSpContainer().getChild(0);
AbstractEscherOptRecord opt = new EscherOptRecord();
- opt.setRecordId(RecordTypes.EscherUserDefined.typeID);
+ opt.setRecordId(EscherRecordTypes.USER_DEFINED.typeID);
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GROUPSHAPE__TABLEPROPERTIES, 1));
EscherArrayProperty p = new EscherArrayProperty((short)(0x4000 | EscherProperties.GROUPSHAPE__TABLEROWPROPERTIES), false, null);
p.setSizeOfElements(0x0004);
p.setNumberOfElementsInArray(numRows);
p.setNumberOfElementsInMemory(numRows);
opt.addEscherProperty(p);
- spCont.addChildBefore(opt, RecordTypes.EscherClientAnchor.typeID);
+ spCont.addChildBefore(opt, EscherRecordTypes.CLIENT_ANCHOR.typeID);
}
/**
}
// update row height in the table properties
- AbstractEscherOptRecord opt = getEscherChild(RecordTypes.EscherUserDefined.typeID);
+ AbstractEscherOptRecord opt = getEscherChild(EscherRecordTypes.USER_DEFINED);
EscherArrayProperty p = opt.lookup(EscherProperties.GROUPSHAPE__TABLEROWPROPERTIES);
byte[] masterBytes = p.getElement(row);
double currentHeight = Units.masterToPoints(LittleEndian.getInt(masterBytes, 0));
}
private void updateRowHeightsProperty() {
- AbstractEscherOptRecord opt = getEscherChild(RecordTypes.EscherUserDefined.typeID);
+ AbstractEscherOptRecord opt = getEscherChild(EscherRecordTypes.USER_DEFINED);
EscherArrayProperty p = opt.lookup(EscherProperties.GROUPSHAPE__TABLEROWPROPERTIES);
byte[] val = new byte[4];
for (int rowIdx = 0; rowIdx < cells.length; rowIdx++) {
import org.apache.poi.sl.usermodel.TabStop;
import org.apache.poi.sl.usermodel.TabStop.TabStopType;
import org.apache.poi.sl.usermodel.TextParagraph;
+import org.apache.poi.sl.usermodel.TextShape.TextPlaceholder;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.StringUtil;
// them to \n
String text = rawText.replace('\r', '\n');
- switch (runType) {
- // 0xB acts like cariage return in page titles and like blank in the
- // others
- case -1:
- case org.apache.poi.hslf.record.TextHeaderAtom.TITLE_TYPE:
- case org.apache.poi.hslf.record.TextHeaderAtom.CENTER_TITLE_TYPE:
- text = text.replace((char) 0x0B, '\n');
- break;
- default:
- text = text.replace((char) 0x0B, ' ');
- break;
- }
+ // 0xB acts like carriage return in page titles and like blank in the others
+ final char repl = (runType == -1 ||
+ runType == TextPlaceholder.TITLE.nativeId ||
+ runType == TextPlaceholder.CENTER_TITLE.nativeId) ? '\n' : ' ';
- return text;
+ return text.replace('\u000b', repl);
}
/**
import static org.apache.poi.hslf.record.RecordTypes.OEPlaceholderAtom;
import static org.apache.poi.hslf.record.RecordTypes.RoundTripHFPlaceholder12;
+import static org.apache.poi.sl.usermodel.TextShape.TextPlaceholder.CENTER_TITLE;
+import static org.apache.poi.sl.usermodel.TextShape.TextPlaceholder.TITLE;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
/* package */ HSLFTextAnchor getAlignment(){
AbstractEscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT);
- HSLFTextAnchor align = HSLFTextAnchor.TOP;
+ final HSLFTextAnchor align;
if (prop == null){
/**
* If vertical alignment was not found in the shape properties then try to
HSLFSheet sh = getSheet();
HSLFMasterSheet master = (sh != null) ? sh.getMasterSheet() : null;
HSLFTextShape masterShape = (master != null) ? master.getPlaceholderByTextType(type) : null;
- if (masterShape != null && type != TextHeaderAtom.OTHER_TYPE) {
+ if (masterShape != null && type != TextPlaceholder.OTHER.nativeId) {
align = masterShape.getAlignment();
} else {
//not found in the master sheet. Use the hardcoded defaults.
- switch (type){
- case TextHeaderAtom.TITLE_TYPE:
- case TextHeaderAtom.CENTER_TITLE_TYPE:
- align = HSLFTextAnchor.MIDDLE;
- break;
- default:
- align = HSLFTextAnchor.TOP;
- break;
- }
+ align = (TextPlaceholder.isTitle(type)) ? HSLFTextAnchor.MIDDLE : HSLFTextAnchor.TOP;
}
} else {
align = HSLFTextAnchor.fromNativeId(prop.getPropertyValue());
}
- if (align == null) {
- align = HSLFTextAnchor.TOP;
- }
-
- return align;
+ return (align == null) ? HSLFTextAnchor.TOP : align;
}
/**
switch (placeholder) {
default:
case BODY:
- runType = TextHeaderAtom.BODY_TYPE;
+ runType = TextPlaceholder.BODY.nativeId;
ph = Placeholder.BODY;
break;
case TITLE:
- runType = TextHeaderAtom.TITLE_TYPE;
+ runType = TITLE.nativeId;
ph = Placeholder.TITLE;
break;
case CENTER_BODY:
- runType = TextHeaderAtom.CENTRE_BODY_TYPE;
+ runType = TextPlaceholder.CENTER_BODY.nativeId;
ph = Placeholder.BODY;
break;
case CENTER_TITLE:
- runType = TextHeaderAtom.CENTER_TITLE_TYPE;
+ runType = CENTER_TITLE.nativeId;
ph = Placeholder.TITLE;
break;
case HALF_BODY:
- runType = TextHeaderAtom.HALF_BODY_TYPE;
+ runType = TextPlaceholder.HALF_BODY.nativeId;
ph = Placeholder.BODY;
break;
case QUARTER_BODY:
- runType = TextHeaderAtom.QUARTER_BODY_TYPE;
+ runType = TextPlaceholder.QUARTER_BODY.nativeId;
ph = Placeholder.BODY;
break;
case NOTES:
- runType = TextHeaderAtom.NOTES_TYPE;
+ runType = TextPlaceholder.NOTES.nativeId;
break;
case OTHER:
- runType = TextHeaderAtom.OTHER_TYPE;
+ runType = TextPlaceholder.OTHER.nativeId;
break;
}
setRunType(runType);
@Override
public TextPlaceholder getTextPlaceholder() {
- switch (getRunType()) {
- default:
- case TextHeaderAtom.BODY_TYPE: return TextPlaceholder.BODY;
- case TextHeaderAtom.TITLE_TYPE: return TextPlaceholder.TITLE;
- case TextHeaderAtom.NOTES_TYPE: return TextPlaceholder.NOTES;
- case TextHeaderAtom.OTHER_TYPE: return TextPlaceholder.OTHER;
- case TextHeaderAtom.CENTRE_BODY_TYPE: return TextPlaceholder.CENTER_BODY;
- case TextHeaderAtom.CENTER_TITLE_TYPE: return TextPlaceholder.CENTER_TITLE;
- case TextHeaderAtom.HALF_BODY_TYPE: return TextPlaceholder.HALF_BODY;
- case TextHeaderAtom.QUARTER_BODY_TYPE: return TextPlaceholder.QUARTER_BODY;
- }
+ return TextPlaceholder.fromNativeId(getRunType());
}
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
-import java.awt.geom.Area;
import java.awt.geom.Dimension2D;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.TreeMap;
+import java.util.function.BiConsumer;
import org.apache.commons.codec.Charsets;
import org.apache.poi.common.usermodel.fonts.FontCharset;
public class HwmfGraphics {
public enum FillDrawStyle {
- NONE, FILL, DRAW, FILL_DRAW
+ NONE(FillDrawStyle::fillNone),
+ FILL(HwmfGraphics::fill),
+ DRAW(HwmfGraphics::draw),
+ FILL_DRAW(FillDrawStyle::fillDraw);
+
+ public final BiConsumer<HwmfGraphics,Shape> handler;
+
+ FillDrawStyle(BiConsumer<HwmfGraphics,Shape> handler) {
+ this.handler = handler;
+ }
+
+ private static void fillNone(HwmfGraphics g, Shape s) {
+ }
+
+ private static void fillDraw(HwmfGraphics g, Shape s) {
+ g.fill(s);
+ g.draw(s);
+ }
}
protected final List<HwmfDrawProperties> propStack = new LinkedList<>();
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.hwmf.usermodel.HwmfPicture;
import org.apache.poi.sl.draw.BitmapImageRenderer;
import org.apache.poi.sl.draw.DrawPictureShape;
return true;
}
}
+
+ @Override
+ public GenericRecord getGenericRecord() {
+ return image;
+ }
}
import java.awt.image.BufferedImage;
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.common.usermodel.GenericRecord;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
-public class HwmfBitmap16 {
- final boolean isPartial;
- int type;
- int width;
- int height;
- int widthBytes;
- int planes;
- int bitsPixel;
-
+public class HwmfBitmap16 implements GenericRecord {
+ private final boolean isPartial;
+ private int type;
+ private int width;
+ private int height;
+ private int widthBytes;
+ private int planes;
+ private int bitsPixel;
+ private byte[] bitmap;
+
public HwmfBitmap16() {
this(false);
}
}
int length = (((width * bitsPixel + 15) >> 4) << 1) * height;
- /*byte buf[] =*/ IOUtils.toByteArray(leis, length);
+ bitmap = IOUtils.toByteArray(leis, length);
// TODO: this is not implemented ... please provide a sample, if it
// ever happens to you, to come here ...
public BufferedImage getImage() {
return new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ final Map<String,Supplier<?>> m = new LinkedHashMap<>();
+ m.put("isPartial", () -> isPartial);
+ m.put("type", () -> type);
+ m.put("width", () -> width);
+ m.put("height", () -> height);
+ m.put("widthBytes", () -> widthBytes);
+ m.put("planes", () -> planes);
+ m.put("bitsPixel", () -> bitsPixel);
+ m.put("bitmap", () -> bitmap);
+ return Collections.unmodifiableMap(m);
+ }
}
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.function.Supplier;
import javax.imageio.ImageIO;
+import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hwmf.usermodel.HwmfPicture;
+import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianConsts;
/**
* The DeviceIndependentBitmap Object defines an image in device-independent bitmap (DIB) format.
*/
-public class HwmfBitmapDib {
+public class HwmfBitmapDib implements GenericRecord {
private static final POILogger logger = POILogFactory.getLogger(HwmfBitmapDib.class);
private static final int BMP_HEADER_SIZE = 14;
}
public byte[] getBMPData() {
+ if (headerWidth <= 0 || headerHeight <= 0) {
+ return null;
+ }
+
if (imageData == null) {
- throw new RecordFormatException("bitmap not initialized ... need to call init() before");
+ throw new RecordFormatException("used to throw exception: bitmap not initialized ... need to call init() before");
}
// sometimes there are missing bytes after the imageData which will be 0-filled
@Override
public String toString() {
- return
- "{ headerSize: " + headerSize +
- ", width: " + headerWidth +
- ", height: " + headerHeight +
- ", planes: " + headerPlanes +
- ", bitCount: '" + headerBitCount + "'" +
- ", compression: '" + headerCompression + "'" +
- ", imageSize: " + headerImageSize +
- ", xPelsPerMeter: " + headerXPelsPerMeter +
- ", yPelsPerMeter: " + headerYPelsPerMeter +
- ", colorUsed: " + headerColorUsed +
- ", colorImportant: " + headerColorImportant +
- ", imageSize: " + (imageData == null ? 0 : imageData.length) +
- "}";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ final Map<String,Supplier<?>> m = new LinkedHashMap<>();
+ m.put("headerSize", () -> headerSize);
+ m.put("width", () -> headerWidth);
+ m.put("height", () -> headerHeight);
+ m.put("planes", () -> headerPlanes);
+ m.put("bitCount", () -> headerBitCount);
+ m.put("compression", () -> headerCompression);
+ m.put("imageSize", () -> headerImageSize);
+ m.put("xPelsPerMeter", () -> headerXPelsPerMeter);
+ m.put("yPelsPerMeter", () -> headerYPelsPerMeter);
+ m.put("colorUsed", () -> headerColorUsed);
+ m.put("colorImportant", () -> headerColorImportant);
+ m.put("image", this::getImage);
+ m.put("bmpData", this::getBMPData);
+ return Collections.unmodifiableMap(m);
}
protected BufferedImage getPlaceholder() {
+ if (headerHeight <= 0 || headerWidth <= 0) {
+ return new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
+ }
+
BufferedImage bi = new BufferedImage(headerWidth, headerHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
import java.awt.Color;
import java.io.IOException;
-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.GenericRecordJsonWriter;
+import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
* Blue (1 byte): An 8-bit unsigned integer that defines the relative intensity of blue.
* Reserved (1 byte): An 8-bit unsigned integer that MUST be 0x00.
*/
-public class HwmfColorRef implements Cloneable {
+public class HwmfColorRef implements Cloneable, GenericRecord {
private Color colorRef = Color.BLACK;
public HwmfColorRef() {}
@Override
public String toString() {
- return String.format(Locale.ROOT, "%#08X", colorRef.getRGB()&0xFFFFFF);
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("color", colorRef::getRGB);
}
}
package org.apache.poi.hwmf.record;
import java.awt.Shape;
-import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Area;
import java.awt.geom.Dimension2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
-import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
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.hwmf.draw.HwmfGraphics;
import org.apache.poi.hwmf.draw.HwmfGraphics.FillDrawStyle;
+import org.apache.poi.util.Dimension2DDouble;
+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;
-public class HwmfDraw {
+@SuppressWarnings("WeakerAccess")
+public final class HwmfDraw {
+
+ private HwmfDraw() {}
+
/**
* The META_MOVETO record sets the output position in the playback device context to a specified
* point.
@Override
public String toString() {
- return pointToString(point);
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public Point2D getPoint() {
+ return point;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("point", this::getPoint);
}
}
@Override
public String toString() {
- return pointToString(point);
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public Point2D getPoint() {
+ return point;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("point", this::getPoint);
}
}
@Override
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- /**
- * A 16-bit signed integer that defines the number of points in the array.
- */
+ //A 16-bit signed integer that defines the number of points in the array.
int numberofPoints = leis.readShort();
poly = new Path2D.Double(Path2D.WIND_EVEN_ODD, numberofPoints);
Path2D p = (Path2D)poly.clone();
// don't close the path
p.setWindingRule(ctx.getProperties().getWindingRule());
- switch (getFillDrawStyle()) {
- case FILL:
- ctx.fill(p);
- break;
- case DRAW:
- ctx.draw(p);
- break;
- case FILL_DRAW:
- ctx.fill(p);
- ctx.draw(p);
- break;
- }
+ getFillDrawStyle().handler.accept(ctx, p);
}
@Override
public String toString() {
- return "{ poly: "+polyToString(poly)+" }";
+ return GenericRecordJsonWriter.marshal(this);
}
/**
protected FillDrawStyle getFillDrawStyle() {
return FillDrawStyle.FILL;
}
+
+ public Path2D getPoly() {
+ return poly;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("poly", this::getPoly);
+ }
}
/**
@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);
}
}
* Brush to use for filling the region.
*/
protected int brushIndex;
+
/**
- * A 16-bit signed integer that defines the height, in logical units, of the
- * region frame.
- */
- protected int height;
- /**
- * A 16-bit signed integer that defines the width, in logical units, of the
- * region frame.
+ * The region frame, in logical units
*/
- protected int width;
+ protected final Dimension2D frame = new Dimension2DDouble();
@Override
public HwmfRecordType getWmfRecordType() {
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
regionIndex = leis.readUShort();
brushIndex = leis.readUShort();
- height = leis.readShort();
- width = leis.readShort();
+ // A 16-bit signed integer that defines the height/width, in logical units, of the region frame.
+ int height = leis.readShort();
+ int width = leis.readShort();
+ frame.setSize(width, height);
return 4*LittleEndianConsts.SHORT_SIZE;
}
ctx.applyObjectTableEntry(brushIndex);
ctx.applyObjectTableEntry(regionIndex);
Rectangle2D inner = ctx.getProperties().getRegion().getBounds();
- double x = inner.getX()-width;
- double y = inner.getY()-height;
- double w = inner.getWidth()+2.0*width;
- double h = inner.getHeight()+2.0*height;
+ double x = inner.getX()-frame.getWidth();
+ double y = inner.getY()-frame.getHeight();
+ double w = inner.getWidth()+2.0*frame.getWidth();
+ double h = inner.getHeight()+2.0*frame.getHeight();
Rectangle2D outer = new Rectangle2D.Double(x,y,w,h);
Area frame = new Area(outer);
frame.subtract(new Area(inner));
ctx.fill(frame);
}
+
+ public int getRegionIndex() {
+ return regionIndex;
+ }
+
+ public int getBrushIndex() {
+ return brushIndex;
+ }
+
+ public Dimension2D getFrame() {
+ return frame;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "regionIndex", this::getRegionIndex,
+ "brushIndex", this::getBrushIndex,
+ "frame", this::getFrame);
+ }
}
/**
@Override
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- // see http://secunia.com/gfx/pdf/SA31675_BA.pdf ;)
- /**
- * A 16-bit unsigned integer that defines the number of polygons in the object.
- */
+ // see also CVE-2008-3014 - https://dl.packetstormsecurity.net/papers/attack/CVE-2008-3014.pdf ;)
+ // A 16-bit unsigned integer that defines the number of polygons in the object.
int numberOfPolygons = leis.readUShort();
- /**
- * A NumberOfPolygons array of 16-bit unsigned integers that define the number of
- * points for each polygon in the object.
- */
+ // A NumberOfPolygons array of 16-bit unsigned integers that define the number of points for
+ // each polygon in the object.
int[] pointsPerPolygon = new int[numberOfPolygons];
int size = LittleEndianConsts.SHORT_SIZE;
}
for (int nPoints : pointsPerPolygon) {
- /**
- * An array of 16-bit signed integers that define the coordinates of the polygons.
- * (Note: MS-WMF wrongly says unsigned integers ...)
- */
+ // An array of 16-bit signed integers that define the coordinates of the polygons.
+ // (Note: MS-WMF wrongly says unsigned integers ...)
Path2D poly = new Path2D.Double(Path2D.WIND_EVEN_ODD, nPoints);
for (int i=0; i<nPoints; i++) {
int x = leis.readShort();
@Override
public String toString() {
- final StringBuilder sb = new StringBuilder();
- sb.append("{ polyList: [");
- boolean isFirst = true;
- for (Path2D p : polyList) {
- if (!isFirst) {
- sb.append(",");
- }
- isFirst = false;
- sb.append("{ points: ");
- sb.append(polyToString(p));
- sb.append(" }");
- }
- sb.append(" }");
- return sb.toString();
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public List<Path2D> getPolyList() {
+ return polyList;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("polyList", this::getPolyList);
}
}
@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);
}
}
Shape s = new Rectangle2D.Double(point.getX(), point.getY(), 1, 1);
ctx.fill(s);
}
+
+ public HwmfColorRef getColorRef() {
+ return colorRef;
+ }
+
+ public Point2D getPoint() {
+ return point;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "colorRef", this::getColorRef,
+ "point", this::getPoint
+ );
+ }
}
/**
* using the pen and filled using the brush, as defined in the playback device context.
*/
public static class WmfRoundRect implements HwmfRecord {
- /**
- * A 16-bit signed integer that defines the height, in logical coordinates, of the
- * ellipse used to draw the rounded corners.
- */
- protected int height;
-
- /**
- * A 16-bit signed integer that defines the width, in logical coordinates, of the
- * ellipse used to draw the rounded corners.
- */
- protected int width;
+ protected final Dimension2D corners = new Dimension2DDouble();
protected final Rectangle2D bounds = new Rectangle2D.Double();
@Override
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- height = leis.readShort();
- width = leis.readShort();
+ // A 16-bit signed integer that defines the height/width, in logical coordinates,
+ // of the ellipse used to draw the rounded corners.
+ int height = leis.readShort();
+ int width = leis.readShort();
+ corners.setSize(width, height);
return 2*LittleEndianConsts.SHORT_SIZE+readBounds(leis, bounds);
}
}
protected RoundRectangle2D getShape() {
- return new RoundRectangle2D.Double(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(), width, height);
+ return new RoundRectangle2D.Double(
+ bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(),
+ corners.getWidth(), corners.getHeight()
+ );
+ }
+
+ public Dimension2D getCorners() {
+ return corners;
}
+
+ public Rectangle2D getBounds() {
+ return bounds;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "bounds", this::getBounds,
+ "corners", this::getCorners
+ );
+ }
+
}
* The META_ARC record draws an elliptical arc.
*/
public static class WmfArc implements HwmfRecord {
+ public enum WmfArcClosure {
+ ARC(HwmfRecordType.arc, Arc2D.OPEN, FillDrawStyle.DRAW),
+ CHORD(HwmfRecordType.chord, Arc2D.CHORD, FillDrawStyle.FILL_DRAW),
+ PIE(HwmfRecordType.pie, Arc2D.PIE, FillDrawStyle.FILL_DRAW);
+
+ public final HwmfRecordType recordType;
+ public final int awtType;
+ public final FillDrawStyle drawStyle;
+
+ WmfArcClosure(HwmfRecordType recordType, int awtType, FillDrawStyle drawStyle) {
+ this.recordType = recordType;
+ this.awtType = awtType;
+ this.drawStyle = drawStyle;
+ }
+ }
+
/** starting point of the arc */
protected final Point2D startPoint = new Point2D.Double();
@Override
public void draw(HwmfGraphics ctx) {
- Shape s = getShape();
- switch (getFillDrawStyle()) {
- case FILL:
- ctx.fill(s);
- break;
- case DRAW:
- ctx.draw(s);
- break;
- case FILL_DRAW:
- ctx.fill(s);
- ctx.draw(s);
- break;
- }
+ getFillDrawStyle().handler.accept(ctx, getShape());
}
- protected FillDrawStyle getFillDrawStyle() {
+ public WmfArcClosure getArcClosure() {
switch (getWmfRecordType()) {
default:
case arc:
- return FillDrawStyle.DRAW;
+ return WmfArcClosure.ARC;
case chord:
+ return WmfArcClosure.CHORD;
case pie:
- return FillDrawStyle.FILL_DRAW;
+ return WmfArcClosure.PIE;
}
}
+ protected FillDrawStyle getFillDrawStyle() {
+ return getArcClosure().drawStyle;
+ }
+
protected Arc2D getShape() {
double startAngle = Math.toDegrees(Math.atan2(-(startPoint.getY() - bounds.getCenterY()), startPoint.getX() - bounds.getCenterX()));
double endAngle = Math.toDegrees(Math.atan2(-(endPoint.getY() - bounds.getCenterY()), endPoint.getX() - bounds.getCenterX()));
startAngle += 360;
}
- int arcClosure;
- switch (getWmfRecordType()) {
- default:
- case arc:
- arcClosure = Arc2D.OPEN;
- break;
- case chord:
- arcClosure = Arc2D.CHORD;
- break;
- case pie:
- arcClosure = Arc2D.PIE;
- break;
- }
-
- return new Arc2D.Double(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(), startAngle, arcAngle, arcClosure);
+ return new Arc2D.Double(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(),
+ startAngle, arcAngle, getArcClosure().awtType);
}
@Override
public String toString() {
- Arc2D arc = getShape();
- return
- "{ startPoint: "+pointToString(startPoint)+
- ", endPoint: "+pointToString(endPoint)+
- ", startAngle: "+arc.getAngleStart()+
- ", extentAngle: "+arc.getAngleExtent()+
- ", bounds: "+boundsToString(bounds)+
- " }";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public Point2D getStartPoint() {
+ return startPoint;
+ }
+
+ public Point2D getEndPoint() {
+ return endPoint;
+ }
+
+ public Rectangle2D getBounds() {
+ return bounds;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ final Arc2D arc = getShape();
+ return GenericRecordUtil.getGenericProperties(
+ "startPoint", this::getStartPoint,
+ "endPoint", this::getEndPoint,
+ "startAngle", arc::getAngleStart,
+ "extentAngle", arc::getAngleExtent,
+ "bounds", this::getBounds
+ );
}
}
@Override
public String toString() {
- return "{ index: "+objectIndex +" }";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public int getObjectIndex() {
+ return objectIndex;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("objectIndex", this::getObjectIndex);
}
}
+ @SuppressWarnings("DuplicatedCode")
static int readBounds(LittleEndianInputStream leis, Rectangle2D bounds) {
- /**
- * The 16-bit signed integers that defines the corners of the bounding rectangle.
- */
+ // The 16-bit signed integers that defines the corners of the bounding rectangle.
int bottom = leis.readShort();
int right = leis.readShort();
int top = leis.readShort();
return 4 * LittleEndianConsts.SHORT_SIZE;
}
+ @SuppressWarnings("DuplicatedCode")
static int readRectS(LittleEndianInputStream leis, Rectangle2D bounds) {
- /**
- * The 16-bit signed integers that defines the corners of the bounding rectangle.
- */
+ // The 16-bit signed integers that defines the corners of the bounding rectangle.
int left = leis.readShort();
int top = leis.readShort();
int right = leis.readShort();
}
static int readPointS(LittleEndianInputStream leis, Point2D point) {
- /** a signed integer that defines the x/y-coordinate, in logical units. */
+ // a signed integer that defines the x/y-coordinate, in logical units.
int y = leis.readShort();
int x = leis.readShort();
point.setLocation(x, y);
return 2*LittleEndianConsts.SHORT_SIZE;
}
- static String polyToString(Path2D poly) {
- StringBuilder sb = new StringBuilder();
- sb.append("[");
- final PathIterator iter = poly.getPathIterator(null);
- double[] pnts = new double[6];
- while (!iter.isDone()) {
- int segType = iter.currentSegment(pnts);
- switch (segType) {
- case PathIterator.SEG_MOVETO:
- sb.append("{ type: 'move', x: "+pnts[0]+", y: "+pnts[1]+" }, ");
- break;
- case PathIterator.SEG_LINETO:
- sb.append("{ type: 'lineto', x: "+pnts[0]+", y: "+pnts[1]+" }, ");
- break;
- case PathIterator.SEG_QUADTO:
- sb.append("{ type: 'quad', x1: "+pnts[0]+", y1: "+pnts[1]+", x2: "+pnts[2]+", y2: "+pnts[3]+" }, ");
- break;
- case PathIterator.SEG_CUBICTO:
- sb.append("{ type: 'cubic', x1: "+pnts[0]+", y1: "+pnts[1]+", x2: "+pnts[2]+", y2: "+pnts[3]+", x3: "+pnts[4]+", y3: "+pnts[5]+" }, ");
- break;
- case PathIterator.SEG_CLOSE:
- sb.append("{ type: 'close' }, ");
- break;
- }
- iter.next();
- }
- sb.append("]");
- return sb.toString();
- }
-
- @Internal
- public static String pointToString(Point2D point) {
- return (point == null) ? "null" : "{ x: "+point.getX()+", y: "+point.getY()+" }";
- }
-
- @Internal
- public static String boundsToString(Rectangle2D bounds) {
- return (bounds == null) ? "null" : "{ x: "+bounds.getX()+", y: "+bounds.getY()+", w: "+bounds.getWidth()+", h: "+bounds.getHeight()+" }";
- }
-
- @Internal
- public static String dimToString(Dimension2D dim) {
- return (dim == null) ? "null" : "{ w: "+dim.getWidth()+", h: "+dim.getHeight()+" }";
- }
-
@Internal
public static Rectangle2D normalizeBounds(Rectangle2D bounds) {
return (bounds.getWidth() >= 0 && bounds.getHeight() >= 0) ? bounds
package org.apache.poi.hwmf.record;
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.common.usermodel.GenericRecord;
import org.apache.poi.hwmf.draw.HwmfGraphics;
-import org.apache.poi.util.HexDump;
+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.LittleEndianCP950Reader;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
* The MetafileEscapes specifies printer driver functionality that
* might not be directly accessible through WMF records
*/
+@SuppressWarnings("WeakerAccess")
public class HwmfEscape implements HwmfRecord {
private static final int MAX_OBJECT_SIZE = 0xFFFF;
}
public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("escape - function: "+escapeFunction+"\n");
- sb.append(escapeData.toString());
- return sb.toString();
+ return GenericRecordJsonWriter.marshal(this);
}
- public static class WmfEscapeUnknownData implements HwmfEscapeData {
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "escapeFunction", this::getEscapeFunction,
+ "escapeData", this::getEscapeData
+ );
+ }
+
+ public static class WmfEscapeUnknownData implements HwmfEscapeData, GenericRecord {
EscapeFunction escapeFunction;
private byte[] escapeDataBytes;
public int init(LittleEndianInputStream leis, long recordSize, EscapeFunction escapeFunction) throws IOException {
this.escapeFunction = escapeFunction;
escapeDataBytes = IOUtils.toByteArray(leis,recordSize,MAX_OBJECT_SIZE);
- return 0;
+ return (int)recordSize;
}
@Override
public String toString() {
- return HexDump.dump(escapeDataBytes, 0, 0);
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("escapeDataBytes", this::getEscapeDataBytes);
}
}
- public static class WmfEscapeEMF implements HwmfEscapeData {
+ public static class WmfEscapeEMF implements HwmfEscapeData, GenericRecord {
// The magic for EMF parts, i.e. the byte sequence for "WMFC"
private static final int EMF_COMMENT_IDENTIFIER = 0x43464D57;
if (commentIdentifier != EMF_COMMENT_IDENTIFIER) {
// there are some WMF implementation using this record as a MFCOMMENT or similar
// if the commentIdentifier doesn't match, then return immediately
- return LittleEndianConsts.INT_SIZE;
+ emfData = IOUtils.toByteArray(leis, recordSize-LittleEndianConsts.INT_SIZE, MAX_OBJECT_SIZE);
+ remainingBytes = emfData.length;
+ return (int)recordSize;
}
// A 32-bit unsigned integer that identifies the type of comment in this record.
public byte[] getEmfData() {
return emfData;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ final Map<String,Supplier<?>> m = new LinkedHashMap<>();
+ m.put("commentIdentifier", () -> commentIdentifier);
+ m.put("commentType", () -> commentType);
+ m.put("version", () -> version);
+ m.put("checksum", () -> checksum);
+ m.put("flags", () -> flags);
+ m.put("commentRecordCount", this::getCommentRecordCount);
+ m.put("currentRecordSize", this::getCurrentRecordSize);
+ m.put("remainingBytes", this::getRemainingBytes);
+ m.put("emfRecordSize", this::getEmfRecordSize);
+ m.put("emfData", this::getEmfData);
+ return Collections.unmodifiableMap(m);
+ }
}
}
package org.apache.poi.hwmf.record;
-import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
import static org.apache.poi.hwmf.record.HwmfDraw.readPointS;
import java.awt.Color;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
+import java.util.Map;
+import java.util.function.Supplier;
import org.apache.poi.hwmf.draw.HwmfDrawProperties;
import org.apache.poi.hwmf.draw.HwmfGraphics;
import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode.HwmfBkMode;
+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 HwmfFill {
- /**
- * A record which contains an image (to be extracted)
- */
+ /** A record which contains an image (to be extracted) */
public interface HwmfImageRecord {
default BufferedImage getImage() {
* i.e. if contains explicit RGB values or indexes into a palette.
*/
public enum ColorUsage {
- /**
- * The color table contains RGB values
- */
+ /** The color table contains RGB values */
DIB_RGB_COLORS(0x0000),
/**
* The color table contains 16-bit indices into the current logical palette in
if (region != null) {
ctx.fill(region);
}
-
+ }
+
+ public int getRegionIndex() {
+ return regionIndex;
+ }
+
+ public int getBrushIndex() {
+ return brushIndex;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "regionIndex", this::getRegionIndex,
+ "brushIndex", this::getBrushIndex
+ );
}
}
ctx.fill(region);
}
}
+
+ public int getRegionIndex() {
+ return regionIndex;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("regionIndex", this::getRegionIndex);
+ }
}
*/
public static class WmfFloodFill implements HwmfRecord {
- /**
- * A 32-bit ColorRef Object that defines the color value.
- */
+ /** A 32-bit ColorRef Object that defines the color value. */
protected final HwmfColorRef colorRef = new HwmfColorRef();
/** the point where filling is to start. */
public void draw(HwmfGraphics ctx) {
}
+
+ public HwmfColorRef getColorRef() {
+ return colorRef;
+ }
+
+ public Point2D getStart() {
+ return start;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "colorRef", this::getColorRef,
+ "start", this::getStart
+ );
+ }
}
/**
@Override
public String toString() {
- return "{ polyFillMode: '"+ polyFillMode +"' }";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public HwmfPolyfillMode getPolyFillMode() {
+ return polyFillMode;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("polyFillMode", this::getPolyFillMode);
}
}
* the playback device context.
*/
public static class WmfExtFloodFill extends WmfFloodFill {
-
- /**
- * A 16-bit unsigned integer that defines the fill operation to be performed. This
- * member MUST be one of the values in the FloodFill Enumeration table:
- *
- * FLOODFILLBORDER = 0x0000:
- * The fill area is bounded by the color specified by the Color member.
- * This style is identical to the filling performed by the META_FLOODFILL record.
- *
- * FLOODFILLSURFACE = 0x0001:
- * The fill area is bounded by the color that is specified by the Color member.
- * Filling continues outward in all directions as long as the color is encountered.
- * This style is useful for filling areas with multicolored boundaries.
- */
- protected int mode;
+
+ public enum HwmfFloodFillMode {
+ /**
+ * The fill area is bounded by the color specified by the Color member.
+ * This style is identical to the filling performed by the META_FLOODFILL record.
+ */
+ FLOOD_FILL_BORDER,
+ /**
+ * The fill area is bounded by the color that is specified by the Color member.
+ * Filling continues outward in all directions as long as the color is encountered.
+ * This style is useful for filling areas with multicolored boundaries.
+ */
+ FLOOD_FILL_SURFACE
+ }
+
+ protected HwmfFloodFillMode mode;
@Override
public HwmfRecordType getWmfRecordType() {
@Override
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- mode = leis.readUShort();
+ // A 16-bit unsigned integer that defines the fill operation to be performed. This
+ // member MUST be one of the values in the FloodFill Enumeration table:
+ mode = HwmfFloodFillMode.values()[leis.readUShort()];
return super.init(leis, recordSize, recordFunction)+LittleEndianConsts.SHORT_SIZE;
}
public void draw(HwmfGraphics ctx) {
}
+
+ public HwmfFloodFillMode getMode() {
+ return mode;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("mode", this::getMode);
+ }
}
/**
* A 16-bit unsigned integer used to index into the WMF Object Table to get
* the region to be inverted.
*/
- private int region;
+ private int regionIndex;
@Override
public HwmfRecordType getWmfRecordType() {
@Override
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- region = leis.readUShort();
+ regionIndex = leis.readUShort();
return LittleEndianConsts.SHORT_SIZE;
}
public void draw(HwmfGraphics ctx) {
}
+
+ public int getRegionIndex() {
+ return regionIndex;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("regionIndex", this::getRegionIndex);
+ }
}
@Override
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- int rasterOpCode = leis.readUShort();
- int rasterOpIndex = leis.readUShort();
-
- rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
- assert(rasterOpCode == rasterOperation.opCode);
-
+ rasterOperation = readRasterOperation(leis);
return readBounds2(leis, bounds)+2*LittleEndianConsts.SHORT_SIZE;
}
public void draw(HwmfGraphics ctx) {
}
+
+ public HwmfTernaryRasterOp getRasterOperation() {
+ return rasterOperation;
+ }
+
+ public Rectangle2D getBounds() {
+ return bounds;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "rasterOperation", this::getRasterOperation,
+ "bounds", this::getBounds);
+ }
}
/**
@Override
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));
+ final boolean hasBitmap = hasBitmap(recordSize, recordFunction);
- int rasterOpCode = leis.readUShort();
- int rasterOpIndex = leis.readUShort();
-
- rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
- assert(rasterOpCode == rasterOperation.opCode);
+ rasterOperation = readRasterOperation(leis);
int size = 2*LittleEndianConsts.SHORT_SIZE;
@Override
public String toString() {
- return
- "{ rasterOperation: '"+rasterOperation+"'"+
- ", srcBounds: "+boundsToString(srcBounds)+
- ", dstBounds: "+boundsToString(dstBounds)+
- "}";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public HwmfTernaryRasterOp getRasterOperation() {
+ return rasterOperation;
+ }
+
+ public Rectangle2D getSrcBounds() {
+ return srcBounds;
+ }
+
+ public Rectangle2D getDstBounds() {
+ return dstBounds;
+ }
+
+ public HwmfBitmap16 getTarget() {
+ return target;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "rasterOperation", this::getRasterOperation,
+ "srcBounds", this::getSrcBounds,
+ "dstBounds", this::getDstBounds,
+ "target", this::getTarget
+ );
}
}
@Override
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- int rasterOpCode = leis.readUShort();
- int rasterOpIndex = leis.readUShort();
-
- rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
- assert(rasterOpCode == rasterOperation.opCode);
-
+ rasterOperation = readRasterOperation(leis);
colorUsage = ColorUsage.valueOf(leis.readUShort());
int size = 3*LittleEndianConsts.SHORT_SIZE;
@Override
public String toString() {
- return
- "{ rasterOperation: '"+rasterOperation+"'"+
- ", colorUsage: '"+colorUsage+"'"+
- ", srcBounds: "+boundsToString(srcBounds)+
- ", dstBounds: "+boundsToString(dstBounds)+
- "}";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public HwmfTernaryRasterOp getRasterOperation() {
+ return rasterOperation;
+ }
+
+ public ColorUsage getColorUsage() {
+ return colorUsage;
+ }
+
+ public Rectangle2D getSrcBounds() {
+ return srcBounds;
+ }
+
+ public Rectangle2D getDstBounds() {
+ return dstBounds;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "rasterOperation", this::getRasterOperation,
+ "colorUsage", this::getColorUsage,
+ "srcBounds", this::getSrcBounds,
+ "dstBounds", this::getDstBounds
+ );
}
}
@Override
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- boolean hasBitmap = (recordSize/2 != ((recordFunction >> 8) + 3));
+ final boolean hasBitmap = hasBitmap(recordSize/2, recordFunction);
- int rasterOpCode = leis.readUShort();
- int rasterOpIndex = leis.readUShort();
-
- rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
- assert(rasterOpCode == rasterOperation.opCode);
+ rasterOperation = readRasterOperation(leis);
int size = 2*LittleEndianConsts.SHORT_SIZE;
public byte[] getBMPData() {
return dib.getBMPData();
}
+
+ public ColorUsage getColorUsage() {
+ return colorUsage;
+ }
+
+ public int getScanCount() {
+ return scanCount;
+ }
+
+ public int getStartScan() {
+ return startScan;
+ }
+
+ public Rectangle2D getSrcBounds() {
+ return srcBounds;
+ }
+
+ public Rectangle2D getDstBounds() {
+ return dstBounds;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "colorUsage", this::getColorUsage,
+ "scanCount", this::getScanCount,
+ "startScan", this::getStartScan,
+ "srcBounds", this::getSrcBounds,
+ "dstBounds", this::getDstBounds,
+ "dib", () -> dib
+ );
+ }
}
@Override
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- boolean hasBitmap = (recordSize/2 != ((recordFunction >> 8) + 3));
+ final boolean hasBitmap = hasBitmap(recordSize/2, recordFunction);
- int rasterOpCode = leis.readUShort();
- int rasterOpIndex = leis.readUShort();
-
- rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
- assert(rasterOpCode == rasterOperation.opCode);
+ rasterOperation = readRasterOperation(leis);
int size = 2*LittleEndianConsts.SHORT_SIZE;
@Override
public int init(LittleEndianInputStream leis, long recordSize, int recordFunction) throws IOException {
- boolean hasBitmap = (recordSize > ((recordFunction >> 8) + 3));
+ final boolean hasBitmap = hasBitmap(recordSize, recordFunction);
- int rasterOpCode = leis.readUShort();
- int rasterOpIndex = leis.readUShort();
-
- rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
- assert(rasterOperation != null && rasterOpCode == rasterOperation.opCode);
+ rasterOperation = readRasterOperation(leis);
int size = 2*LittleEndianConsts.SHORT_SIZE;
public byte[] getBMPData() {
return (target != null && target.isValid()) ? target.getBMPData() : null;
}
+
+ public HwmfTernaryRasterOp getRasterOperation() {
+ return rasterOperation;
+ }
+
+ public Rectangle2D getSrcBounds() {
+ return srcBounds;
+ }
+
+ public Rectangle2D getDstBounds() {
+ return dstBounds;
+ }
+
+ public HwmfBitmapDib getTarget() {
+ return target;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "rasterOperation", this::getRasterOperation,
+ "srcBounds", this::getSrcBounds,
+ "dstBounds", this::getDstBounds,
+ "target", this::getTarget
+ );
+ }
}
static int readBounds2(LittleEndianInputStream leis, Rectangle2D bounds) {
- /**
- * The 16-bit signed integers that defines the corners of the bounding rectangle.
- */
+ // The 16-bit signed integers that defines the corners of the bounding rectangle.
int h = leis.readShort();
int w = leis.readShort();
int y = leis.readShort();
return 4 * LittleEndianConsts.SHORT_SIZE;
}
+ private static boolean hasBitmap(long recordSize, int recordFunction) {
+ return (recordSize > ((recordFunction >> 8) + 3));
+ }
+
+ private static HwmfTernaryRasterOp readRasterOperation(LittleEndianInputStream leis) {
+ int rasterOpCode = leis.readUShort();
+ int rasterOpIndex = leis.readUShort();
+
+ HwmfTernaryRasterOp rasterOperation = HwmfTernaryRasterOp.valueOf(rasterOpIndex);
+ assert(rasterOperation != null && rasterOpCode == rasterOperation.opCode);
+ return rasterOperation;
+ }
}
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.common.usermodel.GenericRecord;
import org.apache.poi.common.usermodel.fonts.FontCharset;
import org.apache.poi.common.usermodel.fonts.FontFamily;
import org.apache.poi.common.usermodel.fonts.FontHeader;
import org.apache.poi.common.usermodel.fonts.FontPitch;
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;
* The Font object specifies the attributes of a logical font
*/
@SuppressWarnings({"unused", "Duplicates"})
-public class HwmfFont implements FontInfo {
+public class HwmfFont implements FontInfo, GenericRecord {
/**
* The output precision defines how closely the output must match the requested font's height,
* ClipPrecision Flags specify clipping precision, which defines how to clip characters that are
* partially outside a clipping region. These flags can be combined to specify multiple options.
*/
- public static class WmfClipPrecision {
+ public static class WmfClipPrecision implements GenericRecord {
/** Specifies that default clipping MUST be used. */
- private static final BitField CLIP_DEFAULT_PRECIS = BitFieldFactory.getInstance(0x0000);
+ private static final BitField DEFAULT_PRECIS = BitFieldFactory.getInstance(0x0003);
/** This value SHOULD NOT be used. */
- private static final BitField CLIP_CHARACTER_PRECIS = BitFieldFactory.getInstance(0x0001);
+ private static final BitField CHARACTER_PRECIS = BitFieldFactory.getInstance(0x0001);
/** This value MAY be returned when enumerating rasterized, TrueType and vector fonts. */
- private static final BitField CLIP_STROKE_PRECIS = BitFieldFactory.getInstance(0x0002);
+ private static final BitField STROKE_PRECIS = BitFieldFactory.getInstance(0x0002);
/**
* This value is used to control font rotation, as follows:
* If clear, device fonts SHOULD rotate counterclockwise, but the rotation of other fonts
* SHOULD be determined by the orientation of the coordinate system.
*/
- private static final BitField CLIP_LH_ANGLES = BitFieldFactory.getInstance(0x0010);
+ private static final BitField LH_ANGLES = BitFieldFactory.getInstance(0x0010);
/** This value SHOULD NOT be used. */
- private static final BitField CLIP_TT_ALWAYS = BitFieldFactory.getInstance(0x0020);
+ private static final BitField TT_ALWAYS = BitFieldFactory.getInstance(0x0020);
- /** This value specifies that font association SHOULD< be turned off. */
- private static final BitField CLIP_DFA_DISABLE = BitFieldFactory.getInstance(0x0040);
+ /** This value specifies that font association SHOULD be turned off. */
+ private static final BitField DFA_DISABLE = BitFieldFactory.getInstance(0x0040);
/**
* This value specifies that font embedding MUST be used to render document content;
* embedded fonts are read-only.
*/
- private static final BitField CLIP_EMBEDDED = BitFieldFactory.getInstance(0x0080);
+ private static final BitField EMBEDDED = BitFieldFactory.getInstance(0x0080);
- int flag;
+ private static final int[] FLAG_MASKS = {
+ 0x0001, 0x0002, 0x0010, 0x0020, 0x0040, 0x0080
+ };
+
+ private static final String[] FLAG_NAMES = {
+ "CHARACTER_PRECIS",
+ "STROKE_PRECIS",
+ "LH_ANGLES",
+ "TT_ALWAYS",
+ "DFA_DISABLE",
+ "EMBEDDED"
+ };
+
+ private int flag;
public int init(LittleEndianInputStream leis) {
flag = leis.readUByte();
return LittleEndianConsts.BYTE_SIZE;
}
+ public boolean isDefaultPrecision() {
+ return !DEFAULT_PRECIS.isSet(flag);
+ }
+
+ public boolean isCharacterPrecision() {
+ return CHARACTER_PRECIS.isSet(flag);
+ }
+
+ public boolean isStrokePrecision() {
+ return STROKE_PRECIS.isSet(flag);
+ }
+
+ public boolean isLeftHandAngles() {
+ return LH_ANGLES.isSet(flag);
+ }
+
+ public boolean isTrueTypeAlways() {
+ return TT_ALWAYS.isSet(flag);
+ }
+
+ public boolean isFontAssociated() {
+ return !DFA_DISABLE.isSet(flag);
+ }
+
+ public boolean useEmbeddedFont() {
+ return EMBEDDED.isSet(flag);
+ }
+
@Override
public String toString() {
- return
- (((flag&0x3) == 0 ? "default " : " ")+
- (CLIP_CHARACTER_PRECIS.isSet(flag) ? "char " : " ")+
- (CLIP_STROKE_PRECIS.isSet(flag) ? "stroke " : " ")+
- (CLIP_LH_ANGLES.isSet(flag) ? "angles " : " ")+
- (CLIP_TT_ALWAYS.isSet(flag) ? "tt_always " : " ")+
- (CLIP_DFA_DISABLE.isSet(flag) ? "dfa " : " ")+
- (CLIP_EMBEDDED.isSet(flag) ? "embedded " : " ")
- ).trim()
- ;
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "isDefaultPrecision", this::isDefaultPrecision,
+ "flag", GenericRecordUtil.getBitsAsString(() -> flag, FLAG_MASKS, FLAG_NAMES)
+ );
}
}
@Override
public String toString() {
- return "{ height: "+height+
- ", width: "+width+
- ", escapment: "+escapement+
- ", weight: "+weight+
- ", italic: "+italic+
- ", underline: "+underline+
- ", strikeOut: "+strikeOut+
- ", charset: '"+charSet+"'"+
- ", outPrecision: '"+outPrecision+"'"+
- ", clipPrecision: '"+clipPrecision+"'"+
- ", quality: '"+quality+"'"+
- ", pitch: '"+getPitch()+"'"+
- ", family: '"+getFamily()+"'"+
- ", facename: '"+facename+"'"+
- "}";
+ return GenericRecordJsonWriter.marshal(this);
}
protected int readString(LittleEndianInputStream leis, StringBuilder sb, int limit) throws IOException {
return readBytes;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ final Map<String,Supplier<?>> m = new LinkedHashMap<>();
+ m.put("height", this::getHeight);
+ m.put("width", this::getWidth);
+ m.put("escapment", this::getEscapement);
+ m.put("weight", this::getWeight);
+ m.put("italic", this::isItalic);
+ m.put("underline", this::isUnderline);
+ m.put("strikeOut", this::isStrikeOut);
+ m.put("charset", this::getCharset);
+ m.put("outPrecision", this::getOutPrecision);
+ m.put("clipPrecision", this::getClipPrecision);
+ m.put("quality", this::getQuality);
+ m.put("pitch", this::getPitch);
+ m.put("family", this::getFamily);
+ m.put("typeface", this::getTypeface);
+ return Collections.unmodifiableMap(m);
+ }
}
package org.apache.poi.hwmf.record;
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.common.usermodel.GenericRecord;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
-public class HwmfHeader {
- private int type;
+public class HwmfHeader implements GenericRecord {
+ public enum HwmfHeaderMetaType {
+ MEMORY_METAFILE, DISK_METAFILE
+ }
+
+ private HwmfHeaderMetaType type;
private int recordSize;
private int version;
private int filesize;
public HwmfHeader(LittleEndianInputStream leis) throws IOException {
// Type (2 bytes): A 16-bit unsigned integer that defines the type of metafile
// MEMORYMETAFILE = 0x0001, DISKMETAFILE = 0x0002
- type = leis.readUShort();
+ type = HwmfHeaderMetaType.values()[leis.readUShort()-1];
// HeaderSize (2 bytes): A 16-bit unsigned integer that defines the number
// of 16-bit words in the header.
assert(len == bytesLeft);
}
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ final Map<String,Supplier<?>> m = new LinkedHashMap<>();
+ m.put("type", () -> type);
+ m.put("recordSize", () -> recordSize);
+ m.put("version", () -> version);
+ m.put("filesize", () -> filesize);
+ m.put("numberOfObjects", () -> numberOfObjects);
+ m.put("maxRecord", () -> maxRecord);
+ m.put("numberOfMembers", () -> numberOfMembers);
+ return Collections.unmodifiableMap(m);
+ }
}
import java.awt.geom.Dimension2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
+import java.util.Map;
+import java.util.function.Supplier;
import org.apache.poi.hwmf.draw.HwmfDrawProperties;
import org.apache.poi.hwmf.draw.HwmfGraphics;
import org.apache.poi.hwmf.record.HwmfFill.HwmfImageRecord;
import org.apache.poi.hwmf.record.HwmfMisc.WmfSetBkMode.HwmfBkMode;
import org.apache.poi.util.Dimension2DDouble;
+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 HwmfMisc {
/**
public String toString() {
return "{}";
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return null;
+ }
}
/**
public void draw(HwmfGraphics ctx) {
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return null;
+ }
}
/**
@Override
public String toString() {
- return "{ nSavedDC: "+nSavedDC+" }";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public int getNSavedDC() {
+ return nSavedDC;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("nSavedDC", this::getNSavedDC);
}
}
@Override
public String toString() {
- return "{ colorRef: "+colorRef+" }";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public HwmfColorRef getColorRef() {
+ return colorRef;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("colorRef", this::getColorRef);
}
}
@Override
public String toString() {
- return "{ bkMode: '"+bkMode+"' }";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public HwmfBkMode getBkMode() {
+ return bkMode;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("bkMode", this::getBkMode);
}
}
public void draw(HwmfGraphics ctx) {
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("layout", () -> layout);
+ }
}
/**
@Override
public String toString() {
- return "{ mapMode: '"+mapMode+"' }";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public HwmfMapMode getMapMode() {
+ return mapMode;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("mapMode", this::getMapMode);
}
}
@Override
public String toString() {
- return "{ mapperValues: "+mapperValues+" }";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("mapperValues", () -> mapperValues);
}
}
@Override
public String toString() {
- return "{ drawMode: '"+drawMode+"' }";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public HwmfBinaryRasterOp getDrawMode() {
+ return drawMode;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("drawMode", this::getDrawMode);
}
}
@Override
public String toString() {
- return "{ stretchBltMode: '"+stretchBltMode+"' }";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public StretchBltMode getStretchBltMode() {
+ return stretchBltMode;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("stretchBltMode", this::getStretchBltMode);
}
}
return null;
}
}
+
+ public HwmfBrushStyle getStyle() {
+ return style;
+ }
+
+ public ColorUsage getColorUsage() {
+ return colorUsage;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "style", this::getStyle,
+ "colorUsage", this::getColorUsage,
+ "pattern", () -> (patternDib != null && patternDib.isValid()) ? patternDib : pattern16,
+ "bmpData", this::getBMPData
+ );
+ }
}
/**
@Override
public String toString() {
- return "{ index: "+objectIndex+" }";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public int getObjectIndex() {
+ return objectIndex;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("objectIndex", this::getObjectIndex);
}
}
dp.setBrushBitmap(pattern.getImage());
dp.setBrushStyle(HwmfBrushStyle.BS_PATTERN);
}
+
+ public HwmfBitmap16 getPattern() {
+ return pattern;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("pattern", this::getPattern);
+ }
}
public static class WmfCreatePenIndirect implements HwmfRecord, HwmfObjectTableEntry {
@Override
public String toString() {
- return
- "{ penStyle: "+penStyle+
- ", dimension: { width: "+dimension.getWidth()+", height: "+dimension.getHeight()+" }"+
- ", colorRef: "+colorRef+"}";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public HwmfPenStyle getPenStyle() {
+ return penStyle;
+ }
+
+ public Dimension2D getDimension() {
+ return dimension;
+ }
+
+ public HwmfColorRef getColorRef() {
+ return colorRef;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "penStyle", this::getPenStyle,
+ "dimension", this::getDimension,
+ "colorRef", this::getColorRef
+ );
}
}
@Override
public String toString() {
- return
- "{ brushStyle: '"+brushStyle+"'"+
- ", colorRef: "+colorRef+
- ", brushHatch: '"+brushHatch+"' }";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public HwmfBrushStyle getBrushStyle() {
+ return brushStyle;
+ }
+
+ public HwmfColorRef getColorRef() {
+ return colorRef;
+ }
+
+ public HwmfHatchStyle getBrushHatch() {
+ return brushHatch;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "brushStyle", this::getBrushStyle,
+ "colorRef", this::getColorRef,
+ "brushHatch", this::getBrushHatch
+ );
}
}
}
\ No newline at end of file
package org.apache.poi.hwmf.record;
+import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
+
import java.awt.Color;
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.hwmf.draw.HwmfDrawProperties;
import org.apache.poi.hwmf.draw.HwmfGraphics;
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;
public class HwmfPalette {
- public static class PaletteEntry {
+ public static class PaletteEntry implements GenericRecord {
private static final BitField PC_RESERVED = BitFieldFactory.getInstance(0x01);
private static final BitField PC_EXPLICIT = BitFieldFactory.getInstance(0x02);
private static final BitField PC_NOCOLLAPSE = BitFieldFactory.getInstance(0x04);
+ private static final int[] FLAGS_MASKS = { 1,2,4 };
+
+ private static final String[] FLAGS_NAMES = { "RESERVED", "EXPLICIT", "NOCOLLAPSE" };
+
private int values;
private Color colorRef;
public boolean isNoCollapse() {
return PC_NOCOLLAPSE.isSet(values);
}
+
+ public Color getColorRef() {
+ return colorRef;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "flags", getBitsAsString(() -> values, FLAGS_MASKS, FLAGS_NAMES),
+ "color", this::getColorRef
+ );
+ }
}
public static abstract class WmfPaletteParent implements HwmfRecord, HwmfObjectTableEntry {
}
protected int readPaletteEntries(LittleEndianInputStream leis, int nbrOfEntries) throws IOException {
- /**
- * NumberOfEntries (2 bytes): A 16-bit unsigned integer that defines the number of objects in
- * aPaletteEntries.
- */
+ // NumberOfEntries (2 bytes): A 16-bit unsigned integer that defines the number of objects in
+ // aPaletteEntries.
final int numberOfEntries = (nbrOfEntries > -1) ? nbrOfEntries : leis.readUShort();
int size = (nbrOfEntries > -1) ? 0 : LittleEndianConsts.SHORT_SIZE;
for (int i=0; i<numberOfEntries; i++) {
ctx.addObjectTableEntry(this);
}
- protected List<PaletteEntry> getPaletteCopy() {
+ List<PaletteEntry> getPaletteCopy() {
List<PaletteEntry> newPalette = new ArrayList<>();
for (PaletteEntry et : palette) {
newPalette.add(new PaletteEntry(et));
return newPalette;
}
- protected int getPaletteStart() {
+ int getPaletteStart() {
return start;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "paletteStart", this::getPaletteStart,
+ "pallete", this::getPaletteCopy
+ );
+ }
}
/**
palette = palette.subList(0, numberOfEntries);
props.setPalette(palette);
}
+
+ public int getNumberOfEntries() {
+ return numberOfEntries;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("numberOfEntries", this::getNumberOfEntries);
+ }
}
/**
public void draw(HwmfGraphics ctx) {
ctx.applyObjectTableEntry(paletteIndex);
}
+
+ public int getPaletteIndex() {
+ return paletteIndex;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("paletteIndex", this::getPaletteIndex);
+ }
}
/**
public void draw(HwmfGraphics ctx) {
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return null;
+ }
}
/**
HwmfDrawProperties props = ctx.getProperties();
List<PaletteEntry> dest = props.getPalette();
List<PaletteEntry> src = getPaletteCopy();
- int start = getPaletteStart();
+ final int start = getPaletteStart();
if (dest == null) {
dest = new ArrayList<>();
}
package org.apache.poi.hwmf.record;
import java.awt.BasicStroke;
+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.GenericRecordJsonWriter;
+import org.apache.poi.util.GenericRecordUtil;
/**
* The 16-bit PenStyle Enumeration is used to specify different types of pens
* The defaults in case the other values of the subsection aren't set are
* solid, round end caps, round joins and cosmetic type.
*/
-public class HwmfPenStyle implements Cloneable {
+public class HwmfPenStyle implements Cloneable, GenericRecord {
public enum HwmfLineCap {
/** Rounded ends */
ROUND(0, BasicStroke.CAP_ROUND),
@Override
public String toString() {
- return
- "{ lineCap: '"+getLineCap()+"'"+
- ", lineDash: '"+getLineDash()+"'"+
- ", lineJoin: '"+getLineJoin()+"'"+
- (isAlternateDash()?", alternateDash: true ":"")+
- (isGeometric()?", geometric: true ":"")+
- "}";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "lineCap", this::getLineCap,
+ "lineJoin", this::getLineJoin,
+ "lineDash", this::getLineDash,
+ "lineDashes", this::getLineDashes,
+ "alternateDash", this::isAlternateDash,
+ "geometric", this::isGeometric
+ );
}
}
import java.io.IOException;
+import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hwmf.draw.HwmfGraphics;
import org.apache.poi.util.LittleEndianInputStream;
-public interface HwmfRecord {
+public interface HwmfRecord extends GenericRecord {
HwmfRecordType getWmfRecordType();
/**
* @param ctx the graphics context to modify
*/
void draw(HwmfGraphics ctx);
+
+ @Override
+ default Enum getGenericRecordType() {
+ return getWmfRecordType();
+ }
}
package org.apache.poi.hwmf.record;
-import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
-import static org.apache.poi.hwmf.record.HwmfDraw.pointToString;
import static org.apache.poi.hwmf.record.HwmfDraw.readPointS;
import static org.apache.poi.hwmf.record.HwmfDraw.readRectS;
+import static org.apache.poi.util.GenericRecordUtil.getBitsAsString;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+import java.util.function.Supplier;
-import org.apache.commons.codec.Charsets;
+import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hwmf.draw.HwmfDrawProperties;
import org.apache.poi.hwmf.draw.HwmfGraphics;
import org.apache.poi.hwmf.record.HwmfMisc.WmfSetMapMode;
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.LocaleUtil;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
public void draw(HwmfGraphics ctx) {
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("charExtra", () -> charExtra);
+ }
}
/**
@Override
public String toString() {
- return "{ colorRef: "+colorRef+" }";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public HwmfColorRef getColorRef() {
+ return colorRef;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("colorRef", this::getColorRef);
}
}
public void draw(HwmfGraphics ctx) {
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "breakCount", () -> breakCount,
+ "breakExtra", () -> breakExtra
+ );
+ }
}
/**
System.arraycopy(rawTextBytes, 0, ret, 0, stringLength);
return ret;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("text", () -> getText(StandardCharsets.US_ASCII));
+ }
}
- public static class WmfExtTextOutOptions {
+ public static class WmfExtTextOutOptions implements GenericRecord {
/**
* Indicates that the background color that is defined in the playback device context
* SHOULD be used to fill the rectangle.
/** This bit is reserved and SHOULD NOT be used. */
private static final BitField ETO_REVERSE_INDEX_MAP = BitFieldFactory.getInstance(0x10000);
- protected int flag;
+ private static final int[] FLAGS_MASKS = {
+ 0x0002, 0x0004, 0x0010, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x10000
+ };
+
+ private static final String[] FLAGS_NAMES = {
+ "OPAQUE", "CLIPPED", "GLYPH_INDEX", "RTLREADING", "NO_RECT", "SMALL_CHARS", "NUMERICSLOCAL",
+ "NUMERICSLATIN", "IGNORELANGUAGE", "PDY", "REVERSE_INDEX_MAP"
+ };
+
+ protected int flags;
public int init(LittleEndianInputStream leis) {
- flag = leis.readUShort();
+ flags = leis.readUShort();
return LittleEndianConsts.SHORT_SIZE;
}
public boolean isOpaque() {
- return ETO_OPAQUE.isSet(flag);
+ return ETO_OPAQUE.isSet(flags);
}
public boolean isClipped() {
- return ETO_CLIPPED.isSet(flag);
+ return ETO_CLIPPED.isSet(flags);
}
public boolean isYDisplaced() {
- return ETO_PDY.isSet(flag);
+ return ETO_PDY.isSet(flags);
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("flags", getBitsAsString(() -> flags, FLAGS_MASKS, FLAGS_NAMES));
}
}
@Override
public String toString() {
- String text = "";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ private String getGenericText() {
try {
- text = getText(isUnicode() ? Charsets.UTF_16LE : LocaleUtil.CHARSET_1252);
- } catch (IOException ignored) {
+ return getText(isUnicode() ? StandardCharsets.UTF_16LE : StandardCharsets.US_ASCII);
+ } catch (IOException e) {
+ return "";
}
+ }
- return
- "{ reference: " + pointToString(reference) +
- ", bounds: " + boundsToString(bounds) +
- ", text: '"+text.replaceAll("\\p{Cntrl}",".")+"'"+
- "}";
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "reference", this::getReference,
+ "bounds", this::getBounds,
+ "text", this::getGenericText
+ );
}
}
@Override
public String toString() {
- return
- "{ align: '"+ getAlignLatin() + "'" +
- ", valign: '"+ getVAlignLatin() + "'" +
- ", alignAsian: '"+ getAlignAsian() + "'" +
- ", valignAsian: '"+ getVAlignAsian() + "'" +
- "}";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "align", this::getAlignLatin,
+ "valign", this::getVAlignLatin,
+ "alignAsian", this::getAlignAsian,
+ "valignAsian", this::getVAlignAsian
+ );
}
private HwmfTextAlignment getAlignLatin() {
@Override
public String toString() {
- return "{ font: "+font+" } ";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("font", this::getFont);
}
}
}
package org.apache.poi.hwmf.record;
-import static org.apache.poi.hwmf.record.HwmfDraw.boundsToString;
-import static org.apache.poi.hwmf.record.HwmfDraw.dimToString;
import static org.apache.poi.hwmf.record.HwmfDraw.normalizeBounds;
-import static org.apache.poi.hwmf.record.HwmfDraw.pointToString;
import static org.apache.poi.hwmf.record.HwmfDraw.readBounds;
import static org.apache.poi.hwmf.record.HwmfDraw.readPointS;
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.Map;
+import java.util.function.Supplier;
+import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hwmf.draw.HwmfDrawProperties;
import org.apache.poi.hwmf.draw.HwmfGraphics;
import org.apache.poi.util.Dimension2DDouble;
+import org.apache.poi.util.GenericRecordJsonWriter;
+import org.apache.poi.util.GenericRecordUtil;
import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream;
@Override
public String toString() {
- return pointToString(origin);
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public Point2D getOrigin() {
+ return origin;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("origin", this::getOrigin);
}
}
@Override
public String toString() {
- return dimToString(extents);
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public Dimension2D getExtents() {
+ return extents;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("extents", this::getExtents);
}
}
@Override
public String toString() {
- return pointToString(offset);
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public Point2D getOffset() {
+ return offset;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("offset", this::getOffset);
}
}
@Override
public String toString() {
- return pointToString(origin);
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public Point2D getOrigin() {
+ return origin;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("origin", this::getOrigin);
+ }
+
}
/**
@Override
public String toString() {
- return dimToString(size);
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("size", this::getSize);
}
}
@Override
public String toString() {
- return pointToString(offset);
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public Point2D getOffset() {
+ return offset;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("offset", this::getOffset);
}
}
@Override
public String toString() {
- return "{ scaleX: "+scale.getWidth()+", scaleY: "+scale.getHeight()+" }";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public Dimension2D getScale() {
+ return scale;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("scale", this::getScale);
}
+
}
@Override
public String toString() {
- return "{ scaleX: "+scale.getWidth()+", scaleY: "+scale.getHeight()+" }";
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public Dimension2D getScale() {
+ return scale;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("scale", this::getScale);
}
}
@Override
public String toString() {
- return pointToString(offset);
+ return GenericRecordJsonWriter.marshal(this);
+ }
+
+ public Point2D getOffset() {
+ return offset;
}
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("offset", this::getOffset);
+ }
+
}
/**
@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);
}
}
@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);
}
}
public void draw(HwmfGraphics ctx) {
}
+
+ public int getRegion() {
+ return region;
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties("region", this::getRegion);
+ }
}
- public static class WmfScanObject {
+ public static class WmfScanObject implements GenericRecord {
/**
* A 16-bit unsigned integer that specifies the number of horizontal (x-axis)
* coordinates in the ScanLines array. This value MUST be a multiple of 2, since left and right
size += LittleEndianConsts.SHORT_SIZE;
return size;
}
+
+ @SuppressWarnings("ArraysAsListWithZeroOrOneArgument")
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return GenericRecordUtil.getGenericProperties(
+ "count", () -> count,
+ "top", () -> top,
+ "bottom", () -> bottom,
+ "left_scanline", () -> Arrays.asList(left_scanline),
+ "right_scanline", () -> Arrays.asList(right_scanline),
+ "count2", () -> count2
+ );
+ }
}
public static class WmfCreateRegion implements HwmfRecord, HwmfObjectTableEntry {
*/
private int maxScan;
- private Rectangle2D bounds = new Rectangle2D.Double();
+ private final Rectangle2D bounds = new Rectangle2D.Double();
/**
* An array of Scan objects that define the scanlines in the region.
ctx.getProperties().setRegion(region);
}
+
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ final Map<String,Supplier<?>> m = new LinkedHashMap<>();
+ m.put("nextInChain", () -> nextInChain);
+ m.put("objectType", () -> objectType);
+ m.put("objectCount", () -> objectCount);
+ m.put("regionSize", () -> regionSize);
+ m.put("scanCount", () -> scanCount);
+ m.put("maxScan", () -> maxScan);
+ m.put("bounds", () -> bounds);
+ m.put("scanObjects", () -> Arrays.asList(scanObjects));
+ return Collections.unmodifiableMap(m);
+ }
}
}
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
+import java.util.Spliterator;
+import java.util.function.Supplier;
+import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hwmf.draw.HwmfDrawProperties;
import org.apache.poi.hwmf.draw.HwmfGraphics;
import org.apache.poi.hwmf.record.HwmfHeader;
import org.apache.poi.util.RecordFormatException;
import org.apache.poi.util.Units;
-public class HwmfPicture {
+public class HwmfPicture implements Iterable<HwmfRecord>, GenericRecord {
/** Max. record length - processing longer records will throw an exception */
public static final int MAX_RECORD_LENGTH = 50_000_000;
public Iterable<HwmfEmbedded> getEmbeddings() {
return () -> new HwmfEmbeddedIterator(HwmfPicture.this);
}
+
+ @Override
+ public Iterator<HwmfRecord> iterator() {
+ return getRecords().iterator();
+ }
+
+ @Override
+ public Spliterator<HwmfRecord> spliterator() {
+ return getRecords().spliterator();
+ }
+
+ @Override
+ public Map<String, Supplier<?>> getGenericProperties() {
+ return null;
+ }
+
+ @Override
+ public List<? extends GenericRecord> getGenericChildren() {
+ return getRecords();
+ }
}
package org.apache.poi.hslf.model;
-import static org.apache.poi.hslf.record.TextHeaderAtom.BODY_TYPE;
-import static org.apache.poi.hslf.record.TextHeaderAtom.CENTER_TITLE_TYPE;
-import static org.apache.poi.hslf.record.TextHeaderAtom.CENTRE_BODY_TYPE;
-import static org.apache.poi.hslf.record.TextHeaderAtom.TITLE_TYPE;
+import static org.apache.poi.sl.usermodel.TextShape.TextPlaceholder.BODY;
+import static org.apache.poi.sl.usermodel.TextShape.TextPlaceholder.CENTER_BODY;
+import static org.apache.poi.sl.usermodel.TextShape.TextPlaceholder.CENTER_TITLE;
+import static org.apache.poi.sl.usermodel.TextShape.TextPlaceholder.TITLE;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import org.apache.poi.hslf.model.textproperties.CharFlagsTextProp;
import org.apache.poi.hslf.model.textproperties.TextProp;
import org.apache.poi.hslf.record.Environment;
-import org.apache.poi.hslf.record.TextHeaderAtom;
import org.apache.poi.hslf.usermodel.HSLFMasterSheet;
import org.apache.poi.hslf.usermodel.HSLFSlide;
import org.apache.poi.hslf.usermodel.HSLFSlideMaster;
import org.apache.poi.hslf.usermodel.HSLFTextParagraph;
import org.apache.poi.hslf.usermodel.HSLFTextRun;
import org.apache.poi.hslf.usermodel.HSLFTitleMaster;
+import org.apache.poi.sl.usermodel.TextShape.TextPlaceholder;
import org.junit.Test;
/**
assertEquals(2, ppt.getSlideMasters().size());
//character attributes
- assertEquals(40, getMasterVal(ppt, 0, TITLE_TYPE, "font.size", true));
- assertEquals(48, getMasterVal(ppt, 1, TITLE_TYPE, "font.size", true));
+ assertEquals(40, getMasterVal(ppt, 0, TITLE, "font.size", true));
+ assertEquals(48, getMasterVal(ppt, 1, TITLE, "font.size", true));
- int font1 = getMasterVal(ppt, 0, TITLE_TYPE, "font.index", true);
- int font2 = getMasterVal(ppt, 1, TITLE_TYPE, "font.index", true);
+ int font1 = getMasterVal(ppt, 0, TITLE, "font.index", true);
+ int font2 = getMasterVal(ppt, 1, TITLE, "font.index", true);
assertEquals("Arial", env.getFontCollection().getFontInfo(font1).getTypeface());
assertEquals("Georgia", env.getFontCollection().getFontInfo(font2).getTypeface());
- CharFlagsTextProp prop1 = getMasterProp(ppt, 0, TITLE_TYPE, "char_flags", true);
- assertEquals(false, prop1.getSubValue(CharFlagsTextProp.BOLD_IDX));
- assertEquals(false, prop1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
- assertEquals(true, prop1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
+ CharFlagsTextProp prop1 = getMasterProp(ppt, 0, TITLE, "char_flags", true);
+ assertFalse(prop1.getSubValue(CharFlagsTextProp.BOLD_IDX));
+ assertFalse(prop1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
+ assertTrue(prop1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
- CharFlagsTextProp prop2 = getMasterProp(ppt, 1, TITLE_TYPE, "char_flags", true);
- assertEquals(false, prop2.getSubValue(CharFlagsTextProp.BOLD_IDX));
- assertEquals(true, prop2.getSubValue(CharFlagsTextProp.ITALIC_IDX));
- assertEquals(false, prop2.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
+ CharFlagsTextProp prop2 = getMasterProp(ppt, 1, TITLE, "char_flags", true);
+ assertFalse(prop2.getSubValue(CharFlagsTextProp.BOLD_IDX));
+ assertTrue(prop2.getSubValue(CharFlagsTextProp.ITALIC_IDX));
+ assertFalse(prop2.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
//now paragraph attributes
- assertEquals(0x266B, getMasterVal(ppt, 0, BODY_TYPE, "bullet.char", false));
- assertEquals(0x2022, getMasterVal(ppt, 1, BODY_TYPE, "bullet.char", false));
+ assertEquals(0x266B, getMasterVal(ppt, 0, BODY, "bullet.char", false));
+ assertEquals(0x2022, getMasterVal(ppt, 1, BODY, "bullet.char", false));
- int b1 = getMasterVal(ppt, 0, BODY_TYPE, "bullet.font", false);
- int b2 = getMasterVal(ppt, 1, BODY_TYPE, "bullet.font", false);
+ int b1 = getMasterVal(ppt, 0, BODY, "bullet.font", false);
+ int b2 = getMasterVal(ppt, 1, BODY, "bullet.font", false);
assertEquals("Arial", env.getFontCollection().getFontInfo(b1).getTypeface());
assertEquals("Georgia", env.getFontCollection().getFontInfo(b2).getTypeface());
}
@SuppressWarnings("unchecked")
- private static <T extends TextProp> T getMasterProp(HSLFSlideShow ppt, int masterIdx, int txtype, String propName, boolean isCharacter) {
- return (T)ppt.getSlideMasters().get(masterIdx).getPropCollection(txtype, 0, propName, isCharacter).findByName(propName);
+ private static <T extends TextProp> T getMasterProp(HSLFSlideShow ppt, int masterIdx, TextPlaceholder txtype, String propName, boolean isCharacter) {
+ return (T)ppt.getSlideMasters().get(masterIdx).getPropCollection(txtype.nativeId, 0, propName, isCharacter).findByName(propName);
}
- private static int getMasterVal(HSLFSlideShow ppt, int masterIdx, int txtype, String propName, boolean isCharacter) {
+ private static int getMasterVal(HSLFSlideShow ppt, int masterIdx, TextPlaceholder txtype, String propName, boolean isCharacter) {
return getMasterProp(ppt, masterIdx, txtype, propName, isCharacter).getValue();
}
HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("slide_master.ppt"));
assertEquals(1, ppt.getTitleMasters().size());
- assertEquals(40, getMasterVal(ppt, 0, CENTER_TITLE_TYPE, "font.size", true));
- CharFlagsTextProp prop1 = getMasterProp(ppt, 0, CENTER_TITLE_TYPE, "char_flags", true);
- assertEquals(false, prop1.getSubValue(CharFlagsTextProp.BOLD_IDX));
- assertEquals(false, prop1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
- assertEquals(true, prop1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
+ assertEquals(40, getMasterVal(ppt, 0, CENTER_TITLE, "font.size", true));
+ CharFlagsTextProp prop1 = getMasterProp(ppt, 0, CENTER_TITLE, "char_flags", true);
+ assertFalse(prop1.getSubValue(CharFlagsTextProp.BOLD_IDX));
+ assertFalse(prop1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
+ assertTrue(prop1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
- assertEquals(32, getMasterVal(ppt, 0, CENTRE_BODY_TYPE, "font.size", true));
- CharFlagsTextProp prop2 = getMasterProp(ppt, 0, CENTRE_BODY_TYPE, "char_flags", true);
- assertEquals(false, prop2.getSubValue(CharFlagsTextProp.BOLD_IDX));
- assertEquals(false, prop2.getSubValue(CharFlagsTextProp.ITALIC_IDX));
- assertEquals(false, prop2.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
+ assertEquals(32, getMasterVal(ppt, 0, CENTER_BODY, "font.size", true));
+ CharFlagsTextProp prop2 = getMasterProp(ppt, 0, CENTER_BODY, "char_flags", true);
+ assertFalse(prop2.getSubValue(CharFlagsTextProp.BOLD_IDX));
+ assertFalse(prop2.getSubValue(CharFlagsTextProp.ITALIC_IDX));
+ assertFalse(prop2.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
ppt.close();
}
for (List<HSLFTextParagraph> txt : slide.getTextParagraphs()) {
HSLFTextRun rt = txt.get(0).getTextRuns().get(0);
- switch(txt.get(0).getRunType()){
- case TextHeaderAtom.CENTER_TITLE_TYPE:
+ switch(TextPlaceholder.fromNativeId(txt.get(0).getRunType())){
+ case CENTER_TITLE:
assertEquals("Arial", rt.getFontFamily());
assertEquals(32, rt.getFontSize(), 0);
- assertEquals(true, rt.isBold());
- assertEquals(true, rt.isUnderlined());
+ assertTrue(rt.isBold());
+ assertTrue(rt.isUnderlined());
break;
- case TextHeaderAtom.CENTRE_BODY_TYPE:
+ case CENTER_BODY:
assertEquals("Courier New", rt.getFontFamily());
assertEquals(20, rt.getFontSize(), 0);
- assertEquals(true, rt.isBold());
- assertEquals(false, rt.isUnderlined());
+ assertTrue(rt.isBold());
+ assertFalse(rt.isUnderlined());
break;
}
assertEquals(3, slide.size());
for (List<HSLFTextParagraph> tparas : slide.get(0).getTextParagraphs()) {
HSLFTextParagraph tpara = tparas.get(0);
- if (tpara.getRunType() == TextHeaderAtom.TITLE_TYPE){
+ if (tpara.getRunType() == TITLE.nativeId){
HSLFTextRun rt = tpara.getTextRuns().get(0);
assertEquals(40, rt.getFontSize(), 0);
- assertEquals(true, rt.isUnderlined());
+ assertTrue(rt.isUnderlined());
assertEquals("Arial", rt.getFontFamily());
- } else if (tpara.getRunType() == TextHeaderAtom.BODY_TYPE){
+ } else if (tpara.getRunType() == BODY.nativeId){
HSLFTextRun rt = tpara.getTextRuns().get(0);
assertEquals(0, tpara.getIndentLevel());
assertEquals(32, rt.getFontSize(), 0);
for (List<HSLFTextParagraph> tparas : slide.get(1).getTextParagraphs()) {
HSLFTextParagraph tpara = tparas.get(0);
- if (tpara.getRunType() == TextHeaderAtom.TITLE_TYPE){
+ if (tpara.getRunType() == TITLE.nativeId){
HSLFTextRun rt = tpara.getTextRuns().get(0);
assertEquals(48, rt.getFontSize(), 0);
- assertEquals(true, rt.isItalic());
+ assertTrue(rt.isItalic());
assertEquals("Georgia", rt.getFontFamily());
- } else if (tpara.getRunType() == TextHeaderAtom.BODY_TYPE){
+ } else if (tpara.getRunType() == BODY.nativeId){
HSLFTextRun rt;
rt = tpara.getTextRuns().get(0);
assertEquals(0, tpara.getIndentLevel());
for (List<HSLFTextParagraph> tparas : slide.getTextParagraphs()) {
HSLFTextParagraph tpara = tparas.get(0);
- if (tpara.getRunType() == TextHeaderAtom.TITLE_TYPE){
+ if (tpara.getRunType() == TITLE.nativeId){
HSLFTextRun rt = tpara.getTextRuns().get(0);
assertEquals(40, rt.getFontSize(), 0);
- assertEquals(true, rt.isUnderlined());
+ assertTrue(rt.isUnderlined());
assertEquals("Arial", rt.getFontFamily());
- } else if (tpara.getRunType() == TextHeaderAtom.BODY_TYPE){
+ } else if (tpara.getRunType() == BODY.nativeId){
int[] indents = {32, 28, 24};
for (HSLFTextRun rt : tpara.getTextRuns()) {
int indent = tpara.getIndentLevel();
import java.util.List;
import org.apache.poi.POIDataSamples;
-import org.apache.poi.hslf.record.TextHeaderAtom;
import org.apache.poi.hslf.usermodel.HSLFShape;
import org.apache.poi.hslf.usermodel.HSLFSlide;
import org.apache.poi.hslf.usermodel.HSLFSlideShow;
import org.apache.poi.sl.usermodel.Slide;
import org.apache.poi.sl.usermodel.SlideShow;
import org.apache.poi.sl.usermodel.TableShape;
+import org.apache.poi.sl.usermodel.TextShape.TextPlaceholder;
import org.junit.Test;
/**
HSLFTableCell cell = tbl.getCell(0, 0);
//table cells have type=TextHeaderAtom.OTHER_TYPE, see bug #46033
- assertEquals(TextHeaderAtom.OTHER_TYPE, cell.getTextParagraphs().get(0).getRunType());
+ assertEquals(TextPlaceholder.OTHER.nativeId, cell.getTextParagraphs().get(0).getRunType());
HSLFShape tblSh = slide.getShapes().get(0);
assertTrue(tblSh instanceof HSLFTable);
package org.apache.poi.hslf.record;
-import org.junit.Test;
-
import static org.junit.Assert.assertEquals;
+import org.apache.poi.ddf.EscherRecordTypes;
+import org.junit.Test;
+
/**
* Tests that RecordTypes returns the right records and classes when asked
*/
@Test
public void testEscherNameLookups() {
- assertEquals("EscherDggContainer", RecordTypes.EscherDggContainer.name());
- assertEquals("EscherClientTextbox", RecordTypes.EscherClientTextbox.name());
- assertEquals("EscherSelection", RecordTypes.EscherSelection.name());
+ assertEquals("DGG_CONTAINER", EscherRecordTypes.DGG_CONTAINER.name());
+ assertEquals("CLIENT_TEXTBOX", EscherRecordTypes.CLIENT_TEXTBOX.name());
+ assertEquals("SELECTION", EscherRecordTypes.SELECTION.name());
}
@Test
// This is checking the "unhandled default" stuff works
assertEquals(RecordTypes.UnknownRecordPlaceholder, RecordTypes.forTypeID(-10));
}
-
- @Test
- public void testEscherClassLookups() {
- // Should all come back with null, as DDF handles them
- assertEquals(null, RecordTypes.EscherDggContainer.recordConstructor);
- assertEquals(null, RecordTypes.EscherBStoreContainer.recordConstructor);
- }
}
package org.apache.poi.hslf.record;
-import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
+import junit.framework.TestCase;
+import org.apache.poi.sl.usermodel.TextShape.TextPlaceholder;
+
/**
* Tests that TextHeaderAtom works properly
*
TextHeaderAtom n_tha = new TextHeaderAtom(notes_data,0,12);
TextHeaderAtom t_tha = new TextHeaderAtom(title_data,0,12);
TextHeaderAtom b_tha = new TextHeaderAtom(body_data,0,12);
- assertEquals(TextHeaderAtom.NOTES_TYPE, n_tha.getTextType());
- assertEquals(TextHeaderAtom.TITLE_TYPE, t_tha.getTextType());
- assertEquals(TextHeaderAtom.BODY_TYPE, b_tha.getTextType());
+ assertEquals(TextPlaceholder.NOTES.nativeId, n_tha.getTextType());
+ assertEquals(TextPlaceholder.TITLE.nativeId, t_tha.getTextType());
+ assertEquals(TextPlaceholder.BODY.nativeId, b_tha.getTextType());
}
public void testWrite() throws Exception {
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
-
import org.apache.poi.hslf.model.textproperties.TextProp;
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.sl.usermodel.TextShape.TextPlaceholder;
/**
TxMasterStyleAtom[] txmaster = getMasterStyles();
for (final TxMasterStyleAtom atom : txmaster) {
final int txtype = atom.getTextType();
- switch (txtype){
- case TextHeaderAtom.TITLE_TYPE:
+ switch (TextPlaceholder.fromNativeId(txtype)){
+ case TITLE:
checkTitleType(atom);
break;
- case TextHeaderAtom.BODY_TYPE:
+ case BODY:
checkBodyType(atom);
break;
- case TextHeaderAtom.NOTES_TYPE:
+ case NOTES:
checkNotesType(atom);
break;
- case TextHeaderAtom.OTHER_TYPE:
+ case OTHER:
checkOtherType(atom);
break;
- case TextHeaderAtom.CENTRE_BODY_TYPE:
+ case CENTER_BODY:
break;
- case TextHeaderAtom.CENTER_TITLE_TYPE:
+ case CENTER_TITLE:
break;
- case TextHeaderAtom.HALF_BODY_TYPE:
+ case HALF_BODY:
break;
- case TextHeaderAtom.QUARTER_BODY_TYPE:
+ case QUARTER_BODY:
break;
default:
fail("Unknown text type: " + txtype);
}
assertEquals("Document.Environment must contain TxMasterStyleAtom with type=TextHeaderAtom.OTHER_TYPE",
- TextHeaderAtom.OTHER_TYPE, txstyle.getTextType());
+ TextPlaceholder.OTHER.nativeId, txstyle.getTextType());
lst.add(txstyle);
}
}
import java.util.Map;
import org.apache.poi.hslf.HSLFTestDataSamples;
-import org.apache.poi.hslf.record.TextHeaderAtom;
import org.apache.poi.sl.usermodel.ShapeType;
+import org.apache.poi.sl.usermodel.TextShape.TextPlaceholder;
import org.junit.Test;
/**
assertEquals("Text in a TextBox", rawText);
break;
case RECT:
- if(runType == TextHeaderAtom.OTHER_TYPE) {
+ if(runType == TextPlaceholder.OTHER.nativeId) {
assertEquals("Rectangle", rawText);
- } else if(runType == TextHeaderAtom.TITLE_TYPE) {
+ } else if(runType == TextPlaceholder.TITLE.nativeId) {
assertEquals("Title Placeholder", rawText);
}
break;
import static org.apache.poi.POITestCase.assertContains;
import static org.junit.Assert.assertEquals;
-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.File;
-import java.io.FileFilter;
import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
-import java.util.Locale;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
-import javax.imageio.ImageIO;
import org.apache.poi.POIDataSamples;
-import org.apache.poi.hwmf.record.HwmfFill.HwmfImageRecord;
import org.apache.poi.hwmf.record.HwmfFont;
import org.apache.poi.hwmf.record.HwmfRecord;
import org.apache.poi.hwmf.record.HwmfRecordType;
import org.apache.poi.hwmf.record.HwmfText;
-import org.apache.poi.hwmf.usermodel.HwmfEmbedded;
import org.apache.poi.hwmf.usermodel.HwmfPicture;
-import org.apache.poi.sl.usermodel.PictureData;
-import org.apache.poi.sl.usermodel.PictureData.PictureType;
-import org.apache.poi.sl.usermodel.SlideShow;
-import org.apache.poi.sl.usermodel.SlideShowFactory;
import org.apache.poi.util.LocaleUtil;
import org.apache.poi.util.RecordFormatException;
-import org.apache.poi.util.Units;
import org.junit.Ignore;
import org.junit.Test;
private static final POIDataSamples samples = POIDataSamples.getSlideShowInstance();
+ // ******************************************************************************
+ // for manual mass parsing and rendering tests of .wmfs use HemfPictureTest.paint() !
+ // ******************************************************************************
@Test
public void parse() throws IOException {
}
}
- @Test
- @Ignore("This is work-in-progress and not a real unit test ...")
- public void paint() throws IOException {
- boolean dumpEmbedded = true;
- boolean dumpRecords = false;
-
- File f = new File("testme.wmf");
- FileInputStream fis = new FileInputStream(f);
- HwmfPicture wmf = new HwmfPicture(fis);
- fis.close();
-
- Dimension2D dim = wmf.getSize();
- double width = Units.pointsToPixel(dim.getWidth());
- // keep aspect ratio for height
- double height = Units.pointsToPixel(dim.getHeight());
- double scale = (width > height) ? 1500 / width : 1500 / width;
- width = Math.abs(width * scale);
- height = Math.abs(height * scale);
-
- BufferedImage bufImg = new BufferedImage((int)width, (int)height, BufferedImage.TYPE_INT_ARGB);
- Graphics2D g = bufImg.createGraphics();
- g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
- g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
- g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
- g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
-
- wmf.draw(g, new Rectangle2D.Double(0,0,width,height));
-
- g.dispose();
-
- ImageIO.write(bufImg, "PNG", new File("bla.png"));
-
- if (dumpEmbedded) {
- int embIdx = 0;
- for (HwmfEmbedded emb : wmf.getEmbeddings()) {
- final File embName = new File("build/tmp", "emb_"+embIdx + emb.getEmbeddedType().extension);
- try (FileOutputStream fos = new FileOutputStream(embName)) {
- fos.write(emb.getRawData());
- }
- embIdx++;
- }
- }
-
- if (dumpRecords) {
- try (FileWriter fw = new FileWriter("wmf-records.log")) {
- for (HwmfRecord r : wmf.getRecords()) {
- fw.write(r.getWmfRecordType().name());
- fw.write(":");
- fw.write(r.toString());
- fw.write("\n");
- }
- }
- }
- }
-
- @Test
- @Ignore("This is work-in-progress and not a real unit test ...")
- public void fetchWmfFromGovdocs() throws IOException {
- URL url = new URL("http://digitalcorpora.org/corpora/files/govdocs1/by_type/ppt.zip");
- File outdir = new File("build/ppt");
- outdir.mkdirs();
- ZipInputStream zis = new ZipInputStream(url.openStream());
- ZipEntry ze;
- while ((ze = zis.getNextEntry()) != null) {
- String basename = ze.getName().replaceAll(".*?([^/]+)\\.wmf", "$1");
- FilterInputStream fis = new FilterInputStream(zis){
- @Override
- public void close() throws IOException {}
- };
- try {
- SlideShow<?,?> ss = SlideShowFactory.create(fis);
- int wmfIdx = 1;
- for (PictureData pd : ss.getPictureData()) {
- if (pd.getType() != PictureType.WMF) {
- continue;
- }
- byte[] wmfData = pd.getData();
- String filename = String.format(Locale.ROOT, "%s-%04d.wmf", basename, wmfIdx);
- FileOutputStream fos = new FileOutputStream(new File(outdir, filename));
- fos.write(wmfData);
- fos.close();
- wmfIdx++;
- }
- ss.close();
- } catch (Exception e) {
- System.out.println(ze.getName()+" ignored.");
- }
- }
- }
-
- @Test
- @Ignore("This is work-in-progress and not a real unit test ...")
- public void parseWmfs() throws IOException {
- // parse and render the extracted wmfs from the fetchWmfFromGovdocs step
- boolean outputFiles = false;
- boolean renderWmf = true;
- File indir = new File("E:\\project\\poi\\misc\\govdocs-ppt");
- File outdir = new File("build/wmf");
- outdir.mkdirs();
- final String startFile = "";
- File[] files = indir.listFiles(new FileFilter() {
- boolean foundStartFile;
-
- @Override
- public boolean accept(File pathname) {
- foundStartFile |= startFile.isEmpty() || pathname.getName().contains(startFile);
- return foundStartFile && pathname.getName().matches("(?i).*\\.wmf?$");
- }
- });
- for (File f : files) {
- try {
- String basename = f.getName().replaceAll(".*?([^/]+)\\.wmf", "$1");
- FileInputStream fis = new FileInputStream(f);
- HwmfPicture wmf = new HwmfPicture(fis);
- fis.close();
-
- int bmpIndex = 1;
- for (HwmfRecord r : wmf.getRecords()) {
- if (r instanceof HwmfImageRecord) {
- BufferedImage bi = ((HwmfImageRecord)r).getImage();
- if (bi != null && outputFiles) {
- String filename = String.format(Locale.ROOT, "%s-%04d.png", basename, bmpIndex);
- ImageIO.write(bi, "PNG", new File(outdir, filename));
- }
- bmpIndex++;
- }
- }
-
- if (renderWmf) {
- Dimension2D dim = wmf.getSize();
- int width = Units.pointsToPixel(dim.getWidth());
- // keep aspect ratio for height
- int height = Units.pointsToPixel(dim.getHeight());
-
- BufferedImage bufImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
- Graphics2D g = bufImg.createGraphics();
- g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
- g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
- g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
- g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
-
- wmf.draw(g);
-
- g.dispose();
-
- ImageIO.write(bufImg, "PNG", new File(outdir, basename+".png"));
- }
- } catch (Exception e) {
- System.out.println(f.getName()+" ignored.");
- }
- }
- }
@Test
@Ignore("If we decide we can use common crawl file specified, we can turn this back on")
public String getRecordName() { return ""; }
@Override
protected Object[][] getAttributeMap() { return null; }
+ @Override
+ public Enum getGenericRecordType() { return EscherRecordTypes.UNKNOWN; }
}
@Test