/*
* 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;
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;
/* 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;
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 */
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 */