Browse Source

#64693 - POI HwmfGraphics cannot read the embedded document title

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1881322 13f79535-47bb-0310-9956-ffa450edef68
tags/before_ooxml_3rd_edition
Andreas Beeker 3 years ago
parent
commit
b00ca445b2
23 changed files with 348 additions and 71 deletions
  1. 21
    12
      src/java/org/apache/poi/sl/draw/Drawable.java
  2. 8
    0
      src/java/org/apache/poi/sl/draw/ImageRenderer.java
  3. 42
    0
      src/java/org/apache/poi/util/GenericRecordJsonWriter.java
  4. 3
    1
      src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java
  5. 6
    0
      src/ooxml/java/org/apache/poi/xslf/util/EMFHandler.java
  6. 3
    0
      src/ooxml/java/org/apache/poi/xslf/util/MFProxy.java
  7. 15
    2
      src/ooxml/java/org/apache/poi/xslf/util/PPTHandler.java
  8. 22
    2
      src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java
  9. 20
    8
      src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java
  10. 4
    1
      src/resources/devtools/forbidden-signatures.txt
  11. 14
    0
      src/scratchpad/src/org/apache/poi/hemf/draw/HemfImageRenderer.java
  12. 18
    3
      src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfComment.java
  13. 1
    0
      src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfText.java
  14. 3
    3
      src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusDraw.java
  15. 15
    0
      src/scratchpad/src/org/apache/poi/hemf/usermodel/HemfPicture.java
  16. 37
    9
      src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java
  17. 17
    3
      src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfImageRenderer.java
  18. 7
    4
      src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java
  19. 22
    5
      src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java
  20. 30
    0
      src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfCharsetAware.java
  21. 20
    4
      src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java
  22. 20
    14
      src/testcases/org/apache/poi/poifs/filesystem/TestFileMagic.java
  23. BIN
      test-data/slideshow/bug64693.pptx

+ 21
- 12
src/java/org/apache/poi/sl/draw/Drawable.java View File

protected DrawableHint(int id) { protected DrawableHint(int id) {
super(id); super(id);
} }
public boolean isCompatibleValue(Object val) { public boolean isCompatibleValue(Object val) {
return true; return true;
} }
public String toString() { public String toString() {
switch (intKey()) { switch (intKey()) {
case 1: return "DRAW_FACTORY"; case 1: return "DRAW_FACTORY";
case 11: return "GRESTORE"; case 11: return "GRESTORE";
case 12: return "CURRENT_SLIDE"; case 12: return "CURRENT_SLIDE";
case 13: return "BUFFERED_IMAGE"; case 13: return "BUFFERED_IMAGE";
case 14: return "DEFAULT_CHARSET";
default: return "UNKNOWN_ID "+intKey(); default: return "UNKNOWN_ID "+intKey();
} }
} }
} }
/** /**
* {@link DrawFactory} which will be used to draw objects into this graphics context * {@link DrawFactory} which will be used to draw objects into this graphics context
*/ */
* Internal key for caching the preset geometries * Internal key for caching the preset geometries
*/ */
DrawableHint PRESET_GEOMETRY_CACHE = new DrawableHint(6); DrawableHint PRESET_GEOMETRY_CACHE = new DrawableHint(6);
/** /**
* draw text via {@link java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, float, float)} * draw text via {@link java.awt.Graphics2D#drawString(java.text.AttributedCharacterIterator, float, float)}
*/ */
/** /**
* Use this object to resolve unknown / missing fonts when rendering slides. * Use this object to resolve unknown / missing fonts when rendering slides.
* The font handler must be of type {@link DrawFontManager}.<p> * The font handler must be of type {@link DrawFontManager}.<p>
*
* In case a {@code FONT_HANDLER} is register, {@code FONT_FALLBACK} and {@code FONT_MAP} are ignored
*
* In case a {@code FONT_HANDLER} is register, {@code FONT_FALLBACK} and {@code FONT_MAP} are ignored
*/ */
DrawableHint FONT_HANDLER = new DrawableHint(7); DrawableHint FONT_HANDLER = new DrawableHint(7);
/** /**
* Key for a font fallback map of type {@code Map<String,String>} which maps * Key for a font fallback map of type {@code Map<String,String>} which maps
* the original font family (key) to the fallback font family (value). * the original font family (key) to the fallback font family (value).
* the original font family (key) to the mapped font family (value) * the original font family (key) to the mapped font family (value)
*/ */
DrawableHint FONT_MAP = new DrawableHint(9); DrawableHint FONT_MAP = new DrawableHint(9);
DrawableHint GSAVE = new DrawableHint(10); DrawableHint GSAVE = new DrawableHint(10);
DrawableHint GRESTORE = new DrawableHint(11); DrawableHint GRESTORE = new DrawableHint(11);
/** /**
* The Common SL Draw API works sometimes cascading, but there are places * The Common SL Draw API works sometimes cascading, but there are places
* where the current slide context need to be evaluated, e.g. when slide numbers * where the current slide context need to be evaluated, e.g. when slide numbers
*/ */
DrawableHint BUFFERED_IMAGE = new DrawableHint(13); DrawableHint BUFFERED_IMAGE = new DrawableHint(13);


/**
* Sets the default charset to render text elements.
* Opposed to other windows libraries in POI this simply defaults to Windows-1252.
* The rendering value is of type {@link java.nio.charset.Charset}
*/
DrawableHint DEFAULT_CHARSET = new DrawableHint(14);


/** /**
* Apply 2-D transforms before drawing this shape. This includes rotation and flipping. * Apply 2-D transforms before drawing this shape. This includes rotation and flipping.
* *
* @param graphics the graphics whos transform matrix will be modified * @param graphics the graphics whos transform matrix will be modified
*/ */
void applyTransform(Graphics2D graphics); void applyTransform(Graphics2D graphics);
/** /**
* Draw this shape into the supplied canvas * Draw this shape into the supplied canvas
* *
* @param graphics the graphics to draw into * @param graphics the graphics to draw into
*/ */
void draw(Graphics2D graphics); void draw(Graphics2D graphics);
/** /**
* draw any content within this shape (image, text, etc.). * draw any content within this shape (image, text, etc.).
* *
* @param graphics the graphics to draw into * @param graphics the graphics to draw into
*/ */
void drawContent(Graphics2D graphics);
void drawContent(Graphics2D graphics);
} }

+ 8
- 0
src/java/org/apache/poi/sl/draw/ImageRenderer.java View File

import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.Charset;


import org.apache.poi.common.usermodel.GenericRecord; import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.util.Dimension2DDouble; import org.apache.poi.util.Dimension2DDouble;


default GenericRecord getGenericRecord() { return null; } default GenericRecord getGenericRecord() { return null; }


/**
* Sets the default charset to render text elements.
* Opposed to other windows libraries in POI this simply defaults to Windows-1252.
*
* @param defaultCharset the default charset
*/
default void setDefaultCharset(Charset defaultCharset) {}
} }

