/*
* prop0.c
* Copyright (C) 2002-2004 A.J. van Os; Released under GNU GPL
*
* Description:
* Read the property information from a Word for DOS file
*/

#include <string.h>
#include <time.h>
#include "antiword.h"


/*
* tConvertDosDate - convert DOS date format
*
* returns Unix time_t or -1
*/
static time_t
tConvertDosDate(const char *szDosDate)
{
       struct tm       tTime;
       const char      *pcTmp;
       time_t          tResult;

       memset(&tTime, 0, sizeof(tTime));
       pcTmp = szDosDate;
       /* Get the month */
       if (!isdigit(*pcTmp)) {
               return (time_t)-1;
       }
       tTime.tm_mon = (int)(*pcTmp - '0');
       pcTmp++;
       if (isdigit(*pcTmp)) {
               tTime.tm_mon *= 10;
               tTime.tm_mon += (int)(*pcTmp - '0');
               pcTmp++;
       }
       /* Get the first separater */
       if (isalnum(*pcTmp)) {
               return (time_t)-1;
       }
       pcTmp++;
       /* Get the day */
       if (!isdigit(*pcTmp)) {
               return (time_t)-1;
       }
       tTime.tm_mday = (int)(*pcTmp - '0');
       pcTmp++;
       if (isdigit(*pcTmp)) {
               tTime.tm_mday *= 10;
               tTime.tm_mday += (int)(*pcTmp - '0');
               pcTmp++;
       }
       /* Get the second separater */
       if (isalnum(*pcTmp)) {
               return (time_t)-1;
       }
       pcTmp++;
       /* Get the year */
       if (!isdigit(*pcTmp)) {
               return (time_t)-1;
       }
       tTime.tm_year = (int)(*pcTmp - '0');
       pcTmp++;
       if (isdigit(*pcTmp)) {
               tTime.tm_year *= 10;
               tTime.tm_year += (int)(*pcTmp - '0');
               pcTmp++;
       }
       /* Check the values */
       if (tTime.tm_mon == 0 || tTime.tm_mday == 0 || tTime.tm_mday > 31) {
               return (time_t)-1;
       }
       /* Correct the values */
       tTime.tm_mon--;         /* From 01-12 to 00-11 */
       if (tTime.tm_year < 80) {
               tTime.tm_year += 100;   /* 00 means 2000 is 100 */
       }
       tTime.tm_isdst = -1;
       tResult = mktime(&tTime);
       NO_DBG_MSG(ctime(&tResult));
       return tResult;
} /* end of tConvertDosDate */

/*
* Build the lists with Document Property Information for Word for DOS files
*/
void
vGet0DopInfo(FILE *pFile, const UCHAR *aucHeader)
{
       document_block_type     tDocument;
       UCHAR   *aucBuffer;
       ULONG   ulBeginSumdInfo, ulBeginNextBlock;
       size_t  tLen;
       USHORT  usOffset;

       tDocument.ucHdrFtrSpecification = 0;
       tDocument.usDefaultTabWidth = usGetWord(0x70, aucHeader); /* dxaTab */
       tDocument.tCreateDate = (time_t)-1;
       tDocument.tRevisedDate = (time_t)-1;

       ulBeginSumdInfo = 128 * (ULONG)usGetWord(0x1c, aucHeader);
       DBG_HEX(ulBeginSumdInfo);
       ulBeginNextBlock = 128 * (ULONG)usGetWord(0x6a, aucHeader);
       DBG_HEX(ulBeginNextBlock);

       if (ulBeginSumdInfo < ulBeginNextBlock && ulBeginNextBlock != 0) {
               /* There is a summary information block */
               tLen = (size_t)(ulBeginNextBlock - ulBeginSumdInfo);
               aucBuffer = xmalloc(tLen);
               /* Read the summary information block */
               if (bReadBytes(aucBuffer, tLen, ulBeginSumdInfo, pFile)) {
                       usOffset = usGetWord(12, aucBuffer);
                       if (aucBuffer[usOffset] != 0) {
                               NO_DBG_STRN(aucBuffer + usOffset, 8);
                               tDocument.tRevisedDate =
                               tConvertDosDate((char *)aucBuffer + usOffset);
                       }
                       usOffset = usGetWord(14, aucBuffer);
                       if (aucBuffer[usOffset] != 0) {
                               NO_DBG_STRN(aucBuffer + usOffset, 8);
                               tDocument.tCreateDate =
                               tConvertDosDate((char *)aucBuffer + usOffset);
                       }
               }
               aucBuffer = xfree(aucBuffer);
       }
       vCreateDocumentInfoList(&tDocument);
} /* end of vGet0DopInfo */

