/*******************************************************************************
* Copyright (c) 2009, Adobe Systems Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* · Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* · Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* · Neither the name of Adobe Systems Incorporated nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
package com.adobe.dp.office.metafile;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
public class EMFParser extends MetafileParser {
final private static int ENHMETA_SIGNATURE = 0x464d4520;
final private static int EMR_HEADER = 1;
final private static int EMR_POLYBEZIER = 2;
final private static int EMR_POLYGON = 3;
final private static int EMR_POLYLINE = 4;
final private static int EMR_POLYBEZIERTO = 5;
final private static int EMR_POLYLINETO = 6;
final private static int EMR_POLYPOLYLINE = 7;
final private static int EMR_POLYPOLYGON = 8;
final private static int EMR_SETWINDOWEXTEX = 9;
final private static int EMR_SETWINDOWORGEX = 10;
final private static int EMR_SETVIEWPORTEXTEX = 11;
final private static int EMR_SETVIEWPORTORGEX = 12;
final private static int EMR_SETBRUSHORGEX = 13;
final private static int EMR_EOF = 14;
final private static int EMR_SETPIXELV = 15;
final private static int EMR_SETMAPPERFLAGS = 16;
final private static int EMR_SETMAPMODE = 17;
final private static int EMR_SETBKMODE = 18;
final private static int EMR_SETPOLYFILLMODE = 19;
final private static int EMR_SETROP2 = 20;
final private static int EMR_SETSTRETCHBLTMODE = 21;
final private static int EMR_SETTEXTALIGN = 22;
final private static int EMR_SETCOLORADJUSTMENT = 23;
final private static int EMR_SETTEXTCOLOR = 24;
final private static int EMR_SETBKCOLOR = 25;
final private static int EMR_OFFSETCLIPRGN = 26;
final private static int EMR_MOVETOEX = 27;
final private static int EMR_SETMETARGN = 28;
final private static int EMR_EXCLUDECLIPRECT = 29;
final private static int EMR_INTERSECTCLIPRECT = 30;
final private static int EMR_SCALEVIEWPORTEXTEX = 31;
final private static int EMR_SCALEWINDOWEXTEX = 32;
final private static int EMR_SAVEDC = 33;
final private static int EMR_RESTOREDC = 34;
final private static int EMR_SETWORLDTRANSFORM = 35;
final private static int EMR_MODIFYWORLDTRANSFORM = 36;
final private static int EMR_SELECTOBJECT = 37;
final private static int EMR_CREATEPEN = 38;
final private static int EMR_CREATEBRUSHINDIRECT = 39;
final private static int EMR_DELETEOBJECT = 40;
final private static int EMR_ANGLEARC = 41;
final private static int EMR_ELLIPSE = 42;
final private static int EMR_RECTANGLE = 43;
final private static int EMR_ROUNDRECT = 44;
final private static int EMR_ARC = 45;
final private static int EMR_CHORD = 46;
final private static int EMR_PIE = 47;
final private static int EMR_SELECTPALETTE = 48;
final private static int EMR_CREATEPALETTE = 49;
final private static int EMR_SETPALETTEENTRIES = 50;
final private static int EMR_RESIZEPALETTE = 51;
final private static int EMR_REALIZEPALETTE = 52;
final private static int EMR_EXTFLOODFILL = 53;
final private static int EMR_LINETO = 54;
final private static int EMR_ARCTO = 55;
final private static int EMR_POLYDRAW = 56;
final private static int EMR_SETARCDIRECTION = 57;
final private static int EMR_SETMITERLIMIT = 58;
final private static int EMR_BEGINPATH = 59;
final private static int EMR_ENDPATH = 60;
final private static int EMR_CLOSEFIGURE = 61;
final private static int EMR_FILLPATH = 62;
final private static int EMR_STROKEANDFILLPATH = 63;
final private static int EMR_STROKEPATH = 64;
final private static int EMR_FLATTENPATH = 65;
final private static int EMR_WIDENPATH = 66;
final private static int EMR_SELECTCLIPPATH = 67;
final private static int EMR_ABORTPATH = 68;
final private static int EMR_GDICOMMENT = 70;
final private static int EMR_FILLRGN = 71;
final private static int EMR_FRAMERGN = 72;
final private static int EMR_INVERTRGN = 73;
final private static int EMR_PAINTRGN = 74;
final private static int EMR_EXTSELECTCLIPRGN = 75;
final private static int EMR_BITBLT = 76;
final private static int EMR_STRETCHBLT = 77;
final private static int EMR_MASKBLT = 78;
final private static int EMR_PLGBLT = 79;
final private static int EMR_SETDIBITSTODEVICE = 80;
final private static int EMR_STRETCHDIBITS = 81;
final private static int EMR_EXTCREATEFONTINDIRECTW = 82;
final private static int EMR_EXTTEXTOUTA = 83;
final private static int EMR_EXTTEXTOUTW = 84;
final private static int EMR_POLYBEZIER16 = 85;
final private static int EMR_POLYGON16 = 86;
final private static int EMR_POLYLINE16 = 87;
final private static int EMR_POLYBEZIERTO16 = 88;
final private static int EMR_POLYLINETO16 = 89;
final private static int EMR_POLYPOLYLINE16 = 90;
final private static int EMR_POLYPOLYGON16 = 91;
final private static int EMR_POLYDRAW16 = 92;
final private static int EMR_CREATEMONOBRUSH = 93;
final private static int EMR_CREATEDIBPATTERNBRUSHPT = 94;
final private static int EMR_EXTCREATEPEN = 95;
final private static int EMR_POLYTEXTOUTA = 96;
final private static int EMR_POLYTEXTOUTW = 97;
final private static int EMR_SETICMMODE = 98;
final private static int EMR_CREATECOLORSPACE = 99;
final private static int EMR_SETCOLORSPACE = 100;
final private static int EMR_DELETECOLORSPACE = 101;
final private static int EMR_GLSRECORD = 102;
final private static int EMR_GLSBOUNDEDRECORD = 103;
final private static int EMR_PIXELFORMAT = 104;
final private static int EMR_COLORCORRECTPALETTE = 111;
final private static int EMR_SETICMPROFILEA = 112;
final private static int EMR_SETICMPROFILEW = 113;
final private static int EMR_ALPHABLEND = 114;
final private static int EMR_SETLAYOUT = 115;
final private static int EMR_TRANSPARENTBLT = 116;
final private static int EMR_GRADIENTFILL = 118;
final private static int EMR_COLORMATCHTOTARGETW = 121;
final private static int EMR_CREATECOLORSPACEW = 122;
// GDI comment
final private static int GDICOMMENT_BEGINGROUP = 0x00000002;
final private static int GDICOMMENT_ENDGROUP = 0x00000003;
final private static int GDICOMMENT_UNICODE_STRING = 0x00000040;
final private static int GDICOMMENT_UNICODE_END = 0x00000080;
// final private static int GDICOMMENT_MULTIFORMATS = 0x40000004;
final private static int GDICOMMENT_WINDOWS_METAFILE = 0x80000001;
final private static int GDICOMMENT_IDENTIFIER = 0x43494447;
final private static int GDICOMMENT_EMFPLUS = 0x2b464d45;
public EMFParser(InputStream in, GDISurface handler) throws IOException {
super(in, handler);
readFileHeader();
}
private void readFileHeader() throws IOException {
int iType = readInt();
if (iType != EMR_HEADER)
throw new IOException("corrupted header");
int nSize = readInt();
setRemainsBytes(nSize - 8);
int boundsLeft = readInt();
int boundsTop = readInt();
int boundsRight = readInt();
int boundsBottom = readInt();
skipInts(4);
int dSignature = readInt();
if (dSignature != ENHMETA_SIGNATURE)
throw new IOException("corrupted header signature");
int nVersion = readInt();
if (nVersion != 0x10000)
throw new IOException("unsupported version");
finishRecord();
handler.setBounds(boundsLeft, boundsTop, boundsRight, boundsBottom);
}
private void readGDIComment() throws IOException {
int len = readInt();
if (len < 8) {
byte[] arr = new byte[len];
readBytes(arr);
handler.comment(arr, 0, arr.length);
} else {
int id = readInt();
if (id == GDICOMMENT_IDENTIFIER) {
int commType = readInt();
switch (commType) {
case GDICOMMENT_BEGINGROUP: {
int boundsLeft = readInt();
int boundsTop = readInt();
int boundsRight = readInt();
int boundsBottom = readInt();
int uChars = readInt();
StringBuffer desc = new StringBuffer();
while (uChars > 0) {
uChars--;
desc.append((char) readShort());
}
handler.commentBeginGroup(boundsLeft, boundsTop, boundsRight, boundsBottom, desc.toString());
break;
}
case GDICOMMENT_ENDGROUP:
handler.commentEndGroup();
break;
case GDICOMMENT_WINDOWS_METAFILE: {
int version = readInt();
readInt(); // checksum
int flags = readInt();
if (flags != 0)
throw new IOException("GDICOMMENT_WINDOWS_METAFILE: flags not zero");
int mfLen = readInt();
byte[] mfBytes = new byte[mfLen];
readBytes(mfBytes);
handler.commentMetafile(version, mfBytes, 0, mfLen);
break;
}
case GDICOMMENT_UNICODE_STRING:
case GDICOMMENT_UNICODE_END:
default: {
byte[] d = new byte[len - 4];
readBytes(d);
handler.commentGDIC(commType, d, 0, len);
break;
}
}
} else if (id == GDICOMMENT_EMFPLUS) {
byte[] d = new byte[len - 4];
readBytes(d);
handler.commentEMFPlus(d, 0, len);
} else {
byte[] arr = new byte[len];
arr[0] = (byte) id;
arr[1] = (byte) (id >> 8);
arr[2] = (byte) (id >> 16);
arr[3] = (byte) (id >> 24);
readBytes(arr, 4, len - 4);
handler.comment(arr, 0, arr.length);
}
}
}
public boolean readNext() throws IOException {
try {
int type = readInt();
int size = readInt();
setRemainsBytes(size - 8);
//System.out.println("RECORD " + type + " [" + size + "]");
switch (type) {
case EMR_HEADER:
throw new IOException("unexpected header record");
case EMR_POLYBEZIER:
case EMR_POLYGON:
case EMR_POLYLINE:
case EMR_POLYBEZIERTO:
case EMR_POLYLINETO:
case EMR_POLYPOLYLINE:
case EMR_POLYPOLYGON:
break;
case EMR_SETWINDOWEXTEX: {
int width = readInt();
int height = readInt();
handler.setWindowExt(width, height);
break;
}
case EMR_SETWINDOWORGEX: {
int x = readInt();
int y = readInt();
handler.setWindowOrg(x, y);
break;
}
case EMR_SETVIEWPORTEXTEX: {
int width = readInt();
int height = readInt();
handler.setViewportExt(width, height);
break;
}
case EMR_SETVIEWPORTORGEX: {
int x = readInt();
int y = readInt();
handler.setViewportExt(x, y);
break;
}
case EMR_SETBRUSHORGEX:
break;
case EMR_EOF:
finishRecord();
return false;
case EMR_SETPIXELV:
case EMR_SETMAPPERFLAGS:
break;
case EMR_SETMAPMODE: {
int mode = readInt();
handler.setMapMode(mode);
break;
}
case EMR_SETBKMODE: {
int mode = readInt();
handler.setBkMode(mode);
break;
}
case EMR_SETPOLYFILLMODE:
case EMR_SETROP2:
case EMR_SETSTRETCHBLTMODE:
break;
case EMR_SETTEXTALIGN: {
int textAlign = readInt();
handler.setTextAlign(textAlign);
}
case EMR_SETCOLORADJUSTMENT:
case EMR_SETTEXTCOLOR:
case EMR_SETBKCOLOR:
case EMR_OFFSETCLIPRGN:
case EMR_MOVETOEX:
case EMR_SETMETARGN:
case EMR_EXCLUDECLIPRECT:
case EMR_INTERSECTCLIPRECT:
case EMR_SCALEVIEWPORTEXTEX:
case EMR_SCALEWINDOWEXTEX:
break;
case EMR_SAVEDC:
handler.saveDC();
break;
case EMR_RESTOREDC:
handler.restoreDC();
break;
case EMR_SETWORLDTRANSFORM:
case EMR_MODIFYWORLDTRANSFORM:
break;
case EMR_SELECTOBJECT: {
int index = readInt();
GDIObject gdi = (GDIObject) objects.get(index);
handler.selectObject(gdi);
break;
}
case EMR_CREATEPEN:
break;
case EMR_CREATEBRUSHINDIRECT: {
int index = readInt();
int style = readInt();
int color = readRGB();
int hatch = readInt();
GDIBrush brush = handler.createBrushIndirect(style, color, hatch);
storeObject(brush, index);
break;
}
case EMR_DELETEOBJECT: {
int index = readInt();
GDIObject gdi = (GDIObject) objects.get(index);
objects.set(index, null);
handler.deleteObject(gdi);
gdi.dispose();
}
case EMR_ANGLEARC:
case EMR_ELLIPSE:
case EMR_RECTANGLE:
case EMR_ROUNDRECT:
case EMR_ARC:
case EMR_CHORD:
case EMR_PIE:
case EMR_SELECTPALETTE:
case EMR_CREATEPALETTE:
case EMR_SETPALETTEENTRIES:
case EMR_RESIZEPALETTE:
case EMR_REALIZEPALETTE:
case EMR_EXTFLOODFILL:
case EMR_LINETO:
case EMR_ARCTO:
case EMR_POLYDRAW:
case EMR_SETARCDIRECTION:
break;
case EMR_SETMITERLIMIT: {
int miterLimit = readInt();
handler.setMiterLimit(miterLimit);
}
case EMR_BEGINPATH:
case EMR_ENDPATH:
case EMR_CLOSEFIGURE:
case EMR_FILLPATH:
case EMR_STROKEANDFILLPATH:
case EMR_STROKEPATH:
case EMR_FLATTENPATH:
case EMR_WIDENPATH:
case EMR_SELECTCLIPPATH:
case EMR_ABORTPATH:
break;
case EMR_GDICOMMENT:
readGDIComment();
break;
case EMR_FILLRGN:
case EMR_FRAMERGN:
case EMR_INVERTRGN:
case EMR_PAINTRGN:
case EMR_EXTSELECTCLIPRGN:
case EMR_BITBLT:
case EMR_STRETCHBLT:
case EMR_MASKBLT:
case EMR_PLGBLT:
case EMR_SETDIBITSTODEVICE:
break;
case EMR_STRETCHDIBITS: {
readInt(); // boundsLeft
readInt(); // boundsTop
readInt(); // boundsRight
readInt(); // boundsBottom
int xDest = readInt();
int yDest = readInt();
int xSrc = readInt();
int ySrc = readInt();
int cxSrc = readInt();
int cySrc = readInt();
int offBmiSrc = readInt();
readInt(); // cbBmiSrc
int offBitsSrc = readInt();
readInt(); // cbBitsSrc
readInt(); // iUsageSrc
readInt(); // dwRop
int cxDest = readInt();
int cyDest = readInt();
skipBytes(offBmiSrc - 80);
GDIBitmap bitmap = readDIB(offBitsSrc - 80);
handler.stretchDIB(bitmap, xDest, yDest, cxDest, cyDest, xSrc, ySrc, cxSrc, cySrc);
break;
}
case EMR_EXTCREATEFONTINDIRECTW:
case EMR_EXTTEXTOUTA:
case EMR_EXTTEXTOUTW:
case EMR_POLYBEZIER16:
case EMR_POLYGON16:
case EMR_POLYLINE16:
case EMR_POLYBEZIERTO16:
case EMR_POLYLINETO16:
break;
case EMR_POLYPOLYLINE16:
case EMR_POLYPOLYGON16: {
readInt(); // boundsLeft
readInt(); // boundsTop
readInt(); // boundsRight
readInt(); // boundsBottom
int nPolys = readInt();
int[] lens = new int[nPolys];
int total = 0;
for (int i = 0; i < nPolys; i++) {
int len = readInt();
lens[i] = len;
total += len;
}
int totalPts = readInt();
if (totalPts < total)
throw new IOException("invalid POLYPOLYXXX record");
total *= 2;
int[] points = new int[total];
for (int i = 0; i < total; i++) {
points[i] = readShort();
}
if (type == EMR_POLYPOLYLINE16)
handler.polyPolyline(lens, points);
else
handler.polyPolygon(lens, points);
break;
}
case EMR_POLYDRAW16:
case EMR_CREATEMONOBRUSH:
case EMR_CREATEDIBPATTERNBRUSHPT:
break;
case EMR_EXTCREATEPEN: {
int index = readInt();
readInt(); // dibOffset
readInt(); // dibSize
readInt(); // brushBitsOffset
readInt(); // brushBitsSize
int style = readInt();
int width = readInt();
readInt(); // brushStyle
int color = readRGB();
readInt(); // hatch
readInt(); // numEntries
// styleEntry[numEntries];
GDIPen pen = handler.extCreatePen(style, width, color);
storeObject(pen, index);
break;
}
case EMR_POLYTEXTOUTA:
case EMR_POLYTEXTOUTW:
case EMR_SETICMMODE:
case EMR_CREATECOLORSPACE:
case EMR_SETCOLORSPACE:
case EMR_DELETECOLORSPACE:
case EMR_GLSRECORD:
case EMR_GLSBOUNDEDRECORD:
case EMR_PIXELFORMAT:
case EMR_COLORCORRECTPALETTE:
case EMR_SETICMPROFILEA:
case EMR_SETICMPROFILEW:
case EMR_ALPHABLEND:
case EMR_SETLAYOUT:
case EMR_TRANSPARENTBLT:
case EMR_GRADIENTFILL:
case EMR_COLORMATCHTOTARGETW:
case EMR_CREATECOLORSPACEW:
break;
default:
throw new IOException("unknown command");
}
finishRecord();
} catch (EOFException e) {
e.printStackTrace();
return false;
}
return true;
}
public void readAll() throws IOException {
while (readNext()) {
}
close();
}
}