+ 42
- 0
src/java/org/apache/poi/util/GenericRecordJsonWriter.java View File

import java.awt.geom.PathIterator; import java.awt.geom.PathIterator;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DirectColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.PackedColorModel;
import java.io.Closeable; import java.io.Closeable;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
private static final Pattern ESC_CHARS = Pattern.compile("[\"\\p{Cntrl}\\\\]"); private static final Pattern ESC_CHARS = Pattern.compile("[\"\\p{Cntrl}\\\\]");
private static final String NL = System.getProperty("line.separator"); private static final String NL = System.getProperty("line.separator");



@FunctionalInterface @FunctionalInterface
protected interface GenericRecordHandler { protected interface GenericRecordHandler {
/** /**
handler(Path2D.class, GenericRecordJsonWriter::printPath); handler(Path2D.class, GenericRecordJsonWriter::printPath);
handler(AffineTransform.class, GenericRecordJsonWriter::printAffineTransform); handler(AffineTransform.class, GenericRecordJsonWriter::printAffineTransform);
handler(Color.class, GenericRecordJsonWriter::printColor); handler(Color.class, GenericRecordJsonWriter::printColor);
handler(BufferedImage.class, GenericRecordJsonWriter::printImage);
handler(Array.class, GenericRecordJsonWriter::printArray); handler(Array.class, GenericRecordJsonWriter::printArray);
handler(Object.class, GenericRecordJsonWriter::printObject); handler(Object.class, GenericRecordJsonWriter::printObject);
} }
return true; return true;
} }


protected boolean printImage(String name, Object o) {
BufferedImage img = (BufferedImage)o;

final String[] COLOR_SPACES = {
"XYZ","Lab","Luv","YCbCr","Yxy","RGB","GRAY","HSV","HLS","CMYK","Unknown","CMY","Unknown"
};

final String[] IMAGE_TYPES = {
"CUSTOM","INT_RGB","INT_ARGB","INT_ARGB_PRE","INT_BGR","3BYTE_BGR","4BYTE_ABGR","4BYTE_ABGR_PRE",
"USHORT_565_RGB","USHORT_555_RGB","BYTE_GRAY","USHORT_GRAY","BYTE_BINARY","BYTE_INDEXED"
};

printName(name);
ColorModel cm = img.getColorModel();
String colorType =
(cm instanceof IndexColorModel) ? "indexed" :
(cm instanceof ComponentColorModel) ? "component" :
(cm instanceof DirectColorModel) ? "direct" :
(cm instanceof PackedColorModel) ? "packed" : "unknown";
fw.write(
"{ \"width\": "+img.getWidth()+
", \"height\": "+img.getHeight()+
", \"type\": \""+IMAGE_TYPES[img.getType()]+"\""+
", \"colormodel\": \""+colorType+"\""+
", \"pixelBits\": "+cm.getPixelSize()+
", \"numComponents\": "+cm.getNumComponents()+
", \"colorSpace\": \""+COLOR_SPACES[Math.min(cm.getColorSpace().getType(),12)]+"\""+
", \"transparency\": "+cm.getTransparency()+
", \"alpha\": "+cm.hasAlpha()+
"}"
);
return true;
}

static String trimHex(final long l, final int size) { static String trimHex(final long l, final int size) {
final String b = Long.toHexString(l); final String b = Long.toHexString(l);
int len = b.length(); int len = b.length();

+ 3
- 1
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java View File

// SYMBOL is missing // SYMBOL is missing


if (font == null || !font.isSetTypeface() || "".equals(font.getTypeface())) { if (font == null || !font.isSetTypeface() || "".equals(font.getTypeface())) {
font = coll.getLatin();
// don't fallback to latin but bubble up in the style hierarchy (slide -> layout -> master -> theme)
return null;
// font = coll.getLatin();
} }
} }



+ 6
- 0
src/ooxml/java/org/apache/poi/xslf/util/EMFHandler.java View File

import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Collections; import java.util.Collections;


import org.apache.poi.common.usermodel.GenericRecord; import org.apache.poi.common.usermodel.GenericRecord;
? ((EmbeddedExtractor) imgr).getEmbeddings() ? ((EmbeddedExtractor) imgr).getEmbeddings()
: Collections.emptyList(); : Collections.emptyList();
} }

@Override
void setDefaultCharset(Charset charset) {
imgr.setDefaultCharset(charset);
}
} }

+ 3
- 0
src/ooxml/java/org/apache/poi/xslf/util/MFProxy.java View File

import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;


abstract GenericRecord getRoot(); abstract GenericRecord getRoot();


abstract Iterable<EmbeddedPart> getEmbeddings(int slideNo); abstract Iterable<EmbeddedPart> getEmbeddings(int slideNo);

abstract void setDefaultCharset(Charset charset);
} }

+ 15
- 2
src/ooxml/java/org/apache/poi/xslf/util/PPTHandler.java View File

import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Set; import java.util.Set;
import java.util.Spliterator; import java.util.Spliterator;
import java.util.Spliterators; import java.util.Spliterators;
import org.apache.poi.sl.usermodel.SlideShowFactory; import org.apache.poi.sl.usermodel.SlideShowFactory;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.LocaleUtil;


/** Handler for ppt and pptx files */ /** Handler for ppt and pptx files */
@Internal @Internal
class PPTHandler extends MFProxy { class PPTHandler extends MFProxy {
private SlideShow<?,?> ppt; private SlideShow<?,?> ppt;
private Slide<?,?> slide; private Slide<?,?> slide;
private Charset defaultCharset = LocaleUtil.CHARSET_1252;


@Override @Override
public void parse(File file) throws IOException { public void parse(File file) throws IOException {
throw e; throw e;
} }
} }
if (ppt == null) {
throw new IOException("Unknown file format or missing poi-scratchpad.jar / poi-ooxml.jar");
}
slide = ppt.getSlides().get(0); slide = ppt.getSlides().get(0);
} }


throw e; throw e;
} }
} }
if (ppt == null) {
throw new IOException("Unknown file format or missing poi-scratchpad.jar / poi-ooxml.jar");
}
slide = ppt.getSlides().get(0); slide = ppt.getSlides().get(0);
} }


; ;
} }


private static EmbeddedPart fromObjectShape(Shape s) {
final ObjectShape os = (ObjectShape)s;
private static EmbeddedPart fromObjectShape(Shape<?,?> s) {
final ObjectShape<?,?> os = (ObjectShape<?,?>)s;
final ObjectData od = os.getObjectData(); final ObjectData od = os.getObjectData();
EmbeddedPart embed = new EmbeddedPart(); EmbeddedPart embed = new EmbeddedPart();
embed.setName(od.getFileName()); embed.setName(od.getFileName());
}); });
return embed; return embed;
} }