/*
* Fill the section information block with information
* from a Word for DOS file.
*/
static void
vGet0SectionInfo(const UCHAR *aucGrpprl, size_t tBytes,
               section_block_type *pSection)
{
       USHORT  usCcol;
       UCHAR   ucTmp;

       fail(aucGrpprl == NULL || pSection == NULL);

       if (tBytes < 2) {
               return;
       }
       /* bkc */
       ucTmp = ucGetByte(1, aucGrpprl);
       DBG_HEX(ucTmp);
       ucTmp &= 0x07;
       DBG_HEX(ucTmp);
       pSection->bNewPage = ucTmp != 0 && ucTmp != 1;
       if (tBytes < 18) {
               return;
       }
       /* ccolM1 */
       usCcol = (USHORT)ucGetByte(17, aucGrpprl);
       DBG_DEC(usCcol);
} /* end of vGet0SectionInfo */

/*
* Build the lists with Section Property Information for Word for DOS files
*/
void
vGet0SepInfo(FILE *pFile, const UCHAR *aucHeader)
{
       section_block_type      tSection;
       UCHAR   *aucBuffer;
       ULONG   ulBeginOfText, ulTextOffset, ulBeginSectInfo;
       ULONG   ulCharPos, ulSectPage, ulBeginNextBlock;
       size_t  tSectInfoLen, tIndex, tSections, tBytes;
       UCHAR   aucTmp[2], aucFpage[35];

       fail(pFile == NULL || aucHeader == NULL);

       ulBeginOfText = 128;
       NO_DBG_HEX(ulBeginOfText);
       ulBeginSectInfo = 128 * (ULONG)usGetWord(0x18, aucHeader);
       DBG_HEX(ulBeginSectInfo);
       ulBeginNextBlock = 128 * (ULONG)usGetWord(0x1a, aucHeader);
       DBG_HEX(ulBeginNextBlock);
       if (ulBeginSectInfo == ulBeginNextBlock) {
               /* There is no section information block */
               return;
       }

       /* Get the the number of sections */
       if (!bReadBytes(aucTmp, 2, ulBeginSectInfo, pFile)) {
               return;
       }
       tSections = (size_t)usGetWord(0, aucTmp);
       NO_DBG_DEC(tSections);

       /* Read the Section Descriptors */
       tSectInfoLen = 10 * tSections;
       NO_DBG_DEC(tSectInfoLen);
       aucBuffer = xmalloc(tSectInfoLen);
       if (!bReadBytes(aucBuffer, tSectInfoLen, ulBeginSectInfo + 4, pFile)) {
               aucBuffer = xfree(aucBuffer);
               return;
       }
       NO_DBG_PRINT_BLOCK(aucBuffer, tSectInfoLen);

       /* Read the Section Properties */
       for (tIndex = 0; tIndex < tSections; tIndex++) {
               ulTextOffset = ulGetLong(10 * tIndex, aucBuffer);
               NO_DBG_HEX(ulTextOffset);
               ulCharPos = ulBeginOfText + ulTextOffset;
               NO_DBG_HEX(ulTextOffset);
               ulSectPage = ulGetLong(10 * tIndex + 6, aucBuffer);
               NO_DBG_HEX(ulSectPage);
               if (ulSectPage == FC_INVALID ||         /* Must use defaults */
                   ulSectPage < 128 ||                 /* Should not happen */
                   ulSectPage >= ulBeginSectInfo) {    /* Should not happen */
                       DBG_HEX_C(ulSectPage != FC_INVALID, ulSectPage);
                       vDefault2SectionInfoList(ulCharPos);
                       continue;
               }
               /* Get the number of bytes to read */
               if (!bReadBytes(aucTmp, 1, ulSectPage, pFile)) {
                       continue;
               }
               tBytes = 1 + (size_t)ucGetByte(0, aucTmp);
               NO_DBG_DEC(tBytes);
               if (tBytes > sizeof(aucFpage)) {
                       DBG_DEC(tBytes);
                       tBytes = sizeof(aucFpage);
               }
               /* Read the bytes */
               if (!bReadBytes(aucFpage, tBytes, ulSectPage, pFile)) {
                       continue;
               }
               NO_DBG_PRINT_BLOCK(aucFpage, tBytes);
               /* Process the bytes */
               vGetDefaultSection(&tSection);
               vGet0SectionInfo(aucFpage + 1, tBytes - 1, &tSection);
               vAdd2SectionInfoList(&tSection, ulCharPos);
       }
       /* Clean up before you leave */
       aucBuffer = xfree(aucBuffer);
} /* end of vGet0SepInfo */

