examples/PIPS/antiword/src/blocklist.c

00001 /*
00002  * blocklist.c
00003  * Copyright (C) 1998-2005 A.J. van Os; Released under GNU GPL
00004  *
00005  * Description:
00006  * Build, read and destroy the lists of Word "text" blocks
00007  */
00008 
00009 #include <stdlib.h>
00010 #include "antiword.h"
00011 
00012 
00013 /*
00014  * Private structure to hide the way the information
00015  * is stored from the rest of the program
00016  */
00017 typedef struct list_mem_tag {
00018         text_block_type         tInfo;
00019         struct list_mem_tag     *pNext;
00020 } list_mem_type;
00021 
00022 typedef struct readinfo_tag {
00023         list_mem_type           *pBlockCurrent;
00024         ULONG                   ulBlockOffset;
00025         size_t                  tByteNext;
00026         UCHAR                   aucBlock[BIG_BLOCK_SIZE];
00027 } readinfo_type;
00028 
00029 /* Variables to describe the start of the block lists */
00030 static list_mem_type    *pTextAnchor = NULL;
00031 static list_mem_type    *pFootnoteAnchor = NULL;
00032 static list_mem_type    *pHdrFtrAnchor = NULL;
00033 static list_mem_type    *pMacroAnchor = NULL;
00034 static list_mem_type    *pAnnotationAnchor = NULL;
00035 static list_mem_type    *pEndnoteAnchor = NULL;
00036 static list_mem_type    *pTextBoxAnchor = NULL;
00037 static list_mem_type    *pHdrTextBoxAnchor = NULL;
00038 /* Variable needed to build the block list */
00039 static list_mem_type    *pBlockLast = NULL;
00040 /* Variable needed to read the block lists */
00041 static readinfo_type    tOthers = { NULL, 0, 0, };
00042 static readinfo_type    tHdrFtr = { NULL, 0, 0, };
00043 static readinfo_type    tFootnote = { NULL, 0, 0, };
00044 
00045 
00046 /*
00047  * pFreeOneList - free a text block list
00048  *
00049  * Will always return NULL
00050  */
00051 static list_mem_type *
00052 pFreeOneList(list_mem_type *pAnchor)
00053 {
00054         list_mem_type   *pCurr, *pNext;
00055 
00056         pCurr = pAnchor;
00057         while (pCurr != NULL) {
00058                 pNext = pCurr->pNext;
00059                 pCurr = xfree(pCurr);
00060                 pCurr = pNext;
00061         }
00062         return NULL;
00063 } /* end of pFreeOneList */
00064 
00065 /*
00066  * vDestroyTextBlockList - destroy the text block lists
00067  */
00068 void
00069 vDestroyTextBlockList(void)
00070 {
00071         DBG_MSG("vDestroyTextBlockList");
00072 
00073         /* Free the lists one by one */
00074         pTextAnchor = pFreeOneList(pTextAnchor);
00075         pFootnoteAnchor = pFreeOneList(pFootnoteAnchor);
00076         pHdrFtrAnchor = pFreeOneList(pHdrFtrAnchor);
00077         pMacroAnchor = pFreeOneList(pMacroAnchor);
00078         pAnnotationAnchor = pFreeOneList(pAnnotationAnchor);
00079         pEndnoteAnchor = pFreeOneList(pEndnoteAnchor);
00080         pTextBoxAnchor = pFreeOneList(pTextBoxAnchor);
00081         pHdrTextBoxAnchor = pFreeOneList(pHdrTextBoxAnchor);
00082         /* Reset all the controle variables */
00083         pBlockLast = NULL;
00084         tOthers.pBlockCurrent = NULL;
00085         tHdrFtr.pBlockCurrent = NULL;
00086         tFootnote.pBlockCurrent = NULL;
00087 } /* end of vDestroyTextBlockList */
00088 
00089 /*
00090  * bAdd2TextBlockList - add an element to the text block list
00091  *
00092  * returns: TRUE when successful, otherwise FALSE
00093  */
00094 BOOL
00095 bAdd2TextBlockList(const text_block_type *pTextBlock)
00096 {
00097         list_mem_type   *pListMember;
00098 
00099         fail(pTextBlock == NULL);
00100         fail(pTextBlock->ulFileOffset == FC_INVALID);
00101         fail(pTextBlock->ulCharPos == CP_INVALID);
00102         fail(pTextBlock->ulLength == 0);
00103         fail(pTextBlock->bUsesUnicode && odd(pTextBlock->ulLength));
00104 
00105         NO_DBG_MSG("bAdd2TextBlockList");
00106         NO_DBG_HEX(pTextBlock->ulFileOffset);
00107         NO_DBG_HEX(pTextBlock->ulCharPos);
00108         NO_DBG_HEX(pTextBlock->ulLength);
00109         NO_DBG_DEC(pTextBlock->bUsesUnicode);
00110         NO_DBG_DEC(pTextBlock->usPropMod);
00111 
00112         if (pTextBlock->ulFileOffset == FC_INVALID ||
00113             pTextBlock->ulCharPos == CP_INVALID ||
00114             pTextBlock->ulLength == 0 ||
00115             (pTextBlock->bUsesUnicode && odd(pTextBlock->ulLength))) {
00116                 werr(0, "Software (textblock) error");
00117                 return FALSE;
00118         }
00119         /*
00120          * Check for continuous blocks of the same character size and
00121          * the same properties modifier
00122          */
00123         if (pBlockLast != NULL &&
00124             pBlockLast->tInfo.ulFileOffset +
00125              pBlockLast->tInfo.ulLength == pTextBlock->ulFileOffset &&
00126             pBlockLast->tInfo.ulCharPos +
00127              pBlockLast->tInfo.ulLength == pTextBlock->ulCharPos &&
00128             pBlockLast->tInfo.bUsesUnicode == pTextBlock->bUsesUnicode &&
00129             pBlockLast->tInfo.usPropMod == pTextBlock->usPropMod) {
00130                 /* These are continous blocks */
00131                 pBlockLast->tInfo.ulLength += pTextBlock->ulLength;
00132                 return TRUE;
00133         }
00134         /* Make a new block */
00135         pListMember = xmalloc(sizeof(list_mem_type));
00136         /* Add the block to the list */
00137         pListMember->tInfo = *pTextBlock;
00138         pListMember->pNext = NULL;
00139         if (pTextAnchor == NULL) {
00140                 pTextAnchor = pListMember;
00141         } else {
00142                 fail(pBlockLast == NULL);
00143                 pBlockLast->pNext = pListMember;
00144         }
00145         pBlockLast = pListMember;
00146         return TRUE;
00147 } /* end of bAdd2TextBlockList */
00148 
00149 /*
00150  * vSpitList - Split the list in two
00151  */
00152 static void
00153 vSpitList(list_mem_type **ppAnchorCurr, list_mem_type **ppAnchorNext,
00154         ULONG ulListLen)
00155 {
00156         list_mem_type   *pCurr;
00157         long            lCharsToGo, lBytesTooFar;
00158 
00159         fail(ppAnchorCurr == NULL);
00160         fail(ppAnchorNext == NULL);
00161         fail(ulListLen > (ULONG)LONG_MAX);
00162 
00163         pCurr = NULL;
00164         lCharsToGo = (long)ulListLen;
00165         lBytesTooFar = -1;
00166         if (ulListLen != 0) {
00167                 DBG_DEC(ulListLen);
00168                 for (pCurr = *ppAnchorCurr;
00169                      pCurr != NULL;
00170                      pCurr = pCurr->pNext) {
00171                         NO_DBG_DEC(pCurr->tInfo.ulLength);
00172                         fail(pCurr->tInfo.ulLength == 0);
00173                         fail(pCurr->tInfo.ulLength > (ULONG)LONG_MAX);
00174                         if (pCurr->tInfo.bUsesUnicode) {
00175                                 fail(odd(pCurr->tInfo.ulLength));
00176                                 lCharsToGo -= (long)(pCurr->tInfo.ulLength / 2);
00177                                 if (lCharsToGo < 0) {
00178                                         lBytesTooFar = -2 * lCharsToGo;
00179                                 }
00180                         } else {
00181                                 lCharsToGo -= (long)pCurr->tInfo.ulLength;
00182                                 if (lCharsToGo < 0) {
00183                                         lBytesTooFar = -lCharsToGo;
00184                                 }
00185                         }
00186                         if (lCharsToGo <= 0) {
00187                                 break;
00188                         }
00189                 }
00190         }
00191 /* Split the list */
00192         if (ulListLen == 0) {
00193                 /* Current blocklist is empty */
00194                 *ppAnchorNext = *ppAnchorCurr;
00195                 *ppAnchorCurr = NULL;
00196         } else if (pCurr == NULL) {
00197                 /* No blocks for the next list */
00198                 *ppAnchorNext = NULL;
00199         } else if (lCharsToGo == 0) {
00200                 /* Move the integral number of blocks to the next list */
00201                 *ppAnchorNext = pCurr->pNext;
00202                 pCurr->pNext = NULL;
00203         } else {
00204                 /* Split the part current block list, part next block list */
00205                 DBG_DEC(lBytesTooFar);
00206                 fail(lBytesTooFar <= 0);
00207                 *ppAnchorNext = xmalloc(sizeof(list_mem_type));
00208                 DBG_HEX(pCurr->tInfo.ulFileOffset);
00209                 (*ppAnchorNext)->tInfo.ulFileOffset =
00210                                 pCurr->tInfo.ulFileOffset +
00211                                 pCurr->tInfo.ulLength -
00212                                 lBytesTooFar;
00213                 DBG_HEX((*ppAnchorNext)->tInfo.ulFileOffset);
00214                 DBG_HEX(pCurr->tInfo.ulCharPos);
00215                 (*ppAnchorNext)->tInfo.ulCharPos =
00216                                 pCurr->tInfo.ulCharPos +
00217                                 pCurr->tInfo.ulLength -
00218                                 lBytesTooFar;
00219                 DBG_HEX((*ppAnchorNext)->tInfo.ulCharPos);
00220                 (*ppAnchorNext)->tInfo.ulLength = (ULONG)lBytesTooFar;
00221                 pCurr->tInfo.ulLength -= (ULONG)lBytesTooFar;
00222                 (*ppAnchorNext)->tInfo.bUsesUnicode = pCurr->tInfo.bUsesUnicode;
00223                 (*ppAnchorNext)->tInfo.usPropMod = pCurr->tInfo.usPropMod;
00224                 /* Move the integral number of blocks to the next list */
00225                 (*ppAnchorNext)->pNext = pCurr->pNext;
00226                 pCurr->pNext = NULL;
00227         }
00228 } /* end of vSpitList */
00229 
00230 #if defined(DEBUG) || defined(__riscos)
00231 /*
00232  * ulComputeListLength - compute the length of a list
00233  *
00234  * returns the list length in characters
00235  */
00236 static ULONG
00237 ulComputeListLength(const list_mem_type *pAnchor)
00238 {
00239         const list_mem_type     *pCurr;
00240         ULONG           ulTotal;
00241 
00242         ulTotal = 0;
00243         for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
00244                 fail(pCurr->tInfo.ulLength == 0);
00245                 if (pCurr->tInfo.bUsesUnicode) {
00246                         fail(odd(pCurr->tInfo.ulLength));
00247                         ulTotal += pCurr->tInfo.ulLength / 2;
00248                 } else {
00249                         ulTotal += pCurr->tInfo.ulLength;
00250                 }
00251         }
00252         return ulTotal;
00253 } /* end of ulComputeListLength */
00254 #endif /* DEBUG || __riscos */
00255 
00256 #if defined(DEBUG)
00257 /*
00258  * vCheckList - check the number of bytes in a block list
00259  */
00260 static void
00261 vCheckList(const list_mem_type *pAnchor, ULONG ulListLen, char *szMsg)
00262 {
00263         ULONG           ulTotal;
00264 
00265         ulTotal = ulComputeListLength(pAnchor);
00266         DBG_DEC(ulTotal);
00267         if (ulTotal != ulListLen) {
00268                 DBG_DEC(ulListLen);
00269                 werr(1, szMsg);
00270         }
00271 } /* end of vCheckList */
00272 #endif /* DEBUG */
00273 
00274 /*
00275  * bIsEmptyBox - check to see if the given text box is empty
00276  */
00277 static BOOL
00278 bIsEmptyBox(FILE *pFile, const list_mem_type *pAnchor)
00279 {
00280         const list_mem_type     *pCurr;
00281         size_t  tIndex, tSize;
00282         UCHAR   *aucBuffer;
00283         char    cChar;
00284 
00285         fail(pFile == NULL);
00286 
00287         if (pAnchor == NULL) {
00288                 return TRUE;
00289         }
00290 
00291         aucBuffer = NULL;
00292         for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
00293                 fail(pCurr->tInfo.ulLength == 0);
00294                 tSize = (size_t)pCurr->tInfo.ulLength;
00295 #if defined(__dos) && !defined(__DJGPP__)
00296                 if (pCurr->tInfo.ulLength > 0xffffUL) {
00297                         tSize = 0xffff;
00298                 }
00299 #endif /* __dos && !__DJGPP__ */
00300                 fail(aucBuffer != NULL);
00301                 aucBuffer = xmalloc(tSize);
00302                 if (!bReadBytes(aucBuffer, tSize,
00303                                 pCurr->tInfo.ulFileOffset, pFile)) {
00304                         aucBuffer = xfree(aucBuffer);
00305                         return FALSE;
00306                 }
00307                 for (tIndex = 0; tIndex < tSize; tIndex++) {
00308                         cChar = (char)aucBuffer[tIndex];
00309                         switch (cChar) {
00310                         case '\0': case '\r': case '\n':
00311                         case '\f': case '\t': case '\v':
00312                         case ' ':
00313                                 break;
00314                         default:
00315                                 aucBuffer = xfree(aucBuffer);
00316                                 return FALSE;
00317                         }
00318                 }
00319                 aucBuffer = xfree(aucBuffer);
00320         }
00321         fail(aucBuffer != NULL);
00322         return TRUE;
00323 } /* end of bIsEmptyBox */
00324 
00325 /*
00326  * vSplitBlockList - split the block list in the various parts
00327  *
00328  * Split the blocklist in a Text block list, a Footnote block list, a
00329  * HeaderFooter block list, a Macro block list, an Annotation block list,
00330  * an Endnote block list, a TextBox list and a HeaderTextBox list.
00331  *
00332  * NOTE:
00333  * The various ul*Len input parameters are given in characters, but the
00334  * length of the blocks are in bytes.
00335  */
00336 void
00337 vSplitBlockList(FILE *pFile, ULONG ulTextLen, ULONG ulFootnoteLen,
00338         ULONG ulHdrFtrLen, ULONG ulMacroLen, ULONG ulAnnotationLen,
00339         ULONG ulEndnoteLen, ULONG ulTextBoxLen, ULONG ulHdrTextBoxLen,
00340         BOOL bMustExtend)
00341 {
00342         list_mem_type   *apAnchors[8];
00343         list_mem_type   *pGarbageAnchor, *pCurr;
00344         size_t          tIndex;
00345 
00346         DBG_MSG("vSplitBlockList");
00347 
00348         pGarbageAnchor = NULL;
00349 
00350         DBG_MSG_C(ulTextLen != 0, "Text block list");
00351         vSpitList(&pTextAnchor, &pFootnoteAnchor, ulTextLen);
00352         DBG_MSG_C(ulFootnoteLen != 0, "Footnote block list");
00353         vSpitList(&pFootnoteAnchor, &pHdrFtrAnchor, ulFootnoteLen);
00354         DBG_MSG_C(ulHdrFtrLen != 0, "Header/Footer block list");
00355         vSpitList(&pHdrFtrAnchor, &pMacroAnchor, ulHdrFtrLen);
00356         DBG_MSG_C(ulMacroLen != 0, "Macro block list");
00357         vSpitList(&pMacroAnchor, &pAnnotationAnchor, ulMacroLen);
00358         DBG_MSG_C(ulAnnotationLen != 0, "Annotation block list");
00359         vSpitList(&pAnnotationAnchor, &pEndnoteAnchor, ulAnnotationLen);
00360         DBG_MSG_C(ulEndnoteLen != 0, "Endnote block list");
00361         vSpitList(&pEndnoteAnchor, &pTextBoxAnchor, ulEndnoteLen);
00362         DBG_MSG_C(ulTextBoxLen != 0, "Textbox block list");
00363         vSpitList(&pTextBoxAnchor, &pHdrTextBoxAnchor, ulTextBoxLen);
00364         DBG_MSG_C(ulHdrTextBoxLen != 0, "HeaderTextbox block list");
00365         vSpitList(&pHdrTextBoxAnchor, &pGarbageAnchor, ulHdrTextBoxLen);
00366 
00367         /* Free the garbage block list, this should not be needed */
00368         DBG_DEC_C(pGarbageAnchor != NULL, pGarbageAnchor->tInfo.ulLength);
00369         pGarbageAnchor = pFreeOneList(pGarbageAnchor);
00370 
00371 #if defined(DEBUG)
00372         vCheckList(pTextAnchor, ulTextLen, "Software error (Text)");
00373         vCheckList(pFootnoteAnchor, ulFootnoteLen, "Software error (Footnote)");
00374         vCheckList(pHdrFtrAnchor, ulHdrFtrLen, "Software error (Hdr/Ftr)");
00375         vCheckList(pMacroAnchor, ulMacroLen, "Software error (Macro)");
00376         vCheckList(pAnnotationAnchor, ulAnnotationLen,
00377                                                 "Software error (Annotation)");
00378         vCheckList(pEndnoteAnchor, ulEndnoteLen, "Software error (Endnote)");
00379         vCheckList(pTextBoxAnchor, ulTextBoxLen, "Software error (TextBox)");
00380         vCheckList(pHdrTextBoxAnchor, ulHdrTextBoxLen,
00381                                                 "Software error (HdrTextBox)");
00382 #endif /* DEBUG */
00383 
00384         /* Remove the list if the text box is empty */
00385         if (bIsEmptyBox(pFile, pTextBoxAnchor)) {
00386                 pTextBoxAnchor = pFreeOneList(pTextBoxAnchor);
00387         }
00388         if (bIsEmptyBox(pFile, pHdrTextBoxAnchor)) {
00389                 pHdrTextBoxAnchor = pFreeOneList(pHdrTextBoxAnchor);
00390         }
00391 
00392         if (!bMustExtend) {
00393                 return;
00394         }
00395         /*
00396          * All blocks (except the last one) must have a length that
00397          * is a multiple of the Big Block Size
00398          */
00399 
00400         apAnchors[0] = pTextAnchor;
00401         apAnchors[1] = pFootnoteAnchor;
00402         apAnchors[2] = pHdrFtrAnchor;
00403         apAnchors[3] = pMacroAnchor;
00404         apAnchors[4] = pAnnotationAnchor;
00405         apAnchors[5] = pEndnoteAnchor;
00406         apAnchors[6] = pTextBoxAnchor;
00407         apAnchors[7] = pHdrTextBoxAnchor;
00408 
00409         for (tIndex = 0; tIndex < elementsof(apAnchors); tIndex++) {
00410                 for (pCurr = apAnchors[tIndex];
00411                      pCurr != NULL;
00412                      pCurr = pCurr->pNext) {
00413                         if (pCurr->pNext != NULL &&
00414                             pCurr->tInfo.ulLength % BIG_BLOCK_SIZE != 0) {
00415                                 DBG_DEC(tIndex);
00416                                 DBG_HEX(pCurr->tInfo.ulFileOffset);
00417                                 DBG_HEX(pCurr->tInfo.ulCharPos);
00418                                 DBG_DEC(pCurr->tInfo.ulLength);
00419                                 pCurr->tInfo.ulLength /= BIG_BLOCK_SIZE;
00420                                 pCurr->tInfo.ulLength++;
00421                                 pCurr->tInfo.ulLength *= BIG_BLOCK_SIZE;
00422                                 DBG_DEC(pCurr->tInfo.ulLength);
00423                         }
00424                 }
00425         }
00426 } /* end of vSplitBlockList */
00427 
00428 #if defined(__riscos)
00429 /*
00430  * ulGetDocumentLength - get the total character length of the printable lists
00431  *
00432  * returns: The total number of characters
00433  */
00434 ULONG
00435 ulGetDocumentLength(void)
00436 {
00437         long            ulTotal;
00438 
00439         DBG_MSG("ulGetDocumentLength");
00440 
00441         ulTotal = ulComputeListLength(pTextAnchor);
00442         ulTotal += ulComputeListLength(pFootnoteAnchor);
00443         ulTotal += ulComputeListLength(pEndnoteAnchor);
00444         ulTotal += ulComputeListLength(pTextBoxAnchor);
00445         ulTotal += ulComputeListLength(pHdrTextBoxAnchor);
00446         DBG_DEC(ulTotal);
00447         return ulTotal;
00448 } /* end of ulGetDocumentLength */
00449 #endif /* __riscos */
00450 
00451 #if 0
00452 /*
00453  * bExistsHdrFtr - are there headers and/or footers?
00454  */
00455 BOOL
00456 bExistsHdrFtr(void)
00457 {
00458         return pHdrFtrAnchor != NULL &&
00459                 pHdrFtrAnchor->tInfo.ulLength != 0;
00460 } /* end of bExistsHdrFtr */
00461 #endif
00462 
00463 /*
00464  * bExistsTextBox - is there a text box?
00465  */
00466 BOOL
00467 bExistsTextBox(void)
00468 {
00469         return pTextBoxAnchor != NULL &&
00470                 pTextBoxAnchor->tInfo.ulLength != 0;
00471 } /* end of bExistsTextBox */
00472 
00473 /*
00474  * bExistsHdrTextBox - is there a header text box?
00475  */
00476 BOOL
00477 bExistsHdrTextBox(void)
00478 {
00479         return pHdrTextBoxAnchor != NULL &&
00480                 pHdrTextBoxAnchor->tInfo.ulLength != 0;
00481 } /* end of bExistsHdrTextBox */
00482 
00483 /*
00484  * usGetNextByte - get the next byte from the specified block list
00485  */
00486 static USHORT
00487 usGetNextByte(FILE *pFile, readinfo_type *pInfoCurrent, list_mem_type *pAnchor,
00488         ULONG *pulFileOffset, ULONG *pulCharPos, USHORT *pusPropMod)
00489 {
00490         ULONG   ulReadOff;
00491         size_t  tReadLen;
00492 
00493         fail(pInfoCurrent == NULL);
00494 
00495         if (pInfoCurrent->pBlockCurrent == NULL ||
00496             pInfoCurrent->tByteNext >= sizeof(pInfoCurrent->aucBlock) ||
00497             pInfoCurrent->ulBlockOffset + pInfoCurrent->tByteNext >=
00498                                 pInfoCurrent->pBlockCurrent->tInfo.ulLength) {
00499                 if (pInfoCurrent->pBlockCurrent == NULL) {
00500                         /* First block, first part */
00501                         pInfoCurrent->pBlockCurrent = pAnchor;
00502                         pInfoCurrent->ulBlockOffset = 0;
00503                 } else if (pInfoCurrent->ulBlockOffset +
00504                                 sizeof(pInfoCurrent->aucBlock) <
00505                                 pInfoCurrent->pBlockCurrent->tInfo.ulLength) {
00506                         /* Same block, next part */
00507                         pInfoCurrent->ulBlockOffset +=
00508                                         sizeof(pInfoCurrent->aucBlock);
00509                 } else {
00510                         /* Next block, first part */
00511                         pInfoCurrent->pBlockCurrent =
00512                                         pInfoCurrent->pBlockCurrent->pNext;
00513                         pInfoCurrent->ulBlockOffset = 0;
00514                 }
00515                 if (pInfoCurrent->pBlockCurrent == NULL) {
00516                         /* Past the last part of the last block */
00517                         return (USHORT)EOF;
00518                 }
00519                 tReadLen = (size_t)
00520                         (pInfoCurrent->pBlockCurrent->tInfo.ulLength -
00521                          pInfoCurrent->ulBlockOffset);
00522                 if (tReadLen > sizeof(pInfoCurrent->aucBlock)) {
00523                         tReadLen = sizeof(pInfoCurrent->aucBlock);
00524                 }
00525                 ulReadOff = pInfoCurrent->pBlockCurrent->tInfo.ulFileOffset +
00526                                 pInfoCurrent->ulBlockOffset;
00527                 if (!bReadBytes(pInfoCurrent->aucBlock,
00528                                                 tReadLen, ulReadOff, pFile)) {
00529                         /* Don't read from this list any longer */
00530                         pInfoCurrent->pBlockCurrent = NULL;
00531                         return (USHORT)EOF;
00532                 }
00533                 pInfoCurrent->tByteNext = 0;
00534         }
00535         if (pulFileOffset != NULL) {
00536                 *pulFileOffset =
00537                         pInfoCurrent->pBlockCurrent->tInfo.ulFileOffset +
00538                         pInfoCurrent->ulBlockOffset +
00539                         pInfoCurrent->tByteNext;
00540         }
00541         if (pulCharPos != NULL) {
00542                 *pulCharPos =
00543                         pInfoCurrent->pBlockCurrent->tInfo.ulCharPos +
00544                         pInfoCurrent->ulBlockOffset +
00545                         pInfoCurrent->tByteNext;
00546         }
00547         if (pusPropMod != NULL) {
00548                 *pusPropMod = pInfoCurrent->pBlockCurrent->tInfo.usPropMod;
00549         }
00550         return (USHORT)pInfoCurrent->aucBlock[pInfoCurrent->tByteNext++];
00551 } /* end of usGetNextByte */
00552 
00553 
00554 /*
00555  * usGetNextChar - get the next character from the specified block list
00556  */
00557 static USHORT
00558 usGetNextChar(FILE *pFile, list_id_enum eListID,
00559         ULONG *pulFileOffset, ULONG *pulCharPos, USHORT *pusPropMod)
00560 {
00561         readinfo_type   *pReadinfo;
00562         list_mem_type   *pAnchor;
00563         USHORT  usLSB, usMSB;
00564 
00565         switch (eListID) {
00566         case text_list:
00567                 pReadinfo = &tOthers;
00568                 pAnchor = pTextAnchor;
00569                 break;
00570         case footnote_list:
00571                 pReadinfo = &tFootnote;
00572                 pAnchor = pFootnoteAnchor;
00573                 break;
00574         case hdrftr_list:
00575                 pReadinfo = &tHdrFtr;
00576                 pAnchor = pHdrFtrAnchor;
00577                 break;
00578         case endnote_list:
00579                 pReadinfo = &tOthers;
00580                 pAnchor = pEndnoteAnchor;
00581                 break;
00582         case textbox_list:
00583                 pReadinfo = &tOthers;
00584                 pAnchor = pTextBoxAnchor;
00585                 break;
00586         case hdrtextbox_list:
00587                 pReadinfo = &tOthers;
00588                 pAnchor = pHdrTextBoxAnchor;
00589                 break;
00590         default:
00591                 DBG_DEC(eListID);
00592                 return (USHORT)EOF;
00593         }
00594 
00595         usLSB = usGetNextByte(pFile, pReadinfo, pAnchor,
00596                                 pulFileOffset, pulCharPos, pusPropMod);
00597         if (usLSB == (USHORT)EOF) {
00598                 return (USHORT)EOF;
00599         }
00600         fail(pReadinfo->pBlockCurrent == NULL);
00601 
00602         if (pReadinfo->pBlockCurrent->tInfo.bUsesUnicode) {
00603                 usMSB = usGetNextByte(pFile,
00604                                 pReadinfo, pAnchor, NULL, NULL, NULL);
00605         } else {
00606                 usMSB = 0x00;
00607         }
00608         if (usMSB == (USHORT)EOF) {
00609                 DBG_MSG("usGetNextChar: Unexpected EOF");
00610                 DBG_HEX_C(pulFileOffset != NULL, *pulFileOffset);
00611                 DBG_HEX_C(pulCharPos != NULL, *pulCharPos);
00612                 return (USHORT)EOF;
00613         }
00614         return (usMSB << 8) | usLSB;
00615 } /* end of usGetNextChar */
00616 
00617 /*
00618  * usNextChar - get the next character from the given block list
00619  */
00620 USHORT
00621 usNextChar(FILE *pFile, list_id_enum eListID,
00622         ULONG *pulFileOffset, ULONG *pulCharPos, USHORT *pusPropMod)
00623 {
00624         USHORT  usRetVal;
00625 
00626         fail(pFile == NULL);
00627 
00628         usRetVal = usGetNextChar(pFile, eListID,
00629                                 pulFileOffset, pulCharPos, pusPropMod);
00630         if (usRetVal == (USHORT)EOF) {
00631                 if (pulFileOffset != NULL) {
00632                         *pulFileOffset = FC_INVALID;
00633                 }
00634                 if (pulCharPos != NULL) {
00635                         *pulCharPos = CP_INVALID;
00636                 }
00637                 if (pusPropMod != NULL) {
00638                         *pusPropMod = IGNORE_PROPMOD;
00639                 }
00640         }
00641         return usRetVal;
00642 } /* end of usNextChar */
00643 
00644 /*
00645  * usToHdrFtrPosition - Go to a character position in header/foorter list
00646  *
00647  * Returns the character found on the specified character position
00648  */
00649 USHORT
00650 usToHdrFtrPosition(FILE *pFile, ULONG ulCharPos)
00651 {
00652         ULONG   ulCharPosCurr;
00653         USHORT  usChar;
00654 
00655         tHdrFtr.pBlockCurrent = NULL;   /* To reset the header/footer list */
00656         do {
00657                 usChar = usNextChar(pFile,
00658                                 hdrftr_list, NULL, &ulCharPosCurr, NULL);
00659         } while (usChar != (USHORT)EOF && ulCharPosCurr != ulCharPos);
00660         return usChar;
00661 } /* end of usToHdrFtrPosition */
00662 
00663 /*
00664  * usToFootnotePosition - Go to a character position in footnote list
00665  *
00666  * Returns the character found on the specified character position
00667  */
00668 USHORT
00669 usToFootnotePosition(FILE *pFile, ULONG ulCharPos)
00670 {
00671         ULONG   ulCharPosCurr;
00672         USHORT  usChar;
00673 
00674         tFootnote.pBlockCurrent = NULL; /* To reset the footnote list */
00675         do {
00676                 usChar = usNextChar(pFile,
00677                                 footnote_list, NULL, &ulCharPosCurr, NULL);
00678         } while (usChar != (USHORT)EOF && ulCharPosCurr != ulCharPos);
00679         return usChar;
00680 } /* end of usToFootnotePosition */
00681 
00682 /*
00683  * Convert a character position to an offset in the file.
00684  * Logical to physical offset.
00685  *
00686  * Returns:     FC_INVALID: in case of error
00687  *              otherwise: the computed file offset
00688  */
00689 ULONG
00690 ulCharPos2FileOffsetX(ULONG ulCharPos, list_id_enum *peListID)
00691 {
00692         static list_id_enum     eListIDs[8] = {
00693                 text_list,      footnote_list,          hdrftr_list,
00694                 macro_list,     annotation_list,        endnote_list,
00695                 textbox_list,   hdrtextbox_list,
00696         };
00697         list_mem_type   *apAnchors[8];
00698         list_mem_type   *pCurr;
00699         list_id_enum    eListGuess;
00700         ULONG           ulBestGuess;
00701         size_t          tIndex;
00702 
00703         fail(peListID == NULL);
00704 
00705         if (ulCharPos == CP_INVALID) {
00706                 *peListID = no_list;
00707                 return FC_INVALID;
00708         }
00709 
00710         apAnchors[0] = pTextAnchor;
00711         apAnchors[1] = pFootnoteAnchor;
00712         apAnchors[2] = pHdrFtrAnchor;
00713         apAnchors[3] = pMacroAnchor;
00714         apAnchors[4] = pAnnotationAnchor;
00715         apAnchors[5] = pEndnoteAnchor;
00716         apAnchors[6] = pTextBoxAnchor;
00717         apAnchors[7] = pHdrTextBoxAnchor;
00718 
00719         eListGuess = no_list;     /* Best guess is no list */
00720         ulBestGuess = FC_INVALID; /* Best guess is "file offset not found" */
00721 
00722         for (tIndex = 0; tIndex < elementsof(apAnchors); tIndex++) {
00723                 for (pCurr = apAnchors[tIndex];
00724                      pCurr != NULL;
00725                      pCurr = pCurr->pNext) {
00726                         if (ulCharPos == pCurr->tInfo.ulCharPos +
00727                              pCurr->tInfo.ulLength &&
00728                             pCurr->pNext != NULL) {
00729                                 /*
00730                                  * The character position is one beyond this
00731                                  * block, so we guess it's the first byte of
00732                                  * the next block (if there is a next block)
00733                                  */
00734                                 eListGuess= eListIDs[tIndex];
00735                                 ulBestGuess = pCurr->pNext->tInfo.ulFileOffset;
00736                         }
00737 
00738                         if (ulCharPos < pCurr->tInfo.ulCharPos ||
00739                             ulCharPos >= pCurr->tInfo.ulCharPos +
00740                              pCurr->tInfo.ulLength) {
00741                                 /* Character position is not in this block */
00742                                 continue;
00743                         }
00744 
00745                         /* The character position is in the current block */
00746                         *peListID = eListIDs[tIndex];
00747                         return pCurr->tInfo.ulFileOffset +
00748                                 ulCharPos - pCurr->tInfo.ulCharPos;
00749                 }
00750         }
00751         /* Passed beyond the end of the last list */
00752         NO_DBG_HEX(ulCharPos);
00753         NO_DBG_HEX(ulBestGuess);
00754         *peListID = eListGuess;
00755         return ulBestGuess;
00756 } /* end of ulCharPos2FileOffsetX */
00757 
00758 /*
00759  * Convert a character position to an offset in the file.
00760  * Logical to physical offset.
00761  *
00762  * Returns:     FC_INVALID: in case of error
00763  *              otherwise: the computed file offset
00764  */
00765 ULONG
00766 ulCharPos2FileOffset(ULONG ulCharPos)
00767 {
00768         list_id_enum    eListID;
00769 
00770         return ulCharPos2FileOffsetX(ulCharPos, &eListID);
00771 } /* end of ulCharPos2FileOffset */
00772 
00773 /*
00774  * Convert an offset in the header/footer list to a character position.
00775  *
00776  * Returns:     CP_INVALID: in case of error
00777  *              otherwise: the computed character position
00778  */
00779 ULONG
00780 ulHdrFtrOffset2CharPos(ULONG ulHdrFtrOffset)
00781 {
00782         list_mem_type   *pCurr;
00783         ULONG           ulOffset;
00784 
00785         ulOffset = ulHdrFtrOffset;
00786         for (pCurr = pHdrFtrAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
00787                 if (ulOffset >= pCurr->tInfo.ulLength) {
00788                         /* The offset is not in this block */
00789                         ulOffset -= pCurr->tInfo.ulLength;
00790                         continue;
00791                 }
00792                 return pCurr->tInfo.ulCharPos + ulOffset;
00793         }
00794         return CP_INVALID;
00795 } /* end of ulHdrFtrOffset2CharPos */
00796 
00797 /*
00798  * Get the sequence number beloning to the given file offset
00799  *
00800  * Returns the sequence number
00801  */
00802 ULONG
00803 ulGetSeqNumber(ULONG ulFileOffset)
00804 {
00805         list_mem_type   *pCurr;
00806         ULONG           ulSeq;
00807 
00808         if (ulFileOffset == FC_INVALID) {
00809                 return FC_INVALID;
00810         }
00811 
00812         ulSeq = 0;
00813         for (pCurr = pTextAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
00814                 if (ulFileOffset >= pCurr->tInfo.ulFileOffset &&
00815                     ulFileOffset < pCurr->tInfo.ulFileOffset +
00816                      pCurr->tInfo.ulLength) {
00817                         /* The file offset is within the current textblock */
00818                         return ulSeq + ulFileOffset - pCurr->tInfo.ulFileOffset;
00819                 }
00820                 ulSeq += pCurr->tInfo.ulLength;
00821         }
00822         return FC_INVALID;
00823 } /* end of ulGetSeqNumber */

Generated by  doxygen 1.6.2