@Override
void setDefaultCharset(Charset charset) {
}
} }

+ 22
- 2
src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java View File

import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
import java.util.regex.Pattern; import java.util.regex.Pattern;


import org.apache.poi.common.usermodel.GenericRecord; import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.poifs.filesystem.FileMagic; import org.apache.poi.poifs.filesystem.FileMagic;
import org.apache.poi.sl.draw.Drawable;
import org.apache.poi.sl.draw.EmbeddedExtractor.EmbeddedPart; import org.apache.poi.sl.draw.EmbeddedExtractor.EmbeddedPart;
import org.apache.poi.util.Dimension2DDouble; import org.apache.poi.util.Dimension2DDouble;
import org.apache.poi.util.GenericRecordJsonWriter; import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.LocaleUtil;
import org.apache.poi.xslf.util.OutputFormat.BitmapFormat; import org.apache.poi.xslf.util.OutputFormat.BitmapFormat;
import org.apache.poi.xslf.util.OutputFormat.SVGFormat; import org.apache.poi.xslf.util.OutputFormat.SVGFormat;


" -inputType <type> default input file type (OLE2,WMF,EMF), default is OLE2 = Powerpoint\n" + " -inputType <type> default input file type (OLE2,WMF,EMF), default is OLE2 = Powerpoint\n" +
" some files (usually wmf) don't have a header, i.e. an identifiable file magic\n" + " some files (usually wmf) don't have a header, i.e. an identifiable file magic\n" +
" -textAsShapes text elements are saved as shapes in SVG, necessary for variable spacing\n" + " -textAsShapes text elements are saved as shapes in SVG, necessary for variable spacing\n" +
" often found in math formulas";
" often found in math formulas\n" +
" -charset sets the default charset to be used, defaults to Windows-1252";


System.out.println(msg); System.out.println(msg);
// no System.exit here, as we also run in junit tests! // no System.exit here, as we also run in junit tests!
private boolean extractEmbedded = false; private boolean extractEmbedded = false;
private FileMagic defaultFileType = FileMagic.OLE2; private FileMagic defaultFileType = FileMagic.OLE2;
private boolean textAsShapes = false; private boolean textAsShapes = false;
private Charset charset = LocaleUtil.CHARSET_1252;


private PPTX2PNG() { private PPTX2PNG() {
} }
case "-extractEmbedded": case "-extractEmbedded":
extractEmbedded = true; extractEmbedded = true;
break; break;
case "-charset":
if (opt != null) {
charset = Charset.forName(opt);
i++;
} else {
charset = LocaleUtil.CHARSET_1252;
}
break;

default: default:
file = new File(args[i]); file = new File(args[i]);
break; break;
graphics.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_SPEED); graphics.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_SPEED);
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
graphics.setRenderingHint(Drawable.DEFAULT_CHARSET, getDefaultCharset());


graphics.scale(scale / lenSide, scale / lenSide); graphics.scale(scale / lenSide, scale / lenSide);


} }


private void dumpRecords(MFProxy proxy) throws IOException { private void dumpRecords(MFProxy proxy) throws IOException {
if (dumpfile == null) {
if (dumpfile == null || "null".equals(dumpfile.getPath())) {
return; return;
} }
GenericRecord gr = proxy.getRoot(); GenericRecord gr = proxy.getRoot();
proxy.setQuite(quiet); proxy.setQuite(quiet);
proxy.parse(file); proxy.parse(file);
} }
proxy.setDefaultCharset(charset);


return proxy; return proxy;
} }
return INPUT_PATTERN.matcher(inname).replaceAll(outpat); return INPUT_PATTERN.matcher(inname).replaceAll(outpat);
} }


private Charset getDefaultCharset() {
return charset;
}