/*
* Fill the style information block with information
* from a Word for DOS file.
*/
static void
vGet0StyleInfo(int iFodo, const UCHAR *aucGrpprl, style_block_type *pStyle)
{
       int     iBytes;
       UCHAR   ucTmp;

       fail(iFodo <= 0 || aucGrpprl == NULL || pStyle == NULL);

       pStyle->usIstdNext = ISTD_NORMAL;

       iBytes = (int)ucGetByte(iFodo, aucGrpprl);
       if (iBytes < 1) {
               return;
       }
       /* stc if styled */
       ucTmp = ucGetByte(iFodo + 1, aucGrpprl);
       if ((ucTmp & BIT(0)) != 0) {
               ucTmp >>= 1;
               if (ucTmp >= 88 && ucTmp <= 94) {
                       /* Header levels 1 through 7 */
                       pStyle->usIstd = ucTmp - 87;
                       pStyle->ucNumLevel = 1;
               }
       }
       if (iBytes < 2) {
               return;
       }
       /* jc */
       ucTmp = ucGetByte(iFodo + 2, aucGrpprl);
       pStyle->ucAlignment = ucTmp & 0x02;
       if (iBytes < 3) {
               return;
       }
       /* stc */
       ucTmp = ucGetByte(iFodo + 3, aucGrpprl);
       ucTmp &= 0x7f;
       if (ucTmp >= 88 && ucTmp <= 94) {
               /* Header levels 1 through 7 */
               pStyle->usIstd = ucTmp - 87;
               pStyle->ucNumLevel = 1;
       }
       if (iBytes < 6) {
               return;
       }
       /* dxaRight */
       pStyle->sRightIndent = (short)usGetWord(iFodo + 5, aucGrpprl);
       NO_DBG_DEC(pStyle->sRightIndent);
       if (iBytes < 8) {
               return;
       }
       /* dxaLeft */
       pStyle->sLeftIndent = (short)usGetWord(iFodo + 7, aucGrpprl);
       NO_DBG_DEC(pStyle->sLeftIndent);
       if (iBytes < 10) {
               return;
       }
       /* dxaLeft1 */
       pStyle->sLeftIndent1 = (short)usGetWord(iFodo + 9, aucGrpprl);
       NO_DBG_DEC(pStyle->sLeftIndent1);
       if (iBytes < 14) {
               return;
       }
       /* dyaBefore */
       pStyle->usBeforeIndent = usGetWord(iFodo + 13, aucGrpprl);
       NO_DBG_DEC(pStyle->usBeforeIndent);
       if (iBytes < 16) {
               return;
       }
       /* dyaAfter */
       pStyle->usAfterIndent = usGetWord(iFodo + 15, aucGrpprl);
       NO_DBG_DEC(pStyle->usAfterIndent);
} /* end of vGet0StyleInfo */

