Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * blocklist.c
3
 * Copyright (C) 1998-2005 A.J. van Os; Released under GNU GPL
4
 *
5
 * Description:
6
 * Build, read and destroy the lists 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
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;
28
 
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, };
44
 
45
 
46
/*
47
 * pFreeOneList - free a text block list
48
 *
49
 * Will always return NULL
50
 */
51
static list_mem_type *
52
pFreeOneList(list_mem_type *pAnchor)
53
{
54
	list_mem_type	*pCurr, *pNext;
55
 
56
	pCurr = pAnchor;
57
	while (pCurr != NULL) {
58
		pNext = pCurr->pNext;
59
		pCurr = xfree(pCurr);
60
		pCurr = pNext;
61
	}
62
	return NULL;
63
} /* end of pFreeOneList */
64
 
65
/*
66
 * vDestroyTextBlockList - destroy the text block lists
67
 */
68
void
69
vDestroyTextBlockList(void)
70
{
71
	DBG_MSG("vDestroyTextBlockList");
72
 
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 */
88
 
89
/*
90
 * bAdd2TextBlockList - add an element to the text block list
91
 *
92
 * returns: TRUE when successful, otherwise FALSE
93
 */
94
BOOL
95
bAdd2TextBlockList(const text_block_type *pTextBlock)
96
{
97
	list_mem_type	*pListMember;
98
 
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));
104
 
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);
111
 
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;
118
	}
119
	/*
120
	 * Check for continuous blocks of the same character size and
121
	 * the same properties modifier
122
	 */
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;
133
	}
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;
144
	}
145
	pBlockLast = pListMember;
146
	return TRUE;
147
} /* end of bAdd2TextBlockList */
148
 
149
/*
150
 * vSpitList - Split the list in two
151
 */
152
static void
153
vSpitList(list_mem_type **ppAnchorCurr, list_mem_type **ppAnchorNext,
154
	ULONG ulListLen)
155
{
156
	list_mem_type	*pCurr;
157
	long		lCharsToGo, lBytesTooFar;
158
 
159
	fail(ppAnchorCurr == NULL);
160
	fail(ppAnchorNext == NULL);
161
	fail(ulListLen > (ULONG)LONG_MAX);
162
 
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;
179
				}
180
			} else {
181
				lCharsToGo -= (long)pCurr->tInfo.ulLength;
182
				if (lCharsToGo < 0) {
183
					lBytesTooFar = -lCharsToGo;
184
				}
185
			}
186
			if (lCharsToGo <= 0) {
187
				break;
188
			}
189
		}
190
	}
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;
227
	}
228
} /* end of vSpitList */
229
 
230
#if defined(DEBUG) || defined(__riscos)
231
/*
232
 * ulComputeListLength - compute the length of a list
233
 *
234
 * returns the list length in characters
235
 */
236
static ULONG
237
ulComputeListLength(const list_mem_type *pAnchor)
238
{
239
	const list_mem_type	*pCurr;
240
	ULONG		ulTotal;
241
 
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;
250
		}
251
	}
252
	return ulTotal;
253
} /* end of ulComputeListLength */
254
#endif /* DEBUG || __riscos */
255
 
256
#if defined(DEBUG)
257
/*
258
 * vCheckList - check the number of bytes in a block list
259
 */
260
static void
261
vCheckList(const list_mem_type *pAnchor, ULONG ulListLen, char *szMsg)
262
{
263
	ULONG		ulTotal;
264
 
265
	ulTotal = ulComputeListLength(pAnchor);
266
	DBG_DEC(ulTotal);
267
	if (ulTotal != ulListLen) {
268
		DBG_DEC(ulListLen);
269
		werr(1, szMsg);
270
	}
271
} /* end of vCheckList */
272
#endif /* DEBUG */
273
 
274
/*
275
 * bIsEmptyBox - check to see if the given text box is empty
276
 */