static class NoScratchpadException extends IOException { static class NoScratchpadException extends IOException {
NoScratchpadException() { NoScratchpadException() {
} }

+ 20
- 8
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java View File



package org.apache.poi.xslf.usermodel; package org.apache.poi.xslf.usermodel;


import static java.util.Arrays.asList;
import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeFalse;


import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
/** /**
* Test class for testing PPTX2PNG utility which renders .ppt and .pptx slideshows * Test class for testing PPTX2PNG utility which renders .ppt and .pptx slideshows
*/ */
@SuppressWarnings("ConstantConditions")
@RunWith(Parameterized.class) @RunWith(Parameterized.class)
public class TestPPTX2PNG { public class TestPPTX2PNG {
private static boolean xslfOnly; private static boolean xslfOnly;
private static final POIDataSamples samples = POIDataSamples.getSlideShowInstance(); private static final POIDataSamples samples = POIDataSamples.getSlideShowInstance();
private static final File basedir = null; private static final File basedir = null;
private static final String files = private static final String files =
"53446.ppt, alterman_security.ppt, alterman_security.pptx, KEY02.pptx, themes.pptx, " +
"bug64693.pptx, 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," + "backgrounds.pptx, layouts.pptx, sample.pptx, shapes.pptx, 54880_chinese.ppt, keyframes.pptx," +
"customGeo.pptx, customGeo.ppt, wrench.emf, santa.wmf, missing-moveto.ppt"; "customGeo.pptx, customGeo.ppt, wrench.emf, santa.wmf, missing-moveto.ppt";


@Parameter @Parameter
public String pptFile; public String pptFile;


@SuppressWarnings("ConstantConditions")
@Parameters(name="{0}") @Parameters(name="{0}")
public static Collection<String> data() { public static Collection<String> data() {
Function<String, Stream<String>> fun = (basedir == null) ? Stream::of : Function<String, Stream<String>> fun = (basedir == null) ? Stream::of :
public void render() throws Exception { public void render() throws Exception {
assumeFalse("ignore HSLF (.ppt) / HEMF (.emf) / HWMF (.wmf) files in no-scratchpad run", xslfOnly && pptFile.matches(".*\\.(ppt|emf|wmf)$")); assumeFalse("ignore HSLF (.ppt) / HEMF (.emf) / HWMF (.wmf) files in no-scratchpad run", xslfOnly && pptFile.matches(".*\\.(ppt|emf|wmf)$"));


String[] args = {
// bug64693.pptx

final List<String> args = new ArrayList<>(asList(
"-format", "null", // png,gif,jpg,svg or null for test "-format", "null", // png,gif,jpg,svg or null for test
"-slide", "-1", // -1 for all "-slide", "-1", // -1 for all
"-outdir", new File("build/tmp/").getCanonicalPath(), "-outdir", new File("build/tmp/").getCanonicalPath(),
"-dump", "null", "-dump", "null",
"-quiet", "-quiet",
"-fixside", "long", "-fixside", "long",
"-scale", "800",
// "-scale", "1.333333333",
(basedir == null ? samples.getFile(pptFile) : new File(basedir, pptFile)).getAbsolutePath()
};
PPTX2PNG.main(args);
"-scale", "800"
));

if ("bug64693.pptx".equals(pptFile)) {
args.addAll(asList(
"-charset", "GBK"
));
}

args.add((basedir == null ? samples.getFile(pptFile) : new File(basedir, pptFile)).getAbsolutePath());

PPTX2PNG.main(args.toArray(new String[0]));
} }
} }

+ 4
- 1
src/resources/devtools/forbidden-signatures.txt View File

javax.xml.bind.DatatypeConverter javax.xml.bind.DatatypeConverter
@defaultMessage don't rely on the threads ContextClassLoader - provide the classloader via load(Class, Classloader) @defaultMessage don't rely on the threads ContextClassLoader - provide the classloader via load(Class, Classloader)
java.util.ServiceLoader#load(java.lang.Class)
java.util.ServiceLoader#load(java.lang.Class)
@defaultMessage use java.nio.charset.StandardCharsets instead
org.apache.commons.codec.Charsets

+ 14
- 0
src/scratchpad/src/org/apache/poi/hemf/draw/HemfImageRenderer.java View File

import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.Charset;


import org.apache.poi.common.usermodel.GenericRecord; import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hemf.usermodel.HemfPicture; import org.apache.poi.hemf.usermodel.HemfPicture;
import org.apache.poi.hwmf.draw.HwmfGraphicsState; import org.apache.poi.hwmf.draw.HwmfGraphicsState;
import org.apache.poi.hwmf.draw.HwmfImageRenderer; import org.apache.poi.hwmf.draw.HwmfImageRenderer;
import org.apache.poi.sl.draw.BitmapImageRenderer; import org.apache.poi.sl.draw.BitmapImageRenderer;
import org.apache.poi.sl.draw.Drawable;
import org.apache.poi.sl.draw.EmbeddedExtractor; import org.apache.poi.sl.draw.EmbeddedExtractor;
import org.apache.poi.sl.draw.ImageRenderer; import org.apache.poi.sl.draw.ImageRenderer;
import org.apache.poi.sl.usermodel.PictureData; import org.apache.poi.sl.usermodel.PictureData;
public class HemfImageRenderer implements ImageRenderer, EmbeddedExtractor { public class HemfImageRenderer implements ImageRenderer, EmbeddedExtractor {
HemfPicture image; HemfPicture image;
double alpha; double alpha;
boolean charsetInitialized = false;


@Override @Override
public boolean canRender(String contentType) { public boolean canRender(String contentType) {
return false; return false;
} }


Charset cs = (Charset)graphics.getRenderingHint(Drawable.DEFAULT_CHARSET);
if (cs != null && !charsetInitialized) {
setDefaultCharset(cs);
}

HwmfGraphicsState graphicsState = new HwmfGraphicsState(); HwmfGraphicsState graphicsState = new HwmfGraphicsState();
graphicsState.backup(graphics); graphicsState.backup(graphics);


public Rectangle2D getBounds() { public Rectangle2D getBounds() {
return Units.pointsToPixel(image == null ? new Rectangle2D.Double() : image.getBoundsInPoints()); return Units.pointsToPixel(image == null ? new Rectangle2D.Double() : image.getBoundsInPoints());
} }

@Override
public void setDefaultCharset(Charset defaultCharset) {
image.setDefaultCharset(defaultCharset);
charsetInitialized = true;
}
} }

+ 18
- 3
src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfComment.java View File



import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import org.apache.poi.hemf.draw.HemfGraphics.EmfRenderState; import org.apache.poi.hemf.draw.HemfGraphics.EmfRenderState;
import org.apache.poi.hemf.record.emfplus.HemfPlusRecord; import org.apache.poi.hemf.record.emfplus.HemfPlusRecord;
import org.apache.poi.hemf.record.emfplus.HemfPlusRecordIterator; import org.apache.poi.hemf.record.emfplus.HemfPlusRecordIterator;
import org.apache.poi.hwmf.usermodel.HwmfCharsetAware;
import org.apache.poi.hwmf.usermodel.HwmfPicture; import org.apache.poi.hwmf.usermodel.HwmfPicture;
import org.apache.poi.util.GenericRecordJsonWriter; import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.GenericRecordUtil; import org.apache.poi.util.GenericRecordUtil;
} }
} }


public static class EmfComment implements HemfRecord {
public static class EmfComment implements HemfRecord, HwmfCharsetAware {
private EmfCommentData data; private EmfCommentData data;


@Override @Override
} }
assert(commentIdentifier == commentType.id); assert(commentIdentifier == commentType.id);
} }

@Override
public void setCharsetProvider(Supplier<Charset> provider) {
if (data instanceof HwmfCharsetAware) {
((HwmfCharsetAware)data).setCharsetProvider(provider);
}
}
} }


public static class EmfCommentDataIterator implements Iterator<EmfCommentData> { public static class EmfCommentDataIterator implements Iterator<EmfCommentData> {
* Private data is unknown to EMF; it is meaningful only to applications that know the format of the * Private data is unknown to EMF; it is meaningful only to applications that know the format of the
* data and how to use it. EMR_COMMENT private data records MAY be ignored. * data and how to use it. EMR_COMMENT private data records MAY be ignored.
*/ */
public static class EmfCommentDataGeneric implements EmfCommentData {
public static class EmfCommentDataGeneric implements EmfCommentData, HwmfCharsetAware {
private byte[] privateData; private byte[] privateData;
private Supplier<Charset> charsetProvider = () -> LocaleUtil.CHARSET_1252;


@Override @Override
public HemfCommentRecordType getCommentRecordType() { public HemfCommentRecordType getCommentRecordType() {
} }


public String getPrivateDataAsString() { public String getPrivateDataAsString() {
return new String(privateData, LocaleUtil.CHARSET_1252);
return new String(privateData, charsetProvider.get());
} }


@Override @Override
"privateDataAsString", this::getPrivateDataAsString "privateDataAsString", this::getPrivateDataAsString
); );
} }

@Override
public void setCharsetProvider(Supplier<Charset> provider) {
charsetProvider = provider;
}
} }


/** The EMR_COMMENT_EMFPLUS record contains embedded EMF+ records. */ /** The EMR_COMMENT_EMFPLUS record contains embedded EMF+ records. */

+ 1
- 0
src/scratchpad/src/org/apache/poi/hemf/record/emf/HemfText.java View File

// the axis to convert from page space units to .01mm units. // the axis to convert from page space units to .01mm units.
// This SHOULD be used only if the graphics mode specified by iGraphicsMode is GM_COMPATIBLE. // This SHOULD be used only if the graphics mode specified by iGraphicsMode is GM_COMPATIBLE.
Dimension2D scl = graphicsMode == EmfGraphicsMode.GM_COMPATIBLE ? scale : null; Dimension2D scl = graphicsMode == EmfGraphicsMode.GM_COMPATIBLE ? scale : null;
ctx.setCharsetProvider(charsetProvider);
ctx.drawString(rawTextBytes, stringLength, reference, scl, bounds, options, dx, isUnicode()); ctx.drawString(rawTextBytes, stringLength, reference, scl, bounds, options, dx, isUnicode());
} }