/*
* Build the lists with Paragraph Information for Word for DOS files
*/
void
vGet0PapInfo(FILE *pFile, const UCHAR *aucHeader)
{
       style_block_type        tStyle;
       ULONG   ulBeginParfInfo, ulCharPos, ulCharPosNext;
       int     iIndex, iRun, iFodo;
       UCHAR   aucFpage[128];

       fail(pFile == NULL || aucHeader == NULL);

       ulBeginParfInfo = 128 * (ULONG)usGetWord(0x12, aucHeader);
       NO_DBG_HEX(ulBeginParfInfo);

       do {
               if (!bReadBytes(aucFpage, 128, ulBeginParfInfo, pFile)) {
                       return;
               }
               NO_DBG_PRINT_BLOCK(aucFpage, 128);
               ulCharPosNext = ulGetLong(0, aucFpage);
               iRun = (int)ucGetByte(0x7f, aucFpage);
               NO_DBG_DEC(iRun);
               for (iIndex = 0; iIndex < iRun; iIndex++) {
                       iFodo = (int)usGetWord(6 * iIndex + 8, aucFpage);
                       if (iFodo <= 0 || iFodo > 0x79) {
                               DBG_DEC_C(iFodo != (int)0xffff, iFodo);
                               continue;
                       }
                       vFillStyleFromStylesheet(0, &tStyle);
                       vGet0StyleInfo(iFodo, aucFpage + 4, &tStyle);
                       ulCharPos = ulCharPosNext;
                       ulCharPosNext = ulGetLong(6 * iIndex + 4, aucFpage);
                       tStyle.ulFileOffset = ulCharPos;
                       vAdd2StyleInfoList(&tStyle);
               }
               ulBeginParfInfo += 128;
       } while (ulCharPosNext == ulBeginParfInfo);
} /* end of vGet0PapInfo */