277
static BOOL
278
bIsEmptyBox(FILE *pFile, const list_mem_type *pAnchor)
279
{
280
	const list_mem_type	*pCurr;
281
	size_t	tIndex, tSize;
282
	UCHAR	*aucBuffer;
283
	char	cChar;
284
 
285
	fail(pFile == NULL);
286
 
287
	if (pAnchor == NULL) {
288
		return TRUE;
289
	}
290
 
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;
298
		}
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;
306
		}
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;
317
			}
318
		}
319
		aucBuffer = xfree(aucBuffer);
320
	}
321
	fail(aucBuffer != NULL);
322
	return TRUE;
323
} /* end of bIsEmptyBox */
324
 
325
/*
326
 * vSplitBlockList - split the block list in the various parts
327
 *
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.
331
 *
332
 * NOTE:
333
 * The various ul*Len input parameters are given in characters, but the
334
 * length of the blocks are in bytes.
335
 */
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)
341
{
342
	list_mem_type	*apAnchors[8];
343
	list_mem_type	*pGarbageAnchor, *pCurr;
344
	size_t		tIndex;
345
 
346
	DBG_MSG("vSplitBlockList");
347
 
348
	pGarbageAnchor = NULL;
349
 
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);
366
 
367
	/* Free the garbage block list, this should not be needed */
368
	DBG_DEC_C(pGarbageAnchor != NULL, pGarbageAnchor->tInfo.ulLength);
369
	pGarbageAnchor = pFreeOneList(pGarbageAnchor);
370
 
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 */
383
 
384
	/* Remove the list if the text box is empty */
385
	if (bIsEmptyBox(pFile, pTextBoxAnchor)) {
386
		pTextBoxAnchor = pFreeOneList(pTextBoxAnchor);
387
	}
388
	if (bIsEmptyBox(pFile, pHdrTextBoxAnchor)) {
389
		pHdrTextBoxAnchor = pFreeOneList(pHdrTextBoxAnchor);
390
	}
391
 
392
	if (!bMustExtend) {
393
		return;
394
	}
395
	/*
396
	 * All blocks (except the last one) must have a length that
397
	 * is a multiple of the Big Block Size
398
	 */
399
 
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;
408
 
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);
423
			}
424
		}
425
	}
426
} /* end of vSplitBlockList */
427
 
428
#if defined(__riscos)
429
/*
430
 * ulGetDocumentLength - get the total character length of the printable lists
431
 *
432
 * returns: The total number of characters
433
 */
434
ULONG
435
ulGetDocumentLength(void)
436
{
437
	long		ulTotal;
438
 
439
	DBG_MSG("ulGetDocumentLength");
440
 
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 */
450
 
451
#if 0
452
/*
453
 * bExistsHdrFtr - are there headers and/or footers?
454
 */
455
BOOL
456
bExistsHdrFtr(void)
457
{
458
	return pHdrFtrAnchor != NULL &&
459
		pHdrFtrAnchor->tInfo.ulLength != 0;
460
} /* end of bExistsHdrFtr */
461
#endif
462
 
463
/*
464
 * bExistsTextBox - is there a text box?
465
 */
466
BOOL
467
bExistsTextBox(void)
468
{
469
	return pTextBoxAnchor != NULL &&
470
		pTextBoxAnchor->tInfo.ulLength != 0;
471
} /* end of bExistsTextBox */
472
 
473
/*
474
 * bExistsHdrTextBox - is there a header text box?
475
 */
476
BOOL
477
bExistsHdrTextBox(void)
478
{
479
	return pHdrTextBoxAnchor != NULL &&
480
		pHdrTextBoxAnchor->tInfo.ulLength != 0;
481
} /* end of bExistsHdrTextBox */
482
 
483
/*
484
 * usGetNextByte - get the next byte from the specified block list
485
 */
486
static USHORT
487
usGetNextByte(FILE *pFile, readinfo_type *pInfoCurrent, list_mem_type *pAnchor,
488
	ULONG *pulFileOffset, ULONG *pulCharPos, USHORT *pusPropMod)
489
{
490
	ULONG	ulReadOff;
491
	size_t	tReadLen;
492
 
493
	fail(pInfoCurrent == NULL);
494
 
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;
514
		}
515
		if (pInfoCurrent->pBlockCurrent == NULL) {
516
			/* Past the last part of the last block */
517
			return (USHORT)EOF;
518
		}
519
		tReadLen = (size_t)
520
			(pInfoCurrent->pBlockCurrent->tInfo.ulLength -
521
			 pInfoCurrent->ulBlockOffset);
522
		if (tReadLen > sizeof(pInfoCurrent->aucBlock)) {
523
			tReadLen = sizeof(pInfoCurrent->aucBlock);
524
		}
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;
532
		}
