Imported from antiword-0.37.tar.gz.
[antiword.git] / blocklist.c
blobc847c27e9664fc95b8eb806b19e5cc77ea2e6db9
1 /*
2 * blocklist.c
3 * Copyright (C) 1998-2005 A.J. van Os; Released under GNU GPL
5 * Description:
6 * Build, read and destroy the lists of Word "text" blocks
7 */
9 #include <stdlib.h>
10 #include "antiword.h"
14 * Private structure to hide the way the information
15 * is stored from the rest of the program
17 typedef struct list_mem_tag {
18 text_block_type tInfo;
19 struct list_mem_tag *pNext;
20 } list_mem_type;
22 typedef struct readinfo_tag {
23 list_mem_type *pBlockCurrent;
24 ULONG ulBlockOffset;
25 size_t tByteNext;
26 UCHAR aucBlock[BIG_BLOCK_SIZE];
27 } readinfo_type;
29 /* Variables to describe the start of the block lists */
30 static list_mem_type *pTextAnchor = NULL;
31 static list_mem_type *pFootnoteAnchor = NULL;
32 static list_mem_type *pHdrFtrAnchor = NULL;
33 static list_mem_type *pMacroAnchor = NULL;
34 static list_mem_type *pAnnotationAnchor = NULL;
35 static list_mem_type *pEndnoteAnchor = NULL;
36 static list_mem_type *pTextBoxAnchor = NULL;
37 static list_mem_type *pHdrTextBoxAnchor = NULL;
38 /* Variable needed to build the block list */
39 static list_mem_type *pBlockLast = NULL;
40 /* Variable needed to read the block lists */
41 static readinfo_type tOthers = { NULL, 0, 0, };
42 static readinfo_type tHdrFtr = { NULL, 0, 0, };
43 static readinfo_type tFootnote = { NULL, 0, 0, };
47 * pFreeOneList - free a text block list
49 * Will always return NULL
51 static list_mem_type *
52 pFreeOneList(list_mem_type *pAnchor)
54 list_mem_type *pCurr, *pNext;
56 pCurr = pAnchor;
57 while (pCurr != NULL) {
58 pNext = pCurr->pNext;
59 pCurr = xfree(pCurr);
60 pCurr = pNext;
62 return NULL;
63 } /* end of pFreeOneList */
66 * vDestroyTextBlockList - destroy the text block lists
68 void
69 vDestroyTextBlockList(void)
71 DBG_MSG("vDestroyTextBlockList");
73 /* Free the lists one by one */
74 pTextAnchor = pFreeOneList(pTextAnchor);
75 pFootnoteAnchor = pFreeOneList(pFootnoteAnchor);
76 pHdrFtrAnchor = pFreeOneList(pHdrFtrAnchor);
77 pMacroAnchor = pFreeOneList(pMacroAnchor);
78 pAnnotationAnchor = pFreeOneList(pAnnotationAnchor);
79 pEndnoteAnchor = pFreeOneList(pEndnoteAnchor);
80 pTextBoxAnchor = pFreeOneList(pTextBoxAnchor);
81 pHdrTextBoxAnchor = pFreeOneList(pHdrTextBoxAnchor);
82 /* Reset all the controle variables */
83 pBlockLast = NULL;
84 tOthers.pBlockCurrent = NULL;
85 tHdrFtr.pBlockCurrent = NULL;
86 tFootnote.pBlockCurrent = NULL;
87 } /* end of vDestroyTextBlockList */
90 * bAdd2TextBlockList - add an element to the text block list
92 * returns: TRUE when successful, otherwise FALSE
94 BOOL
95 bAdd2TextBlockList(const text_block_type *pTextBlock)
97 list_mem_type *pListMember;
99 fail(pTextBlock == NULL);
100 fail(pTextBlock->ulFileOffset == FC_INVALID);
101 fail(pTextBlock->ulCharPos == CP_INVALID);
102 fail(pTextBlock->ulLength == 0);
103 fail(pTextBlock->bUsesUnicode && odd(pTextBlock->ulLength));
105 NO_DBG_MSG("bAdd2TextBlockList");
106 NO_DBG_HEX(pTextBlock->ulFileOffset);
107 NO_DBG_HEX(pTextBlock->ulCharPos);
108 NO_DBG_HEX(pTextBlock->ulLength);
109 NO_DBG_DEC(pTextBlock->bUsesUnicode);
110 NO_DBG_DEC(pTextBlock->usPropMod);
112 if (pTextBlock->ulFileOffset == FC_INVALID ||
113 pTextBlock->ulCharPos == CP_INVALID ||
114 pTextBlock->ulLength == 0 ||
115 (pTextBlock->bUsesUnicode && odd(pTextBlock->ulLength))) {
116 werr(0, "Software (textblock) error");
117 return FALSE;
120 * Check for continuous blocks of the same character size and
121 * the same properties modifier
123 if (pBlockLast != NULL &&
124 pBlockLast->tInfo.ulFileOffset +
125 pBlockLast->tInfo.ulLength == pTextBlock->ulFileOffset &&
126 pBlockLast->tInfo.ulCharPos +
127 pBlockLast->tInfo.ulLength == pTextBlock->ulCharPos &&
128 pBlockLast->tInfo.bUsesUnicode == pTextBlock->bUsesUnicode &&
129 pBlockLast->tInfo.usPropMod == pTextBlock->usPropMod) {
130 /* These are continous blocks */
131 pBlockLast->tInfo.ulLength += pTextBlock->ulLength;
132 return TRUE;
134 /* Make a new block */
135 pListMember = xmalloc(sizeof(list_mem_type));
136 /* Add the block to the list */
137 pListMember->tInfo = *pTextBlock;
138 pListMember->pNext = NULL;
139 if (pTextAnchor == NULL) {
140 pTextAnchor = pListMember;
141 } else {
142 fail(pBlockLast == NULL);
143 pBlockLast->pNext = pListMember;
145 pBlockLast = pListMember;
146 return TRUE;
147 } /* end of bAdd2TextBlockList */
150 * vSpitList - Split the list in two
152 static void
153 vSpitList(list_mem_type **ppAnchorCurr, list_mem_type **ppAnchorNext,
154 ULONG ulListLen)
156 list_mem_type *pCurr;
157 long lCharsToGo, lBytesTooFar;
159 fail(ppAnchorCurr == NULL);
160 fail(ppAnchorNext == NULL);
161 fail(ulListLen > (ULONG)LONG_MAX);
163 pCurr = NULL;
164 lCharsToGo = (long)ulListLen;
165 lBytesTooFar = -1;
166 if (ulListLen != 0) {
167 DBG_DEC(ulListLen);
168 for (pCurr = *ppAnchorCurr;
169 pCurr != NULL;
170 pCurr = pCurr->pNext) {
171 NO_DBG_DEC(pCurr->tInfo.ulLength);
172 fail(pCurr->tInfo.ulLength == 0);
173 fail(pCurr->tInfo.ulLength > (ULONG)LONG_MAX);
174 if (pCurr->tInfo.bUsesUnicode) {
175 fail(odd(pCurr->tInfo.ulLength));
176 lCharsToGo -= (long)(pCurr->tInfo.ulLength / 2);
177 if (lCharsToGo < 0) {
178 lBytesTooFar = -2 * lCharsToGo;
180 } else {
181 lCharsToGo -= (long)pCurr->tInfo.ulLength;
182 if (lCharsToGo < 0) {
183 lBytesTooFar = -lCharsToGo;
186 if (lCharsToGo <= 0) {
187 break;
191 /* Split the list */
192 if (ulListLen == 0) {
193 /* Current blocklist is empty */
194 *ppAnchorNext = *ppAnchorCurr;
195 *ppAnchorCurr = NULL;
196 } else if (pCurr == NULL) {
197 /* No blocks for the next list */
198 *ppAnchorNext = NULL;
199 } else if (lCharsToGo == 0) {
200 /* Move the integral number of blocks to the next list */
201 *ppAnchorNext = pCurr->pNext;
202 pCurr->pNext = NULL;
203 } else {
204 /* Split the part current block list, part next block list */
205 DBG_DEC(lBytesTooFar);
206 fail(lBytesTooFar <= 0);
207 *ppAnchorNext = xmalloc(sizeof(list_mem_type));
208 DBG_HEX(pCurr->tInfo.ulFileOffset);
209 (*ppAnchorNext)->tInfo.ulFileOffset =
210 pCurr->tInfo.ulFileOffset +
211 pCurr->tInfo.ulLength -
212 lBytesTooFar;
213 DBG_HEX((*ppAnchorNext)->tInfo.ulFileOffset);
214 DBG_HEX(pCurr->tInfo.ulCharPos);
215 (*ppAnchorNext)->tInfo.ulCharPos =
216 pCurr->tInfo.ulCharPos +
217 pCurr->tInfo.ulLength -
218 lBytesTooFar;
219 DBG_HEX((*ppAnchorNext)->tInfo.ulCharPos);
220 (*ppAnchorNext)->tInfo.ulLength = (ULONG)lBytesTooFar;
221 pCurr->tInfo.ulLength -= (ULONG)lBytesTooFar;
222 (*ppAnchorNext)->tInfo.bUsesUnicode = pCurr->tInfo.bUsesUnicode;
223 (*ppAnchorNext)->tInfo.usPropMod = pCurr->tInfo.usPropMod;
224 /* Move the integral number of blocks to the next list */
225 (*ppAnchorNext)->pNext = pCurr->pNext;
226 pCurr->pNext = NULL;
228 } /* end of vSpitList */
230 #if defined(DEBUG) || defined(__riscos)
232 * ulComputeListLength - compute the length of a list
234 * returns the list length in characters
236 static ULONG
237 ulComputeListLength(const list_mem_type *pAnchor)
239 const list_mem_type *pCurr;
240 ULONG ulTotal;
242 ulTotal = 0;
243 for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
244 fail(pCurr->tInfo.ulLength == 0);
245 if (pCurr->tInfo.bUsesUnicode) {
246 fail(odd(pCurr->tInfo.ulLength));
247 ulTotal += pCurr->tInfo.ulLength / 2;
248 } else {
249 ulTotal += pCurr->tInfo.ulLength;
252 return ulTotal;
253 } /* end of ulComputeListLength */
254 #endif /* DEBUG || __riscos */
256 #if defined(DEBUG)
258 * vCheckList - check the number of bytes in a block list
260 static void
261 vCheckList(const list_mem_type *pAnchor, ULONG ulListLen, char *szMsg)
263 ULONG ulTotal;
265 ulTotal = ulComputeListLength(pAnchor);
266 DBG_DEC(ulTotal);
267 if (ulTotal != ulListLen) {
268 DBG_DEC(ulListLen);
269 werr(1, szMsg);
271 } /* end of vCheckList */
272 #endif /* DEBUG */
275 * bIsEmptyBox - check to see if the given text box is empty
277 static BOOL
278 bIsEmptyBox(FILE *pFile, const list_mem_type *pAnchor)
280 const list_mem_type *pCurr;
281 size_t tIndex, tSize;
282 UCHAR *aucBuffer;
283 char cChar;
285 fail(pFile == NULL);
287 if (pAnchor == NULL) {
288 return TRUE;
291 aucBuffer = NULL;
292 for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
293 fail(pCurr->tInfo.ulLength == 0);
294 tSize = (size_t)pCurr->tInfo.ulLength;
295 #if defined(__dos) && !defined(__DJGPP__)
296 if (pCurr->tInfo.ulLength > 0xffffUL) {
297 tSize = 0xffff;
299 #endif /* __dos && !__DJGPP__ */
300 fail(aucBuffer != NULL);
301 aucBuffer = xmalloc(tSize);
302 if (!bReadBytes(aucBuffer, tSize,
303 pCurr->tInfo.ulFileOffset, pFile)) {
304 aucBuffer = xfree(aucBuffer);
305 return FALSE;
307 for (tIndex = 0; tIndex < tSize; tIndex++) {
308 cChar = (char)aucBuffer[tIndex];
309 switch (cChar) {
310 case '\0': case '\r': case '\n':
311 case '\f': case '\t': case '\v':
312 case ' ':
313 break;
314 default:
315 aucBuffer = xfree(aucBuffer);
316 return FALSE;
319 aucBuffer = xfree(aucBuffer);
321 fail(aucBuffer != NULL);
322 return TRUE;
323 } /* end of bIsEmptyBox */
326 * vSplitBlockList - split the block list in the various parts
328 * Split the blocklist in a Text block list, a Footnote block list, a
329 * HeaderFooter block list, a Macro block list, an Annotation block list,
330 * an Endnote block list, a TextBox list and a HeaderTextBox list.
332 * NOTE:
333 * The various ul*Len input parameters are given in characters, but the
334 * length of the blocks are in bytes.
336 void
337 vSplitBlockList(FILE *pFile, ULONG ulTextLen, ULONG ulFootnoteLen,
338 ULONG ulHdrFtrLen, ULONG ulMacroLen, ULONG ulAnnotationLen,
339 ULONG ulEndnoteLen, ULONG ulTextBoxLen, ULONG ulHdrTextBoxLen,
340 BOOL bMustExtend)
342 list_mem_type *apAnchors[8];
343 list_mem_type *pGarbageAnchor, *pCurr;
344 size_t tIndex;
346 DBG_MSG("vSplitBlockList");
348 pGarbageAnchor = NULL;
350 DBG_MSG_C(ulTextLen != 0, "Text block list");
351 vSpitList(&pTextAnchor, &pFootnoteAnchor, ulTextLen);
352 DBG_MSG_C(ulFootnoteLen != 0, "Footnote block list");
353 vSpitList(&pFootnoteAnchor, &pHdrFtrAnchor, ulFootnoteLen);
354 DBG_MSG_C(ulHdrFtrLen != 0, "Header/Footer block list");
355 vSpitList(&pHdrFtrAnchor, &pMacroAnchor, ulHdrFtrLen);
356 DBG_MSG_C(ulMacroLen != 0, "Macro block list");
357 vSpitList(&pMacroAnchor, &pAnnotationAnchor, ulMacroLen);
358 DBG_MSG_C(ulAnnotationLen != 0, "Annotation block list");
359 vSpitList(&pAnnotationAnchor, &pEndnoteAnchor, ulAnnotationLen);
360 DBG_MSG_C(ulEndnoteLen != 0, "Endnote block list");
361 vSpitList(&pEndnoteAnchor, &pTextBoxAnchor, ulEndnoteLen);
362 DBG_MSG_C(ulTextBoxLen != 0, "Textbox block list");
363 vSpitList(&pTextBoxAnchor, &pHdrTextBoxAnchor, ulTextBoxLen);
364 DBG_MSG_C(ulHdrTextBoxLen != 0, "HeaderTextbox block list");
365 vSpitList(&pHdrTextBoxAnchor, &pGarbageAnchor, ulHdrTextBoxLen);
367 /* Free the garbage block list, this should not be needed */
368 DBG_DEC_C(pGarbageAnchor != NULL, pGarbageAnchor->tInfo.ulLength);
369 pGarbageAnchor = pFreeOneList(pGarbageAnchor);
371 #if defined(DEBUG)
372 vCheckList(pTextAnchor, ulTextLen, "Software error (Text)");
373 vCheckList(pFootnoteAnchor, ulFootnoteLen, "Software error (Footnote)");
374 vCheckList(pHdrFtrAnchor, ulHdrFtrLen, "Software error (Hdr/Ftr)");
375 vCheckList(pMacroAnchor, ulMacroLen, "Software error (Macro)");
376 vCheckList(pAnnotationAnchor, ulAnnotationLen,
377 "Software error (Annotation)");
378 vCheckList(pEndnoteAnchor, ulEndnoteLen, "Software error (Endnote)");
379 vCheckList(pTextBoxAnchor, ulTextBoxLen, "Software error (TextBox)");
380 vCheckList(pHdrTextBoxAnchor, ulHdrTextBoxLen,
381 "Software error (HdrTextBox)");
382 #endif /* DEBUG */
384 /* Remove the list if the text box is empty */
385 if (bIsEmptyBox(pFile, pTextBoxAnchor)) {
386 pTextBoxAnchor = pFreeOneList(pTextBoxAnchor);
388 if (bIsEmptyBox(pFile, pHdrTextBoxAnchor)) {
389 pHdrTextBoxAnchor = pFreeOneList(pHdrTextBoxAnchor);
392 if (!bMustExtend) {
393 return;
396 * All blocks (except the last one) must have a length that
397 * is a multiple of the Big Block Size
400 apAnchors[0] = pTextAnchor;
401 apAnchors[1] = pFootnoteAnchor;
402 apAnchors[2] = pHdrFtrAnchor;
403 apAnchors[3] = pMacroAnchor;
404 apAnchors[4] = pAnnotationAnchor;
405 apAnchors[5] = pEndnoteAnchor;
406 apAnchors[6] = pTextBoxAnchor;
407 apAnchors[7] = pHdrTextBoxAnchor;
409 for (tIndex = 0; tIndex < elementsof(apAnchors); tIndex++) {
410 for (pCurr = apAnchors[tIndex];
411 pCurr != NULL;
412 pCurr = pCurr->pNext) {
413 if (pCurr->pNext != NULL &&
414 pCurr->tInfo.ulLength % BIG_BLOCK_SIZE != 0) {
415 DBG_DEC(tIndex);
416 DBG_HEX(pCurr->tInfo.ulFileOffset);
417 DBG_HEX(pCurr->tInfo.ulCharPos);
418 DBG_DEC(pCurr->tInfo.ulLength);
419 pCurr->tInfo.ulLength /= BIG_BLOCK_SIZE;
420 pCurr->tInfo.ulLength++;
421 pCurr->tInfo.ulLength *= BIG_BLOCK_SIZE;
422 DBG_DEC(pCurr->tInfo.ulLength);
426 } /* end of vSplitBlockList */
428 #if defined(__riscos)
430 * ulGetDocumentLength - get the total character length of the printable lists
432 * returns: The total number of characters
434 ULONG
435 ulGetDocumentLength(void)
437 long ulTotal;
439 DBG_MSG("ulGetDocumentLength");
441 ulTotal = ulComputeListLength(pTextAnchor);
442 ulTotal += ulComputeListLength(pFootnoteAnchor);
443 ulTotal += ulComputeListLength(pEndnoteAnchor);
444 ulTotal += ulComputeListLength(pTextBoxAnchor);
445 ulTotal += ulComputeListLength(pHdrTextBoxAnchor);
446 DBG_DEC(ulTotal);
447 return ulTotal;
448 } /* end of ulGetDocumentLength */
449 #endif /* __riscos */
451 #if 0
453 * bExistsHdrFtr - are there headers and/or footers?
455 BOOL
456 bExistsHdrFtr(void)
458 return pHdrFtrAnchor != NULL &&
459 pHdrFtrAnchor->tInfo.ulLength != 0;
460 } /* end of bExistsHdrFtr */
461 #endif
464 * bExistsTextBox - is there a text box?
466 BOOL
467 bExistsTextBox(void)
469 return pTextBoxAnchor != NULL &&
470 pTextBoxAnchor->tInfo.ulLength != 0;
471 } /* end of bExistsTextBox */
474 * bExistsHdrTextBox - is there a header text box?
476 BOOL
477 bExistsHdrTextBox(void)
479 return pHdrTextBoxAnchor != NULL &&
480 pHdrTextBoxAnchor->tInfo.ulLength != 0;
481 } /* end of bExistsHdrTextBox */
484 * usGetNextByte - get the next byte from the specified block list
486 static USHORT
487 usGetNextByte(FILE *pFile, readinfo_type *pInfoCurrent, list_mem_type *pAnchor,
488 ULONG *pulFileOffset, ULONG *pulCharPos, USHORT *pusPropMod)
490 ULONG ulReadOff;
491 size_t tReadLen;
493 fail(pInfoCurrent == NULL);
495 if (pInfoCurrent->pBlockCurrent == NULL ||
496 pInfoCurrent->tByteNext >= sizeof(pInfoCurrent->aucBlock) ||
497 pInfoCurrent->ulBlockOffset + pInfoCurrent->tByteNext >=
498 pInfoCurrent->pBlockCurrent->tInfo.ulLength) {
499 if (pInfoCurrent->pBlockCurrent == NULL) {
500 /* First block, first part */
501 pInfoCurrent->pBlockCurrent = pAnchor;
502 pInfoCurrent->ulBlockOffset = 0;
503 } else if (pInfoCurrent->ulBlockOffset +
504 sizeof(pInfoCurrent->aucBlock) <
505 pInfoCurrent->pBlockCurrent->tInfo.ulLength) {
506 /* Same block, next part */
507 pInfoCurrent->ulBlockOffset +=
508 sizeof(pInfoCurrent->aucBlock);
509 } else {
510 /* Next block, first part */
511 pInfoCurrent->pBlockCurrent =
512 pInfoCurrent->pBlockCurrent->pNext;
513 pInfoCurrent->ulBlockOffset = 0;
515 if (pInfoCurrent->pBlockCurrent == NULL) {
516 /* Past the last part of the last block */
517 return (USHORT)EOF;
519 tReadLen = (size_t)
520 (pInfoCurrent->pBlockCurrent->tInfo.ulLength -
521 pInfoCurrent->ulBlockOffset);
522 if (tReadLen > sizeof(pInfoCurrent->aucBlock)) {
523 tReadLen = sizeof(pInfoCurrent->aucBlock);
525 ulReadOff = pInfoCurrent->pBlockCurrent->tInfo.ulFileOffset +
526 pInfoCurrent->ulBlockOffset;
527 if (!bReadBytes(pInfoCurrent->aucBlock,
528 tReadLen, ulReadOff, pFile)) {
529 /* Don't read from this list any longer */
530 pInfoCurrent->pBlockCurrent = NULL;
531 return (USHORT)EOF;
533 pInfoCurrent->tByteNext = 0;
535 if (pulFileOffset != NULL) {
536 *pulFileOffset =
537 pInfoCurrent->pBlockCurrent->tInfo.ulFileOffset +
538 pInfoCurrent->ulBlockOffset +
539 pInfoCurrent->tByteNext;
541 if (pulCharPos != NULL) {
542 *pulCharPos =
543 pInfoCurrent->pBlockCurrent->tInfo.ulCharPos +
544 pInfoCurrent->ulBlockOffset +
545 pInfoCurrent->tByteNext;
547 if (pusPropMod != NULL) {
548 *pusPropMod = pInfoCurrent->pBlockCurrent->tInfo.usPropMod;
550 return (USHORT)pInfoCurrent->aucBlock[pInfoCurrent->tByteNext++];
551 } /* end of usGetNextByte */
555 * usGetNextChar - get the next character from the specified block list
557 static USHORT
558 usGetNextChar(FILE *pFile, list_id_enum eListID,
559 ULONG *pulFileOffset, ULONG *pulCharPos, USHORT *pusPropMod)
561 readinfo_type *pReadinfo;
562 list_mem_type *pAnchor;
563 USHORT usLSB, usMSB;
565 switch (eListID) {
566 case text_list:
567 pReadinfo = &tOthers;
568 pAnchor = pTextAnchor;
569 break;
570 case footnote_list:
571 pReadinfo = &tFootnote;
572 pAnchor = pFootnoteAnchor;
573 break;
574 case hdrftr_list:
575 pReadinfo = &tHdrFtr;
576 pAnchor = pHdrFtrAnchor;
577 break;
578 case endnote_list:
579 pReadinfo = &tOthers;
580 pAnchor = pEndnoteAnchor;
581 break;
582 case textbox_list:
583 pReadinfo = &tOthers;
584 pAnchor = pTextBoxAnchor;
585 break;
586 case hdrtextbox_list:
587 pReadinfo = &tOthers;
588 pAnchor = pHdrTextBoxAnchor;
589 break;
590 default:
591 DBG_DEC(eListID);
592 return (USHORT)EOF;
595 usLSB = usGetNextByte(pFile, pReadinfo, pAnchor,
596 pulFileOffset, pulCharPos, pusPropMod);
597 if (usLSB == (USHORT)EOF) {
598 return (USHORT)EOF;
600 fail(pReadinfo->pBlockCurrent == NULL);
602 if (pReadinfo->pBlockCurrent->tInfo.bUsesUnicode) {
603 usMSB = usGetNextByte(pFile,
604 pReadinfo, pAnchor, NULL, NULL, NULL);
605 } else {
606 usMSB = 0x00;
608 if (usMSB == (USHORT)EOF) {
609 DBG_MSG("usGetNextChar: Unexpected EOF");
610 DBG_HEX_C(pulFileOffset != NULL, *pulFileOffset);
611 DBG_HEX_C(pulCharPos != NULL, *pulCharPos);
612 return (USHORT)EOF;
614 return (usMSB << 8) | usLSB;
615 } /* end of usGetNextChar */
618 * usNextChar - get the next character from the given block list
620 USHORT
621 usNextChar(FILE *pFile, list_id_enum eListID,
622 ULONG *pulFileOffset, ULONG *pulCharPos, USHORT *pusPropMod)
624 USHORT usRetVal;
626 fail(pFile == NULL);
628 usRetVal = usGetNextChar(pFile, eListID,
629 pulFileOffset, pulCharPos, pusPropMod);
630 if (usRetVal == (USHORT)EOF) {
631 if (pulFileOffset != NULL) {
632 *pulFileOffset = FC_INVALID;
634 if (pulCharPos != NULL) {
635 *pulCharPos = CP_INVALID;
637 if (pusPropMod != NULL) {
638 *pusPropMod = IGNORE_PROPMOD;
641 return usRetVal;
642 } /* end of usNextChar */
645 * usToHdrFtrPosition - Go to a character position in header/foorter list
647 * Returns the character found on the specified character position
649 USHORT
650 usToHdrFtrPosition(FILE *pFile, ULONG ulCharPos)
652 ULONG ulCharPosCurr;
653 USHORT usChar;
655 tHdrFtr.pBlockCurrent = NULL; /* To reset the header/footer list */
656 do {
657 usChar = usNextChar(pFile,
658 hdrftr_list, NULL, &ulCharPosCurr, NULL);
659 } while (usChar != (USHORT)EOF && ulCharPosCurr != ulCharPos);
660 return usChar;
661 } /* end of usToHdrFtrPosition */
664 * usToFootnotePosition - Go to a character position in footnote list
666 * Returns the character found on the specified character position
668 USHORT
669 usToFootnotePosition(FILE *pFile, ULONG ulCharPos)
671 ULONG ulCharPosCurr;
672 USHORT usChar;
674 tFootnote.pBlockCurrent = NULL; /* To reset the footnote list */
675 do {
676 usChar = usNextChar(pFile,
677 footnote_list, NULL, &ulCharPosCurr, NULL);
678 } while (usChar != (USHORT)EOF && ulCharPosCurr != ulCharPos);
679 return usChar;
680 } /* end of usToFootnotePosition */
683 * Convert a character position to an offset in the file.
684 * Logical to physical offset.
686 * Returns: FC_INVALID: in case of error
687 * otherwise: the computed file offset
689 ULONG
690 ulCharPos2FileOffsetX(ULONG ulCharPos, list_id_enum *peListID)
692 static list_id_enum eListIDs[8] = {
693 text_list, footnote_list, hdrftr_list,
694 macro_list, annotation_list, endnote_list,
695 textbox_list, hdrtextbox_list,
697 list_mem_type *apAnchors[8];
698 list_mem_type *pCurr;
699 list_id_enum eListGuess;
700 ULONG ulBestGuess;
701 size_t tIndex;
703 fail(peListID == NULL);
705 if (ulCharPos == CP_INVALID) {
706 *peListID = no_list;
707 return FC_INVALID;
710 apAnchors[0] = pTextAnchor;
711 apAnchors[1] = pFootnoteAnchor;
712 apAnchors[2] = pHdrFtrAnchor;
713 apAnchors[3] = pMacroAnchor;
714 apAnchors[4] = pAnnotationAnchor;
715 apAnchors[5] = pEndnoteAnchor;
716 apAnchors[6] = pTextBoxAnchor;
717 apAnchors[7] = pHdrTextBoxAnchor;
719 eListGuess = no_list; /* Best guess is no list */
720 ulBestGuess = FC_INVALID; /* Best guess is "file offset not found" */
722 for (tIndex = 0; tIndex < elementsof(apAnchors); tIndex++) {
723 for (pCurr = apAnchors[tIndex];
724 pCurr != NULL;
725 pCurr = pCurr->pNext) {
726 if (ulCharPos == pCurr->tInfo.ulCharPos +
727 pCurr->tInfo.ulLength &&
728 pCurr->pNext != NULL) {
730 * The character position is one beyond this
731 * block, so we guess it's the first byte of
732 * the next block (if there is a next block)
734 eListGuess= eListIDs[tIndex];
735 ulBestGuess = pCurr->pNext->tInfo.ulFileOffset;
738 if (ulCharPos < pCurr->tInfo.ulCharPos ||
739 ulCharPos >= pCurr->tInfo.ulCharPos +
740 pCurr->tInfo.ulLength) {
741 /* Character position is not in this block */
742 continue;
745 /* The character position is in the current block */
746 *peListID = eListIDs[tIndex];
747 return pCurr->tInfo.ulFileOffset +
748 ulCharPos - pCurr->tInfo.ulCharPos;
751 /* Passed beyond the end of the last list */
752 NO_DBG_HEX(ulCharPos);
753 NO_DBG_HEX(ulBestGuess);
754 *peListID = eListGuess;
755 return ulBestGuess;
756 } /* end of ulCharPos2FileOffsetX */
759 * Convert a character position to an offset in the file.
760 * Logical to physical offset.
762 * Returns: FC_INVALID: in case of error
763 * otherwise: the computed file offset
765 ULONG
766 ulCharPos2FileOffset(ULONG ulCharPos)
768 list_id_enum eListID;
770 return ulCharPos2FileOffsetX(ulCharPos, &eListID);
771 } /* end of ulCharPos2FileOffset */
774 * Convert an offset in the header/footer list to a character position.
776 * Returns: CP_INVALID: in case of error
777 * otherwise: the computed character position
779 ULONG
780 ulHdrFtrOffset2CharPos(ULONG ulHdrFtrOffset)
782 list_mem_type *pCurr;
783 ULONG ulOffset;
785 ulOffset = ulHdrFtrOffset;
786 for (pCurr = pHdrFtrAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
787 if (ulOffset >= pCurr->tInfo.ulLength) {
788 /* The offset is not in this block */
789 ulOffset -= pCurr->tInfo.ulLength;
790 continue;
792 return pCurr->tInfo.ulCharPos + ulOffset;
794 return CP_INVALID;
795 } /* end of ulHdrFtrOffset2CharPos */
798 * Get the sequence number beloning to the given file offset
800 * Returns the sequence number
802 ULONG
803 ulGetSeqNumber(ULONG ulFileOffset)
805 list_mem_type *pCurr;
806 ULONG ulSeq;
808 if (ulFileOffset == FC_INVALID) {
809 return FC_INVALID;
812 ulSeq = 0;
813 for (pCurr = pTextAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
814 if (ulFileOffset >= pCurr->tInfo.ulFileOffset &&
815 ulFileOffset < pCurr->tInfo.ulFileOffset +
816 pCurr->tInfo.ulLength) {
817 /* The file offset is within the current textblock */
818 return ulSeq + ulFileOffset - pCurr->tInfo.ulFileOffset;
820 ulSeq += pCurr->tInfo.ulLength;
822 return FC_INVALID;
823 } /* end of ulGetSeqNumber */