examples/PIPS/antiword/src/summary.c

00001 /*
00002  * summary.c
00003  * Copyright (C) 2002-2005 A.J. van Os; Released under GNU GPL
00004  *
00005  * Description:
00006  * Read the summary information of a Word document
00007  */
00008 
00009 #include <time.h>
00010 #include <string.h>
00011 #include "antiword.h"
00012 
00013 #define P_HEADER_SZ             28
00014 #define P_SECTIONLIST_SZ        20
00015 #define P_LENGTH_SZ              4
00016 #define P_SECTION_MAX_SZ        (2 * P_SECTIONLIST_SZ + P_LENGTH_SZ)
00017 #define P_SECTION_SZ(x)         ((x) * P_SECTIONLIST_SZ + P_LENGTH_SZ)
00018 
00019 #define PID_TITLE                2
00020 #define PID_SUBJECT              3
00021 #define PID_AUTHOR               4
00022 #define PID_CREATE_DTM          12
00023 #define PID_LASTSAVE_DTM        13
00024 #define PID_APPNAME             18
00025 
00026 #define PIDD_MANAGER            14
00027 #define PIDD_COMPANY            15
00028 
00029 #define VT_LPSTR                30
00030 #define VT_FILETIME             64
00031 
00032 #define TIME_OFFSET_HI          0x019db1de
00033 #define TIME_OFFSET_LO          0xd53e8000
00034 
00035 static char     *szTitle = NULL;
00036 static char     *szSubject = NULL;
00037 static char     *szAuthor = NULL;
00038 static time_t   tCreateDtm = (time_t)-1;
00039 static time_t   tLastSaveDtm= (time_t)-1;
00040 static char     *szAppName = NULL;
00041 static char     *szManager = NULL;
00042 static char     *szCompany = NULL;
00043 static USHORT   usLid = (USHORT)-1;
00044 
00045 
00046 /*
00047  * vDestroySummaryInfo - destroy the summary information
00048  */
00049 void
00050 vDestroySummaryInfo(void)
00051 {
00052         TRACE_MSG("vDestroySummaryInfo");
00053 
00054         szTitle = xfree(szTitle);
00055         szSubject = xfree(szSubject);
00056         szAuthor = xfree(szAuthor);
00057         tCreateDtm = (time_t)-1;
00058         tLastSaveDtm = (time_t)-1;
00059         szAppName = xfree(szAppName);
00060         szManager = xfree(szManager);
00061         szCompany = xfree(szCompany);
00062         usLid = (USHORT)-1;
00063 } /* end of vDestroySummaryInfo */
00064 
00065 /*
00066  * tConvertDosDate - convert DOS date format
00067  *
00068  * returns Unix time_t or -1
00069  */
00070 static time_t
00071 tConvertDosDate(const char *szDosDate)
00072 {
00073         struct tm       tTime;
00074         const char      *pcTmp;
00075         time_t          tResult;
00076 
00077         memset(&tTime, 0, sizeof(tTime));
00078         pcTmp = szDosDate;
00079         /* Get the month */
00080         if (!isdigit(*pcTmp)) {
00081                 return (time_t)-1;
00082         }
00083         tTime.tm_mon = (int)(*pcTmp - '0');
00084         pcTmp++;
00085         if (isdigit(*pcTmp)) {
00086                 tTime.tm_mon *= 10;
00087                 tTime.tm_mon += (int)(*pcTmp - '0');
00088                 pcTmp++;
00089         }
00090         /* Get the first separater */
00091         if (isalnum(*pcTmp)) {
00092                 return (time_t)-1;
00093         }
00094         pcTmp++;
00095         /* Get the day */
00096         if (!isdigit(*pcTmp)) {
00097                 return (time_t)-1;
00098         }
00099         tTime.tm_mday = (int)(*pcTmp - '0');
00100         pcTmp++;
00101         if (isdigit(*pcTmp)) {
00102                 tTime.tm_mday *= 10;
00103                 tTime.tm_mday += (int)(*pcTmp - '0');
00104                 pcTmp++;
00105         }
00106         /* Get the second separater */
00107         if (isalnum(*pcTmp)) {
00108                 return (time_t)-1;
00109         }
00110         pcTmp++;
00111         /* Get the year */
00112         if (!isdigit(*pcTmp)) {
00113                 return (time_t)-1;
00114         }
00115         tTime.tm_year = (int)(*pcTmp - '0');
00116         pcTmp++;
00117         if (isdigit(*pcTmp)) {
00118                 tTime.tm_year *= 10;
00119                 tTime.tm_year += (int)(*pcTmp - '0');
00120                 pcTmp++;
00121         }
00122         /* Check the values */
00123         if (tTime.tm_mon == 0 || tTime.tm_mday == 0 || tTime.tm_mday > 31) {
00124                 return (time_t)-1;
00125         }
00126         /* Correct the values */
00127         tTime.tm_mon--;         /* From 01-12 to 00-11 */
00128         if (tTime.tm_year < 80) {
00129                 tTime.tm_year += 100;   /* 00 means 2000 is 100 */
00130         }
00131         tTime.tm_isdst = -1;
00132         tResult = mktime(&tTime);
00133         NO_DBG_MSG(ctime(&tResult));
00134         return tResult;
00135 } /* end of tConvertDosDate */
00136 
00137 /*
00138  * szLpstr - get a zero terminate string property
00139  */
00140 static char *
00141 szLpstr(ULONG ulOffset, const UCHAR *aucBuffer)
00142 {
00143         char    *szStart, *szResult, *szTmp;
00144         size_t  tSize;
00145 
00146         tSize = (size_t)ulGetLong(ulOffset + 4, aucBuffer);
00147         NO_DBG_DEC(tSize);
00148         if (tSize == 0) {
00149                 return NULL;
00150         }
00151         /* Remove white space from the start of the string */
00152         szStart = (char *)aucBuffer + ulOffset + 8;
00153         NO_DBG_MSG(szStart);
00154         fail(strlen(szStart) >= tSize);
00155         while (isspace(*szStart)) {
00156                 szStart++;
00157         }
00158         if (szStart[0] == '\0') {
00159                 return NULL;
00160         }
00161         szResult = xstrdup(szStart);
00162         /* Remove white space from the end of the string */
00163         szTmp = szResult + strlen(szResult) - 1;
00164         while (isspace(*szTmp)) {
00165                 *szTmp = '\0';
00166                 szTmp--;
00167         }
00168         NO_DBG_MSG(szResult);
00169         return szResult;
00170 } /* end of szLpstr */
00171 
00172 /*
00173  * tFiletime - get a filetime property
00174  */
00175 static time_t
00176 tFiletime(ULONG ulOffset, const UCHAR *aucBuffer)
00177 {
00178         double  dHi, dLo, dTmp;
00179         ULONG   ulHi, ulLo;
00180         time_t  tResult;
00181 
00182         ulLo = ulGetLong(ulOffset + 4, aucBuffer);
00183         ulHi = ulGetLong(ulOffset + 8, aucBuffer);
00184         NO_DBG_HEX(ulHi);
00185         NO_DBG_HEX(ulLo);
00186 
00187         /* Move the starting point from 01 Jan 1601 to 01 Jan 1970 */
00188         dHi = (double)ulHi - (double)TIME_OFFSET_HI;
00189         dLo = (double)ulLo - (double)TIME_OFFSET_LO;
00190         NO_DBG_FLT(dHi);
00191         NO_DBG_FLT(dLo);
00192 
00193         /* Combine the values and divide by 10^7 to get seconds */
00194         dTmp  = dLo / 10000000.0;       /* 10^7 */
00195         dTmp += dHi * 429.4967926;      /* 2^32 / 10^7 */
00196         NO_DBG_FLT(dTmp);
00197 
00198         /* Make a time_t */
00199         if (dTmp - 0.5 < TIME_T_MIN || dTmp + 0.5 > TIME_T_MAX) {
00200                 return (time_t)-1;
00201         }
00202         tResult = dTmp < 0.0 ? (time_t)(dTmp - 0.5) : (time_t)(dTmp + 0.5);
00203         NO_DBG_MSG(ctime(&tResult));
00204         return tResult;
00205 } /* end of tFiletime */
00206 
00207 /*
00208  * vAnalyseSummaryInfo - analyse the summary information
00209  */
00210 static void
00211 vAnalyseSummaryInfo(const UCHAR *aucBuffer)
00212 {
00213         ULONG   ulOffset;
00214         size_t  tIndex, tCount, tPropID, tPropType;
00215 
00216         tCount = (size_t)ulGetLong(4, aucBuffer);
00217         DBG_DEC(tCount);
00218         for (tIndex = 0; tIndex < tCount; tIndex++) {
00219                 tPropID = (size_t)ulGetLong(8 + tIndex * 8, aucBuffer);
00220                 ulOffset = ulGetLong(12 + tIndex * 8, aucBuffer);
00221                 NO_DBG_DEC(tPropID);
00222                 NO_DBG_HEX(ulOffset);
00223                 tPropType = (size_t)ulGetLong(ulOffset, aucBuffer);
00224                 NO_DBG_DEC(tPropType);
00225                 switch (tPropID) {
00226                 case PID_TITLE:
00227                         if (tPropType == VT_LPSTR && szTitle == NULL) {
00228                                 szTitle = szLpstr(ulOffset, aucBuffer);
00229                         }
00230                         break;
00231                 case PID_SUBJECT:
00232                         if (tPropType == VT_LPSTR && szSubject == NULL) {
00233                                 szSubject = szLpstr(ulOffset, aucBuffer);
00234                         }
00235                         break;
00236                 case PID_AUTHOR:
00237                         if (tPropType == VT_LPSTR && szAuthor == NULL) {
00238                                 szAuthor = szLpstr(ulOffset, aucBuffer);
00239                         }
00240                         break;
00241                 case PID_CREATE_DTM:
00242                         if (tPropType == VT_FILETIME &&
00243                             tCreateDtm == (time_t)-1) {
00244                                 tCreateDtm = tFiletime(ulOffset, aucBuffer);
00245                         }
00246                         break;
00247                 case PID_LASTSAVE_DTM:
00248                         if (tPropType == VT_FILETIME &&
00249                             tLastSaveDtm == (time_t)-1) {
00250                                 tLastSaveDtm = tFiletime(ulOffset, aucBuffer);
00251                         }
00252                         break;
00253                 case PID_APPNAME:
00254                         if (tPropType == VT_LPSTR && szAppName == NULL) {
00255                                 szAppName = szLpstr(ulOffset, aucBuffer);
00256                         }
00257                         break;
00258                 default:
00259                         break;
00260                 }
00261         }
00262 } /* end of vAnalyseSummaryInfo */
00263 
00264 /*
00265  * vAnalyseDocumentSummaryInfo - analyse the document summary information
00266  */
00267 static void
00268 vAnalyseDocumentSummaryInfo(const UCHAR *aucBuffer)
00269 {
00270         ULONG   ulOffset;
00271         size_t  tIndex, tCount, tPropID, tPropType;
00272 
00273         tCount = (size_t)ulGetLong(4, aucBuffer);
00274         DBG_DEC(tCount);
00275         for (tIndex = 0; tIndex < tCount; tIndex++) {
00276                 tPropID = (size_t)ulGetLong(8 + tIndex * 8, aucBuffer);
00277                 ulOffset = ulGetLong(12 + tIndex * 8, aucBuffer);
00278                 NO_DBG_DEC(tPropID);
00279                 NO_DBG_HEX(ulOffset);
00280                 tPropType = (size_t)ulGetLong(ulOffset, aucBuffer);
00281                 NO_DBG_DEC(tPropType);
00282                 switch (tPropID) {
00283                 case PIDD_MANAGER:
00284                         if (tPropType == VT_LPSTR && szManager == NULL) {
00285                                 szManager = szLpstr(ulOffset, aucBuffer);
00286                         }
00287                         break;
00288                 case PIDD_COMPANY:
00289                         if (tPropType == VT_LPSTR && szCompany == NULL) {
00290                                 szCompany = szLpstr(ulOffset, aucBuffer);
00291                         }
00292                         break;
00293                 default:
00294                         break;
00295                 }
00296         }
00297 } /* end of vAnalyseDocumentSummaryInfo */
00298 
00299 /*
00300  * pucAnalyseSummaryInfoHeader-
00301  */
00302 static UCHAR *
00303 pucAnalyseSummaryInfoHeader(FILE *pFile,
00304         ULONG ulStartBlock, ULONG ulSize,
00305         const ULONG *aulBBD, size_t tBBDLen,
00306         const ULONG *aulSBD, size_t tSBDLen)
00307 {
00308         const ULONG     *aulBlockDepot;
00309         UCHAR   *aucBuffer;
00310         size_t  tBlockDepotLen, tBlockSize, tSectionCount, tLength;
00311         ULONG   ulTmp, ulOffset;
00312         USHORT  usLittleEndian, usEmpty, usOS, usVersion;
00313         UCHAR   aucHdr[P_HEADER_SZ], aucSecLst[P_SECTION_MAX_SZ];
00314 
00315         if (ulSize < MIN_SIZE_FOR_BBD_USE) {
00316                 /* Use the Small Block Depot */
00317                 aulBlockDepot = aulSBD;
00318                 tBlockDepotLen = tSBDLen;
00319                 tBlockSize = SMALL_BLOCK_SIZE;
00320         } else {
00321                 /* Use the Big Block Depot */
00322                 aulBlockDepot = aulBBD;
00323                 tBlockDepotLen = tBBDLen;
00324                 tBlockSize = BIG_BLOCK_SIZE;
00325         }
00326 
00327         if (tBlockDepotLen == 0) {
00328                 DBG_MSG("The Block Depot length is zero");
00329                 return NULL;
00330         }
00331 
00332         /* Read the Summery Information header */
00333         if (!bReadBuffer(pFile, ulStartBlock,
00334                         aulBlockDepot, tBlockDepotLen, tBlockSize,
00335                         aucHdr, 0, P_HEADER_SZ)) {
00336                 return NULL;
00337         }
00338         NO_DBG_PRINT_BLOCK(aucHdr, P_HEADER_SZ);
00339 
00340         /* Analyse the Summery Information header */
00341         usLittleEndian =  usGetWord(0, aucHdr);
00342         if (usLittleEndian != 0xfffe) {
00343                 DBG_HEX(usLittleEndian);
00344                 DBG_MSG_C(usLittleEndian == 0xfeff, "Big endian");
00345                 return NULL;
00346         }
00347         usEmpty =  usGetWord(2, aucHdr);
00348         if (usEmpty != 0x0000) {
00349                 DBG_DEC(usEmpty);
00350                 return NULL;
00351         }
00352         ulTmp = ulGetLong(4, aucHdr);
00353         DBG_HEX(ulTmp);
00354         usOS = (USHORT)(ulTmp >> 16);
00355         usVersion = (USHORT)(ulTmp & 0xffff);
00356         switch (usOS) {
00357         case 0:
00358                 DBG_MSG("Win16");
00359                 DBG_HEX(usVersion);
00360                 break;
00361         case 1:
00362                 DBG_MSG("MacOS");
00363                 DBG_HEX(usVersion);
00364                 break;
00365         case 2:
00366                 DBG_MSG("Win32");
00367                 DBG_HEX(usVersion);
00368                 break;
00369         default:
00370                 DBG_DEC(usOS);
00371                 DBG_HEX(usVersion);
00372                 break;
00373         }
00374         tSectionCount = (size_t)ulGetLong(24, aucHdr);
00375         DBG_DEC_C(tSectionCount != 1 && tSectionCount != 2, tSectionCount);
00376         if (tSectionCount != 1 && tSectionCount != 2) {
00377                 return NULL;
00378         }
00379 
00380         /* Read the Summery Information Section Lists */
00381         if (!bReadBuffer(pFile, ulStartBlock,
00382                         aulBlockDepot, tBlockDepotLen, tBlockSize,
00383                         aucSecLst, P_HEADER_SZ, P_SECTION_SZ(tSectionCount))) {
00384                 return NULL;
00385         }
00386         NO_DBG_PRINT_BLOCK(aucSecLst, P_SECTION_SZ(tSectionCount));
00387 
00388         ulTmp = ulGetLong(0, aucSecLst);
00389         DBG_HEX(ulTmp);
00390         ulTmp = ulGetLong(4, aucSecLst);
00391         DBG_HEX(ulTmp);
00392         ulTmp = ulGetLong(8, aucSecLst);
00393         DBG_HEX(ulTmp);
00394         ulTmp = ulGetLong(12, aucSecLst);
00395         DBG_HEX(ulTmp);
00396         ulOffset = ulGetLong(16, aucSecLst);
00397         DBG_DEC_C(ulOffset != P_HEADER_SZ + P_SECTIONLIST_SZ &&
00398                 ulOffset != P_HEADER_SZ + 2 * P_SECTIONLIST_SZ,
00399                 ulOffset);
00400         fail(ulOffset != P_HEADER_SZ + P_SECTIONLIST_SZ &&
00401                 ulOffset != P_HEADER_SZ + 2 * P_SECTIONLIST_SZ);
00402         tLength =
00403                 (size_t)ulGetLong(tSectionCount * P_SECTIONLIST_SZ, aucSecLst);
00404         NO_DBG_HEX(tLength);
00405         fail(ulOffset + tLength > ulSize);
00406 
00407         /* Read the Summery Information */
00408         aucBuffer = xmalloc(tLength);
00409         if (!bReadBuffer(pFile, ulStartBlock,
00410                         aulBlockDepot, tBlockDepotLen, tBlockSize,
00411                         aucBuffer, ulOffset, tLength)) {
00412                 aucBuffer = xfree(aucBuffer);
00413                 return NULL;
00414         }
00415         NO_DBG_PRINT_BLOCK(aucBuffer, tLength);
00416         return aucBuffer;
00417 } /* end of pucAnalyseSummaryInfoHeader */
00418 
00419 /*
00420  * vSet0SummaryInfo - set summary information from a Word for DOS file
00421  */
00422 void
00423 vSet0SummaryInfo(FILE *pFile, const UCHAR *aucHeader)
00424 {
00425         UCHAR   *aucBuffer;
00426         ULONG   ulBeginSumdInfo, ulBeginNextBlock;
00427         size_t  tLen;
00428         USHORT  usCodepage, usOffset;
00429 
00430         TRACE_MSG("vSet0SummaryInfo");
00431 
00432         fail(pFile == NULL || aucHeader == NULL);
00433 
00434         /* First check the header */
00435         usCodepage = usGetWord(0x7e, aucHeader);
00436         DBG_DEC(usCodepage);
00437         switch (usCodepage) {
00438         case 850: usLid = 0x0809; break; /* Latin1 -> British English */
00439         case 862: usLid = 0x040d; break; /* Hebrew */
00440         case 866: usLid = 0x0419; break; /* Russian */
00441         case 0:
00442         case 437:
00443         default: usLid = 0x0409; break; /* ASCII -> American English */
00444         }
00445 
00446         /* Second check the summary information block */
00447         ulBeginSumdInfo = 128 * (ULONG)usGetWord(0x1c, aucHeader);
00448         DBG_HEX(ulBeginSumdInfo);
00449         ulBeginNextBlock = 128 * (ULONG)usGetWord(0x6a, aucHeader);
00450         DBG_HEX(ulBeginNextBlock);
00451 
00452         if (ulBeginSumdInfo >= ulBeginNextBlock || ulBeginNextBlock == 0) {
00453                 /* There is no summary information block */
00454                 return;
00455         }
00456         tLen = (size_t)(ulBeginNextBlock - ulBeginSumdInfo);
00457         aucBuffer = xmalloc(tLen);
00458         /* Read the summary information block */
00459         if (!bReadBytes(aucBuffer, tLen, ulBeginSumdInfo, pFile)) {
00460                 return;
00461         }
00462         usOffset = usGetWord(0, aucBuffer);
00463         if (aucBuffer[usOffset] != 0) {
00464                 NO_DBG_MSG(aucBuffer + usOffset);
00465                 szTitle = xstrdup((char *)aucBuffer + usOffset);
00466         }
00467         usOffset = usGetWord(2, aucBuffer);
00468         if (aucBuffer[usOffset] != 0) {
00469                 NO_DBG_MSG(aucBuffer + usOffset);
00470                 szAuthor = xstrdup((char *)aucBuffer + usOffset);
00471         }
00472         usOffset = usGetWord(12, aucBuffer);
00473         if (aucBuffer[usOffset] != 0) {
00474                 NO_DBG_STRN(aucBuffer + usOffset, 8);
00475                 tLastSaveDtm = tConvertDosDate((char *)aucBuffer + usOffset);
00476         }
00477         usOffset = usGetWord(14, aucBuffer);
00478         if (aucBuffer[usOffset] != 0) {
00479                 NO_DBG_STRN(aucBuffer + usOffset, 8);
00480                 tCreateDtm = tConvertDosDate((char *)aucBuffer + usOffset);
00481         }
00482         aucBuffer = xfree(aucBuffer);
00483 } /* end of vSet0SummaryInfo */
00484 
00485 /*
00486  * vSet2SummaryInfo - set summary information from a WinWord 1/2 file
00487  */
00488 void
00489 vSet2SummaryInfo(FILE *pFile, int iWordVersion, const UCHAR *aucHeader)
00490 {
00491         UCHAR   *aucBuffer;
00492         ULONG   ulBeginSumdInfo, ulBeginDocpInfo, ulTmp;
00493         size_t  tSumdInfoLen, tDocpInfoLen, tLen, tCounter, tStart;
00494 
00495         TRACE_MSG("vSet2SummaryInfo");
00496 
00497         fail(pFile == NULL || aucHeader == NULL);
00498         fail(iWordVersion != 1 && iWordVersion != 2);
00499 
00500         /* First check the header */
00501         usLid = usGetWord(0x06, aucHeader); /* Language IDentification */
00502         DBG_HEX(usLid);
00503         if (usLid < 999 && iWordVersion == 1) {
00504                 switch (usLid) {
00505                 case   1: usLid = 0x0409; break;        /* American English */
00506                 case   2: usLid = 0x0c0c; break;        /* Canadian French */
00507                 case  31: usLid = 0x0413; break;        /* Dutch */
00508                 case  33: usLid = 0x040c; break;        /* French */
00509                 case  34: usLid = 0x040a; break;        /* Spanish */
00510                 case  36: usLid = 0x040e; break;        /* Hungarian */
00511                 case  39: usLid = 0x0410; break;        /* Italian */
00512                 case  44: usLid = 0x0809; break;        /* British English */
00513                 case  45: usLid = 0x0406; break;        /* Danish */
00514                 case  46: usLid = 0x041f; break;        /* Swedish */
00515                 case  47: usLid = 0x0414; break;        /* Norwegian */
00516                 case  48: usLid = 0x0415; break;        /* Polish */
00517                 case  49: usLid = 0x0407; break;        /* German */
00518                 case 351: usLid = 0x0816; break;        /* Portuguese */
00519                 case 358: usLid = 0x040b; break;        /* Finnish */
00520                 default:
00521                         DBG_DEC(usLid);
00522                         DBG_FIXME();
00523                         usLid = 0x0409;         /* American English */
00524                         break;
00525                 }
00526         }
00527 
00528         if (iWordVersion != 2) {
00529                 /* Unknown where to find the associated strings */
00530                 return;
00531         }
00532 
00533         /* Second check the associated strings */
00534         ulBeginSumdInfo = ulGetLong(0x118, aucHeader); /* fcSttbfAssoc */
00535         DBG_HEX(ulBeginSumdInfo);
00536         tSumdInfoLen = (size_t)usGetWord(0x11c, aucHeader); /* cbSttbfAssoc */
00537         DBG_DEC(tSumdInfoLen);
00538 
00539         if (tSumdInfoLen == 0) {
00540                 /* There is no summary information */
00541                 return;
00542         }
00543 
00544         aucBuffer = xmalloc(tSumdInfoLen);
00545         if (!bReadBytes(aucBuffer, tSumdInfoLen, ulBeginSumdInfo, pFile)) {
00546                 aucBuffer = xfree(aucBuffer);
00547                 return;
00548         }
00549         NO_DBG_PRINT_BLOCK(aucBuffer, tSumdInfoLen);
00550         tLen = (size_t)ucGetByte(0, aucBuffer);
00551         DBG_DEC_C(tSumdInfoLen != tLen, tSumdInfoLen);
00552         DBG_DEC_C(tSumdInfoLen != tLen, tLen);
00553         tStart = 1;
00554         for (tCounter = 0; tCounter < 17; tCounter++) {
00555                 if (tStart >= tSumdInfoLen) {
00556                         break;
00557                 }
00558                 tLen = (size_t)ucGetByte(tStart, aucBuffer);
00559                 if (tLen != 0) {
00560                         NO_DBG_DEC(tCounter);
00561                         NO_DBG_STRN(aucBuffer + tStart + 1, tLen);
00562                         switch (tCounter) {
00563                         case 3:
00564                                 szTitle = xmalloc(tLen + 1);
00565                                 strncpy(szTitle,
00566                                         (char *)aucBuffer + tStart + 1, tLen);
00567                                 szTitle[tLen] = '\0';
00568                                 break;
00569                         case 4:
00570                                 szSubject = xmalloc(tLen + 1);
00571                                 strncpy(szSubject,
00572                                         (char *)aucBuffer + tStart + 1, tLen);
00573                                 szSubject[tLen] = '\0';
00574                                 break;
00575                         case 7:
00576                                 szAuthor = xmalloc(tLen + 1);
00577                                 strncpy(szAuthor,
00578                                         (char *)aucBuffer + tStart + 1, tLen);
00579                                 szAuthor[tLen] = '\0';
00580                                 break;
00581                         default:
00582                                 break;
00583                         }
00584                 }
00585                 tStart += tLen + 1;
00586         }
00587         aucBuffer = xfree(aucBuffer);
00588 
00589         /* Third check the document properties */
00590         ulBeginDocpInfo = ulGetLong(0x112, aucHeader); /* fcDop */
00591         DBG_HEX(ulBeginDocpInfo);
00592         tDocpInfoLen = (size_t)usGetWord(0x116, aucHeader); /* cbDop */
00593         DBG_DEC(tDocpInfoLen);
00594         if (tDocpInfoLen < 12) {
00595                 return;
00596         }
00597 
00598         aucBuffer = xmalloc(tDocpInfoLen);
00599         if (!bReadBytes(aucBuffer, tDocpInfoLen, ulBeginDocpInfo, pFile)) {
00600                 aucBuffer = xfree(aucBuffer);
00601                 return;
00602         }
00603         ulTmp = ulGetLong(0x14, aucBuffer); /* dttmCreated */
00604         tCreateDtm = tConvertDTTM(ulTmp);
00605         ulTmp = ulGetLong(0x18, aucBuffer); /* dttmRevised */
00606         tLastSaveDtm = tConvertDTTM(ulTmp);
00607         aucBuffer = xfree(aucBuffer);
00608 } /* end of vSet2SummaryInfo */
00609 
00610 /*
00611  * vSetSummaryInfoOLE - set summary information from a Word 6+ file
00612  */
00613 static void
00614 vSetSummaryInfoOLE(FILE *pFile, const pps_info_type *pPPS,
00615         const ULONG *aulBBD, size_t tBBDLen,
00616         const ULONG *aulSBD, size_t tSBDLen)
00617 {
00618         UCHAR   *pucBuffer;
00619 
00620         fail(pFile == NULL || pPPS == NULL);
00621         fail(aulBBD == NULL || aulSBD == NULL);
00622 
00623         /* Summary Information */
00624         pucBuffer = pucAnalyseSummaryInfoHeader(pFile,
00625                 pPPS->tSummaryInfo.ulSB, pPPS->tSummaryInfo.ulSize,
00626                 aulBBD, tBBDLen, aulSBD, tSBDLen);
00627         if (pucBuffer != NULL) {
00628                 vAnalyseSummaryInfo(pucBuffer);
00629                 pucBuffer = xfree(pucBuffer);
00630         }
00631 
00632         /* Document Summary Information */
00633         pucBuffer = pucAnalyseSummaryInfoHeader(pFile,
00634                 pPPS->tDocSummaryInfo.ulSB, pPPS->tDocSummaryInfo.ulSize,
00635                 aulBBD, tBBDLen, aulSBD, tSBDLen);
00636         if (pucBuffer != NULL) {
00637                 vAnalyseDocumentSummaryInfo(pucBuffer);
00638                 pucBuffer = xfree(pucBuffer);
00639         }
00640 } /* end of vSetSummaryInfoOLE */
00641 
00642 /*
00643  * vSet6SummaryInfo - set summary information from a Word 6/7 file
00644  */
00645 void
00646 vSet6SummaryInfo(FILE *pFile, const pps_info_type *pPPS,
00647         const ULONG *aulBBD, size_t tBBDLen,
00648         const ULONG *aulSBD, size_t tSBDLen,
00649         const UCHAR *aucHeader)
00650 {
00651         TRACE_MSG("vSet6SummaryInfo");
00652 
00653         /* Header Information */
00654         usLid = usGetWord(0x06, aucHeader); /* Language IDentification */
00655         DBG_HEX(usLid);
00656 
00657         /* Summery Information */
00658         vSetSummaryInfoOLE(pFile, pPPS, aulBBD, tBBDLen, aulSBD, tSBDLen);
00659 } /* end of vSet6SummaryInfo */
00660 
00661 /*
00662  * vSet8SummaryInfo - set summary information a Word 8/9/10 file
00663  */
00664 void
00665 vSet8SummaryInfo(FILE *pFile, const pps_info_type *pPPS,
00666         const ULONG *aulBBD, size_t tBBDLen,
00667         const ULONG *aulSBD, size_t tSBDLen,
00668         const UCHAR *aucHeader)
00669 {
00670         USHORT  usTmp;
00671 
00672         TRACE_MSG("vSet8SummaryInfo");
00673 
00674         /* Header Information */
00675         usTmp = usGetWord(0x0a, aucHeader);
00676         if (usTmp & BIT(14)) {
00677                 /* Language IDentification Far East */
00678                 usLid = usGetWord(0x3c, aucHeader);
00679         } else {
00680                 /* Language IDentification */
00681                 usLid = usGetWord(0x06, aucHeader);
00682         }
00683         DBG_HEX(usLid);
00684 
00685         /* Summery Information */
00686         vSetSummaryInfoOLE(pFile, pPPS, aulBBD, tBBDLen, aulSBD, tSBDLen);
00687 } /* end of vSet8SummaryInfo */
00688 
00689 /*
00690  * szGetTitle - get the title field
00691  */
00692 const char *
00693 szGetTitle(void)
00694 {
00695         return szTitle;
00696 } /* end of szGetTitle */
00697 
00698 /*
00699  * szGetSubject - get the subject field
00700  */
00701 const char *
00702 szGetSubject(void)
00703 {
00704         return szSubject;
00705 } /* end of szGetSubject */
00706 
00707 /*
00708  * szGetAuthor - get the author field
00709  */
00710 const char *
00711 szGetAuthor(void)
00712 {
00713         return szAuthor;
00714 } /* end of szGetAuthor */
00715 
00716 /*
00717  * szGetLastSaveDtm - get the last save date field
00718  */
00719 const char *
00720 szGetLastSaveDtm(void)
00721 {
00722         static char     szTime[12];
00723         struct tm       *pTime;
00724 
00725         if (tLastSaveDtm == (time_t)-1) {
00726                 return NULL;
00727         }
00728         pTime = localtime(&tLastSaveDtm);
00729         if (pTime == NULL) {
00730                 return NULL;
00731         }
00732         sprintf(szTime, "%04d-%02d-%02d",
00733                 pTime->tm_year + 1900, pTime->tm_mon + 1, pTime->tm_mday);
00734         return szTime;
00735 } /* end of szGetLastSaveDtm */
00736 
00737 /*
00738  * szGetModDate - get the last save date field
00739  */
00740 const char *
00741 szGetModDate(void)
00742 {
00743         static char     szTime[20];
00744         struct tm       *pTime;
00745 
00746         if (tLastSaveDtm == (time_t)-1) {
00747                 return NULL;
00748         }
00749         pTime = localtime(&tLastSaveDtm);
00750         if (pTime == NULL) {
00751                 return NULL;
00752         }
00753         sprintf(szTime, "D:%04d%02d%02d%02d%02d",
00754                 pTime->tm_year + 1900, pTime->tm_mon + 1, pTime->tm_mday,
00755                 pTime->tm_hour, pTime->tm_min);
00756         return szTime;
00757 } /* end of szGetModDate */
00758 
00759 /*
00760  * szGetCreationDate - get the last save date field
00761  */
00762 const char *
00763 szGetCreationDate(void)
00764 {
00765         static char     szTime[20];
00766         struct tm       *pTime;
00767 
00768         if (tCreateDtm == (time_t)-1) {
00769                 return NULL;
00770         }
00771         pTime = localtime(&tCreateDtm);
00772         if (pTime == NULL) {
00773                 return NULL;
00774         }
00775         sprintf(szTime, "D:%04d%02d%02d%02d%02d",
00776                 pTime->tm_year + 1900, pTime->tm_mon + 1, pTime->tm_mday,
00777                 pTime->tm_hour, pTime->tm_min);
00778         return szTime;
00779 } /* end of szGetCreationDate */
00780 
00781 /*
00782  * szGetCompany - get the company field
00783  */
00784 const char *
00785 szGetCompany(void)
00786 {
00787         return szCompany;
00788 } /* end of szGetCompany */
00789 
00790 /*
00791  * szGetLanguage - get de language field
00792  */
00793 const char *
00794 szGetLanguage(void)
00795 {
00796         if (usLid == (USHORT)-1) {
00797                 /* No Language IDentification */
00798                 return NULL;
00799         }
00800         if (usLid < 999) {
00801                 /* This is a Locale, not a Language IDentification */
00802                 DBG_DEC(usLid);
00803                 return NULL;
00804         }
00805 
00806         /* Exceptions to the general rule */
00807         switch (usLid) {
00808         case 0x0404: return "zh_TW"; /* Traditional Chinese */
00809         case 0x0804: return "zh_CN"; /* Simplified Chinese */
00810         case 0x0c04: return "zh_HK"; /* Hong Kong Chinese */
00811         case 0x1004: return "zh_SG"; /* Singapore Chinese */
00812         case 0x0807: return "de_CH"; /* Swiss German */
00813         case 0x0409: return "en_US"; /* American English */
00814         case 0x0809: return "en_GB"; /* British English */
00815         case 0x0c09: return "en_AU"; /* Australian English */
00816         case 0x080a: return "es_MX"; /* Mexican Spanish */
00817         case 0x080c: return "fr_BE"; /* Belgian French */
00818         case 0x0c0c: return "fr_CA"; /* Canadian French */
00819         case 0x100c: return "fr_CH"; /* Swiss French */
00820         case 0x0810: return "it_CH"; /* Swiss Italian */
00821         case 0x0813: return "nl_BE"; /* Belgian Dutch */
00822         case 0x0416: return "pt_BR"; /* Brazilian Portuguese */
00823         case 0x081a:
00824         case 0x0c1a: return "sr";    /* Serbian */
00825         case 0x081d: return "sv_FI"; /* Finland Swedish */
00826         default:
00827                 break;
00828         }
00829 
00830         /* The general rule */
00831         switch (usLid & 0x00ff) {
00832         case 0x01: return "ar"; /* Arabic */
00833         case 0x02: return "bg"; /* Bulgarian */
00834         case 0x03: return "ca"; /* Catalan */
00835         case 0x04: return "zh"; /* Chinese */
00836         case 0x05: return "cs"; /* Czech */
00837         case 0x06: return "da"; /* Danish */
00838         case 0x07: return "de"; /* German */
00839         case 0x08: return "el"; /* Greek */
00840         case 0x09: return "en"; /* English */
00841         case 0x0a: return "es"; /* Spanish */
00842         case 0x0b: return "fi"; /* Finnish */
00843         case 0x0c: return "fr"; /* French */
00844         case 0x0d: return "he"; /* Hebrew */
00845         case 0x0e: return "hu"; /* Hungarian */
00846         case 0x0f: return "is"; /* Icelandic */
00847         case 0x10: return "it"; /* Italian */
00848         case 0x11: return "ja"; /* Japanese */
00849         case 0x12: return "ko"; /* Korean */
00850         case 0x13: return "nl"; /* Dutch */
00851         case 0x14: return "no"; /* Norwegian */
00852         case 0x15: return "pl"; /* Polish */
00853         case 0x16: return "pt"; /* Portuguese */
00854         case 0x17: return "rm"; /* Rhaeto-Romance */
00855         case 0x18: return "ro"; /* Romanian */
00856         case 0x19: return "ru"; /* Russian */
00857         case 0x1a: return "hr"; /* Croatian */
00858         case 0x1b: return "sk"; /* Slovak */
00859         case 0x1c: return "sq"; /* Albanian */
00860         case 0x1d: return "sv"; /* Swedish */
00861         case 0x1e: return "th"; /* Thai */
00862         case 0x1f: return "tr"; /* Turkish */
00863         case 0x20: return "ur"; /* Urdu */
00864         case 0x21: return "id"; /* Indonesian */
00865         case 0x22: return "uk"; /* Ukrainian */
00866         case 0x23: return "be"; /* Belarusian */
00867         case 0x24: return "sl"; /* Slovenian */
00868         case 0x25: return "et"; /* Estonian */
00869         case 0x26: return "lv"; /* Latvian */
00870         case 0x27: return "lt"; /* Lithuanian */
00871         case 0x29: return "fa"; /* Farsi */
00872         case 0x2a: return "vi"; /* Viet Nam */
00873         case 0x2b: return "hy"; /* Armenian */
00874         case 0x2c: return "az"; /* Azeri */
00875         case 0x2d: return "eu"; /* Basque */
00876         case 0x2f: return "mk"; /* Macedonian */
00877         case 0x36: return "af"; /* Afrikaans */
00878         case 0x37: return "ka"; /* Georgian */
00879         case 0x38: return "fo"; /* Faeroese */
00880         case 0x39: return "hi"; /* Hindi */
00881         case 0x3e: return "ms"; /* Malay */
00882         case 0x3f: return "kk"; /* Kazakh */
00883         default:
00884                 DBG_HEX(usLid);
00885                 DBG_FIXME();
00886                 return NULL;
00887         }
00888 } /* end of szGetLanguage */

Generated by  doxygen 1.6.2