533
		pInfoCurrent->tByteNext = 0;
534
	}
535
	if (pulFileOffset != NULL) {
536
		*pulFileOffset =
537
			pInfoCurrent->pBlockCurrent->tInfo.ulFileOffset +
538
			pInfoCurrent->ulBlockOffset +
539
			pInfoCurrent->tByteNext;
540
	}
541
	if (pulCharPos != NULL) {
542
		*pulCharPos =
543
			pInfoCurrent->pBlockCurrent->tInfo.ulCharPos +
544
			pInfoCurrent->ulBlockOffset +
545
			pInfoCurrent->tByteNext;
546
	}
547
	if (pusPropMod != NULL) {
548
		*pusPropMod = pInfoCurrent->pBlockCurrent->tInfo.usPropMod;
549
	}
550
	return (USHORT)pInfoCurrent->aucBlock[pInfoCurrent->tByteNext++];
551
} /* end of usGetNextByte */
552
 
553
 
554
/*
555
 * usGetNextChar - get the next character from the specified block list
556
 */
557
static USHORT
558
usGetNextChar(FILE *pFile, list_id_enum eListID,
559
	ULONG *pulFileOffset, ULONG *pulCharPos, USHORT *pusPropMod)
560
{
561
	readinfo_type	*pReadinfo;
562
	list_mem_type	*pAnchor;
563
	USHORT	usLSB, usMSB;
564
 
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;
593
	}
594
 
595
	usLSB = usGetNextByte(pFile, pReadinfo, pAnchor,
596
				pulFileOffset, pulCharPos, pusPropMod);
597
	if (usLSB == (USHORT)EOF) {
598
		return (USHORT)EOF;
599
	}
600
	fail(pReadinfo->pBlockCurrent == NULL);
601
 
602
	if (pReadinfo->pBlockCurrent->tInfo.bUsesUnicode) {
603
		usMSB = usGetNextByte(pFile,
604
				pReadinfo, pAnchor, NULL, NULL, NULL);
605
	} else {
606
		usMSB = 0x00;
607
	}
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;
613
	}
614
	return (usMSB << 8) | usLSB;
615
} /* end of usGetNextChar */
616
 
617
/*
618
 * usNextChar - get the next character from the given block list
619
 */
620
USHORT
621
usNextChar(FILE *pFile, list_id_enum eListID,
622
	ULONG *pulFileOffset, ULONG *pulCharPos, USHORT *pusPropMod)
623
{
624
	USHORT	usRetVal;
625
 
626
	fail(pFile == NULL);
627
 
628
	usRetVal = usGetNextChar(pFile, eListID,
629
				pulFileOffset, pulCharPos, pusPropMod);
630
	if (usRetVal == (USHORT)EOF) {
631
		if (pulFileOffset != NULL) {
632
			*pulFileOffset = FC_INVALID;
633
		}
634
		if (pulCharPos != NULL) {
635
			*pulCharPos = CP_INVALID;
636
		}
637
		if (pusPropMod != NULL) {
638
			*pusPropMod = IGNORE_PROPMOD;
639
		}
640
	}
641
	return usRetVal;
642
} /* end of usNextChar */
643
 