+ 3
- 3
src/scratchpad/src/org/apache/poi/hemf/record/emfplus/HemfPlusDraw.java View File

import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Supplier; import java.util.function.Supplier;


import org.apache.commons.codec.Charsets;
import org.apache.commons.math3.linear.LUDecomposition; import org.apache.commons.math3.linear.LUDecomposition;
import org.apache.commons.math3.linear.MatrixUtils; import org.apache.commons.math3.linear.MatrixUtils;
import org.apache.commons.math3.linear.RealMatrix; import org.apache.commons.math3.linear.RealMatrix;
} }


if (REALIZED_ADVANCE.isSet(optionsFlags)) { if (REALIZED_ADVANCE.isSet(optionsFlags)) {
byte[] buf = glyphs.getBytes(Charsets.UTF_16LE);
byte[] buf = glyphs.getBytes(StandardCharsets.UTF_16LE);
ctx.drawString(buf, buf.length, glyphPos.get(0), null, null, null, null, true); ctx.drawString(buf, buf.length, glyphPos.get(0), null, null, null, null, true);
} else { } else {
final OfInt glyphIter = glyphs.codePoints().iterator(); final OfInt glyphIter = glyphs.codePoints().iterator();
glyphPos.forEach(p -> { glyphPos.forEach(p -> {
byte[] buf = new String(new int[]{glyphIter.next()}, 0, 1).getBytes(Charsets.UTF_16LE);
byte[] buf = new String(new int[]{glyphIter.next()}, 0, 1).getBytes(StandardCharsets.UTF_16LE);
ctx.drawString(buf, buf.length, p, null, null, null, null, true); ctx.drawString(buf, buf.length, p, null, null, null, null, true);
}); });
} }

+ 15
- 0
src/scratchpad/src/org/apache/poi/hemf/usermodel/HemfPicture.java View File

import java.awt.geom.Dimension2D; import java.awt.geom.Dimension2D;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.apache.poi.hemf.record.emf.HemfRecord; import org.apache.poi.hemf.record.emf.HemfRecord;
import org.apache.poi.hemf.record.emf.HemfRecordIterator; import org.apache.poi.hemf.record.emf.HemfRecordIterator;
import org.apache.poi.hemf.record.emf.HemfWindowing; import org.apache.poi.hemf.record.emf.HemfWindowing;
import org.apache.poi.hwmf.usermodel.HwmfCharsetAware;
import org.apache.poi.hwmf.usermodel.HwmfEmbedded; import org.apache.poi.hwmf.usermodel.HwmfEmbedded;
import org.apache.poi.util.Dimension2DDouble; import org.apache.poi.util.Dimension2DDouble;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndianInputStream; import org.apache.poi.util.LittleEndianInputStream;
import org.apache.poi.util.LocaleUtil;
import org.apache.poi.util.Units; import org.apache.poi.util.Units;


/** /**
private final LittleEndianInputStream stream; private final LittleEndianInputStream stream;
private final List<HemfRecord> records = new ArrayList<>(); private final List<HemfRecord> records = new ArrayList<>();
private boolean isParsed = false; private boolean isParsed = false;
private Charset defaultCharset = LocaleUtil.CHARSET_1252;


public HemfPicture(InputStream is) { public HemfPicture(InputStream is) {
this(new LittleEndianInputStream(is)); this(new LittleEndianInputStream(is));
header[0] = (HemfHeader) r; header[0] = (HemfHeader) r;
} }
r.setHeader(header[0]); r.setHeader(header[0]);
if (r instanceof HwmfCharsetAware) {
((HwmfCharsetAware)r).setCharsetProvider(this::getDefaultCharset);
}
records.add(r); records.add(r);
}); });
} }
public Map<String, Supplier<?>> getGenericProperties() { public Map<String, Supplier<?>> getGenericProperties() {
return null; return null;
} }

public void setDefaultCharset(Charset defaultCharset) {
this.defaultCharset = defaultCharset;
}

public Charset getDefaultCharset() {
return defaultCharset;
}
} }

+ 37
- 9
src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfGraphics.java View File

import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.AttributedString; import java.text.AttributedString;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.BitSet; import java.util.BitSet;
import java.util.Objects; import java.util.Objects;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Supplier;


import org.apache.commons.codec.Charsets;
import org.apache.poi.common.usermodel.fonts.FontCharset;
import org.apache.poi.common.usermodel.fonts.FontInfo; import org.apache.poi.common.usermodel.fonts.FontInfo;
import org.apache.poi.hwmf.record.HwmfBrushStyle; import org.apache.poi.hwmf.record.HwmfBrushStyle;
import org.apache.poi.hwmf.record.HwmfFont; import org.apache.poi.hwmf.record.HwmfFont;
import org.apache.poi.hwmf.record.HwmfPenStyle.HwmfLineDash; import org.apache.poi.hwmf.record.HwmfPenStyle.HwmfLineDash;
import org.apache.poi.hwmf.record.HwmfRegionMode; import org.apache.poi.hwmf.record.HwmfRegionMode;
import org.apache.poi.hwmf.record.HwmfText.WmfExtTextOutOptions; import org.apache.poi.hwmf.record.HwmfText.WmfExtTextOutOptions;
import org.apache.poi.hwmf.usermodel.HwmfCharsetAware;
import org.apache.poi.sl.draw.BitmapImageRenderer; import org.apache.poi.sl.draw.BitmapImageRenderer;
import org.apache.poi.sl.draw.DrawFactory; import org.apache.poi.sl.draw.DrawFactory;
import org.apache.poi.sl.draw.DrawFontManager; import org.apache.poi.sl.draw.DrawFontManager;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.LocaleUtil; import org.apache.poi.util.LocaleUtil;


public class HwmfGraphics {
public class HwmfGraphics implements HwmfCharsetAware {


public enum FillDrawStyle { public enum FillDrawStyle {
NONE(FillDrawStyle::fillNone), NONE(FillDrawStyle::fillNone),
private final AffineTransform initialAT = new AffineTransform(); private final AffineTransform initialAT = new AffineTransform();




private static final Charset DEFAULT_CHARSET = LocaleUtil.CHARSET_1252;
/** Bounding box from the placeable header */ /** Bounding box from the placeable header */
private final Rectangle2D bbox; private final Rectangle2D bbox;
private Supplier<Charset> charsetProvider = () -> LocaleUtil.CHARSET_1252;


