Windows2003-3790/windows/advcore/gdiplus/test/simpsons/parse.cpp
2020-09-30 16:53:55 +02:00

750 lines
18 KiB
C++

// File: Parse.cpp
// Author: Michael Marr (mikemarr)
//
// History:
// -@- 09/23/97 (mikemarr) copied from projects\vector2d
#include "StdAfx.h"
#include "Parse.h"
#define fGSCALE 1.f
class CAdobeFormatConverter {
public:
CAdobeFormatConverter();
~CAdobeFormatConverter() {}
HRESULT Parse(const char *pData, DWORD nFileLength, RenderCmd **ppCmds);
private:
HRESULT ParseProlog();
HRESULT ParseScript();
HRESULT ParseSetup();
HRESULT ParseObjects();
HRESULT ParseCompoundPath();
HRESULT ParsePath();
HRESULT ParsePaintStyle(const char *&pEnd);
HRESULT ParsePathGeometry(const char *pEnd);
HRESULT ParseTrailers();
private:
void EatLine();
const char * FindNextLine(const char *pch);
const char * FindLF(const char *pch);
const char * FindSpace(const char *pch);
private:
const char * m_pData, *m_pLimit;
float m_fWidth, m_fHeight;
// float m_fMaxHeight;
bool m_bNoBrush, m_bNoPen;
DXFPOINT m_rgPoints[nMAXPOINTS];
DXFPOINT * m_pCurPoint;
BYTE m_rgCodes[nMAXPOINTS];
BYTE * m_pCurCode;
RenderCmd m_rgRenderCmds[nMAXPOLYS];
RenderCmd * m_pCurRenderCmd;
PolyInfo m_rgPolyInfos[nMAXPOLYS];
PolyInfo * m_pCurPolyInfo;
BrushInfo m_rgBrushInfos[nMAXBRUSHES];
BrushInfo * m_pCurBrushInfo;
PenInfo m_rgPenInfos[nMAXPENS];
PenInfo * m_pCurPenInfo;
};
inline bool
mmIsSpace(char ch)
{
return ((ch == ' ') || (ch == chLINEFEED) || (ch == chCARRIAGERETURN));
// return isspace(ch) != 0;
}
inline bool
mmIsDigit(char ch)
{
return ((ch >= '0') && (ch <= '9'));
// return isdigit(ch) != 0;
}
float
mmSimpleAtoF(const char *&pData)
{
const char *pSrc = pData;
// eat white space
while (mmIsSpace(*pSrc)) pSrc++;
bool bNeg;
if (*pSrc == '-') {
bNeg = true;
pSrc++;
} else {
bNeg = false;
}
// get digits before the decimal point
float f;
if (mmIsDigit(*pSrc)) {
f = float(*pSrc++ - '0');
while (mmIsDigit(*pSrc))
f = f * 10.f + float(*pSrc++ - '0');
} else {
f = 0.f;
}
if (*pSrc == '.')
pSrc++;
// get digits after the decimal point
float fDec = 0.1f;
while (mmIsDigit(*pSrc)) {
f += (float(*pSrc++ - '0') * fDec);
fDec *= 0.1f;
}
// REVIEW: assume no exponent for now
pData = pSrc;
return (bNeg ? -f : f);
}
inline const char *
CAdobeFormatConverter::FindLF(const char *pch)
{
// find the linefeed character
while ((*pch != chLINEFEED) && (*pch != chCARRIAGERETURN)) pch++;
MMASSERT(pch <= m_pLimit);
return pch;
}
inline const char *
CAdobeFormatConverter::FindNextLine(const char *pch)
{
// find the linefeed character
while (*pch++ != chLINEFEED);
// check if there is also carriage return
if (*pch == chCARRIAGERETURN)
pch++;
MMASSERT(pch <= m_pLimit);
return pch;
}
inline const char *
CAdobeFormatConverter::FindSpace(const char *pch)
{
// find the linefeed character
while (!mmIsSpace(*pch)) pch++;
MMASSERT(pch <= m_pLimit);
return pch;
}
inline void
CAdobeFormatConverter::EatLine()
{
m_pData = FindNextLine(m_pData);
}
CAdobeFormatConverter::CAdobeFormatConverter()
{
m_pData = m_pLimit = NULL;
m_fWidth = m_fHeight = 0.f;
// m_fMaxHeight = 0.f;
m_bNoBrush = m_bNoPen = true;
}
HRESULT
CAdobeFormatConverter::Parse(const char *pData, DWORD nFileLength, RenderCmd **ppCmds)
{
// MMTRACE("Parse\n");
HRESULT hr = S_OK;
if (ppCmds == NULL)
return E_POINTER;
if (!pData || !nFileLength)
return E_INVALIDARG;
m_pData = pData;
m_pLimit = pData + nFileLength;
// intialize command storage stuff
m_pCurPoint = m_rgPoints;
m_pCurCode = m_rgCodes;
m_pCurPolyInfo = m_rgPolyInfos;
m_pCurRenderCmd = m_rgRenderCmds;
m_pCurBrushInfo = m_rgBrushInfos;
m_pCurPenInfo = m_rgPenInfos;
CHECK_HR(hr = ParseProlog());
CHECK_HR(hr = ParseScript());
e_Exit:
// write a stop command to the end
m_pCurRenderCmd->nType = typeSTOP;
m_pCurRenderCmd->pvData = NULL;
*ppCmds = m_rgRenderCmds;
return hr;
}
HRESULT
CAdobeFormatConverter::ParseProlog()
{
// MMTRACE("ParseProlog\n");
const char *szSearch;
// extract the image dimensions
float f1, f2;
// bounding box is supposed to be a required field with the proper numbers
szSearch = "%%BoundingBox:";
m_pData = strstr(m_pData, szSearch);
m_pData = FindSpace(m_pData);
f1 = mmSimpleAtoF(m_pData);
f2 = mmSimpleAtoF(m_pData);
m_fWidth = mmSimpleAtoF(m_pData);
m_fHeight = mmSimpleAtoF(m_pData);
// if (sscanf(m_pData, "%f %f %f %f", &f1, &f2, &m_fWidth, &m_fHeight) != 4)
// return E_FAIL;
if ((m_fWidth <= 0.f) || (m_fHeight < 0.f))
return E_FAIL;
// m_fMaxHeight = float(m_nHeight);
// search until we find end string
szSearch = "%%EndProlog";
m_pData = strstr(m_pData, szSearch);
if (m_pData == NULL)
return E_FAIL;
EatLine();
return S_OK;
}
HRESULT
CAdobeFormatConverter::ParseScript()
{
// MMTRACE("ParseScript\n");
HRESULT hr;
if (FAILED(hr = ParseSetup()) ||
FAILED(hr = ParseObjects()) ||
FAILED(hr = ParseTrailers()))
return hr;
return S_OK;
}
HRESULT
CAdobeFormatConverter::ParseSetup()
{
// MMTRACE("ParseSetup\n");
const char *szSearch;
// search until we find end string
szSearch = "%%EndSetup";
m_pData = strstr(m_pData, szSearch);
if (m_pData == NULL)
return E_FAIL;
EatLine();
return S_OK;
}
HRESULT
CAdobeFormatConverter::ParseObjects()
{
// MMTRACE("ParseObjects\n");
HRESULT hr = S_OK;
const char *szPageTrailer = "%%PageTrailer";
const char *szTrailer = "%%Trailer";
int cPageTrailer = strlen(szPageTrailer);
int cTrailer = strlen(szTrailer);
// process dimensions
/* const char *pEnd;
pEnd = FindLF(m_pData);
// pEnd = strchr(m_pData, '\n');
if ((pEnd[-1] == 'b') && (pEnd[-2] == 'L')) {
// get the dimensions out
int n1, n2, n3, n4, n5, n6, n7, n8;
if ((sscanf(m_pData, "%d %d %d %d %d %d %d %d %d %d %d",
&n1, &n2, &n3, &n4, &n5, &n6, &n7, &n8, &m_nWidth, &m_nHeight) != 10) ||
(m_nWidth <= 0) || (m_nHeight < 0))
{
return E_FAIL;
}
m_fMaxHeight = float(m_nHeight);
m_pData = FindNextLine(pEnd);
}
pEnd = FindLF(m_pData);
// pEnd = strchr(m_pData, '\n');
if ((pEnd[-1] == 'n') && (pEnd[-2] == 'L')) {
// skip layer information
m_pData = FindNextLine(pEnd);
}
*/
for (;;) {
switch (m_pData[0]) {
case '%':
if ((strncmp(m_pData, szPageTrailer, cPageTrailer) == 0) ||
(strncmp(m_pData, szTrailer, cTrailer) == 0))
{
// end of object definitions
goto e_Exit;
} else {
// comment
EatLine();
}
break;
case '*':
if (m_pData[1] == 'u')
CHECK_HR(hr = ParseCompoundPath());
else {
hr = E_FAIL;
goto e_Exit;
}
break;
default:
CHECK_HR(hr = ParsePath());
break;
}
}
e_Exit:
if (hr == S_OK)
EatLine();
return hr;
}
HRESULT
CAdobeFormatConverter::ParseCompoundPath()
{
// MMTRACE("ParseCompoundPath\n");
HRESULT hr = S_OK;
// remove the "*u"
MMASSERT((m_pData[0] == '*') && (m_pData[1] == 'u'));
// if (strncmp(m_pData, "*u", 2) != 0)
// return E_UNEXPECTED;
EatLine();
while (m_pData[0] != '*')
CHECK_HR(hr = ParsePath());
// remove the "*U"
MMASSERT((m_pData[0] == '*') && (m_pData[1] == 'U'));
// if (strncmp(m_pData, "*U", 2) != 0)
// return E_UNEXPECTED;
EatLine();
e_Exit:
return hr;
}
inline
UINT GetUInt(const char *pData)
{
return (UINT) atoi(pData);
}
typedef DWORD FP;
#define nEXPBIAS 127
#define nEXPSHIFTS 23
#define nEXPLSB (1 << nEXPSHIFTS)
#define maskMANT (nEXPLSB - 1)
#define FloatToFixed08(nDst, fSrc) MACSTART \
float fTmp = fSrc; \
DWORD nRaw = *((FP *) &(fTmp)); \
if (nRaw < ((nEXPBIAS + 23 - 31) << nEXPSHIFTS)) \
nDst = 0; \
else \
nDst = ((nRaw | nEXPLSB) << 8) >> ((nEXPBIAS + 23) - (nRaw >> nEXPSHIFTS)); \
MACEND
HRESULT
CAdobeFormatConverter::ParsePaintStyle(const char *&pEnd)
{
HRESULT hr = S_OK;
BOOL bNotDone = TRUE;
// int nLineJoin = 1, nLineCap = 1;
float fLineWidth = 1.f;
float fGrayFill, fGrayStroke;
float fCyan, fYellow, fMagenta, fBlack;
bool bColorFill = false, bGrayFill = false, bGrayStroke = false;
// parse paint style
for (; pEnd; pEnd = FindLF(m_pData)) {
switch(pEnd[-1]) {
//
// path attributes
//
case 'd': // process dash
// REVIEW: skip this for now -- assume NULL pattern
break;
case 'j': // process line join type
// REVIEW: skip this for now, since it is always 1
// nLineJoin = mmSimpleAtoI(m_pData);
break;
case 'J': // process line cap type
// REVIEW: skip this for now, since it is always 1
// nLineCap = mmSimpleAtoI(m_pData);
break;
case 'w': // process line width
// REVIEW: skip this for now, since it is always 1.f
// fLineWidth = mmSimpleAtoF(m_pData);
break;
//
// fill color
//
case 'g': // process gray color for fill
fGrayFill = mmSimpleAtoF(m_pData);
bGrayFill = true;
break;
case 'k': // process color
fCyan = mmSimpleAtoF(m_pData);
fMagenta = mmSimpleAtoF(m_pData);
fYellow = mmSimpleAtoF(m_pData);
fBlack = mmSimpleAtoF(m_pData);
bColorFill = true;
break;
//
// stroke color
//
case 'G': // process gray color for stroke
fGrayStroke = mmSimpleAtoF(m_pData);
bGrayStroke = true;
break;
default:
goto Exit;
break;
}
m_pData = FindNextLine(pEnd);
// m_pData = pEnd + 1;
}
Exit:
// output GDI commands
//
// create a brush
//
if (bColorFill || bGrayFill) {
static DWORD nLastRed = 256, nLastGreen = 256, nLastBlue = 256;
DWORD nTmpRed, nTmpGreen, nTmpBlue;
if (bColorFill) {
FloatToFixed08(nTmpRed, fCyan + fBlack); CLAMPMAX(nTmpRed, 255); nTmpRed = 255 - nTmpRed;
FloatToFixed08(nTmpGreen, fMagenta + fBlack); CLAMPMAX(nTmpGreen, 255); nTmpGreen = 255 - nTmpGreen;
FloatToFixed08(nTmpBlue, fYellow + fBlack); CLAMPMAX(nTmpBlue, 255); nTmpBlue = 255 - nTmpBlue;
} else if (bGrayFill) {
DWORD nTmpGray;
FloatToFixed08(nTmpGray, fGrayFill); CLAMPMAX(nTmpGray, 255);
nTmpRed = nTmpGreen = nTmpBlue = nTmpGray;
}
if ((nLastRed != nTmpRed) || (nLastGreen != nTmpGreen) || (nLastBlue != nTmpBlue)) {
// define a new brush
nLastRed = nTmpRed; nLastGreen = nTmpGreen; nLastBlue = nTmpBlue;
// fprintf(m_pFile, "\t// select a new brush\n");
// fprintf(m_pFile, "\tBrush.Color = DXSAMPLE(255, %d, %d, %d);\n", nRed, nGreen, nBlue);
// fprintf(m_pFile, "\tpDX2D->SetBrush(&Brush);\n\n");
m_pCurBrushInfo->Color = DXSAMPLE(255, BYTE(nTmpRed), BYTE(nTmpGreen), BYTE(nTmpBlue));
m_pCurRenderCmd->nType = typeBRUSH;
m_pCurRenderCmd->pvData = (void *) m_pCurBrushInfo++;
m_pCurRenderCmd++;
m_bNoBrush = false;
}
}
// create a pen
if (bGrayStroke) {
static bool bPenInit = false;
// we only have one pen in the simpsons.ai
if (!bPenInit) {
// if ((fGrayStroke != 0.f) || (nLineJoin != 1) || (nLineCap != 1)) {
if (fGrayStroke != 0.f) {
MMTRACE("error: can not support pen type\n");
return E_FAIL;
}
bPenInit = true;
// fprintf(m_pFile, "\t// select a new pen\n");
// fprintf(m_pFile, "\tPen.Color = DXSAMPLE(255, 0, 0, 0);\n");
// fprintf(m_pFile, "\tPen.Width = %.2ff;\n", fLineWidth * fGSCALE);
// fprintf(m_pFile, "\tPen.Style = PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_ROUND | PS_JOIN_ROUND;\n");
// fprintf(m_pFile, "\tpDX2D->SetPen(&Pen);\n\n");
// REVIEW: only can make one kind of pen right now
m_pCurPenInfo->Color = DXSAMPLE(255, 0, 0, 0);
m_pCurPenInfo->fWidth = fLineWidth * fGSCALE;
m_pCurPenInfo->dwStyle = PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_ROUND | PS_JOIN_ROUND;
m_pCurRenderCmd->nType = typePEN;
m_pCurRenderCmd->pvData = (void *) m_pCurPenInfo++;
m_pCurRenderCmd++;
m_bNoPen = false;
}
}
return S_OK;
}
#define GetCoordX(_fX) ((_fX) * fGSCALE)
#define GetCoordY(_fY) ((m_fHeight - (_fY)) * fGSCALE)
HRESULT
CAdobeFormatConverter::ParsePathGeometry(const char *pEnd)
{
HRESULT hr = S_OK;
// float fX1, fY1, fXBez1, fYBez1, fXBez2, fYBez2;
m_pCurPolyInfo->pPoints = m_pCurPoint;
m_pCurPolyInfo->pCodes = m_pCurCode;
// parse path geometry
DWORD cPoints = 0;
bool bFlatten = false;
for (; pEnd; pEnd = FindLF(m_pData)) {
switch(pEnd[-1]) {
case 'm':
// fprintf(m_pFile, "\t// define geometry path\n");
// sscanf(m_pData, "%f %f", &fX1, &fY1);
// fprintf(m_pFile, "\tppt = rgpt; pb = rgCodes;\n");
// fprintf(m_pFile, "\tppt->x = %.2ff; ppt->y = %.2ff; *pb++ = PT_MOVETO; ppt++;\n", GetCoordX(fX1), GetCoordY(fY1));
m_pCurPoint->x = GetCoordX(mmSimpleAtoF(m_pData));
m_pCurPoint->y = GetCoordY(mmSimpleAtoF(m_pData));
m_pCurPoint++;
*m_pCurCode++ = PT_MOVETO;
cPoints++;
break;
case 'L':
case 'l':
// sscanf(m_pData, "%f %f", &fX1, &fY1);
// fprintf(m_pFile, "\tppt->x = %.2ff; ppt->y = %.2ff; *pb++ = PT_LINETO; ppt++;\n", GetCoordX(fX1), GetCoordY(fY1));
m_pCurPoint->x = GetCoordX(mmSimpleAtoF(m_pData));
m_pCurPoint->y = GetCoordY(mmSimpleAtoF(m_pData));
m_pCurPoint++;
*m_pCurCode++ = PT_LINETO;
cPoints++;
break;
case 'C':
case 'c':
bFlatten = true;
m_pCurPoint[0].x = GetCoordX(mmSimpleAtoF(m_pData));
m_pCurPoint[0].y = GetCoordY(mmSimpleAtoF(m_pData));
m_pCurPoint[1].x = GetCoordX(mmSimpleAtoF(m_pData));
m_pCurPoint[1].y = GetCoordY(mmSimpleAtoF(m_pData));
m_pCurPoint[2].x = GetCoordX(mmSimpleAtoF(m_pData));
m_pCurPoint[2].y = GetCoordY(mmSimpleAtoF(m_pData));
m_pCurPoint += 3;
m_pCurCode[0] = PT_BEZIERTO;
m_pCurCode[1] = PT_BEZIERTO;
m_pCurCode[2] = PT_BEZIERTO;
m_pCurCode += 3;
cPoints += 3;
// sscanf(m_pData, "%f %f %f %f %f %f", &fXBez1, &fYBez1, &fXBez2, &fYBez2, &fX1, &fY1);
// fprintf(m_pFile, "\tppt[0].x = %.2ff; ppt[0].y = %.2ff; pb[0] = PT_BEZIERTO;\n", GetCoordX(fXBez1), GetCoordY(fYBez1));
// fprintf(m_pFile, "\tppt[1].x = %.2ff; ppt[1].y = %.2ff; pb[1] = PT_BEZIERTO;\n", GetCoordX(fXBez2), GetCoordY(fYBez2));
// fprintf(m_pFile, "\tppt[2].x = %.2ff; ppt[2].y = %.2ff; pb[2] = PT_BEZIERTO; ppt += 3; pb += 3;\n", GetCoordX(fX1), GetCoordY(fY1));
break;
default:
goto Exit;
break;
}
// skip the line
m_pData = FindNextLine(pEnd);
}
Exit:
// create the path
// char *pFillType = (bFlatten ? "0" : "DX2D_NO_FLATTEN");
if (cPoints) {
DWORD dwFlags;
switch(pEnd[-1]) {
case 'f': // close path and fill
if (m_bNoBrush) {
// fprintf(m_pFile, "\tpDX2D->SetBrush(&Brush);\n"); m_nLines++;
m_bNoBrush = false;
}
if (m_bNoPen == false) {
// fprintf(m_pFile, "\tpDX2D->SetPen(NULL);\n"); m_nLines++;
m_bNoPen = true;
}
dwFlags = DX2D_FILL;
break;
case 'S': // stroke path
if (m_bNoPen) {
// fprintf(m_pFile, "\tpDX2D->SetPen(&Pen);\n"); m_nLines++;
m_bNoPen = false;
}
if (m_bNoBrush == false) {
// fprintf(m_pFile, "\tpDX2D->SetBrush(NULL);\n"); m_nLines++;
m_bNoBrush = true;
}
dwFlags = DX2D_STROKE;
break;
default:
MMTRACE("error: unknown render mode -- aborting\n");
return E_FAIL;
break;
}
// fprintf(m_pFile, "\tpDX2D->AAPolyDraw(rgpt, rgCodes, %d, %s);\n", iPoint, pFillType);
m_pCurPolyInfo->cPoints = cPoints;
m_pCurPolyInfo->dwFlags = dwFlags | (bFlatten ? 0 : DX2D_NO_FLATTEN);
m_pCurRenderCmd->nType = typePOLY;
m_pCurRenderCmd->pvData = (PolyInfo *) m_pCurPolyInfo++;
m_pCurRenderCmd++;
m_pData = FindNextLine(pEnd);
}
return S_OK;
}
HRESULT
CAdobeFormatConverter::ParsePath()
{
// MMTRACE("ParsePath\n");
HRESULT hr;
const char *pStart = m_pData, *pEnd = FindLF(m_pData);
if (FAILED(hr = ParsePaintStyle(pEnd)))
return hr;
if (FAILED(hr = ParsePathGeometry(pEnd)))
return hr;
// skip it if we don't know how to deal with it
if (pStart == m_pData) {
// if ((m_pData[0] != 'L') || (m_pData[1] != 'B')) {
// MMTRACE("warning: control data of unknown type -- ignoring line\n");
// }
m_pData = FindNextLine(pEnd);
}
return hr;
}
HRESULT
CAdobeFormatConverter::ParseTrailers()
{
return S_OK;
}
HRESULT
OpenFileMapping(const char *szFilename, LPHANDLE phMapping,
DWORD *pnFileLength)
{
MMASSERT(szFilename && phMapping && pnFileLength);
HRESULT hr = S_OK;
HANDLE hFile = NULL, hMapping = NULL;
DWORD nFileLength = 0, dwHighSize = 0;
MMTRACE("Opening File: %s\n", szFilename);
// open the file
hFile = CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0);
if ((hFile == NULL) || (hFile == INVALID_HANDLE_VALUE)) {
MMTRACE("error: file not found - %s\n", szFilename);
return STG_E_FILENOTFOUND;
}
// get the length of the file
if (((nFileLength = GetFileSize(hFile, &dwHighSize)) == 0xFFFFFFFF) || dwHighSize ||
// create a file mapping object
((hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) == NULL))
{
MMTRACE("error: creating file mapping\n");
hr = E_FAIL;
}
MMTRACE("\tLength: %d\n", nFileLength);
if (hFile)
CloseHandle(hFile);
*phMapping = hMapping;
*pnFileLength = nFileLength;
return hr;
}
#define szDEFFILENAME "\\dtrans\\tools\\simpsons\\simpsons.ai"
HRESULT
ParseAIFile(const char *szFilename, RenderCmd **ppCmds)
{
HRESULT hr = S_OK;
static CAdobeFormatConverter afc;
static RenderCmd s_CmdStop = {typeSTOP, NULL};
DWORD nStartTick, nEndTick;
DWORD nFileLength;
HANDLE hMapping = NULL;
char *pData = NULL;
if (szFilename == NULL)
szFilename = szDEFFILENAME;
nStartTick = GetTickCount();
CHECK_HR(hr = OpenFileMapping(szFilename, &hMapping, &nFileLength));
// create a map view
if ((pData = (char *) MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0)) == NULL) {
hr = E_FAIL;
goto e_Exit;
}
CHECK_HR(hr = afc.Parse(pData, nFileLength, ppCmds));
e_Exit:
if (pData)
UnmapViewOfFile(pData);
if (hMapping)
CloseHandle(hMapping);
if (FAILED(hr)) {
// set to the null command list
*ppCmds = &s_CmdStop;
MMTRACE("\terror parsing file\n");
} else {
nEndTick = GetTickCount();
sprintf(g_rgchTmpBuf, "\tParse Time: %d\n", nEndTick - nStartTick);
OutputDebugString(g_rgchTmpBuf);
}
return hr;
}