644
/*
645
 * usToHdrFtrPosition - Go to a character position in header/foorter list
646
 *
647
 * Returns the character found on the specified character position
648
 */
649
USHORT
650
usToHdrFtrPosition(FILE *pFile, ULONG ulCharPos)
651
{
652
	ULONG	ulCharPosCurr;
653
	USHORT	usChar;
654
 
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 */
662
 
663
/*
664
 * usToFootnotePosition - Go to a character position in footnote list
665
 *
666
 * Returns the character found on the specified character position
667
 */
668
USHORT
669
usToFootnotePosition(FILE *pFile, ULONG ulCharPos)
670
{
671
	ULONG	ulCharPosCurr;
672
	USHORT	usChar;
673
 
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 */
681
 
682
/*
683
 * Convert a character position to an offset in the file.
684
 * Logical to physical offset.
685
 *
686
 * Returns:	FC_INVALID: in case of error
687
 *		otherwise: the computed file offset
688
 */
689
ULONG
690
ulCharPos2FileOffsetX(ULONG ulCharPos, list_id_enum *peListID)
691
{
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,
696
	};
697
	list_mem_type	*apAnchors[8];
698
	list_mem_type	*pCurr;
699
	list_id_enum	eListGuess;
700
	ULONG		ulBestGuess;
701
	size_t		tIndex;
702
 
703
	fail(peListID == NULL);
704
 
705
	if (ulCharPos == CP_INVALID) {
706
		*peListID = no_list;
707
		return FC_INVALID;
708
	}
709
 
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;
718
 
719
	eListGuess = no_list;	  /* Best guess is no list */
720
	ulBestGuess = FC_INVALID; /* Best guess is "file offset not found" */
721
 
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) {
729
				/*
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)
733
				 */
734
				eListGuess= eListIDs[tIndex];
735
				ulBestGuess = pCurr->pNext->tInfo.ulFileOffset;
736
			}
737
 
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;
743
			}
744
 
745
			/* The character position is in the current block */
746
			*peListID = eListIDs[tIndex];
747
			return pCurr->tInfo.ulFileOffset +
748
				ulCharPos - pCurr->tInfo.ulCharPos;
749
		}
750
	}
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 */
757
 
758
/*
759
 * Convert a character position to an offset in the file.
760
 * Logical to physical offset.
761
 *
762
 * Returns:	FC_INVALID: in case of error
763
 *		otherwise: the computed file offset
764
 */
765
ULONG
766
ulCharPos2FileOffset(ULONG ulCharPos)
767
{
768
	list_id_enum	eListID;
769
 
770
	return ulCharPos2FileOffsetX(ulCharPos, &eListID);
771
} /* end of ulCharPos2FileOffset */
772
 
773
/*
774
 * Convert an offset in the header/footer list to a character position.
775
 *
776
 * Returns:	CP_INVALID: in case of error
777
 *		otherwise: the computed character position
778
 */
779
ULONG
780
ulHdrFtrOffset2CharPos(ULONG ulHdrFtrOffset)
781
{
782
	list_mem_type	*pCurr;
783
	ULONG		ulOffset;
784
 
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;
791
		}
792
		return pCurr->tInfo.ulCharPos + ulOffset;
793
	}
794
	return CP_INVALID;
795
} /* end of ulHdrFtrOffset2CharPos */
796
 
797
/*
798
 * Get the sequence number beloning to the given file offset
799
 *
800
 * Returns the sequence number
801
 */
802
ULONG
803
ulGetSeqNumber(ULONG ulFileOffset)
804
{
805
	list_mem_type	*pCurr;
806
	ULONG		ulSeq;
807
 
808
	if (ulFileOffset == FC_INVALID) {
809
		return FC_INVALID;
810
	}
811
 
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;
819
		}
820
		ulSeq += pCurr->tInfo.ulLength;
821
	}
822
	return FC_INVALID;
823
} /* end of ulGetSeqNumber */