/** /**
* Initialize a graphics context for wmf rendering * Initialize a graphics context for wmf rendering
} }
} }


private static Charset getCharset(HwmfFont font, boolean isUnicode) {
private Charset getCharset(HwmfFont font, boolean isUnicode) {
if (isUnicode) { if (isUnicode) {
return Charsets.UTF_16LE;
return StandardCharsets.UTF_16LE;
} }


Charset charset = font.getCharset().getCharset();
return (charset == null) ? DEFAULT_CHARSET : charset;
FontCharset fc = font.getCharset();
if (fc == FontCharset.DEFAULT) {
return charsetProvider.get();
}

Charset charset = fc.getCharset();
return (charset == null) ? charsetProvider.get() : charset;
} }


private static String trimText(HwmfFont font, boolean isUnicode, byte[] text, int length) {
@Override
public void setCharsetProvider(Supplier<Charset> provider) {
charsetProvider = provider;
}

private String trimText(HwmfFont font, boolean isUnicode, byte[] text, int length) {
final Charset charset = getCharset(font, isUnicode); final Charset charset = getCharset(font, isUnicode);


int trimLen; int trimLen;
graphicsCtx.fill(dstBounds); graphicsCtx.fill(dstBounds);
break; break;
default: default:
case SRCAND:
case SRCCOPY: case SRCCOPY:
case SRCINVERT:
if (img == null) { if (img == null) {
return; return;
} }
// the difference is, that clippings are 0-based, whereas the srcBounds are absolute in the user-space // the difference is, that clippings are 0-based, whereas the srcBounds are absolute in the user-space
// of the referenced image and can be also negative // of the referenced image and can be also negative
Composite old = graphicsCtx.getComposite(); Composite old = graphicsCtx.getComposite();
graphicsCtx.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
int newComp;
switch (prop.getRasterOp()) {
default:
case SRCCOPY:
newComp = AlphaComposite.SRC_OVER;
break;
case SRCINVERT:
newComp = AlphaComposite.SRC_IN;
break;
case SRCAND:
newComp = AlphaComposite.SRC;
break;
}
graphicsCtx.setComposite(AlphaComposite.getInstance(newComp));


boolean useDeviceBounds = (img instanceof HwmfImageRenderer); boolean useDeviceBounds = (img instanceof HwmfImageRenderer);



+ 17
- 3
src/scratchpad/src/org/apache/poi/hwmf/draw/HwmfImageRenderer.java View File

import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Iterator; import java.util.Iterator;


import org.apache.poi.common.usermodel.GenericRecord; import org.apache.poi.common.usermodel.GenericRecord;
import org.apache.poi.hwmf.usermodel.HwmfPicture; import org.apache.poi.hwmf.usermodel.HwmfPicture;
import org.apache.poi.sl.draw.BitmapImageRenderer; import org.apache.poi.sl.draw.BitmapImageRenderer;
import org.apache.poi.sl.draw.DrawPictureShape; import org.apache.poi.sl.draw.DrawPictureShape;
import org.apache.poi.sl.draw.Drawable;
import org.apache.poi.sl.draw.EmbeddedExtractor; import org.apache.poi.sl.draw.EmbeddedExtractor;
import org.apache.poi.sl.draw.ImageRenderer; import org.apache.poi.sl.draw.ImageRenderer;
import org.apache.poi.sl.usermodel.PictureData.PictureType; import org.apache.poi.sl.usermodel.PictureData.PictureType;
public class HwmfImageRenderer implements ImageRenderer, EmbeddedExtractor { public class HwmfImageRenderer implements ImageRenderer, EmbeddedExtractor {
HwmfPicture image; HwmfPicture image;
double alpha; double alpha;
boolean charsetInitialized = false;


@Override @Override
public boolean canRender(String contentType) { public boolean canRender(String contentType) {
@Override @Override
public BufferedImage getImage(Dimension2D dim) { public BufferedImage getImage(Dimension2D dim) {
if (image == null) { if (image == null) {
return new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
return new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
} }
BufferedImage bufImg = new BufferedImage((int)dim.getWidth(), (int)dim.getHeight(), BufferedImage.TYPE_INT_ARGB); BufferedImage bufImg = new BufferedImage((int)dim.getWidth(), (int)dim.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bufImg.createGraphics(); Graphics2D g = bufImg.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);


return BitmapImageRenderer.setAlpha(bufImg, alpha); return BitmapImageRenderer.setAlpha(bufImg, alpha);
} }
@Override @Override
public boolean drawImage(Graphics2D graphics, Rectangle2D anchor) { public boolean drawImage(Graphics2D graphics, Rectangle2D anchor) {
return drawImage(graphics, anchor, null); return drawImage(graphics, anchor, null);
return false; return false;
} }


Charset cs = (Charset)graphics.getRenderingHint(Drawable.DEFAULT_CHARSET);
if (cs != null && !charsetInitialized) {
setDefaultCharset(cs);
}

HwmfGraphicsState graphicsState = new HwmfGraphicsState(); HwmfGraphicsState graphicsState = new HwmfGraphicsState();
graphicsState.backup(graphics); graphicsState.backup(graphics);


public Rectangle2D getBounds() { public Rectangle2D getBounds() {
return Units.pointsToPixel(image == null ? new Rectangle2D.Double() : image.getBoundsInPoints()); return Units.pointsToPixel(image == null ? new Rectangle2D.Double() : image.getBoundsInPoints());
} }

@Override
public void setDefaultCharset(Charset defaultCharset) {
image.setDefaultCharset(defaultCharset);
charsetInitialized = true;
}
} }

+ 7
- 4
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfBitmapDib.java View File



if (foreground != null && background != null && headerBitCount == HwmfBitmapDib.BitCount.BI_BITCOUNT_1) { if (foreground != null && background != null && headerBitCount == HwmfBitmapDib.BitCount.BI_BITCOUNT_1) {
IndexColorModel cmOld = (IndexColorModel)bi.getColorModel(); IndexColorModel cmOld = (IndexColorModel)bi.getColorModel();
int transPixel = hasAlpha ? (((cmOld.getRGB(0) & 0xFFFFFF) == 0) ? 0 : 1) : -1;
int fg = foreground.getRGB();
int bg = background.getRGB() & (hasAlpha ? 0xFFFFFF : 0xFFFFFFFF);
boolean ordered = (cmOld.getRGB(0) & 0xFFFFFF) == (bg & 0xFFFFFF);
int transPixel = ordered ? 0 : 1;
int[] cmap = ordered ? new int[]{ bg, fg } : new int[]{ fg, bg };
int transferType = bi.getData().getTransferType(); int transferType = bi.getData().getTransferType();
int fg = foreground.getRGB(), bg = background.getRGB();
int[] cmap = { (transPixel == 0 ? bg : fg), (transPixel == 1 ? bg : fg) };
IndexColorModel cmNew = new IndexColorModel(1, cmap.length, cmap, 0, hasAlpha, transPixel, transferType);

IndexColorModel cmNew = new IndexColorModel(1, 2, cmap, 0, hasAlpha, transPixel, transferType);
bi = new BufferedImage(cmNew, bi.getRaster(), false, null); bi = new BufferedImage(cmNew, bi.getRaster(), false, null);
} }



+ 22
- 5
src/scratchpad/src/org/apache/poi/hwmf/record/HwmfText.java View File

import org.apache.poi.hwmf.draw.HwmfDrawProperties; import org.apache.poi.hwmf.draw.HwmfDrawProperties;
import org.apache.poi.hwmf.draw.HwmfGraphics; import org.apache.poi.hwmf.draw.HwmfGraphics;
import org.apache.poi.hwmf.record.HwmfMisc.WmfSetMapMode; import org.apache.poi.hwmf.record.HwmfMisc.WmfSetMapMode;
import org.apache.poi.hwmf.usermodel.HwmfCharsetAware;
import org.apache.poi.util.BitField; import org.apache.poi.util.BitField;
import org.apache.poi.util.BitFieldFactory; import org.apache.poi.util.BitFieldFactory;
import org.apache.poi.util.GenericRecordJsonWriter; import org.apache.poi.util.GenericRecordJsonWriter;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndianConsts; import org.apache.poi.util.LittleEndianConsts;
import org.apache.poi.util.LittleEndianInputStream; import org.apache.poi.util.LittleEndianInputStream;
import org.apache.poi.util.LocaleUtil;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;


* The META_TEXTOUT record outputs a character string at the specified location by using the font, * The META_TEXTOUT record outputs a character string at the specified location by using the font,
* background color, and text color that are defined in the playback device context. * background color, and text color that are defined in the playback device context.
*/ */
public static class WmfTextOut implements HwmfRecord {
public static class WmfTextOut implements HwmfRecord, HwmfCharsetAware {
/** /**
* A 16-bit signed integer that defines the length of the string, in bytes, pointed to by String. * A 16-bit signed integer that defines the length of the string, in bytes, pointed to by String.
*/ */


protected Point2D reference = new Point2D.Double(); protected Point2D reference = new Point2D.Double();


protected Supplier<Charset> charsetProvider = () -> LocaleUtil.CHARSET_1252;

@Override @Override
public HwmfRecordType getWmfRecordType() { public HwmfRecordType getWmfRecordType() {
return HwmfRecordType.textOut; return HwmfRecordType.textOut;


@Override @Override
public void draw(HwmfGraphics ctx) { public void draw(HwmfGraphics ctx) {
ctx.setCharsetProvider(charsetProvider);
ctx.drawString(getTextBytes(), stringLength, reference); ctx.drawString(getTextBytes(), stringLength, reference);
} }


"reference", () -> reference "reference", () -> reference
); );
} }

