3 * Copyright (C) 1998-2005 A.J. van Os; Released under GNU GPL
6 * Build, read and destroy the lists of Word "text" blocks
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
;
22 typedef struct readinfo_tag
{
23 list_mem_type
*pBlockCurrent
;
26 UCHAR aucBlock
[BIG_BLOCK_SIZE
];
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
;
57 while (pCurr
!= NULL
) {
63 } /* end of pFreeOneList */
66 * vDestroyTextBlockList - destroy the text block lists
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 */
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
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");
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
;
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
;
142 fail(pBlockLast
== NULL
);
143 pBlockLast
->pNext
= pListMember
;
145 pBlockLast
= pListMember
;
147 } /* end of bAdd2TextBlockList */
150 * vSpitList - Split the list in two
153 vSpitList(list_mem_type
**ppAnchorCurr
, list_mem_type
**ppAnchorNext
,
156 list_mem_type
*pCurr
;
157 long lCharsToGo
, lBytesTooFar
;
159 fail(ppAnchorCurr
== NULL
);
160 fail(ppAnchorNext
== NULL
);
161 fail(ulListLen
> (ULONG
)LONG_MAX
);
164 lCharsToGo
= (long)ulListLen
;
166 if (ulListLen
!= 0) {
168 for (pCurr
= *ppAnchorCurr
;
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
;
181 lCharsToGo
-= (long)pCurr
->tInfo
.ulLength
;
182 if (lCharsToGo
< 0) {
183 lBytesTooFar
= -lCharsToGo
;
186 if (lCharsToGo
<= 0) {
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
;
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
-
213 DBG_HEX((*ppAnchorNext
)->tInfo
.ulFileOffset
);
214 DBG_HEX(pCurr
->tInfo
.ulCharPos
);
215 (*ppAnchorNext
)->tInfo
.ulCharPos
=
216 pCurr
->tInfo
.ulCharPos
+
217 pCurr
->tInfo
.ulLength
-
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
;
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
237 ulComputeListLength(const list_mem_type
*pAnchor
)
239 const list_mem_type
*pCurr
;
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;
249 ulTotal
+= pCurr
->tInfo
.ulLength
;
253 } /* end of ulComputeListLength */
254 #endif /* DEBUG || __riscos */
258 * vCheckList - check the number of bytes in a block list
261 vCheckList(const list_mem_type
*pAnchor
, ULONG ulListLen
, char *szMsg
)
265 ulTotal
= ulComputeListLength(pAnchor
);
267 if (ulTotal
!= ulListLen
) {
271 } /* end of vCheckList */
275 * bIsEmptyBox - check to see if the given text box is empty
278 bIsEmptyBox(FILE *pFile
, const list_mem_type
*pAnchor
)
280 const list_mem_type
*pCurr
;
281 size_t tIndex
, tSize
;
287 if (pAnchor
== 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
) {
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
);
307 for (tIndex
= 0; tIndex
< tSize
; tIndex
++) {
308 cChar
= (char)aucBuffer
[tIndex
];
310 case '\0': case '\r': case '\n':
311 case '\f': case '\t': case '\v':
315 aucBuffer
= xfree(aucBuffer
);
319 aucBuffer
= xfree(aucBuffer
);
321 fail(aucBuffer
!= NULL
);
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.
333 * The various ul*Len input parameters are given in characters, but the
334 * length of the blocks are in bytes.
337 vSplitBlockList(FILE *pFile
, ULONG ulTextLen
, ULONG ulFootnoteLen
,
338 ULONG ulHdrFtrLen
, ULONG ulMacroLen
, ULONG ulAnnotationLen
,
339 ULONG ulEndnoteLen
, ULONG ulTextBoxLen
, ULONG ulHdrTextBoxLen
,
342 list_mem_type
*apAnchors
[8];
343 list_mem_type
*pGarbageAnchor
, *pCurr
;
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
);
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)");
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
);
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
];
412 pCurr
= pCurr
->pNext
) {
413 if (pCurr
->pNext
!= NULL
&&
414 pCurr
->tInfo
.ulLength
% BIG_BLOCK_SIZE
!= 0) {
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
435 ulGetDocumentLength(void)
439 DBG_MSG("ulGetDocumentLength");
441 ulTotal
= ulComputeListLength(pTextAnchor
);
442 ulTotal
+= ulComputeListLength(pFootnoteAnchor
);
443 ulTotal
+= ulComputeListLength(pEndnoteAnchor
);
444 ulTotal
+= ulComputeListLength(pTextBoxAnchor
);
445 ulTotal
+= ulComputeListLength(pHdrTextBoxAnchor
);
448 } /* end of ulGetDocumentLength */
449 #endif /* __riscos */
453 * bExistsHdrFtr - are there headers and/or footers?
458 return pHdrFtrAnchor
!= NULL
&&
459 pHdrFtrAnchor
->tInfo
.ulLength
!= 0;
460 } /* end of bExistsHdrFtr */
464 * bExistsTextBox - is there a text box?
469 return pTextBoxAnchor
!= NULL
&&
470 pTextBoxAnchor
->tInfo
.ulLength
!= 0;
471 } /* end of bExistsTextBox */
474 * bExistsHdrTextBox - is there a header text box?
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
487 usGetNextByte(FILE *pFile
, readinfo_type
*pInfoCurrent
, list_mem_type
*pAnchor
,
488 ULONG
*pulFileOffset
, ULONG
*pulCharPos
, USHORT
*pusPropMod
)
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
);
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 */
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
;
533 pInfoCurrent
->tByteNext
= 0;
535 if (pulFileOffset
!= NULL
) {
537 pInfoCurrent
->pBlockCurrent
->tInfo
.ulFileOffset
+
538 pInfoCurrent
->ulBlockOffset
+
539 pInfoCurrent
->tByteNext
;
541 if (pulCharPos
!= NULL
) {
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
558 usGetNextChar(FILE *pFile
, list_id_enum eListID
,
559 ULONG
*pulFileOffset
, ULONG
*pulCharPos
, USHORT
*pusPropMod
)
561 readinfo_type
*pReadinfo
;
562 list_mem_type
*pAnchor
;
567 pReadinfo
= &tOthers
;
568 pAnchor
= pTextAnchor
;
571 pReadinfo
= &tFootnote
;
572 pAnchor
= pFootnoteAnchor
;
575 pReadinfo
= &tHdrFtr
;
576 pAnchor
= pHdrFtrAnchor
;
579 pReadinfo
= &tOthers
;
580 pAnchor
= pEndnoteAnchor
;
583 pReadinfo
= &tOthers
;
584 pAnchor
= pTextBoxAnchor
;
586 case hdrtextbox_list
:
587 pReadinfo
= &tOthers
;
588 pAnchor
= pHdrTextBoxAnchor
;
595 usLSB
= usGetNextByte(pFile
, pReadinfo
, pAnchor
,
596 pulFileOffset
, pulCharPos
, pusPropMod
);
597 if (usLSB
== (USHORT
)EOF
) {
600 fail(pReadinfo
->pBlockCurrent
== NULL
);
602 if (pReadinfo
->pBlockCurrent
->tInfo
.bUsesUnicode
) {
603 usMSB
= usGetNextByte(pFile
,
604 pReadinfo
, pAnchor
, NULL
, NULL
, NULL
);
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
);
614 return (usMSB
<< 8) | usLSB
;
615 } /* end of usGetNextChar */
618 * usNextChar - get the next character from the given block list
621 usNextChar(FILE *pFile
, list_id_enum eListID
,
622 ULONG
*pulFileOffset
, ULONG
*pulCharPos
, USHORT
*pusPropMod
)
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
;
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
650 usToHdrFtrPosition(FILE *pFile
, ULONG ulCharPos
)
655 tHdrFtr
.pBlockCurrent
= NULL
; /* To reset the header/footer list */
657 usChar
= usNextChar(pFile
,
658 hdrftr_list
, NULL
, &ulCharPosCurr
, NULL
);
659 } while (usChar
!= (USHORT
)EOF
&& ulCharPosCurr
!= ulCharPos
);
661 } /* end of usToHdrFtrPosition */
664 * usToFootnotePosition - Go to a character position in footnote list
666 * Returns the character found on the specified character position
669 usToFootnotePosition(FILE *pFile
, ULONG ulCharPos
)
674 tFootnote
.pBlockCurrent
= NULL
; /* To reset the footnote list */
676 usChar
= usNextChar(pFile
,
677 footnote_list
, NULL
, &ulCharPosCurr
, NULL
);
678 } while (usChar
!= (USHORT
)EOF
&& ulCharPosCurr
!= ulCharPos
);
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
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
;
703 fail(peListID
== NULL
);
705 if (ulCharPos
== CP_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
];
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 */
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
;
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
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
780 ulHdrFtrOffset2CharPos(ULONG ulHdrFtrOffset
)
782 list_mem_type
*pCurr
;
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
;
792 return pCurr
->tInfo
.ulCharPos
+ ulOffset
;
795 } /* end of ulHdrFtrOffset2CharPos */
798 * Get the sequence number beloning to the given file offset
800 * Returns the sequence number
803 ulGetSeqNumber(ULONG ulFileOffset
)
805 list_mem_type
*pCurr
;
808 if (ulFileOffset
== FC_INVALID
) {
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
;
823 } /* end of ulGetSeqNumber */