examples/PIPS/antiword/src/listlist.c

00001 /*
00002  * listlist.c
00003  * Copyright (C) 2002,2003 A.J. van Os; Released under GPL
00004  *
00005  * Description:
00006  * Build, read and destroy a list of Word list information
00007  *
00008  * Note:
00009  * This list only exists when the Word document is saved by Word 8 or later
00010  */
00011 
00012 #include "antiword.h"
00013 
00014 /*
00015  * Private structure to hide the way the information
00016  * is stored from the rest of the program
00017  */
00018 typedef struct list_desc_tag {
00019         list_block_type         tInfo;
00020         ULONG                   ulListID;
00021         USHORT                  usIstd;
00022         UCHAR                   ucListLevel;
00023         struct list_desc_tag    *pNext;
00024 } list_desc_type;
00025 
00026 typedef struct list_value_tag {
00027         USHORT                  usValue;
00028         USHORT                  usListIndex;
00029         UCHAR                   ucListLevel;
00030         struct list_value_tag   *pNext;
00031 } list_value_type;
00032 
00033 /* Variables needed to describe the LFO list (pllfo) */
00034 static ULONG            *aulLfoList = NULL;
00035 static USHORT           usLfoLen = 0;
00036 /* Variables needed to write the List Information List */
00037 static list_desc_type   *pAnchor = NULL;
00038 static list_desc_type   *pBlockLast = NULL;
00039 /* Variable needed for numbering new lists */
00040 static list_value_type  *pValues = NULL;
00041 /* Variables needed for numbering old lists */
00042 static int      iOldListSeqNumber = 0;
00043 static USHORT   usOldListValue = 0;
00044 
00045 
00046 /*
00047  * vDestroyListInfoList - destroy the List Information List
00048  */
00049 void
00050 vDestroyListInfoList(void)
00051 {
00052         list_desc_type  *pCurr, *pNext;
00053         list_value_type *pValueCurr, *pValueNext;
00054 
00055         DBG_MSG("vDestroyListInfoList");
00056 
00057         /* Free the LFO list */
00058         usLfoLen = 0;
00059         aulLfoList = xfree(aulLfoList);
00060 
00061         /* Free the List Information List */
00062         pCurr = pAnchor;
00063         while (pCurr != NULL) {
00064                 pNext = pCurr->pNext;
00065                 pCurr = xfree(pCurr);
00066                 pCurr = pNext;
00067         }
00068         pAnchor = NULL;
00069         /* Reset all control variables */
00070         pBlockLast = NULL;
00071 
00072         /* Free the values list */
00073         pValueCurr = pValues;
00074         while (pValueCurr != NULL) {
00075                 pValueNext = pValueCurr->pNext;
00076                 pValueCurr = xfree(pValueCurr);
00077                 pValueCurr = pValueNext;
00078         }
00079         pValues = NULL;
00080         /* Reset the values for the old lists */
00081         iOldListSeqNumber = 0;
00082         usOldListValue = 0;
00083 } /* end of vDestroyListInfoList */
00084 
00085 /*
00086  * vBuildLfoList - build the LFO list (pllfo)
00087  */
00088 void
00089 vBuildLfoList(const UCHAR *aucBuffer, size_t tBufLen)
00090 {
00091         size_t  tRecords;
00092         int     iIndex;
00093 
00094         fail(aucBuffer == NULL);
00095 
00096         if (tBufLen < 4) {
00097                 return;
00098         }
00099         tRecords = (size_t)ulGetLong(0, aucBuffer);
00100         NO_DBG_DEC(tRecords);
00101         if (4 + 16 * tRecords > tBufLen || tRecords >= 0x7fff) {
00102                 /* Just a sanity check */
00103                 DBG_DEC(tRecords);
00104                 DBG_DEC(4 + 16 * tRecords);
00105                 DBG_DEC(tBufLen);
00106                 return;
00107         }
00108         aulLfoList = xcalloc(tRecords, sizeof(ULONG));
00109         for (iIndex = 0; iIndex < (int)tRecords; iIndex++) {
00110                 aulLfoList[iIndex] = ulGetLong(4 + 16 * iIndex, aucBuffer);
00111                 NO_DBG_HEX(aulLfoList[iIndex]);
00112         }
00113         usLfoLen = (USHORT)tRecords;
00114 } /* end of vBuildLfoList */
00115 
00116 /*
00117  * vAdd2ListInfoList - add an element to the List Information list
00118  */
00119 void
00120 vAdd2ListInfoList(ULONG ulListID, USHORT usIstd, UCHAR ucListLevel,
00121         const list_block_type *pListBlock)
00122 {
00123         list_desc_type  *pListMember;
00124 
00125         fail(pListBlock == NULL);
00126 
00127         NO_DBG_HEX(ulListID);
00128         NO_DBG_DEC(usIstd);
00129         NO_DBG_DEC(ucListLevel);
00130         NO_DBG_DEC(pListBlock->ulStartAt);
00131         NO_DBG_DEC(pListBlock->bNoRestart);
00132         NO_DBG_DEC(pListBlock->sLeftIndent);
00133         NO_DBG_HEX(pListBlock->ucNFC);
00134         NO_DBG_HEX(pListBlock->usListChar);
00135 
00136         /* Create list member */
00137         pListMember = xmalloc(sizeof(list_desc_type));
00138         /* Fill the list member */
00139         pListMember->tInfo = *pListBlock;
00140         pListMember->ulListID = ulListID;
00141         pListMember->usIstd = usIstd;
00142         pListMember->ucListLevel = ucListLevel;
00143         pListMember->pNext = NULL;
00144         /* Correct the values where needed */
00145         if (pListMember->tInfo.ulStartAt > 0xffff) {
00146                 DBG_DEC(pListMember->tInfo.ulStartAt);
00147                 pListMember->tInfo.ulStartAt = 1;
00148         }
00149         /* Add the new member to the list */
00150         if (pAnchor == NULL) {
00151                 pAnchor = pListMember;
00152         } else {
00153                 fail(pBlockLast == NULL);
00154                 pBlockLast->pNext = pListMember;
00155         }
00156         pBlockLast = pListMember;
00157 } /* end of vAdd2ListInfoList */
00158 
00159 /*
00160  * Get a matching record from the List Information List
00161  *
00162  * Returns NULL if no matching records is found
00163  */
00164 const list_block_type *
00165 pGetListInfo(USHORT usListIndex, UCHAR ucListLevel)
00166 {
00167         list_desc_type  *pCurr;
00168         list_block_type *pNearMatch;
00169         ULONG   ulListID;
00170 
00171         if (usListIndex == 0) {
00172                 return NULL;
00173         }
00174         if (usListIndex - 1 >= usLfoLen || ucListLevel > 8) {
00175                 DBG_DEC(usListIndex);
00176                 DBG_DEC(ucListLevel);
00177                 return NULL;
00178         }
00179         fail(aulLfoList == NULL);
00180         ulListID = aulLfoList[usListIndex - 1];
00181         NO_DBG_HEX(ulListID);
00182 
00183         pNearMatch = NULL;
00184         for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
00185                 if (pCurr->ulListID != ulListID) {
00186                         /* No match */
00187                         continue;
00188                 }
00189                 if (pCurr->ucListLevel == ucListLevel) {
00190                         /* Exact match */
00191                         return &pCurr->tInfo;
00192                 }
00193                 if (pCurr->ucListLevel == 0) {
00194                         /* Near match */
00195                         pNearMatch = &pCurr->tInfo;
00196                 }
00197         }
00198         /* No exact match, use a near match if any */
00199         return pNearMatch;
00200 } /* end of pGetListInfo */
00201 
00202 /*
00203  * Get a matching record from the List Information List
00204  *
00205  * Returns NULL if no matching records is found
00206  */
00207 const list_block_type *
00208 pGetListInfoByIstd(USHORT usIstd)
00209 {
00210         list_desc_type  *pCurr;
00211 
00212         if (usIstd == ISTD_INVALID || usIstd == STI_NIL || usIstd == STI_USER) {
00213                 return NULL;
00214         }
00215 
00216         for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
00217                 if (pCurr->usIstd == usIstd) {
00218                         return &pCurr->tInfo;
00219                 }
00220         }
00221         return NULL;
00222 } /* end of pGetListInfoByIstd */
00223 
00224 /*
00225  * vRestartListValues - reset the less significant list levels
00226  */
00227 static void
00228 vRestartListValues(USHORT usListIndex, UCHAR ucListLevel)
00229 {
00230         list_value_type *pPrev, *pCurr, *pNext;
00231         int             iCounter;
00232 
00233         iCounter = 0;
00234         pPrev = NULL;
00235         pCurr = pValues;
00236 
00237         while (pCurr != NULL) {
00238                 if (pCurr->usListIndex != usListIndex ||
00239                     pCurr->ucListLevel <= ucListLevel) {
00240                         pPrev = pCurr;
00241                         pCurr = pCurr->pNext;
00242                         continue;
00243                 }
00244                 /* Reset the level by deleting the record */
00245                 pNext = pCurr->pNext;
00246                 if (pPrev == NULL) {
00247                         pValues = pNext;
00248                 } else {
00249                         pPrev->pNext = pNext;
00250                 }
00251                 DBG_DEC(pCurr->usListIndex);
00252                 DBG_DEC(pCurr->ucListLevel);
00253                 pCurr = xfree(pCurr);
00254                 pCurr = pNext;
00255                 iCounter++;
00256         }
00257         DBG_DEC_C(iCounter > 0, iCounter);
00258 } /* end of vRestartListValues */
00259 
00260 /*
00261  * usGetListValue - Get the current value of the given list
00262  *
00263  * Returns the value of the given list
00264  */
00265 USHORT
00266 usGetListValue(int iListSeqNumber, int iWordVersion,
00267         const style_block_type *pStyle)
00268 {
00269         list_value_type *pCurr;
00270         USHORT          usValue;
00271 
00272         fail(iListSeqNumber < 0);
00273         fail(iListSeqNumber < iOldListSeqNumber);
00274         fail(iWordVersion < 0);
00275         fail(pStyle == NULL);
00276 
00277         if (iListSeqNumber <= 0) {
00278                 return 0;
00279         }
00280 
00281         if (iWordVersion < 8) {
00282                 /* Old style list */
00283                 if (iListSeqNumber == iOldListSeqNumber ||
00284                     (iListSeqNumber == iOldListSeqNumber + 1 &&
00285                      eGetNumType(pStyle->ucNumLevel) == level_type_sequence)) {
00286                         if (!pStyle->bNumPause) {
00287                                 usOldListValue++;
00288                         }
00289                 } else {
00290                         usOldListValue = pStyle->usStartAt;
00291                 }
00292                 iOldListSeqNumber = iListSeqNumber;
00293                 return usOldListValue;
00294         }
00295 
00296         /* New style list */
00297         if (pStyle->usListIndex == 0 ||
00298             pStyle->usListIndex - 1 >= usLfoLen ||
00299             pStyle->ucListLevel > 8) {
00300                 /* Out of range; no need to search */
00301                 return 0;
00302         }
00303 
00304         for (pCurr = pValues; pCurr != NULL; pCurr = pCurr->pNext) {
00305                 if (pCurr->usListIndex == pStyle->usListIndex &&
00306                     pCurr->ucListLevel == pStyle->ucListLevel) {
00307                         /* Record found; increment and return the value */
00308                         pCurr->usValue++;
00309                         usValue = pCurr->usValue;
00310                         if (!pStyle->bNoRestart) {
00311                                 vRestartListValues(pStyle->usListIndex,
00312                                                 pStyle->ucListLevel);
00313                         }
00314                         return usValue;
00315                 }
00316         }
00317 
00318         /* Record not found; create it and add it to the front of the list */
00319         pCurr = xmalloc(sizeof(list_value_type));
00320         pCurr->usValue = pStyle->usStartAt;
00321         pCurr->usListIndex = pStyle->usListIndex;
00322         pCurr->ucListLevel = pStyle->ucListLevel;
00323         pCurr->pNext = pValues;
00324         pValues = pCurr;
00325         usValue = pCurr->usValue;
00326         if (!pStyle->bNoRestart) {
00327                 vRestartListValues(pStyle->usListIndex, pStyle->ucListLevel);
00328         }
00329         return usValue;
00330 } /* end of usGetListValue */

Generated by  doxygen 1.6.2