@Override
public void setCharsetProvider(Supplier<Charset> provider) {
charsetProvider = provider;
}
} }


@SuppressWarnings("unused") @SuppressWarnings("unused")
* are defined in the playback device context. Optionally, dimensions can be provided for clipping, * are defined in the playback device context. Optionally, dimensions can be provided for clipping,
* opaquing, or both. * opaquing, or both.
*/ */
public static class WmfExtTextOut implements HwmfRecord {
public static class WmfExtTextOut implements HwmfRecord, HwmfCharsetAware {
/** /**
* The location, in logical units, where the text string is to be placed. * The location, in logical units, where the text string is to be placed.
*/ */
*/ */
protected final List<Integer> dx = new ArrayList<>(); protected final List<Integer> dx = new ArrayList<>();


protected Supplier<Charset> charsetProvider = () -> LocaleUtil.CHARSET_1252;

public WmfExtTextOut() { public WmfExtTextOut() {
this(new WmfExtTextOutOptions()); this(new WmfExtTextOutOptions());
} }


@Override @Override
public void draw(HwmfGraphics ctx) { public void draw(HwmfGraphics ctx) {
ctx.setCharsetProvider(charsetProvider);
ctx.drawString(rawTextBytes, stringLength, reference, null, bounds, options, dx, false); ctx.drawString(rawTextBytes, stringLength, reference, null, bounds, options, dx, false);
} }


return ""; return "";
} }
String ret = new String(rawTextBytes, charset); String ret = new String(rawTextBytes, charset);
return ret.substring(0,
Math.min(ret.length(), stringLength));
return ret.substring(0, Math.min(ret.length(), stringLength));
} }


public Point2D getReference() { public Point2D getReference() {


private String getGenericText() { private String getGenericText() {
try { try {
return getText(isUnicode() ? StandardCharsets.UTF_16LE : StandardCharsets.US_ASCII);
return getText(isUnicode() ? StandardCharsets.UTF_16LE : charsetProvider.get());
} catch (IOException e) { } catch (IOException e) {
return ""; return "";
} }
"dx", () -> dx "dx", () -> dx
); );
} }

@Override
public void setCharsetProvider(Supplier<Charset> provider) {
charsetProvider = provider;
}
} }


public enum HwmfTextAlignment { public enum HwmfTextAlignment {

+ 30
- 0
src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfCharsetAware.java View File

/*
* ====================================================================
* 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.hwmf.usermodel;

import java.nio.charset.Charset;
import java.util.function.Supplier;

/**
* Helper interface to provide a default charset to records which would depend on a system charset
*/
public interface HwmfCharsetAware {
void setCharsetProvider(Supplier<Charset> provider);
}

+ 20
- 4
src/scratchpad/src/org/apache/poi/hwmf/usermodel/HwmfPicture.java View File

import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import org.apache.poi.util.Dimension2DDouble; import org.apache.poi.util.Dimension2DDouble;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndianInputStream; import org.apache.poi.util.LittleEndianInputStream;
import org.apache.poi.util.LocaleUtil;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
import org.apache.poi.util.RecordFormatException; import org.apache.poi.util.RecordFormatException;
public static final int MAX_RECORD_LENGTH = 50_000_000; public static final int MAX_RECORD_LENGTH = 50_000_000;


private static final POILogger logger = POILogFactory.getLogger(HwmfPicture.class); private static final POILogger logger = POILogFactory.getLogger(HwmfPicture.class);
final List<HwmfRecord> records = new ArrayList<>(); final List<HwmfRecord> records = new ArrayList<>();
final HwmfPlaceableHeader placeableHeader; final HwmfPlaceableHeader placeableHeader;
final HwmfHeader header; final HwmfHeader header;
/** The default charset */
private Charset defaultCharset = LocaleUtil.CHARSET_1252;

public HwmfPicture(InputStream inputStream) throws IOException { public HwmfPicture(InputStream inputStream) throws IOException {


try (LittleEndianInputStream leis = new LittleEndianInputStream(inputStream)) { try (LittleEndianInputStream leis = new LittleEndianInputStream(inputStream)) {
throw new RecordFormatException("Tried to skip "+remainingSize + " but skipped: "+skipped); throw new RecordFormatException("Tried to skip "+remainingSize + " but skipped: "+skipped);
} }
} }

if (wr instanceof HwmfCharsetAware) {
((HwmfCharsetAware)wr).setCharsetProvider(this::getDefaultCharset);
}
} }
} }
} }
Rectangle2D bounds = new Rectangle2D.Double(0,0,width,height); Rectangle2D bounds = new Rectangle2D.Double(0,0,width,height);
draw(ctx, bounds); draw(ctx, bounds);
} }
public void draw(Graphics2D ctx, Rectangle2D graphicsBounds) { public void draw(Graphics2D ctx, Rectangle2D graphicsBounds) {
HwmfGraphicsState state = new HwmfGraphicsState(); HwmfGraphicsState state = new HwmfGraphicsState();
state.backup(ctx); state.backup(ctx);
} }
if (wOrg != null && wExt != null) { if (wOrg != null && wExt != null) {
return new Rectangle2D.Double(wOrg.getX(), wOrg.getY(), wExt.getSize().getWidth(), wExt.getSize().getHeight()); return new Rectangle2D.Double(wOrg.getX(), wOrg.getY(), wExt.getSize().getWidth(), wExt.getSize().getHeight());
}
}
} }
return null; return null;
} }
public List<? extends GenericRecord> getGenericChildren() { public List<? extends GenericRecord> getGenericChildren() {
return getRecords(); return getRecords();
} }

