home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / anwor032.zip / antiword.0.32 / blocklist.c < prev    next >
C/C++ Source or Header  |  2001-06-11  |  28KB  |  1,048 lines

  1. /*
  2.  * blocklist.c
  3.  * Copyright (C) 1998-2001 A.J. van Os; Released under GPL
  4.  *
  5.  * Description:
  6.  * Build, read and destroy a list of Word text blocks
  7.  */
  8.  
  9. #include <stdlib.h>
  10. #include "antiword.h"
  11.  
  12.  
  13. /*
  14.  * Private structure to hide the way the information
  15.  * is stored from the rest of the program
  16.  */
  17. typedef struct list_mem_tag {
  18.     text_block_type        tInfo;
  19.     struct list_mem_tag    *pNext;
  20. } list_mem_type;
  21.  
  22. /* Variables to describe the start of the five block lists */
  23. static list_mem_type    *pTextAnchor = NULL;
  24. static list_mem_type    *pFootAnchor = NULL;
  25. static list_mem_type    *pUnused1Anchor = NULL;
  26. static list_mem_type    *pEndAnchor = NULL;
  27. static list_mem_type    *pUnused2Anchor = NULL;
  28. /* Variable needed to build the block list */
  29. static list_mem_type    *pBlockLast = NULL;
  30. /* Variable needed to read the text block list */
  31. static list_mem_type    *pTextBlockCurrent = NULL;
  32. /* Variable needed to read the footnote block list */
  33. static list_mem_type    *pFootBlockCurrent = NULL;
  34. /* Variable needed to read the endnote block list */
  35. static list_mem_type    *pEndBlockCurrent = NULL;
  36. /* Last block read */
  37. static unsigned char    aucBlock[BIG_BLOCK_SIZE];
  38.  
  39.  
  40. /*
  41.  * vDestroyTextBlockList - destroy the text block list
  42.  */
  43. void
  44. vDestroyTextBlockList(void)
  45. {
  46.     list_mem_type    *apAnchor[5];
  47.     list_mem_type    *pCurr, *pNext;
  48.     int    iIndex;
  49.  
  50.     DBG_MSG("vDestroyTextBlockList");
  51.  
  52.     apAnchor[0] = pTextAnchor;
  53.     apAnchor[1] = pFootAnchor;
  54.     apAnchor[2] = pUnused1Anchor;
  55.     apAnchor[3] = pEndAnchor;
  56.     apAnchor[4] = pUnused2Anchor;
  57.  
  58.     for (iIndex = 0; iIndex < 5; iIndex++) {
  59.         pCurr = apAnchor[iIndex];
  60.         while (pCurr != NULL) {
  61.             pNext = pCurr->pNext;
  62.             pCurr = xfree(pCurr);
  63.             pCurr = pNext;
  64.         }
  65.     }
  66.     /* Show that there are no lists any more */
  67.     pTextAnchor = NULL;
  68.     pFootAnchor = NULL;
  69.     pUnused1Anchor = NULL;
  70.     pEndAnchor = NULL;
  71.     pUnused2Anchor = NULL;
  72.     /* Reset all the controle variables */
  73.     pBlockLast = NULL;
  74.     pTextBlockCurrent = NULL;
  75.     pFootBlockCurrent = NULL;
  76.     pEndBlockCurrent = NULL;
  77. } /* end of vDestroyTextBlockList */
  78.  
  79. /*
  80.  * bAdd2TextBlockList - add an element to the text block list
  81.  *
  82.  * returns: TRUE when successful, otherwise FALSE
  83.  */
  84. BOOL
  85. bAdd2TextBlockList(text_block_type *pTextBlock)
  86. {
  87.     list_mem_type    *pListMember;
  88.  
  89.     fail(pTextBlock == NULL);
  90.     fail(pTextBlock->lFileOffset < 0);
  91.     fail(pTextBlock->lTextOffset < 0);
  92.     fail(pTextBlock->lLength <= 0);
  93.     fail(pTextBlock->bUsesUnicode && odd(pTextBlock->lLength));
  94.  
  95.     NO_DBG_MSG("bAdd2TextBlockList");
  96.     NO_DBG_HEX(pTextBlock->lFileOffset);
  97.     NO_DBG_HEX(pTextBlock->lTextOffset);
  98.     NO_DBG_HEX(pTextBlock->lLength);
  99.     NO_DBG_DEC(pTextBlock->bUsesUnicode);
  100.     NO_DBG_DEC(pTextBlock->usPropMod);
  101.  
  102.     if (pTextBlock->lFileOffset < 0 ||
  103.         pTextBlock->lTextOffset < 0 ||
  104.         pTextBlock->lLength <= 0 ||
  105.         (pTextBlock->bUsesUnicode && odd(pTextBlock->lLength))) {
  106.         werr(0, "Software (textblock) error");
  107.         return FALSE;
  108.     }
  109.     /*
  110.      * Check for continuous blocks of the same character size and
  111.      * the same properties modifier
  112.      */
  113.     if (pBlockLast != NULL &&
  114.         pBlockLast->tInfo.lFileOffset +
  115.          pBlockLast->tInfo.lLength == pTextBlock->lFileOffset &&
  116.         pBlockLast->tInfo.lTextOffset +
  117.          pBlockLast->tInfo.lLength == pTextBlock->lTextOffset &&
  118.         pBlockLast->tInfo.bUsesUnicode == pTextBlock->bUsesUnicode &&
  119.         pBlockLast->tInfo.usPropMod == pTextBlock->usPropMod) {
  120.         /* These are continous blocks */
  121.         pBlockLast->tInfo.lLength += pTextBlock->lLength;
  122.         return TRUE;
  123.     }
  124.     /* Make a new block */
  125.     pListMember = xmalloc(sizeof(list_mem_type));
  126.     /* Add the block to the list */
  127.     pListMember->tInfo = *pTextBlock;
  128.     pListMember->pNext = NULL;
  129.     if (pTextAnchor == NULL) {
  130.         pTextAnchor = pListMember;
  131.     } else {
  132.         fail(pBlockLast == NULL);
  133.         pBlockLast->pNext = pListMember;
  134.     }
  135.     pBlockLast = pListMember;
  136.     return TRUE;
  137. } /* end of bAdd2TextBlockList */
  138.  
  139.  
  140. /*
  141.  * vSplitBlockList - split the block list in five parts
  142.  *
  143.  * Split the blocklist in a Text block list, a Footnote block list, a
  144.  * Endnote block list and two Unused lists.
  145.  *
  146.  * NOTE:
  147.  * The various l*Len input parameters are given in characters, but the
  148.  * length of the blocks are in bytes.
  149.  */
  150. void
  151. vSplitBlockList(long lTextLen, long lFootnoteLen, long lUnused1Len,
  152.     long lEndnoteLen, long lUnused2Len, BOOL bMustExtend)
  153. {
  154.     list_mem_type    *apAnchors[5];
  155.     list_mem_type    *pGarbageAnchor, *pCurr, *pNext;
  156.     long        lCharsToGo, lBytesTooFar;
  157.     int        iIndex;
  158. #if defined(DEBUG)
  159.     long        lTotal;
  160. #endif /* DEBUG */
  161.  
  162.     DBG_MSG("vSplitBlockList");
  163.  
  164. /* Text block list */
  165.     pCurr = NULL;
  166.     lCharsToGo = lTextLen;
  167.     lBytesTooFar = -1;
  168.     if (lTextLen > 0) {
  169.         DBG_MSG("Text block list");
  170.         DBG_DEC(lTextLen);
  171.         for (pCurr = pTextAnchor;
  172.              pCurr != NULL;
  173.              pCurr = pCurr->pNext) {
  174.             NO_DBG_DEC(pCurr->tInfo.lLength);
  175.             fail(pCurr->tInfo.lLength <= 0);
  176.             if (pCurr->tInfo.bUsesUnicode) {
  177.                 fail(odd(pCurr->tInfo.lLength));
  178.                 lCharsToGo -= pCurr->tInfo.lLength / 2;
  179.                 if (lCharsToGo < 0) {
  180.                     lBytesTooFar = -2 * lCharsToGo;
  181.                 }
  182.             } else {
  183.                 lCharsToGo -= pCurr->tInfo.lLength;
  184.                 if (lCharsToGo < 0) {
  185.                     lBytesTooFar = -lCharsToGo;
  186.                 }
  187.             }
  188.             if (lCharsToGo <= 0) {
  189.                 break;
  190.             }
  191.         }
  192.     }
  193. /* Split the list */
  194.     if (lTextLen <= 0) {
  195.         /* Empty text blocks list */
  196.         pFootAnchor = pTextAnchor;
  197.         pTextAnchor = NULL;
  198.     } else if (pCurr == NULL) {
  199.         /* No footnote blocks */
  200.         pFootAnchor = NULL;
  201.     } else if (lCharsToGo == 0) {
  202.         /* Move the integral number of footnote blocks */
  203.         pFootAnchor = pCurr->pNext;
  204.         pCurr->pNext = NULL;
  205.     } else {
  206.         /* Split the part-text block, part-footnote block */
  207.         DBG_DEC(lBytesTooFar);
  208.         fail(lBytesTooFar <= 0);
  209.         pFootAnchor = xmalloc(sizeof(list_mem_type));
  210.         DBG_HEX(pCurr->tInfo.lFileOffset);
  211.         pFootAnchor->tInfo.lFileOffset =
  212.                 pCurr->tInfo.lFileOffset +
  213.                 pCurr->tInfo.lLength -
  214.                 lBytesTooFar;
  215.         DBG_HEX(pFootAnchor->tInfo.lFileOffset);
  216.         DBG_HEX(pCurr->tInfo.lTextOffset);
  217.         pFootAnchor->tInfo.lTextOffset =
  218.                 pCurr->tInfo.lTextOffset +
  219.                 pCurr->tInfo.lLength -
  220.                 lBytesTooFar;
  221.         DBG_HEX(pFootAnchor->tInfo.lTextOffset);
  222.         pFootAnchor->tInfo.lLength = lBytesTooFar;
  223.         pCurr->tInfo.lLength -= lBytesTooFar;
  224.         pFootAnchor->tInfo.bUsesUnicode = pCurr->tInfo.bUsesUnicode;
  225.         /* Move the integral number of footnote blocks */
  226.         pFootAnchor->pNext = pCurr->pNext;
  227.         pCurr->pNext = NULL;
  228.     }
  229. /* Footnote block list */
  230.     pCurr = NULL;
  231.     lCharsToGo = lFootnoteLen;
  232.     lBytesTooFar = -1;
  233.     if (lFootnoteLen > 0) {
  234.         DBG_MSG("Footnote block list");
  235.         DBG_DEC(lFootnoteLen);
  236.         for (pCurr = pFootAnchor;
  237.              pCurr != NULL;
  238.              pCurr = pCurr->pNext) {
  239.             DBG_DEC(pCurr->tInfo.lLength);
  240.             fail(pCurr->tInfo.lLength <= 0);
  241.             if (pCurr->tInfo.bUsesUnicode) {
  242.                 fail(odd(pCurr->tInfo.lLength));
  243.                 lCharsToGo -= pCurr->tInfo.lLength / 2;
  244.                 if (lCharsToGo < 0) {
  245.                     lBytesTooFar = -2 * lCharsToGo;
  246.                 }
  247.             } else {
  248.                 lCharsToGo -= pCurr->tInfo.lLength;
  249.                 if (lCharsToGo < 0) {
  250.                     lBytesTooFar = -lCharsToGo;
  251.                 }
  252.             }
  253.             if (lCharsToGo <= 0) {
  254.                 break;
  255.             }
  256.         }
  257.     }
  258. /* Split the list */
  259.     if (lFootnoteLen <= 0) {
  260.         /* Empty footnote list */
  261.         pUnused1Anchor = pFootAnchor;
  262.         pFootAnchor = NULL;
  263.     } else if (pCurr == NULL) {
  264.         /* No unused1 blocks */
  265.         pUnused1Anchor = NULL;
  266.     } else if (lCharsToGo == 0) {
  267.         /* Move the integral number of unused1-list blocks */
  268.         pUnused1Anchor = pCurr->pNext;
  269.         pCurr->pNext = NULL;
  270.     } else {
  271.           /* Split the part-footnote block, part-unused1 block */
  272.         DBG_DEC(lBytesTooFar);
  273.         fail(lBytesTooFar <= 0);
  274.         pUnused1Anchor = xmalloc(sizeof(list_mem_type));
  275.         DBG_HEX(pCurr->tInfo.lFileOffset);
  276.         pUnused1Anchor->tInfo.lFileOffset =
  277.                 pCurr->tInfo.lFileOffset +
  278.                 pCurr->tInfo.lLength -
  279.                 lBytesTooFar;
  280.         DBG_HEX(pUnused1Anchor->tInfo.lFileOffset);
  281.         DBG_HEX(pCurr->tInfo.lTextOffset);
  282.         pUnused1Anchor->tInfo.lTextOffset =
  283.                 pCurr->tInfo.lTextOffset +
  284.                 pCurr->tInfo.lLength -
  285.                 lBytesTooFar;
  286.         DBG_HEX(pUnused1Anchor->tInfo.lTextOffset);
  287.         pUnused1Anchor->tInfo.lLength = lBytesTooFar;
  288.         pCurr->tInfo.lLength -= lBytesTooFar;
  289.         pUnused1Anchor->tInfo.bUsesUnicode =
  290.                 pCurr->tInfo.bUsesUnicode;
  291.         /* Move the integral number of unused1 blocks */
  292.         pUnused1Anchor->pNext = pCurr->pNext;
  293.         pCurr->pNext = NULL;
  294.     }
  295. /* Unused1 block list */
  296.     pCurr = NULL;
  297.     lCharsToGo = lUnused1Len;
  298.     lBytesTooFar = -1;
  299.     if (lUnused1Len > 0) {
  300.         DBG_MSG("Unused1 block list");
  301.         DBG_DEC(lUnused1Len);
  302.         for (pCurr = pUnused1Anchor;
  303.              pCurr != NULL;
  304.              pCurr = pCurr->pNext) {
  305.             DBG_DEC(pCurr->tInfo.lLength);
  306.             fail(pCurr->tInfo.lLength <= 0);
  307.             if (pCurr->tInfo.bUsesUnicode) {
  308.                 fail(odd(pCurr->tInfo.lLength));
  309.                 lCharsToGo -= pCurr->tInfo.lLength / 2;
  310.                 if (lCharsToGo < 0) {
  311.                     lBytesTooFar = -2 * lCharsToGo;
  312.                 }
  313.             } else {
  314.                 lCharsToGo -= pCurr->tInfo.lLength;
  315.                 if (lCharsToGo < 0) {
  316.                     lBytesTooFar = -lCharsToGo;
  317.                 }
  318.             }
  319.             if (lCharsToGo <= 0) {
  320.                 break;
  321.             }
  322.         }
  323.     }
  324. /* Split the list */
  325.     if (lUnused1Len <= 0) {
  326.         /* Empty unused1 list */
  327.         pEndAnchor = pUnused1Anchor;
  328.         pUnused1Anchor = NULL;
  329.     } else if (pCurr == NULL) {
  330.         /* No endnote blocks */
  331.         pEndAnchor = NULL;
  332.     } else if (lCharsToGo == 0) {
  333.         /* Move the intergral number of endnote blocks */
  334.         pEndAnchor = pCurr->pNext;
  335.         pCurr->pNext = NULL;
  336.     } else {
  337.         /* Split the part-unused1-list block, part-endnote block */
  338.         DBG_DEC(lBytesTooFar);
  339.         fail(lBytesTooFar <= 0);
  340.         pEndAnchor = xmalloc(sizeof(list_mem_type));
  341.         DBG_HEX(pCurr->tInfo.lFileOffset);
  342.         pEndAnchor->tInfo.lFileOffset =
  343.                 pCurr->tInfo.lFileOffset +
  344.                 pCurr->tInfo.lLength -
  345.                 lBytesTooFar;
  346.         DBG_HEX(pEndAnchor->tInfo.lFileOffset);
  347.         DBG_HEX(pCurr->tInfo.lTextOffset);
  348.         pEndAnchor->tInfo.lTextOffset =
  349.                 pCurr->tInfo.lTextOffset +
  350.                 pCurr->tInfo.lLength -
  351.                 lBytesTooFar;
  352.         DBG_HEX(pEndAnchor->tInfo.lTextOffset);
  353.         pEndAnchor->tInfo.lLength = lBytesTooFar;
  354.         pCurr->tInfo.lLength -= lBytesTooFar;
  355.         pEndAnchor->tInfo.bUsesUnicode = pCurr->tInfo.bUsesUnicode;
  356.         /* Move the integral number of endnote blocks */
  357.         pEndAnchor->pNext = pCurr->pNext;
  358.         pCurr->pNext = NULL;
  359.     }
  360. /* Endnote block list */
  361.     pCurr = NULL;
  362.     lCharsToGo = lEndnoteLen;
  363.     lBytesTooFar = -1;
  364.     if (lEndnoteLen > 0) {
  365.         DBG_MSG("Endnote block list");
  366.         DBG_DEC(lEndnoteLen);
  367.         for (pCurr = pEndAnchor;
  368.              pCurr != NULL;
  369.              pCurr = pCurr->pNext) {
  370.             DBG_DEC(pCurr->tInfo.lLength);
  371.             fail(pCurr->tInfo.lLength <= 0);
  372.             if (pCurr->tInfo.bUsesUnicode) {
  373.                 fail(odd(pCurr->tInfo.lLength));
  374.                 lCharsToGo -= pCurr->tInfo.lLength / 2;
  375.                 if (lCharsToGo <= 0) {
  376.                     lBytesTooFar = -2 * lCharsToGo;
  377.                 }
  378.             } else {
  379.                 lCharsToGo -= pCurr->tInfo.lLength;
  380.                 if (lCharsToGo <= 0) {
  381.                     lBytesTooFar = -lCharsToGo;
  382.                 }
  383.             }
  384.             if (lCharsToGo <= 0) {
  385.                 break;
  386.             }
  387.         }
  388.     }
  389. /* Split the list */
  390.     if (lEndnoteLen <= 0) {
  391.         /* Empty endnote list */
  392.         pUnused2Anchor = pEndAnchor;
  393.         pEndAnchor = NULL;
  394.     } else if (pCurr == NULL) {
  395.         /* No unused2 blocks */
  396.         pUnused2Anchor = NULL;
  397.     } else if (lCharsToGo == 0) {
  398.         /* Move the intergral number of unused2 blocks */
  399.         pUnused2Anchor = pCurr->pNext;
  400.         pCurr->pNext = NULL;
  401.     } else {
  402.         /* Split the part-endnote block, part-unused2 block */
  403.         DBG_DEC(lBytesTooFar);
  404.         fail(lBytesTooFar <= 0);
  405.         pUnused2Anchor = xmalloc(sizeof(list_mem_type));
  406.         DBG_HEX(pCurr->tInfo.lFileOffset);
  407.         pUnused2Anchor->tInfo.lFileOffset =
  408.                 pCurr->tInfo.lFileOffset +
  409.                 pCurr->tInfo.lLength -
  410.                 lBytesTooFar;
  411.         DBG_HEX(pUnused2Anchor->tInfo.lFileOffset);
  412.         DBG_HEX(pCurr->tInfo.lTextOffset);
  413.         pUnused2Anchor->tInfo.lTextOffset =
  414.                 pCurr->tInfo.lTextOffset +
  415.                 pCurr->tInfo.lLength -
  416.                 lBytesTooFar;
  417.         DBG_HEX(pUnused2Anchor->tInfo.lTextOffset);
  418.         pUnused2Anchor->tInfo.lLength = lBytesTooFar;
  419.         pCurr->tInfo.lLength -= lBytesTooFar;
  420.         pUnused2Anchor->tInfo.bUsesUnicode =
  421.                 pCurr->tInfo.bUsesUnicode;
  422.         /* Move the integral number of unused2 blocks */
  423.         pUnused2Anchor->pNext = pCurr->pNext;
  424.         pCurr->pNext = NULL;
  425.     }
  426. /* Unused2 block list */
  427.     pCurr = NULL;
  428.     lCharsToGo = lUnused2Len;
  429.     lBytesTooFar = -1;
  430.     if (lUnused2Len > 0) {
  431.         DBG_MSG("Unused2 block list");
  432.         DBG_DEC(lUnused2Len);
  433.         for (pCurr = pUnused2Anchor;
  434.              pCurr != NULL;
  435.              pCurr = pCurr->pNext) {
  436.             DBG_DEC(pCurr->tInfo.lLength);
  437.             fail(pCurr->tInfo.lLength <= 0);
  438.             if (pCurr->tInfo.bUsesUnicode) {
  439.                 fail(odd(pCurr->tInfo.lLength));
  440.                 lCharsToGo -= pCurr->tInfo.lLength / 2;
  441.                 if (lCharsToGo < 0) {
  442.                     lBytesTooFar = -2 * lCharsToGo;
  443.                 }
  444.             } else {
  445.                 lCharsToGo -= pCurr->tInfo.lLength;
  446.                 if (lCharsToGo < 0) {
  447.                     lBytesTooFar = -lCharsToGo;
  448.                 }
  449.             }
  450.             if (lCharsToGo <= 0) {
  451.                 break;
  452.             }
  453.         }
  454.     }
  455. /* Split the list */
  456.     if (lUnused2Len <= 0) {
  457.         /* Empty unused2 list */
  458.         pGarbageAnchor = pUnused2Anchor;
  459.         pUnused2Anchor = NULL;
  460.     } else if (pCurr == NULL) {
  461.         /* No garbage block list */
  462.         pGarbageAnchor = NULL;
  463.     } else if (lCharsToGo == 0) {
  464.         /* Move the intergral number of garbage blocks */
  465.         pGarbageAnchor = pCurr->pNext;
  466.         pCurr->pNext = NULL;
  467.     } else {
  468.         /* Reduce the part-unused2 block */
  469.         DBG_DEC(lBytesTooFar);
  470.         fail(lBytesTooFar <= 0);
  471.         pCurr->tInfo.lLength -= lBytesTooFar;
  472.         /* Move the integral number of garbage blocks */
  473.         pGarbageAnchor = pCurr->pNext;
  474.         pCurr->pNext = NULL;
  475.     }
  476. /* Free the garbage block list, this should never be needed */
  477.     pCurr = pGarbageAnchor;
  478.     while (pCurr != NULL) {
  479.         DBG_FIXME();
  480.         DBG_HEX(pCurr->tInfo.lFileOffset);
  481.         DBG_DEC(pCurr->tInfo.lLength);
  482.         pNext = pCurr->pNext;
  483.         pCurr = xfree(pCurr);
  484.         pCurr = pNext;
  485.     }
  486.  
  487. #if defined(DEBUG)
  488.     /* Check the number of bytes in the block lists */
  489.     lTotal = 0;
  490.     for (pCurr = pTextAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
  491.         NO_DBG_HEX(pCurr->tInfo.lFileOffset);
  492.         NO_DBG_HEX(pCurr->tInfo.lTextOffset);
  493.         NO_DBG_DEC(pCurr->tInfo.lLength);
  494.         fail(pCurr->tInfo.lLength <= 0);
  495.         if (pCurr->tInfo.bUsesUnicode) {
  496.             fail(odd(pCurr->tInfo.lLength));
  497.             lTotal += pCurr->tInfo.lLength / 2;
  498.         } else {
  499.             lTotal += pCurr->tInfo.lLength;
  500.         }
  501.     }
  502.     DBG_DEC(lTotal);
  503.     if (lTotal != lTextLen) {
  504.         DBG_DEC(lTextLen);
  505.         werr(1, "Software error (Text)");
  506.     }
  507.     lTotal = 0;
  508.     for (pCurr = pFootAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
  509.         DBG_HEX(pCurr->tInfo.lFileOffset);
  510.         NO_DBG_HEX(pCurr->tInfo.lTextOffset);
  511.         DBG_DEC(pCurr->tInfo.lLength);
  512.         fail(pCurr->tInfo.lLength <= 0);
  513.         if (pCurr->tInfo.bUsesUnicode) {
  514.             fail(odd(pCurr->tInfo.lLength));
  515.             lTotal += pCurr->tInfo.lLength / 2;
  516.         } else {
  517.             lTotal += pCurr->tInfo.lLength;
  518.         }
  519.     }
  520.     DBG_DEC(lTotal);
  521.     if (lTotal != lFootnoteLen) {
  522.         DBG_DEC(lFootnoteLen);
  523.         werr(1, "Software error (Footnotes)");
  524.     }
  525.     lTotal = 0;
  526.     for (pCurr = pUnused1Anchor; pCurr != NULL; pCurr = pCurr->pNext) {
  527.         DBG_HEX(pCurr->tInfo.lFileOffset);
  528.         NO_DBG_HEX(pCurr->tInfo.lTextOffset);
  529.         DBG_DEC(pCurr->tInfo.lLength);
  530.         fail(pCurr->tInfo.lLength <= 0);
  531.         if (pCurr->tInfo.bUsesUnicode) {
  532.             fail(odd(pCurr->tInfo.lLength));
  533.             lTotal += pCurr->tInfo.lLength / 2;
  534.         } else {
  535.             lTotal += pCurr->tInfo.lLength;
  536.         }
  537.     }
  538.     DBG_DEC(lTotal);
  539.     if (lTotal != lUnused1Len) {
  540.         DBG_DEC(lUnused1Len);
  541.         werr(1, "Software error (Unused1-list)");
  542.     }
  543.     lTotal = 0;
  544.     for (pCurr = pEndAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
  545.         DBG_HEX(pCurr->tInfo.lFileOffset);
  546.         NO_DBG_HEX(pCurr->tInfo.lTextOffset);
  547.         DBG_DEC(pCurr->tInfo.lLength);
  548.         fail(pCurr->tInfo.lLength <= 0);
  549.         if (pCurr->tInfo.bUsesUnicode) {
  550.             fail(odd(pCurr->tInfo.lLength));
  551.             lTotal += pCurr->tInfo.lLength / 2;
  552.         } else {
  553.             lTotal += pCurr->tInfo.lLength;
  554.         }
  555.     }
  556.     DBG_DEC(lTotal);
  557.     if (lTotal != lEndnoteLen) {
  558.         DBG_DEC(lEndnoteLen);
  559.         werr(1, "Software error (Endnotes)");
  560.     }
  561.     lTotal = 0;
  562.     for (pCurr = pUnused2Anchor; pCurr != NULL; pCurr = pCurr->pNext) {
  563.         DBG_HEX(pCurr->tInfo.lFileOffset);
  564.         NO_DBG_HEX(pCurr->tInfo.lTextOffset);
  565.         DBG_DEC(pCurr->tInfo.lLength);
  566.         fail(pCurr->tInfo.lLength <= 0);
  567.         if (pCurr->tInfo.bUsesUnicode) {
  568.             fail(odd(pCurr->tInfo.lLength));
  569.             lTotal += pCurr->tInfo.lLength / 2;
  570.         } else {
  571.             lTotal += pCurr->tInfo.lLength;
  572.         }
  573.     }
  574.     DBG_DEC(lTotal);
  575.     if (lTotal != lUnused2Len) {
  576.         DBG_DEC(lUnused2Len);
  577.         werr(1, "Software error (Unused2-list)");
  578.     }
  579. #endif /* DEBUG */
  580.  
  581.     if (!bMustExtend) {
  582.         return;
  583.     }
  584.     /*
  585.      * All blocks (except the last one) must have a length that
  586.      * is a multiple of the Big Block Size
  587.      */
  588.  
  589.     apAnchors[0] = pTextAnchor;
  590.     apAnchors[1] = pFootAnchor;
  591.     apAnchors[2] = pUnused1Anchor;
  592.     apAnchors[3] = pEndAnchor;
  593.     apAnchors[4] = pUnused2Anchor;
  594.  
  595.     for (iIndex = 0; iIndex < 5; iIndex++) {
  596.         for (pCurr = apAnchors[iIndex];
  597.              pCurr != NULL;
  598.              pCurr = pCurr->pNext) {
  599.             if (pCurr->pNext != NULL &&
  600.                 pCurr->tInfo.lLength % BIG_BLOCK_SIZE != 0) {
  601.                 DBG_HEX(pCurr->tInfo.lFileOffset);
  602.                 DBG_HEX(pCurr->tInfo.lTextOffset);
  603.                 DBG_DEC(pCurr->tInfo.lLength);
  604.                 pCurr->tInfo.lLength /= BIG_BLOCK_SIZE;
  605.                 pCurr->tInfo.lLength++;
  606.                 pCurr->tInfo.lLength *= BIG_BLOCK_SIZE;
  607.                 DBG_DEC(pCurr->tInfo.lLength);
  608.             }
  609.         }
  610.     }
  611. } /* end of vSplitBlockList */
  612.  
  613. #if defined(__riscos)
  614. /*
  615.  * lGetDocumentLength - get the combined character length of the three lists
  616.  *
  617.  * returns: The total number of characters
  618.  */
  619. long
  620. lGetDocumentLength(void)
  621. {
  622.     list_mem_type    *apAnchors[3];
  623.     list_mem_type    *pCurr;
  624.     long        lTotal;
  625.     int        iIndex;
  626.  
  627.     DBG_MSG("uiGetDocumentLength");
  628.  
  629.     apAnchors[0] = pTextAnchor;
  630.     apAnchors[1] = pFootAnchor;
  631.     apAnchors[2] = pEndAnchor;
  632.  
  633.     lTotal = 0;
  634.     for (iIndex = 0; iIndex < 3; iIndex++) {
  635.         for (pCurr = apAnchors[iIndex];
  636.              pCurr != NULL;
  637.              pCurr = pCurr->pNext) {
  638.             fail(pCurr->tInfo.lLength <= 0);
  639.             if (pCurr->tInfo.bUsesUnicode) {
  640.                 fail(odd(pCurr->tInfo.lLength));
  641.                 lTotal += pCurr->tInfo.lLength / 2;
  642.             } else {
  643.                 lTotal += pCurr->tInfo.lLength;
  644.             }
  645.         }
  646.     }
  647.     DBG_DEC(lTotal);
  648.     return lTotal;
  649. } /* end of tGetDocumentLength */
  650. #endif /* __riscos */
  651.  
  652. /*
  653.  * usNextTextByte - get the next byte from the text block list
  654.  */
  655. static unsigned short
  656. usNextTextByte(FILE *pFile,
  657.     long *plFileOffset, long *plTextOffset, unsigned short *pusPropMod)
  658. {
  659.     static long    lBlockOffset = 0;
  660.     static size_t    tByteNext = 0;
  661.     long    lReadOff;
  662.     size_t    tReadLen;
  663.  
  664.     if (pTextBlockCurrent == NULL ||
  665.         tByteNext >= sizeof(aucBlock) ||
  666.         lBlockOffset + (long)tByteNext >= pTextBlockCurrent->tInfo.lLength) {
  667.         if (pTextBlockCurrent == NULL) {
  668.             /* First block, first part */
  669.             pTextBlockCurrent = pTextAnchor;
  670.             lBlockOffset = 0;
  671.         } else if (lBlockOffset + (long)sizeof(aucBlock) <
  672.                 pTextBlockCurrent->tInfo.lLength) {
  673.             /* Same block, next part */
  674.             lBlockOffset += (long)sizeof(aucBlock);
  675.         } else {
  676.             /* Next block, first part */
  677.             pTextBlockCurrent = pTextBlockCurrent->pNext;
  678.             lBlockOffset = 0;
  679.         }
  680.         if (pTextBlockCurrent == NULL) {
  681.             /* Past the last part of the last block */
  682.             return (unsigned short)EOF;
  683.         }
  684.         tReadLen = (size_t)
  685.             (pTextBlockCurrent->tInfo.lLength - lBlockOffset);
  686.         if (tReadLen > sizeof(aucBlock)) {
  687.             tReadLen = sizeof(aucBlock);
  688.         }
  689.         lReadOff = pTextBlockCurrent->tInfo.lFileOffset +
  690.                 lBlockOffset;
  691.         if (!bReadBytes(aucBlock, tReadLen, lReadOff, pFile)) {
  692.             return (unsigned short)EOF;
  693.         }
  694.         tByteNext = 0;
  695.     }
  696.     if (plFileOffset != NULL) {
  697.         *plFileOffset = pTextBlockCurrent->tInfo.lFileOffset +
  698.             lBlockOffset + (long)tByteNext;
  699.     }
  700.     if (plTextOffset != NULL) {
  701.         *plTextOffset = pTextBlockCurrent->tInfo.lTextOffset +
  702.             lBlockOffset + (long)tByteNext;
  703.     }
  704.     if (pusPropMod != NULL) {
  705.         *pusPropMod = pTextBlockCurrent->tInfo.usPropMod;
  706.     }
  707.     return aucBlock[tByteNext++];
  708. } /* end of usNextTextByte */
  709.  
  710. /*
  711.  * usNextFootByte - get the next byte from the footnote block list
  712.  */
  713. static unsigned short
  714. usNextFootByte(FILE *pFile,
  715.     long *plFileOffset, long *plTextOffset, unsigned short *pusPropMod)
  716. {
  717.     static long    lBlockOffset = 0;
  718.     static size_t    tByteNext = 0;
  719.     long    lReadOff;
  720.     size_t    tReadLen;
  721.  
  722.     if (pFootBlockCurrent == NULL ||
  723.         tByteNext >= sizeof(aucBlock) ||
  724.         lBlockOffset + (long)tByteNext >= pFootBlockCurrent->tInfo.lLength) {
  725.         if (pFootBlockCurrent == NULL) {
  726.             /* First block, first part */
  727.             pFootBlockCurrent = pFootAnchor;
  728.             lBlockOffset = 0;
  729.         } else if (lBlockOffset + (long)sizeof(aucBlock) <
  730.                 pFootBlockCurrent->tInfo.lLength) {
  731.             /* Same block, next part */
  732.             lBlockOffset += (long)sizeof(aucBlock);
  733.         } else {
  734.             /* Next block, first part */
  735.             pFootBlockCurrent = pFootBlockCurrent->pNext;
  736.             lBlockOffset = 0;
  737.         }
  738.         if (pFootBlockCurrent == NULL) {
  739.             /* Past the last part of the last block */
  740.             return (unsigned short)EOF;
  741.         }
  742.         tReadLen = (size_t)
  743.             (pFootBlockCurrent->tInfo.lLength - lBlockOffset);
  744.         if (tReadLen > sizeof(aucBlock)) {
  745.             tReadLen = sizeof(aucBlock);
  746.         }
  747.         lReadOff = pFootBlockCurrent->tInfo.lFileOffset +
  748.                 lBlockOffset;
  749.         if (!bReadBytes(aucBlock, tReadLen, lReadOff, pFile)) {
  750.             return (unsigned short)EOF;
  751.         }
  752.         tByteNext = 0;
  753.     }
  754.     if (plFileOffset != NULL) {
  755.         *plFileOffset = pFootBlockCurrent->tInfo.lFileOffset +
  756.             lBlockOffset + (long)tByteNext;
  757.     }
  758.     if (plTextOffset != NULL) {
  759.         *plTextOffset = pFootBlockCurrent->tInfo.lTextOffset +
  760.             lBlockOffset + (long)tByteNext;
  761.     }
  762.     if (pusPropMod != NULL) {
  763.         *pusPropMod = pFootBlockCurrent->tInfo.usPropMod;
  764.     }
  765.     return aucBlock[tByteNext++];
  766. } /* end of usNextFootByte */
  767.  
  768. /*
  769.  * usNextEndByte - get the next byte from the endnote block list
  770.  */
  771. static unsigned short
  772. usNextEndByte(FILE *pFile,
  773.     long *plFileOffset, long *plTextOffset, unsigned short *pusPropMod)
  774. {
  775.     static long    lBlockOffset = 0;
  776.     static size_t    tByteNext = 0;
  777.     long    lReadOff;
  778.     size_t    tReadLen;
  779.  
  780.     if (pEndBlockCurrent == NULL ||
  781.         tByteNext >= sizeof(aucBlock) ||
  782.         lBlockOffset + (long)tByteNext >= pEndBlockCurrent->tInfo.lLength) {
  783.         if (pEndBlockCurrent == NULL) {
  784.             /* First block, first part */
  785.             pEndBlockCurrent = pEndAnchor;
  786.             lBlockOffset = 0;
  787.         } else if (lBlockOffset + (long)sizeof(aucBlock) <
  788.                 pEndBlockCurrent->tInfo.lLength) {
  789.             /* Same block, next part */
  790.             lBlockOffset += sizeof(aucBlock);
  791.         } else {
  792.             /* Next block, first part */
  793.             pEndBlockCurrent = pEndBlockCurrent->pNext;
  794.             lBlockOffset = 0;
  795.         }
  796.         if (pEndBlockCurrent == NULL) {
  797.             /* Past the last part of the last block */
  798.             return (unsigned short)EOF;
  799.         }
  800.         tReadLen = (size_t)
  801.             (pEndBlockCurrent->tInfo.lLength - lBlockOffset);
  802.         if (tReadLen > sizeof(aucBlock)) {
  803.             tReadLen = sizeof(aucBlock);
  804.         }
  805.         lReadOff = pEndBlockCurrent->tInfo.lFileOffset +
  806.                 lBlockOffset;
  807.         if (!bReadBytes(aucBlock, tReadLen, lReadOff, pFile)) {
  808.             return (unsigned short)EOF;
  809.         }
  810.         tByteNext = 0;
  811.     }
  812.     if (plFileOffset != NULL) {
  813.         *plFileOffset = pEndBlockCurrent->tInfo.lFileOffset +
  814.             lBlockOffset + (long)tByteNext;
  815.     }
  816.     if (plTextOffset != NULL) {
  817.         *plTextOffset = pEndBlockCurrent->tInfo.lTextOffset +
  818.             lBlockOffset + (long)tByteNext;
  819.     }
  820.     if (pusPropMod != NULL) {
  821.         *pusPropMod = pEndBlockCurrent->tInfo.usPropMod;
  822.     }
  823.     return aucBlock[tByteNext++];
  824. } /* end of usNextEndByte */
  825.  
  826. /*
  827.  * usNextTextChar - get the next character from the text block list
  828.  */
  829. static unsigned short
  830. usNextTextChar(FILE *pFile,
  831.     long *plFileOffset, long *plTextOffset, unsigned short *pusPropMod)
  832. {
  833.     unsigned short    usLSB, usMSB;
  834.  
  835.     usLSB = usNextTextByte(pFile, plFileOffset, plTextOffset, pusPropMod);
  836.     if (usLSB == (unsigned short)EOF) {
  837.         return (unsigned short)EOF;
  838.     }
  839.     if (pTextBlockCurrent->tInfo.bUsesUnicode) {
  840.         usMSB = usNextTextByte(pFile, NULL, NULL, NULL);
  841.     } else {
  842.         usMSB = 0x00;
  843.     }
  844.     if (usMSB == (unsigned short)EOF) {
  845.         DBG_MSG("usNextTextChar: Unexpected EOF");
  846.         DBG_HEX_C(plFileOffset != NULL, *plFileOffset);
  847.         DBG_HEX_C(plTextOffset != NULL, *plTextOffset);
  848.         return (unsigned short)EOF;
  849.     }
  850.     return (usMSB << 8) | usLSB;
  851. } /* end of usNextTextChar */
  852.  
  853. /*
  854.  * usNextFootChar - get the next character from the footnote block list
  855.  */
  856. static unsigned short
  857. usNextFootChar(FILE *pFile,
  858.     long *plFileOffset, long *plTextOffset, unsigned short *pusPropMod)
  859. {
  860.     unsigned short    usLSB, usMSB;
  861.  
  862.     usLSB = usNextFootByte(pFile, plFileOffset, plTextOffset, pusPropMod);
  863.     if (usLSB == (unsigned short)EOF) {
  864.         return (unsigned short)EOF;
  865.     }
  866.     if (pFootBlockCurrent->tInfo.bUsesUnicode) {
  867.         usMSB = usNextFootByte(pFile, NULL, NULL, NULL);
  868.     } else {
  869.         usMSB = 0x00;
  870.     }
  871.     if (usMSB == (unsigned short)EOF) {
  872.         DBG_MSG("usNextFootChar: Unexpected EOF");
  873.         DBG_HEX_C(plFileOffset != NULL, *plFileOffset);
  874.         DBG_HEX_C(plTextOffset != NULL, *plTextOffset);
  875.         return (unsigned short)EOF;
  876.     }
  877.     return (usMSB << 8) | usLSB;
  878. } /* end of usNextFootChar */
  879.  
  880. /*
  881.  * usNextEndChar - get the next character from the endnote block list
  882.  */
  883. static unsigned short
  884. usNextEndChar(FILE *pFile,
  885.     long *plFileOffset, long *plTextOffset, unsigned short *pusPropMod)
  886. {
  887.     unsigned short    usLSB, usMSB;
  888.  
  889.     usLSB = usNextEndByte(pFile, plFileOffset, plTextOffset, pusPropMod);
  890.     if (usLSB == (unsigned short)EOF) {
  891.         return (unsigned short)EOF;
  892.     }
  893.     if (pEndBlockCurrent->tInfo.bUsesUnicode) {
  894.         usMSB = usNextEndByte(pFile, NULL, NULL, NULL);
  895.     } else {
  896.         usMSB = 0x00;
  897.     }
  898.     if (usMSB == (unsigned short)EOF) {
  899.         DBG_MSG("usNextEndChar: Unexpected EOF");
  900.         DBG_HEX_C(plFileOffset != NULL, *plFileOffset);
  901.         DBG_HEX_C(plTextOffset != NULL, *plTextOffset);
  902.         return (unsigned short)EOF;
  903.     }
  904.     return (usMSB << 8) | usLSB;
  905. } /* end of usNextEndChar */
  906.  
  907. /*
  908.  * usNextChar - get the next character from the given block list
  909.  */
  910. unsigned short
  911. usNextChar(FILE *pFile, list_id_enum eListID,
  912.     long *plFileOffset, long *plTextOffset, unsigned short *pusPropMod)
  913. {
  914.     fail(pFile == NULL);
  915.  
  916.     switch (eListID) {
  917.     case text_list:
  918.         return usNextTextChar(pFile,
  919.                 plFileOffset, plTextOffset, pusPropMod);
  920.     case footnote_list:
  921.         return usNextFootChar(pFile,
  922.                 plFileOffset, plTextOffset, pusPropMod);
  923.     case endnote_list:
  924.         return usNextEndChar(pFile,
  925.                 plFileOffset, plTextOffset, pusPropMod);
  926.     default:
  927.         if (plFileOffset != NULL) {
  928.             *plFileOffset = -1;
  929.         }
  930.         if (plTextOffset != NULL) {
  931.             *plTextOffset = -1;
  932.         }
  933.         if (pusPropMod != NULL) {
  934.             *pusPropMod = IGNORE_PROPMOD;
  935.         }
  936.         return (unsigned short)EOF;
  937.     }
  938. } /* end of usNextChar */
  939.  
  940. #if 0
  941. /*
  942.  * Translate the start from the begin of the text to the block that contains
  943.  * this offset.
  944.  * Logical offset to block pointer.
  945.  *
  946.  * Returns: block pointer or NULL
  947.  */
  948. static text_block_type *
  949. pTextOffset2Block(long lTextOffset)
  950. {
  951.     list_mem_type    *apAnchors[3];
  952.     list_mem_type    *pCurr;
  953.     int        iIndex;
  954.  
  955.     apAnchors[0] = pTextAnchor;
  956.     apAnchors[1] = pFootAnchor;
  957.     apAnchors[2] = pEndAnchor;
  958.  
  959.     for (iIndex = 0; iIndex < 3; iIndex++) {
  960.         for (pCurr = apAnchors[iIndex];
  961.              pCurr != NULL;
  962.              pCurr = pCurr->pNext) {
  963.             if (lTextOffset >= pCurr->tInfo.lTextOffset &&
  964.                 lTextOffset < pCurr->tInfo.lTextOffset +
  965.                  pCurr->tInfo.lLength) {
  966.                 /* The textoffset is in the current block */
  967.                 return &pCurr->tInfo;
  968.             }
  969.         }
  970.     }
  971.     /* Passed beyond the end of the last list */
  972.     return NULL;
  973. } /* end of pTextOffset2Block */
  974. #endif
  975.  
  976. /*
  977.  * Translate the start from the begin of the text to an offset in the file.
  978.  * Logical to physical offset.
  979.  *
  980.  * Returns:     -1: in case of error
  981.  *        >=0: the computed file offset
  982.  */
  983. long
  984. lTextOffset2FileOffset(long lTextOffset)
  985. {
  986.     list_mem_type    *apAnchors[3];
  987.     list_mem_type    *pCurr;
  988.     long        lBestGuess;
  989.     int        iIndex;
  990.  
  991.     apAnchors[0] = pTextAnchor;
  992.     apAnchors[1] = pFootAnchor;
  993.     apAnchors[2] = pEndAnchor;
  994.  
  995.     lBestGuess = -1;    /* Best guess is "fileoffset not found" */
  996.  
  997.     for (iIndex = 0; iIndex < 3; iIndex++) {
  998.         for (pCurr = apAnchors[iIndex];
  999.              pCurr != NULL;
  1000.              pCurr = pCurr->pNext) {
  1001.             if (lTextOffset == pCurr->tInfo.lTextOffset +
  1002.                  pCurr->tInfo.lLength &&
  1003.                 pCurr->pNext != NULL) {
  1004.                 /*
  1005.                  * The textoffset is one beyond this block,
  1006.                  * so we guess it's the first byte of the next
  1007.                  * block (if there is a next block)
  1008.                  */
  1009.                 lBestGuess = pCurr->pNext->tInfo.lFileOffset;
  1010.             }
  1011.  
  1012.             if (lTextOffset < pCurr->tInfo.lTextOffset ||
  1013.                 lTextOffset >= pCurr->tInfo.lTextOffset +
  1014.                  pCurr->tInfo.lLength) {
  1015.                 /* The textoffset is not in this block */
  1016.                 continue;
  1017.             }
  1018.  
  1019.             /* The textoffset is in the current block */
  1020.             return pCurr->tInfo.lFileOffset +
  1021.                 lTextOffset - pCurr->tInfo.lTextOffset;
  1022.         }
  1023.     }
  1024.     /* Passed beyond the end of the last list */
  1025.     NO_DBG_HEX(lTextOffset);
  1026.     NO_DBG_HEX(lBestGuess);
  1027.     return lBestGuess;
  1028. } /* end of lTextOffset2FileOffset */
  1029.  
  1030. #if 0
  1031. /*
  1032.  * Get the properties modifier for the given logical offset
  1033.  *
  1034.  * Returns: the properties modifier or IGNORE_PROPMOD
  1035.  */
  1036. unsigned short
  1037. pTextOffset2PropMod(long lTextOffset)
  1038. {
  1039.     text_block_type    *pTextBlock;
  1040.  
  1041.     pTextBlock = pTextOffset2Block(lTextOffset);
  1042.     if (pTextBlock == NULL) {
  1043.         return IGNORE_PROPMOD;
  1044.     }
  1045.     return pTextBlock->usPropMod;
  1046. } /* end of pTextOffset2PropMod */
  1047. #endif
  1048.