/*
* Fill the font information block with information
* from a Word for DOS file.
*/
static void
vGet0FontInfo(int iFodo, const UCHAR *aucGrpprl, font_block_type *pFont)
{
       int     iBytes;
       UCHAR   ucTmp;

       fail(iFodo <= 0 || aucGrpprl == NULL || pFont == NULL);

       iBytes = (int)ucGetByte(iFodo, aucGrpprl);
       if (iBytes < 2) {
               return;
       }
       /* fBold, fItalic, cFtc */
       ucTmp = ucGetByte(iFodo + 2, aucGrpprl);
       if ((ucTmp & BIT(0)) != 0) {
               pFont->usFontStyle |= FONT_BOLD;
       }
       if ((ucTmp & BIT(1)) != 0) {
               pFont->usFontStyle |= FONT_ITALIC;
       }
       pFont->ucFontNumber = ucTmp >> 2;
       NO_DBG_DEC(pFont->ucFontNumber);
       if (iBytes < 3) {
               return;
       }
       /* cHps */
       pFont->usFontSize = (USHORT)ucGetByte(iFodo + 3, aucGrpprl);
       NO_DBG_DEC(pFont->usFontSize);
       if (iBytes < 4) {
               return;
       }
       /* cKul, fStrike, fCaps, fSmallCaps, fVanish */
       ucTmp = ucGetByte(iFodo + 4, aucGrpprl);
       if ((ucTmp & BIT(0)) != 0 || (ucTmp & BIT(2)) != 0) {
               pFont->usFontStyle |= FONT_UNDERLINE;
       }
       if ((ucTmp & BIT(1)) != 0) {
               pFont->usFontStyle |= FONT_STRIKE;
       }
       if ((ucTmp & BIT(4)) != 0) {
               pFont->usFontStyle |= FONT_CAPITALS;
       }
       if ((ucTmp & BIT(5)) != 0) {
               pFont->usFontStyle |= FONT_SMALL_CAPITALS;
       }
       if ((ucTmp & BIT(7)) != 0) {
               pFont->usFontStyle |= FONT_HIDDEN;
       }
       DBG_HEX(pFont->usFontStyle);
       if (iBytes < 6) {
               return;
       }
       /* cIss */
       ucTmp = ucGetByte(iFodo + 6, aucGrpprl);
       if (ucTmp != 0) {
               if (ucTmp < 128) {
                       pFont->usFontStyle |= FONT_SUPERSCRIPT;
                       DBG_MSG("Superscript");
               } else {
                       pFont->usFontStyle |= FONT_SUBSCRIPT;
                       DBG_MSG("Subscript");
               }
       }
       if (iBytes < 7) {
               return;
       }
       /* cIco */
       ucTmp = ucGetByte(iFodo + 7, aucGrpprl);
       switch (ucTmp & 0x07) {
       case 0: pFont->ucFontColor = FONT_COLOR_BLACK; break;
       case 1: pFont->ucFontColor = FONT_COLOR_RED; break;
       case 2: pFont->ucFontColor = FONT_COLOR_GREEN; break;
       case 3: pFont->ucFontColor = FONT_COLOR_BLUE; break;
       case 4: pFont->ucFontColor = FONT_COLOR_CYAN; break;
       case 5: pFont->ucFontColor = FONT_COLOR_MAGENTA; break;
       case 6: pFont->ucFontColor = FONT_COLOR_YELLOW; break;
       case 7: pFont->ucFontColor = FONT_COLOR_WHITE; break;
       default:pFont->ucFontColor = FONT_COLOR_BLACK; break;
       }
       NO_DBG_DEC(pFont->ucFontColor);
} /* end of vGet0FontInfo */

/*
* Build the lists with Character Information for Word for DOS files
*/
void
vGet0ChrInfo(FILE *pFile, const UCHAR *aucHeader)
{
       font_block_type         tFont;
       ULONG   ulBeginCharInfo, ulCharPos, ulCharPosNext;
       int     iIndex, iRun, iFodo;
       UCHAR   aucFpage[128];

       fail(pFile == NULL || aucHeader == NULL);

       ulBeginCharInfo = ulGetLong(0x0e, aucHeader);
       NO_DBG_HEX(ulBeginCharInfo);
       ulBeginCharInfo = ROUND128(ulBeginCharInfo);
       NO_DBG_HEX(ulBeginCharInfo);

       do {
               if (!bReadBytes(aucFpage, 128, ulBeginCharInfo, pFile)) {
                       return;
               }
               NO_DBG_PRINT_BLOCK(aucFpage, 128);
               ulCharPosNext = ulGetLong(0, aucFpage);
               iRun = (int)ucGetByte(0x7f, aucFpage);
               NO_DBG_DEC(iRun);
               for (iIndex = 0; iIndex < iRun; iIndex++) {
                       iFodo = (int)usGetWord(6 * iIndex + 8, aucFpage);
                       if (iFodo <= 0 || iFodo > 0x79) {
                               DBG_DEC_C(iFodo != (int)0xffff, iFodo);
                               continue;
                       }
                       vFillFontFromStylesheet(0, &tFont);
                       vGet0FontInfo(iFodo, aucFpage + 4, &tFont);
                       ulCharPos = ulCharPosNext;
                       ulCharPosNext = ulGetLong(6 * iIndex + 4, aucFpage);
                       tFont.ulFileOffset = ulCharPos;
                       vAdd2FontInfoList(&tFont);
               }
               ulBeginCharInfo += 128;
       } while (ulCharPosNext == ulBeginCharInfo);
} /* end of vGet0ChrInfo */