public void setDefaultCharset(Charset defaultCharset) {
this.defaultCharset = defaultCharset;
}

public Charset getDefaultCharset() {
return defaultCharset;
}
} }

+ 20
- 14
src/testcases/org/apache/poi/poifs/filesystem/TestFileMagic.java View File



package org.apache.poi.poifs.filesystem; package org.apache.poi.poifs.filesystem;


import org.apache.commons.codec.Charsets;
import org.apache.poi.POIDataSamples;
import org.apache.poi.util.TempFile;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;


import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
import java.util.Random; import java.util.Random;


import static org.junit.Assert.*;
import org.apache.poi.POIDataSamples;
import org.apache.poi.util.TempFile;
import org.junit.Test;


public class TestFileMagic { public class TestFileMagic {
@Test @Test
public void testFileMagic() { public void testFileMagic() {
assertEquals(FileMagic.XML, FileMagic.valueOf("XML")); assertEquals(FileMagic.XML, FileMagic.valueOf("XML"));
assertEquals(FileMagic.XML, FileMagic.valueOf("<?xml".getBytes(Charsets.UTF_8)));
assertEquals(FileMagic.XML, FileMagic.valueOf("<?xml".getBytes(StandardCharsets.UTF_8)));


assertEquals(FileMagic.HTML, FileMagic.valueOf("HTML")); assertEquals(FileMagic.HTML, FileMagic.valueOf("HTML"));
assertEquals(FileMagic.HTML, FileMagic.valueOf("<!DOCTYP".getBytes(Charsets.UTF_8)));
assertEquals(FileMagic.HTML, FileMagic.valueOf("<!DOCTYPE".getBytes(Charsets.UTF_8)));
assertEquals(FileMagic.HTML, FileMagic.valueOf("<html".getBytes(Charsets.UTF_8)));
assertEquals(FileMagic.HTML, FileMagic.valueOf("\n\r<html".getBytes(Charsets.UTF_8)));
assertEquals(FileMagic.HTML, FileMagic.valueOf("\n<html".getBytes(Charsets.UTF_8)));
assertEquals(FileMagic.HTML, FileMagic.valueOf("\r\n<html".getBytes(Charsets.UTF_8)));
assertEquals(FileMagic.HTML, FileMagic.valueOf("\r<html".getBytes(Charsets.UTF_8)));
assertEquals(FileMagic.HTML, FileMagic.valueOf("<!DOCTYP".getBytes(StandardCharsets.UTF_8)));
assertEquals(FileMagic.HTML, FileMagic.valueOf("<!DOCTYPE".getBytes(StandardCharsets.UTF_8)));
assertEquals(FileMagic.HTML, FileMagic.valueOf("<html".getBytes(StandardCharsets.UTF_8)));
assertEquals(FileMagic.HTML, FileMagic.valueOf("\n\r<html".getBytes(StandardCharsets.UTF_8)));
assertEquals(FileMagic.HTML, FileMagic.valueOf("\n<html".getBytes(StandardCharsets.UTF_8)));
assertEquals(FileMagic.HTML, FileMagic.valueOf("\r\n<html".getBytes(StandardCharsets.UTF_8)));
assertEquals(FileMagic.HTML, FileMagic.valueOf("\r<html".getBytes(StandardCharsets.UTF_8)));


assertEquals(FileMagic.JPEG, FileMagic.valueOf(new byte[]{ (byte)0xFF, (byte)0xD8, (byte)0xFF, (byte)0xDB })); assertEquals(FileMagic.JPEG, FileMagic.valueOf(new byte[]{ (byte)0xFF, (byte)0xD8, (byte)0xFF, (byte)0xDB }));
assertEquals(FileMagic.JPEG, FileMagic.valueOf(new byte[]{ (byte)0xFF, (byte)0xD8, (byte)0xFF, (byte)0xE0, 'a', 'b', 'J', 'F', 'I', 'F', 0x00, 0x01 })); assertEquals(FileMagic.JPEG, FileMagic.valueOf(new byte[]{ (byte)0xFF, (byte)0xD8, (byte)0xFF, (byte)0xE0, 'a', 'b', 'J', 'F', 'I', 'F', 0x00, 0x01 }));
assertEquals(FileMagic.JPEG, FileMagic.valueOf(new byte[]{ (byte)0xFF, (byte)0xD8, (byte)0xFF, (byte)0xEE })); assertEquals(FileMagic.JPEG, FileMagic.valueOf(new byte[]{ (byte)0xFF, (byte)0xD8, (byte)0xFF, (byte)0xEE }));
assertEquals(FileMagic.JPEG, FileMagic.valueOf(new byte[]{ (byte)0xFF, (byte)0xD8, (byte)0xFF, (byte)0xE1, 'd', 'c', 'E', 'x', 'i', 'f', 0x00, 0x00 })); assertEquals(FileMagic.JPEG, FileMagic.valueOf(new byte[]{ (byte)0xFF, (byte)0xD8, (byte)0xFF, (byte)0xE1, 'd', 'c', 'E', 'x', 'i', 'f', 0x00, 0x00 }));


assertEquals(FileMagic.UNKNOWN, FileMagic.valueOf("something".getBytes(Charsets.UTF_8)));
assertEquals(FileMagic.UNKNOWN, FileMagic.valueOf("something".getBytes(StandardCharsets.UTF_8)));
assertEquals(FileMagic.UNKNOWN, FileMagic.valueOf(new byte[0])); assertEquals(FileMagic.UNKNOWN, FileMagic.valueOf(new byte[0]));


try { try {

BIN
test-data/slideshow/bug64693.pptx View File


Loading…
Cancel
Save