mirror of
https://github.com/simon987/antiword.git
synced 2025-04-10 13:06:41 +00:00
839 lines
22 KiB
C
839 lines
22 KiB
C
/*
|
|
* stylesheet.c
|
|
* Copyright (C) 2001-2004 A.J. van Os; Released under GNU GPL
|
|
*
|
|
* Description:
|
|
* Build, read and destroy a list of stylesheet information
|
|
*
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include "antiword.h"
|
|
|
|
|
|
#define SGC_PAP 1
|
|
#define SGC_CHP 2
|
|
|
|
/* Variables needed to describe the stylesheet list */
|
|
static style_block_type *atStyleInfo = NULL;
|
|
static font_block_type *atFontInfo = NULL;
|
|
static BOOL *abFilled = NULL;
|
|
static size_t tStdCount = 0;
|
|
|
|
|
|
/*
|
|
* vDestroyStylesheetList - destroy the stylesheet list
|
|
*/
|
|
void
|
|
vDestroyStylesheetList(void)
|
|
{
|
|
DBG_MSG("vDestroyStylesheetList");
|
|
|
|
tStdCount = 0;
|
|
atStyleInfo = xfree(atStyleInfo);
|
|
atFontInfo = xfree(atFontInfo);
|
|
abFilled = xfree(abFilled);
|
|
} /* end of vDestroyStylesheetList */
|
|
|
|
/*
|
|
* vGetDefaultStyle - fill the style struct with default values
|
|
*/
|
|
static void
|
|
vGetDefaultStyle(style_block_type *pStyle)
|
|
{
|
|
(void)memset(pStyle, 0, sizeof(*pStyle));
|
|
pStyle->usIstd = ISTD_INVALID;
|
|
pStyle->usIstdNext = ISTD_INVALID;
|
|
pStyle->usStartAt = 1;
|
|
pStyle->ucListLevel = 9;
|
|
} /* end of vGetDefaultStyle */
|
|
|
|
/*
|
|
* vGetDefaultFont - fill the font struct with default values
|
|
*/
|
|
static void
|
|
vGetDefaultFont(font_block_type *pFont, USHORT usDefaultFontNumber)
|
|
{
|
|
(void)memset(pFont, 0, sizeof(*pFont));
|
|
pFont->usFontSize = DEFAULT_FONT_SIZE;
|
|
if (usDefaultFontNumber <= (USHORT)UCHAR_MAX) {
|
|
pFont->ucFontNumber = (UCHAR)usDefaultFontNumber;
|
|
} else {
|
|
DBG_DEC(usDefaultFontNumber);
|
|
DBG_FIXME();
|
|
pFont->ucFontNumber = 0;
|
|
}
|
|
} /* end of vGetDefaultFont */
|
|
|
|
/*
|
|
* iGetStyleIndex - get the index of the record with the specified istd
|
|
*
|
|
* returns the index when found, otherwise -1
|
|
*/
|
|
static int
|
|
iGetStyleIndex(USHORT usIstd)
|
|
{
|
|
int iIndex;
|
|
|
|
fail(abFilled == NULL);
|
|
|
|
if (usIstd == ISTD_INVALID || abFilled == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
|
|
if (abFilled[iIndex] && atStyleInfo[iIndex].usIstd == usIstd) {
|
|
/* The record is filled and the istd matches */
|
|
return iIndex;
|
|
}
|
|
}
|
|
return -1;
|
|
} /* end of iGetStyleIndex */
|
|
|
|
/*
|
|
* Get a build-in style for Winword 1/2
|
|
*/
|
|
static void
|
|
vGetBuildinStyle(UCHAR ucStc, style_block_type *pStyle)
|
|
{
|
|
fail(pStyle == NULL);
|
|
|
|
/* Start with de defaults */
|
|
vGetDefaultStyle(pStyle);
|
|
|
|
/* Add the build-in style info */
|
|
switch (ucStc) {
|
|
case 246:
|
|
case 247:
|
|
case 248:
|
|
case 249:
|
|
case 250:
|
|
case 255:
|
|
pStyle->sLeftIndent = 720;
|
|
break;
|
|
case 251:
|
|
case 252:
|
|
pStyle->sLeftIndent = 360;
|
|
break;
|
|
case 253:
|
|
pStyle->usBeforeIndent = 120;
|
|
break;
|
|
case 254:
|
|
pStyle->usBeforeIndent = 240;
|
|
break;
|
|
default:
|
|
if (ucStc >= 233 && ucStc <= 239) {
|
|
pStyle->sLeftIndent = (239 - (short)ucStc) * 360;
|
|
}
|
|
if (ucStc >= 225 && ucStc <= 232) {
|
|
pStyle->sLeftIndent = (232 - (short)ucStc) * 720;
|
|
pStyle->sRightIndent = 720;
|
|
}
|
|
break;
|
|
}
|
|
} /* end of vGetBuildinStyle */
|
|
|
|
/*
|
|
* Get a build-in fontstyle for Winword 1/2
|
|
*/
|
|
static void
|
|
vGetBuildinFont(UCHAR ucStc, font_block_type *pFont)
|
|
{
|
|
fail(pFont == NULL);
|
|
|
|
/* Start with de defaults */
|
|
vGetDefaultFont(pFont, 0);
|
|
|
|
/* Add the build-in fontstyle info */
|
|
switch (ucStc) {
|
|
case 223:
|
|
case 244:
|
|
pFont->usFontSize = 16;
|
|
break;
|
|
case 246:
|
|
case 247:
|
|
case 248:
|
|
pFont->usFontStyle |= FONT_ITALIC;
|
|
break;
|
|
case 249:
|
|
pFont->usFontStyle |= FONT_UNDERLINE;
|
|
break;
|
|
case 250:
|
|
pFont->usFontStyle |= FONT_BOLD;
|
|
break;
|
|
case 251:
|
|
pFont->usFontStyle |= FONT_UNDERLINE;
|
|
pFont->usFontSize = 24;
|
|
break;
|
|
case 252:
|
|
pFont->usFontStyle |= FONT_BOLD;
|
|
pFont->usFontSize = 24;
|
|
break;
|
|
case 253:
|
|
pFont->ucFontNumber = 2;
|
|
pFont->usFontStyle |= FONT_BOLD;
|
|
pFont->usFontSize = 24;
|
|
break;
|
|
case 254:
|
|
pFont->ucFontNumber = 2;
|
|
pFont->usFontStyle |= (FONT_BOLD|FONT_UNDERLINE);
|
|
pFont->usFontSize = 24;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} /* end of vGetBuildinFont */
|
|
|
|
/*
|
|
* Convert a stylecode (stc) as used by WinWord 1/2 into a styleindex (istd)
|
|
* as used by Word 6 and up
|
|
*/
|
|
USHORT
|
|
usStc2istd(UCHAR ucStc)
|
|
{
|
|
/* Old nil style to new nil style */
|
|
if (ucStc == 222) {
|
|
return STI_NIL;
|
|
}
|
|
|
|
/* Heading 1 through 9 must become istd 1 through 9 */
|
|
/* so 254 through 246 must become 1 through 9 and vice versa */
|
|
if ((ucStc >= 1 && ucStc <= 9) ||
|
|
(ucStc >= 246 && ucStc <= 254)) {
|
|
return 255 - (USHORT)ucStc;
|
|
}
|
|
return (USHORT)ucStc;
|
|
} /* end of usStd2istd */
|
|
|
|
/*
|
|
* Build the lists with Stylesheet Information for WinWord 1/2 files
|
|
*/
|
|
void
|
|
vGet2Stylesheet(FILE *pFile, int iWordVersion, const UCHAR *aucHeader)
|
|
{
|
|
style_block_type *pStyle;
|
|
font_block_type *pFont;
|
|
UCHAR *aucBuffer;
|
|
ULONG ulBeginStshInfo;
|
|
size_t tStshInfoLen, tName, tChpx, tPapx, tMaxIndex;
|
|
int iStIndex, iChpxIndex, iPapxIndex, iSt, iChpx, iPapx;
|
|
int iStd, iIndex, iBaseStyleIndex, iCounter;
|
|
USHORT usBaseStyle;
|
|
UCHAR ucStc, ucStcNext, ucStcBase;
|
|
|
|
fail(pFile == NULL || aucHeader == NULL);
|
|
fail(iWordVersion != 1 && iWordVersion != 2);
|
|
|
|
ulBeginStshInfo = ulGetLong(0x5e, aucHeader); /* fcStshf */
|
|
NO_DBG_HEX(ulBeginStshInfo);
|
|
tStshInfoLen = (size_t)usGetWord(0x62, aucHeader); /* cbStshf */
|
|
NO_DBG_DEC(tStshInfoLen);
|
|
|
|
aucBuffer = xmalloc(tStshInfoLen);
|
|
if (!bReadBytes(aucBuffer, tStshInfoLen, ulBeginStshInfo, pFile)) {
|
|
aucBuffer = xfree(aucBuffer);
|
|
return;
|
|
}
|
|
NO_DBG_PRINT_BLOCK(aucBuffer, tStshInfoLen);
|
|
|
|
fail(2 > tStshInfoLen);
|
|
iStd = (int)usGetWord(0, aucBuffer);
|
|
|
|
fail(2 + 2 > tStshInfoLen);
|
|
tName = (size_t)usGetWord(2, aucBuffer);
|
|
|
|
fail(2 + tName + 2 > tStshInfoLen);
|
|
tChpx = (size_t)usGetWord(2 + tName, aucBuffer);
|
|
|
|
fail(2 + tName + tChpx + 2 > tStshInfoLen);
|
|
tPapx = (size_t)usGetWord(2 + tName + tChpx, aucBuffer);
|
|
|
|
fail(2 + tName + tChpx + tPapx + 2 > tStshInfoLen);
|
|
tStdCount = (size_t)usGetWord(2 + tName + tChpx + tPapx, aucBuffer);
|
|
|
|
NO_DBG_HEX(tStdCount);
|
|
|
|
atStyleInfo = xcalloc(tStdCount, sizeof(style_block_type));
|
|
atFontInfo = xcalloc(tStdCount, sizeof(font_block_type));
|
|
abFilled = xcalloc(tStdCount, sizeof(BOOL));
|
|
|
|
do {
|
|
iCounter = 0;
|
|
iStIndex = 2 + 2;
|
|
iChpxIndex = 2 + (int)tName + 2;
|
|
iPapxIndex = 2 + (int)tName + (int)tChpx + 2;
|
|
tMaxIndex = 2 + tName + tChpx + tPapx + 2;
|
|
/* Read the styles one-by-one */
|
|
for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
|
|
pStyle = &atStyleInfo[iIndex];
|
|
pFont = &atFontInfo[iIndex];
|
|
iSt = (int)ucGetByte(iStIndex, aucBuffer);
|
|
iChpx = (int)ucGetByte(iChpxIndex, aucBuffer);
|
|
iPapx = (int)ucGetByte(iPapxIndex, aucBuffer);
|
|
NO_DBG_HEX(iSt);
|
|
NO_DBG_HEX(iChpx);
|
|
NO_DBG_HEX(iPapx);
|
|
if (iSt == 0xff || tMaxIndex + 1 >= tStshInfoLen) {
|
|
/* Undefined style or no information */
|
|
iStIndex++;
|
|
iChpxIndex++;
|
|
iPapxIndex++;
|
|
tMaxIndex += 2;
|
|
if (!abFilled[iIndex]) {
|
|
DBG_HEX_C(iChpx != 0xff, iChpx);
|
|
DBG_HEX_C(iPapx != 0xff, iPapx);
|
|
vGetDefaultStyle(pStyle);
|
|
vGetDefaultFont(pFont, 0);
|
|
abFilled[iIndex] = TRUE;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
NO_DBG_STRN(aucBuffer + iStIndex + 1, iSt);
|
|
iStIndex += iSt + 1;
|
|
|
|
ucStcNext = ucGetByte(tMaxIndex, aucBuffer);
|
|
ucStcBase = ucGetByte(tMaxIndex + 1, aucBuffer);
|
|
ucStc = (UCHAR)((iIndex - iStd) & 0xff);
|
|
NO_DBG_DEC(ucStc);
|
|
|
|
if (iChpx == 0xff || iPapx == 0xff) {
|
|
/* Use a build-in style */
|
|
iChpxIndex++;
|
|
iPapxIndex++;
|
|
tMaxIndex += 2;
|
|
if (!abFilled[iIndex]) {
|
|
DBG_HEX_C(iChpx != 0xff, iChpx);
|
|
DBG_HEX_C(iPapx != 0xff, iPapx);
|
|
vGetBuildinStyle(ucStc, pStyle);
|
|
pStyle->usIstd = usStc2istd(ucStc);
|
|
pStyle->usIstdNext =
|
|
usStc2istd(ucStcNext);
|
|
vGetBuildinFont(ucStc, pFont);
|
|
abFilled[iIndex] = TRUE;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (abFilled[iIndex]) {
|
|
/* This record has already been filled */
|
|
iChpxIndex += iChpx + 1;
|
|
iPapxIndex += iPapx + 1;
|
|
tMaxIndex += 2;
|
|
continue;
|
|
}
|
|
|
|
usBaseStyle = usStc2istd(ucStcBase);
|
|
|
|
if (usBaseStyle == STI_NIL) {
|
|
/* Based on the Nil style */
|
|
vGetDefaultStyle(pStyle);
|
|
vGetDefaultFont(pFont, 0);
|
|
} else {
|
|
iBaseStyleIndex = iGetStyleIndex(usBaseStyle);
|
|
NO_DBG_DEC(iBaseStyleIndex);
|
|
if (iBaseStyleIndex < 0) {
|
|
/* This style is not known yet */
|
|
iChpxIndex += iChpx + 1;
|
|
iPapxIndex += iPapx + 1;
|
|
tMaxIndex += 2;
|
|
continue;
|
|
}
|
|
fail(iBaseStyleIndex >= (int)tStdCount);
|
|
fail(!abFilled[iBaseStyleIndex]);
|
|
/* Based on the specified base style */
|
|
*pStyle = atStyleInfo[iBaseStyleIndex];
|
|
*pFont = atFontInfo[iBaseStyleIndex];
|
|
}
|
|
pStyle->usIstd = usStc2istd(ucStc);
|
|
pStyle->usIstdNext = usStc2istd(ucStcNext);
|
|
|
|
abFilled[iIndex] = TRUE;
|
|
iCounter++;
|
|
|
|
/* Add the changes if any */
|
|
switch (iChpx) {
|
|
case 0x00:
|
|
case 0xff:
|
|
iChpxIndex++;
|
|
break;
|
|
default:
|
|
NO_DBG_PRINT_BLOCK(aucBuffer + iChpxIndex + 1,
|
|
iChpx);
|
|
if (iWordVersion == 1) {
|
|
vGet1FontInfo(0,
|
|
aucBuffer + iChpxIndex + 1,
|
|
(size_t)iChpx, pFont);
|
|
} else {
|
|
vGet2FontInfo(0,
|
|
aucBuffer + iChpxIndex + 1,
|
|
(size_t)iChpx, pFont);
|
|
}
|
|
iChpxIndex += iChpx + 1;
|
|
break;
|
|
}
|
|
|
|
switch (iPapx) {
|
|
case 0x00:
|
|
case 0xff:
|
|
iPapxIndex++;
|
|
break;
|
|
default:
|
|
NO_DBG_PRINT_BLOCK(aucBuffer + iPapxIndex + 8,
|
|
iPapx - 7);
|
|
vGet2StyleInfo(0, aucBuffer + iPapxIndex + 8,
|
|
iPapx - 7, pStyle);
|
|
iPapxIndex += iPapx + 1;
|
|
break;
|
|
}
|
|
tMaxIndex += 2;
|
|
|
|
}
|
|
NO_DBG_DEC(iCounter);
|
|
} while (iCounter > 0);
|
|
|
|
/* Fill records that are still empty */
|
|
for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
|
|
if (!abFilled[iIndex]) {
|
|
NO_DBG_DEC(iIndex);
|
|
vGetDefaultStyle(&atStyleInfo[iIndex]);
|
|
vGetDefaultFont(&atFontInfo[iIndex], 0);
|
|
}
|
|
}
|
|
|
|
/* Clean up before you leave */
|
|
abFilled = xfree(abFilled);
|
|
aucBuffer = xfree(aucBuffer);
|
|
} /* end of vGet2Stylesheet */
|
|
|
|
/*
|
|
* Build the lists with Stylesheet Information for Word 6/7 files
|
|
*/
|
|
void
|
|
vGet6Stylesheet(FILE *pFile, ULONG ulStartBlock,
|
|
const ULONG *aulBBD, size_t tBBDLen, const UCHAR *aucHeader)
|
|
{
|
|
style_block_type *pStyle;
|
|
font_block_type *pFont;
|
|
UCHAR *aucBuffer;
|
|
ULONG ulBeginStshInfo;
|
|
size_t tStshInfoLen, tOffset, tStdLen, tStdBaseInFile;
|
|
size_t tPos, tNameLen, tUpxLen;
|
|
int iIndex, iBaseStyleIndex, iCounter;
|
|
USHORT usTmp, usUpxCount, usStyleType, usBaseStyle;
|
|
USHORT usFtcStandardChpStsh;
|
|
|
|
fail(pFile == NULL || aucHeader == NULL);
|
|
fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
|
|
fail(aulBBD == NULL);
|
|
|
|
ulBeginStshInfo = ulGetLong(0x60, aucHeader); /* fcStshf */
|
|
NO_DBG_HEX(ulBeginStshInfo);
|
|
tStshInfoLen = (size_t)ulGetLong(0x64, aucHeader); /* lcbStshf */
|
|
NO_DBG_DEC(tStshInfoLen);
|
|
|
|
aucBuffer = xmalloc(tStshInfoLen);
|
|
if (!bReadBuffer(pFile, ulStartBlock,
|
|
aulBBD, tBBDLen, BIG_BLOCK_SIZE,
|
|
aucBuffer, ulBeginStshInfo, tStshInfoLen)) {
|
|
aucBuffer = xfree(aucBuffer);
|
|
return;
|
|
}
|
|
NO_DBG_PRINT_BLOCK(aucBuffer, tStshInfoLen);
|
|
|
|
tStdCount = (size_t)usGetWord(2, aucBuffer);
|
|
NO_DBG_DEC(tStdCount);
|
|
tStdBaseInFile = (size_t)usGetWord(4, aucBuffer);
|
|
usFtcStandardChpStsh = usGetWord(14, aucBuffer);
|
|
NO_DBG_DEC(usFtcStandardChpStsh);
|
|
|
|
atStyleInfo = xcalloc(tStdCount, sizeof(style_block_type));
|
|
atFontInfo = xcalloc(tStdCount, sizeof(font_block_type));
|
|
abFilled = xcalloc(tStdCount, sizeof(BOOL));
|
|
|
|
do {
|
|
iCounter = 0;
|
|
/* Read the styles one-by-one */
|
|
for (iIndex = 0, tOffset = 2 + (size_t)usGetWord(0, aucBuffer);
|
|
iIndex < (int)tStdCount;
|
|
iIndex++, tOffset += 2 + tStdLen) {
|
|
NO_DBG_DEC(tOffset);
|
|
tStdLen = (size_t)usGetWord(tOffset, aucBuffer);
|
|
NO_DBG_DEC(tStdLen);
|
|
if (abFilled[iIndex]) {
|
|
/* This record has already been filled */
|
|
continue;
|
|
}
|
|
pStyle = &atStyleInfo[iIndex];
|
|
pFont = &atFontInfo[iIndex];
|
|
if (tStdLen == 0) {
|
|
/* Empty record */
|
|
vGetDefaultStyle(pStyle);
|
|
vGetDefaultFont(pFont, usFtcStandardChpStsh);
|
|
abFilled[iIndex] = TRUE;
|
|
continue;
|
|
}
|
|
usTmp = usGetWord(tOffset + 4, aucBuffer);
|
|
usStyleType = usTmp % 16;
|
|
usBaseStyle = usTmp / 16;
|
|
NO_DBG_DEC(usStyleType);
|
|
NO_DBG_DEC(usBaseStyle);
|
|
if (usBaseStyle == STI_NIL || usBaseStyle == STI_USER) {
|
|
/* Based on the Nil style */
|
|
vGetDefaultStyle(pStyle);
|
|
vGetDefaultFont(pFont, usFtcStandardChpStsh);
|
|
} else {
|
|
iBaseStyleIndex = iGetStyleIndex(usBaseStyle);
|
|
NO_DBG_DEC(iBaseStyleIndex);
|
|
if (iBaseStyleIndex < 0) {
|
|
/* This base style is not known yet */
|
|
continue;
|
|
}
|
|
fail(iBaseStyleIndex >= (int)tStdCount);
|
|
fail(!abFilled[iBaseStyleIndex]);
|
|
/* Based on the specified base style */
|
|
*pStyle = atStyleInfo[iBaseStyleIndex];
|
|
pStyle->usIstd = ISTD_INVALID;
|
|
*pFont = atFontInfo[iBaseStyleIndex];
|
|
}
|
|
abFilled[iIndex] = TRUE;
|
|
iCounter++;
|
|
/* STD */
|
|
usTmp = usGetWord(tOffset + 6, aucBuffer);
|
|
usUpxCount = usTmp % 16;
|
|
pStyle->usIstdNext = usTmp / 16;;
|
|
NO_DBG_DEC(usUpxCount);
|
|
tPos = 2 + tStdBaseInFile;
|
|
NO_DBG_DEC(tPos);
|
|
tNameLen = (size_t)ucGetByte(tOffset + tPos, aucBuffer);
|
|
NO_DBG_DEC(tNameLen);
|
|
NO_DBG_STRN(aucBuffer + tOffset + tPos + 1, tNameLen);
|
|
tNameLen++; /* Include the ASCII NULL character */
|
|
tPos += 1 + tNameLen;
|
|
if (odd(tPos)) {
|
|
tPos++;
|
|
}
|
|
NO_DBG_DEC(tPos);
|
|
if (tPos >= tStdLen) {
|
|
continue;
|
|
}
|
|
tUpxLen = (size_t)usGetWord(tOffset + tPos, aucBuffer);
|
|
NO_DBG_DEC(tUpxLen);
|
|
if (tPos + tUpxLen > tStdLen) {
|
|
/* UPX length too large to be a record */
|
|
DBG_DEC_C(tPos + tUpxLen > tStdLen,
|
|
tPos + tUpxLen);
|
|
continue;
|
|
}
|
|
if (usStyleType == SGC_PAP && usUpxCount >= 1) {
|
|
if (tUpxLen >= 2) {
|
|
NO_DBG_PRINT_BLOCK(
|
|
aucBuffer + tOffset + tPos + 2,
|
|
tUpxLen);
|
|
pStyle->usIstd = usGetWord(
|
|
tOffset + tPos + 2, aucBuffer);
|
|
NO_DBG_DEC(pStyle->usIstd);
|
|
NO_DBG_DEC(pStyle->usIstdNext);
|
|
vGet6StyleInfo(0,
|
|
aucBuffer + tOffset + tPos + 4,
|
|
tUpxLen - 2, pStyle);
|
|
NO_DBG_DEC(pStyle->sLeftIndent);
|
|
NO_DBG_DEC(pStyle->sRightIndent);
|
|
NO_DBG_HEX(pStyle->ucAlignment);
|
|
}
|
|
tPos += 2 + tUpxLen;
|
|
if (odd(tPos)) {
|
|
tPos++;
|
|
}
|
|
NO_DBG_DEC(tPos);
|
|
tUpxLen = (size_t)usGetWord(
|
|
tOffset + tPos, aucBuffer);
|
|
NO_DBG_DEC(tUpxLen);
|
|
}
|
|
if (tUpxLen == 0 || tPos + tUpxLen > tStdLen) {
|
|
/* Too small or too large to be a record */
|
|
DBG_DEC_C(tPos + tUpxLen > tStdLen,
|
|
tPos + tUpxLen);
|
|
continue;
|
|
}
|
|
if ((usStyleType == SGC_PAP && usUpxCount >= 2) ||
|
|
(usStyleType == SGC_CHP && usUpxCount >= 1)) {
|
|
NO_DBG_PRINT_BLOCK(
|
|
aucBuffer + tOffset + tPos + 2,
|
|
tUpxLen);
|
|
vGet6FontInfo(0, ISTD_INVALID,
|
|
aucBuffer + tOffset + tPos + 2,
|
|
(int)tUpxLen, pFont);
|
|
NO_DBG_DEC(pFont->usFontSize);
|
|
NO_DBG_DEC(pFont->ucFontcolor);
|
|
NO_DBG_HEX(pFont->usFontStyle);
|
|
}
|
|
}
|
|
NO_DBG_DEC(iCounter);
|
|
} while (iCounter > 0);
|
|
|
|
/* Fill records that are still empty */
|
|
for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
|
|
if (!abFilled[iIndex]) {
|
|
NO_DBG_DEC(iIndex);
|
|
vGetDefaultStyle(&atStyleInfo[iIndex]);
|
|
vGetDefaultFont(&atFontInfo[iIndex],
|
|
usFtcStandardChpStsh);
|
|
}
|
|
}
|
|
|
|
/* Clean up before you leave */
|
|
abFilled = xfree(abFilled);
|
|
aucBuffer = xfree(aucBuffer);
|
|
} /* end of vGet6Stylesheet */
|
|
|
|
/*
|
|
* Build the lists with Stylesheet Information for Word 8/9/10 files
|
|
*/
|
|
void
|
|
vGet8Stylesheet(FILE *pFile, const pps_info_type *pPPS,
|
|
const ULONG *aulBBD, size_t tBBDLen,
|
|
const ULONG *aulSBD, size_t tSBDLen,
|
|
const UCHAR *aucHeader)
|
|
{
|
|
style_block_type *pStyle;
|
|
font_block_type *pFont;
|
|
const ULONG *aulBlockDepot;
|
|
UCHAR *aucBuffer;
|
|
ULONG ulBeginStshInfo;
|
|
size_t tStshInfoLen, tBlockDepotLen, tOffset, tStdLen, tStdBaseInFile;
|
|
size_t tBlockSize, tPos, tNameLen, tUpxLen;
|
|
int iIndex, iBaseStyleIndex, iCounter;
|
|
USHORT usTmp, usUpxCount, usStyleType, usBaseStyle;
|
|
USHORT usFtcStandardChpStsh;
|
|
|
|
fail(pFile == NULL || pPPS == NULL || aucHeader == NULL);
|
|
fail(aulBBD == NULL || aulSBD == NULL);
|
|
|
|
ulBeginStshInfo = ulGetLong(0xa2, aucHeader); /* fcStshf */
|
|
NO_DBG_HEX(ulBeginStshInfo);
|
|
tStshInfoLen = (size_t)ulGetLong(0xa6, aucHeader); /* lcbStshf */
|
|
NO_DBG_DEC(tStshInfoLen);
|
|
|
|
NO_DBG_DEC(pPPS->tTable.ulSB);
|
|
NO_DBG_HEX(pPPS->tTable.ulSize);
|
|
if (pPPS->tTable.ulSize == 0) {
|
|
DBG_MSG("No stylesheet information");
|
|
return;
|
|
}
|
|
|
|
if (pPPS->tTable.ulSize < MIN_SIZE_FOR_BBD_USE) {
|
|
/* Use the Small Block Depot */
|
|
aulBlockDepot = aulSBD;
|
|
tBlockDepotLen = tSBDLen;
|
|
tBlockSize = SMALL_BLOCK_SIZE;
|
|
} else {
|
|
/* Use the Big Block Depot */
|
|
aulBlockDepot = aulBBD;
|
|
tBlockDepotLen = tBBDLen;
|
|
tBlockSize = BIG_BLOCK_SIZE;
|
|
}
|
|
aucBuffer = xmalloc(tStshInfoLen);
|
|
if (!bReadBuffer(pFile, pPPS->tTable.ulSB,
|
|
aulBlockDepot, tBlockDepotLen, tBlockSize,
|
|
aucBuffer, ulBeginStshInfo, tStshInfoLen)) {
|
|
aucBuffer = xfree(aucBuffer);
|
|
return;
|
|
}
|
|
NO_DBG_PRINT_BLOCK(aucBuffer, tStshInfoLen);
|
|
|
|
tStdCount = (size_t)usGetWord(2, aucBuffer);
|
|
NO_DBG_DEC(tStdCount);
|
|
tStdBaseInFile = (size_t)usGetWord(4, aucBuffer);
|
|
usFtcStandardChpStsh = usGetWord(14, aucBuffer);
|
|
NO_DBG_DEC(usFtcStandardChpStsh);
|
|
|
|
atStyleInfo = xcalloc(tStdCount, sizeof(style_block_type));
|
|
atFontInfo = xcalloc(tStdCount, sizeof(font_block_type));
|
|
abFilled = xcalloc(tStdCount, sizeof(BOOL));
|
|
|
|
do {
|
|
iCounter = 0;
|
|
/* Read the styles one-by-one */
|
|
for (iIndex = 0, tOffset = 2 + (size_t)usGetWord(0, aucBuffer);
|
|
iIndex < (int)tStdCount;
|
|
iIndex++, tOffset += 2 + tStdLen) {
|
|
NO_DBG_DEC(tOffset);
|
|
tStdLen = (size_t)usGetWord(tOffset, aucBuffer);
|
|
NO_DBG_DEC(tStdLen);
|
|
if (abFilled[iIndex]) {
|
|
/* This record has already been filled */
|
|
continue;
|
|
}
|
|
pStyle = &atStyleInfo[iIndex];
|
|
pFont = &atFontInfo[iIndex];
|
|
if (tStdLen == 0) {
|
|
/* Empty record */
|
|
vGetDefaultStyle(pStyle);
|
|
vGetDefaultFont(pFont, usFtcStandardChpStsh);
|
|
abFilled[iIndex] = TRUE;
|
|
continue;
|
|
}
|
|
usTmp = usGetWord(tOffset + 4, aucBuffer);
|
|
usStyleType = usTmp % 16;
|
|
usBaseStyle = usTmp / 16;
|
|
NO_DBG_DEC(usStyleType);
|
|
NO_DBG_DEC(usBaseStyle);
|
|
if (usBaseStyle == STI_NIL || usBaseStyle == STI_USER) {
|
|
/* Based on the Nil style */
|
|
vGetDefaultStyle(pStyle);
|
|
vGetDefaultFont(pFont, usFtcStandardChpStsh);
|
|
} else {
|
|
iBaseStyleIndex = iGetStyleIndex(usBaseStyle);
|
|
NO_DBG_DEC(iBaseStyleIndex);
|
|
if (iBaseStyleIndex < 0) {
|
|
/* This base style is not known yet */
|
|
continue;
|
|
}
|
|
fail(iBaseStyleIndex >= (int)tStdCount);
|
|
fail(!abFilled[iBaseStyleIndex]);
|
|
/* Based on the specified base style */
|
|
*pStyle = atStyleInfo[iBaseStyleIndex];
|
|
pStyle->usIstd = ISTD_INVALID;
|
|
*pFont = atFontInfo[iBaseStyleIndex];
|
|
}
|
|
abFilled[iIndex] = TRUE;
|
|
iCounter++;
|
|
/* STD */
|
|
usTmp = usGetWord(tOffset + 6, aucBuffer);
|
|
usUpxCount = usTmp % 16;
|
|
pStyle->usIstdNext = usTmp / 16;
|
|
NO_DBG_DEC(usUpxCount);
|
|
tPos = 2 + tStdBaseInFile;
|
|
NO_DBG_DEC(tPos);
|
|
tNameLen = (size_t)usGetWord(tOffset + tPos, aucBuffer);
|
|
NO_DBG_DEC(tNameLen);
|
|
tNameLen *= 2; /* From Unicode characters to bytes */
|
|
NO_DBG_UNICODE_N(aucBuffer + tOffset + tPos + 2,
|
|
tNameLen);
|
|
tNameLen += 2; /* Include the Unicode NULL character */
|
|
tPos += 2 + tNameLen;
|
|
if (odd(tPos)) {
|
|
tPos++;
|
|
}
|
|
NO_DBG_DEC(tPos);
|
|
if (tPos >= tStdLen) {
|
|
continue;
|
|
}
|
|
tUpxLen = (size_t)usGetWord(tOffset + tPos, aucBuffer);
|
|
NO_DBG_DEC(tUpxLen);
|
|
if (tPos + tUpxLen > tStdLen) {
|
|
/* UPX length too large to be a record */
|
|
DBG_DEC_C(tPos + tUpxLen > tStdLen,
|
|
tPos + tUpxLen);
|
|
continue;
|
|
}
|
|
if (usStyleType == SGC_PAP && usUpxCount >= 1) {
|
|
if (tUpxLen >= 2) {
|
|
NO_DBG_PRINT_BLOCK(
|
|
aucBuffer + tOffset + tPos + 2,
|
|
tUpxLen);
|
|
pStyle->usIstd = usGetWord(
|
|
tOffset + tPos + 2, aucBuffer);
|
|
NO_DBG_DEC(pStyle->usIstd);
|
|
NO_DBG_DEC(pStyle->usIstdNext);
|
|
vGet8StyleInfo(0,
|
|
aucBuffer + tOffset + tPos + 4,
|
|
tUpxLen - 2, pStyle);
|
|
NO_DBG_DEC(pStyle->sLeftIndent);
|
|
NO_DBG_DEC(pStyle->sRightIndent);
|
|
NO_DBG_HEX(pStyle->ucAlignment);
|
|
}
|
|
tPos += 2 + tUpxLen;
|
|
if (odd(tPos)) {
|
|
tPos++;
|
|
}
|
|
NO_DBG_DEC(tPos);
|
|
tUpxLen = (size_t)usGetWord(
|
|
tOffset + tPos, aucBuffer);
|
|
NO_DBG_DEC(tUpxLen);
|
|
}
|
|
if (tUpxLen == 0 || tPos + tUpxLen > tStdLen) {
|
|
/* Too small or too large to be a record */
|
|
DBG_DEC_C(tPos + tUpxLen > tStdLen,
|
|
tPos + tUpxLen);
|
|
continue;
|
|
}
|
|
if ((usStyleType == SGC_PAP && usUpxCount >= 2) ||
|
|
(usStyleType == SGC_CHP && usUpxCount >= 1)) {
|
|
NO_DBG_PRINT_BLOCK(
|
|
aucBuffer + tOffset + tPos + 2,
|
|
tUpxLen);
|
|
vGet8FontInfo(0, ISTD_INVALID,
|
|
aucBuffer + tOffset + tPos + 2,
|
|
(int)tUpxLen, pFont);
|
|
NO_DBG_DEC(pFont->usFontSize);
|
|
NO_DBG_DEC(pFont->ucFontcolor);
|
|
NO_DBG_HEX(pFont->usFontStyle);
|
|
}
|
|
}
|
|
NO_DBG_DEC(iCounter);
|
|
} while (iCounter > 0);
|
|
|
|
/* Fill records that are still empty */
|
|
for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
|
|
if (!abFilled[iIndex]) {
|
|
NO_DBG_DEC(iIndex);
|
|
vGetDefaultStyle(&atStyleInfo[iIndex]);
|
|
vGetDefaultFont(&atFontInfo[iIndex],
|
|
usFtcStandardChpStsh);
|
|
}
|
|
}
|
|
|
|
/* Clean up before you leave */
|
|
abFilled = xfree(abFilled);
|
|
aucBuffer = xfree(aucBuffer);
|
|
} /* end of vGet8Stylesheet */
|
|
|
|
/*
|
|
* vFillStyleFromStylesheet - fill a style struct with stylesheet info
|
|
*/
|
|
void
|
|
vFillStyleFromStylesheet(USHORT usIstd, style_block_type *pStyle)
|
|
{
|
|
int iIndex;
|
|
|
|
fail(pStyle == NULL);
|
|
|
|
if (usIstd != ISTD_INVALID && usIstd != STI_NIL && usIstd != STI_USER) {
|
|
for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
|
|
if (atStyleInfo[iIndex].usIstd == usIstd) {
|
|
/* Right index found; return style */
|
|
*pStyle = atStyleInfo[iIndex];
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
vGetDefaultStyle(pStyle);
|
|
pStyle->usIstd = usIstd;
|
|
} /* end of vFillStyleFromStylesheet */
|
|
|
|
/*
|
|
* vFillFontFromStylesheet - fill a font struct with stylesheet info
|
|
*/
|
|
void
|
|
vFillFontFromStylesheet(USHORT usIstd, font_block_type *pFont)
|
|
{
|
|
int iIndex;
|
|
|
|
fail(pFont == NULL);
|
|
|
|
if (usIstd != ISTD_INVALID && usIstd != STI_NIL && usIstd != STI_USER) {
|
|
for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
|
|
if (atStyleInfo[iIndex].usIstd == usIstd) {
|
|
/* Right index found; return font */
|
|
*pFont = atFontInfo[iIndex];
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
vGetDefaultFont(pFont, 0);
|
|
} /* end of vFillFontFromStylesheet */
|