xref: /plan9/sys/src/cmd/aux/antiword/listlist.c (revision f5736e95f14e1485b3a0291fa82d86cca323ab61)
1*f5736e95SDavid du Colombier /*
2*f5736e95SDavid du Colombier  * listlist.c
3*f5736e95SDavid du Colombier  * Copyright (C) 2002,2003 A.J. van Os; Released under GPL
4*f5736e95SDavid du Colombier  *
5*f5736e95SDavid du Colombier  * Description:
6*f5736e95SDavid du Colombier  * Build, read and destroy a list of Word list information
7*f5736e95SDavid du Colombier  *
8*f5736e95SDavid du Colombier  * Note:
9*f5736e95SDavid du Colombier  * This list only exists when the Word document is saved by Word 8 or later
10*f5736e95SDavid du Colombier  */
11*f5736e95SDavid du Colombier 
12*f5736e95SDavid du Colombier #include "antiword.h"
13*f5736e95SDavid du Colombier 
14*f5736e95SDavid du Colombier /*
15*f5736e95SDavid du Colombier  * Private structure to hide the way the information
16*f5736e95SDavid du Colombier  * is stored from the rest of the program
17*f5736e95SDavid du Colombier  */
18*f5736e95SDavid du Colombier typedef struct list_desc_tag {
19*f5736e95SDavid du Colombier 	list_block_type		tInfo;
20*f5736e95SDavid du Colombier 	ULONG			ulListID;
21*f5736e95SDavid du Colombier 	USHORT			usIstd;
22*f5736e95SDavid du Colombier 	UCHAR			ucListLevel;
23*f5736e95SDavid du Colombier 	struct list_desc_tag	*pNext;
24*f5736e95SDavid du Colombier } list_desc_type;
25*f5736e95SDavid du Colombier 
26*f5736e95SDavid du Colombier typedef struct list_value_tag {
27*f5736e95SDavid du Colombier 	USHORT			usValue;
28*f5736e95SDavid du Colombier 	USHORT			usListIndex;
29*f5736e95SDavid du Colombier 	UCHAR			ucListLevel;
30*f5736e95SDavid du Colombier 	struct list_value_tag	*pNext;
31*f5736e95SDavid du Colombier } list_value_type;
32*f5736e95SDavid du Colombier 
33*f5736e95SDavid du Colombier /* Variables needed to describe the LFO list (pllfo) */
34*f5736e95SDavid du Colombier static ULONG		*aulLfoList = NULL;
35*f5736e95SDavid du Colombier static USHORT		usLfoLen = 0;
36*f5736e95SDavid du Colombier /* Variables needed to write the List Information List */
37*f5736e95SDavid du Colombier static list_desc_type	*pAnchor = NULL;
38*f5736e95SDavid du Colombier static list_desc_type	*pBlockLast = NULL;
39*f5736e95SDavid du Colombier /* Variable needed for numbering new lists */
40*f5736e95SDavid du Colombier static list_value_type	*pValues = NULL;
41*f5736e95SDavid du Colombier /* Variables needed for numbering old lists */
42*f5736e95SDavid du Colombier static int	iOldListSeqNumber = 0;
43*f5736e95SDavid du Colombier static USHORT	usOldListValue = 0;
44*f5736e95SDavid du Colombier 
45*f5736e95SDavid du Colombier 
46*f5736e95SDavid du Colombier /*
47*f5736e95SDavid du Colombier  * vDestroyListInfoList - destroy the List Information List
48*f5736e95SDavid du Colombier  */
49*f5736e95SDavid du Colombier void
vDestroyListInfoList(void)50*f5736e95SDavid du Colombier vDestroyListInfoList(void)
51*f5736e95SDavid du Colombier {
52*f5736e95SDavid du Colombier 	list_desc_type	*pCurr, *pNext;
53*f5736e95SDavid du Colombier 	list_value_type	*pValueCurr, *pValueNext;
54*f5736e95SDavid du Colombier 
55*f5736e95SDavid du Colombier 	DBG_MSG("vDestroyListInfoList");
56*f5736e95SDavid du Colombier 
57*f5736e95SDavid du Colombier 	/* Free the LFO list */
58*f5736e95SDavid du Colombier 	usLfoLen = 0;
59*f5736e95SDavid du Colombier 	aulLfoList = xfree(aulLfoList);
60*f5736e95SDavid du Colombier 
61*f5736e95SDavid du Colombier 	/* Free the List Information List */
62*f5736e95SDavid du Colombier 	pCurr = pAnchor;
63*f5736e95SDavid du Colombier 	while (pCurr != NULL) {
64*f5736e95SDavid du Colombier 		pNext = pCurr->pNext;
65*f5736e95SDavid du Colombier 		pCurr = xfree(pCurr);
66*f5736e95SDavid du Colombier 		pCurr = pNext;
67*f5736e95SDavid du Colombier 	}
68*f5736e95SDavid du Colombier 	pAnchor = NULL;
69*f5736e95SDavid du Colombier 	/* Reset all control variables */
70*f5736e95SDavid du Colombier 	pBlockLast = NULL;
71*f5736e95SDavid du Colombier 
72*f5736e95SDavid du Colombier 	/* Free the values list */
73*f5736e95SDavid du Colombier 	pValueCurr = pValues;
74*f5736e95SDavid du Colombier 	while (pValueCurr != NULL) {
75*f5736e95SDavid du Colombier 		pValueNext = pValueCurr->pNext;
76*f5736e95SDavid du Colombier 		pValueCurr = xfree(pValueCurr);
77*f5736e95SDavid du Colombier 		pValueCurr = pValueNext;
78*f5736e95SDavid du Colombier 	}
79*f5736e95SDavid du Colombier 	pValues = NULL;
80*f5736e95SDavid du Colombier 	/* Reset the values for the old lists */
81*f5736e95SDavid du Colombier 	iOldListSeqNumber = 0;
82*f5736e95SDavid du Colombier 	usOldListValue = 0;
83*f5736e95SDavid du Colombier } /* end of vDestroyListInfoList */
84*f5736e95SDavid du Colombier 
85*f5736e95SDavid du Colombier /*
86*f5736e95SDavid du Colombier  * vBuildLfoList - build the LFO list (pllfo)
87*f5736e95SDavid du Colombier  */
88*f5736e95SDavid du Colombier void
vBuildLfoList(const UCHAR * aucBuffer,size_t tBufLen)89*f5736e95SDavid du Colombier vBuildLfoList(const UCHAR *aucBuffer, size_t tBufLen)
90*f5736e95SDavid du Colombier {
91*f5736e95SDavid du Colombier 	size_t	tRecords;
92*f5736e95SDavid du Colombier 	int	iIndex;
93*f5736e95SDavid du Colombier 
94*f5736e95SDavid du Colombier 	fail(aucBuffer == NULL);
95*f5736e95SDavid du Colombier 
96*f5736e95SDavid du Colombier 	if (tBufLen < 4) {
97*f5736e95SDavid du Colombier 		return;
98*f5736e95SDavid du Colombier 	}
99*f5736e95SDavid du Colombier 	tRecords = (size_t)ulGetLong(0, aucBuffer);
100*f5736e95SDavid du Colombier 	NO_DBG_DEC(tRecords);
101*f5736e95SDavid du Colombier 	if (4 + 16 * tRecords > tBufLen || tRecords >= 0x7fff) {
102*f5736e95SDavid du Colombier 		/* Just a sanity check */
103*f5736e95SDavid du Colombier 		DBG_DEC(tRecords);
104*f5736e95SDavid du Colombier 		DBG_DEC(4 + 16 * tRecords);
105*f5736e95SDavid du Colombier 		DBG_DEC(tBufLen);
106*f5736e95SDavid du Colombier 		return;
107*f5736e95SDavid du Colombier 	}
108*f5736e95SDavid du Colombier 	aulLfoList = xcalloc(tRecords, sizeof(ULONG));
109*f5736e95SDavid du Colombier 	for (iIndex = 0; iIndex < (int)tRecords; iIndex++) {
110*f5736e95SDavid du Colombier 		aulLfoList[iIndex] = ulGetLong(4 + 16 * iIndex, aucBuffer);
111*f5736e95SDavid du Colombier 		NO_DBG_HEX(aulLfoList[iIndex]);
112*f5736e95SDavid du Colombier 	}
113*f5736e95SDavid du Colombier 	usLfoLen = (USHORT)tRecords;
114*f5736e95SDavid du Colombier } /* end of vBuildLfoList */
115*f5736e95SDavid du Colombier 
116*f5736e95SDavid du Colombier /*
117*f5736e95SDavid du Colombier  * vAdd2ListInfoList - add an element to the List Information list
118*f5736e95SDavid du Colombier  */
119*f5736e95SDavid du Colombier void
vAdd2ListInfoList(ULONG ulListID,USHORT usIstd,UCHAR ucListLevel,const list_block_type * pListBlock)120*f5736e95SDavid du Colombier vAdd2ListInfoList(ULONG ulListID, USHORT usIstd, UCHAR ucListLevel,
121*f5736e95SDavid du Colombier 	const list_block_type *pListBlock)
122*f5736e95SDavid du Colombier {
123*f5736e95SDavid du Colombier 	list_desc_type	*pListMember;
124*f5736e95SDavid du Colombier 
125*f5736e95SDavid du Colombier 	fail(pListBlock == NULL);
126*f5736e95SDavid du Colombier 
127*f5736e95SDavid du Colombier 	NO_DBG_HEX(ulListID);
128*f5736e95SDavid du Colombier 	NO_DBG_DEC(usIstd);
129*f5736e95SDavid du Colombier 	NO_DBG_DEC(ucListLevel);
130*f5736e95SDavid du Colombier 	NO_DBG_DEC(pListBlock->ulStartAt);
131*f5736e95SDavid du Colombier 	NO_DBG_DEC(pListBlock->bNoRestart);
132*f5736e95SDavid du Colombier 	NO_DBG_DEC(pListBlock->sLeftIndent);
133*f5736e95SDavid du Colombier 	NO_DBG_HEX(pListBlock->ucNFC);
134*f5736e95SDavid du Colombier 	NO_DBG_HEX(pListBlock->usListChar);
135*f5736e95SDavid du Colombier 
136*f5736e95SDavid du Colombier 	/* Create list member */
137*f5736e95SDavid du Colombier 	pListMember = xmalloc(sizeof(list_desc_type));
138*f5736e95SDavid du Colombier 	/* Fill the list member */
139*f5736e95SDavid du Colombier 	pListMember->tInfo = *pListBlock;
140*f5736e95SDavid du Colombier 	pListMember->ulListID = ulListID;
141*f5736e95SDavid du Colombier 	pListMember->usIstd = usIstd;
142*f5736e95SDavid du Colombier 	pListMember->ucListLevel = ucListLevel;
143*f5736e95SDavid du Colombier 	pListMember->pNext = NULL;
144*f5736e95SDavid du Colombier 	/* Correct the values where needed */
145*f5736e95SDavid du Colombier 	if (pListMember->tInfo.ulStartAt > 0xffff) {
146*f5736e95SDavid du Colombier 		DBG_DEC(pListMember->tInfo.ulStartAt);
147*f5736e95SDavid du Colombier 		pListMember->tInfo.ulStartAt = 1;
148*f5736e95SDavid du Colombier 	}
149*f5736e95SDavid du Colombier 	/* Add the new member to the list */
150*f5736e95SDavid du Colombier 	if (pAnchor == NULL) {
151*f5736e95SDavid du Colombier 		pAnchor = pListMember;
152*f5736e95SDavid du Colombier 	} else {
153*f5736e95SDavid du Colombier 		fail(pBlockLast == NULL);
154*f5736e95SDavid du Colombier 		pBlockLast->pNext = pListMember;
155*f5736e95SDavid du Colombier 	}
156*f5736e95SDavid du Colombier 	pBlockLast = pListMember;
157*f5736e95SDavid du Colombier } /* end of vAdd2ListInfoList */
158*f5736e95SDavid du Colombier 
159*f5736e95SDavid du Colombier /*
160*f5736e95SDavid du Colombier  * Get a matching record from the List Information List
161*f5736e95SDavid du Colombier  *
162*f5736e95SDavid du Colombier  * Returns NULL if no matching records is found
163*f5736e95SDavid du Colombier  */
164*f5736e95SDavid du Colombier const list_block_type *
pGetListInfo(USHORT usListIndex,UCHAR ucListLevel)165*f5736e95SDavid du Colombier pGetListInfo(USHORT usListIndex, UCHAR ucListLevel)
166*f5736e95SDavid du Colombier {
167*f5736e95SDavid du Colombier 	list_desc_type	*pCurr;
168*f5736e95SDavid du Colombier 	list_block_type	*pNearMatch;
169*f5736e95SDavid du Colombier 	ULONG	ulListID;
170*f5736e95SDavid du Colombier 
171*f5736e95SDavid du Colombier 	if (usListIndex == 0) {
172*f5736e95SDavid du Colombier 		return NULL;
173*f5736e95SDavid du Colombier 	}
174*f5736e95SDavid du Colombier 	if (usListIndex - 1 >= usLfoLen || ucListLevel > 8) {
175*f5736e95SDavid du Colombier 		DBG_DEC(usListIndex);
176*f5736e95SDavid du Colombier 		DBG_DEC(ucListLevel);
177*f5736e95SDavid du Colombier 		return NULL;
178*f5736e95SDavid du Colombier 	}
179*f5736e95SDavid du Colombier 	fail(aulLfoList == NULL);
180*f5736e95SDavid du Colombier 	ulListID = aulLfoList[usListIndex - 1];
181*f5736e95SDavid du Colombier 	NO_DBG_HEX(ulListID);
182*f5736e95SDavid du Colombier 
183*f5736e95SDavid du Colombier 	pNearMatch = NULL;
184*f5736e95SDavid du Colombier 	for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
185*f5736e95SDavid du Colombier 		if (pCurr->ulListID != ulListID) {
186*f5736e95SDavid du Colombier 			/* No match */
187*f5736e95SDavid du Colombier 			continue;
188*f5736e95SDavid du Colombier 		}
189*f5736e95SDavid du Colombier 		if (pCurr->ucListLevel == ucListLevel) {
190*f5736e95SDavid du Colombier 			/* Exact match */
191*f5736e95SDavid du Colombier 			return &pCurr->tInfo;
192*f5736e95SDavid du Colombier 		}
193*f5736e95SDavid du Colombier 		if (pCurr->ucListLevel == 0) {
194*f5736e95SDavid du Colombier 			/* Near match */
195*f5736e95SDavid du Colombier 			pNearMatch = &pCurr->tInfo;
196*f5736e95SDavid du Colombier 		}
197*f5736e95SDavid du Colombier 	}
198*f5736e95SDavid du Colombier 	/* No exact match, use a near match if any */
199*f5736e95SDavid du Colombier 	return pNearMatch;
200*f5736e95SDavid du Colombier } /* end of pGetListInfo */
201*f5736e95SDavid du Colombier 
202*f5736e95SDavid du Colombier /*
203*f5736e95SDavid du Colombier  * Get a matching record from the List Information List
204*f5736e95SDavid du Colombier  *
205*f5736e95SDavid du Colombier  * Returns NULL if no matching records is found
206*f5736e95SDavid du Colombier  */
207*f5736e95SDavid du Colombier const list_block_type *
pGetListInfoByIstd(USHORT usIstd)208*f5736e95SDavid du Colombier pGetListInfoByIstd(USHORT usIstd)
209*f5736e95SDavid du Colombier {
210*f5736e95SDavid du Colombier 	list_desc_type	*pCurr;
211*f5736e95SDavid du Colombier 
212*f5736e95SDavid du Colombier 	if (usIstd == ISTD_INVALID || usIstd == STI_NIL || usIstd == STI_USER) {
213*f5736e95SDavid du Colombier 		return NULL;
214*f5736e95SDavid du Colombier 	}
215*f5736e95SDavid du Colombier 
216*f5736e95SDavid du Colombier 	for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
217*f5736e95SDavid du Colombier 		if (pCurr->usIstd == usIstd) {
218*f5736e95SDavid du Colombier 			return &pCurr->tInfo;
219*f5736e95SDavid du Colombier 		}
220*f5736e95SDavid du Colombier 	}
221*f5736e95SDavid du Colombier 	return NULL;
222*f5736e95SDavid du Colombier } /* end of pGetListInfoByIstd */
223*f5736e95SDavid du Colombier 
224*f5736e95SDavid du Colombier /*
225*f5736e95SDavid du Colombier  * vRestartListValues - reset the less significant list levels
226*f5736e95SDavid du Colombier  */
227*f5736e95SDavid du Colombier static void
vRestartListValues(USHORT usListIndex,UCHAR ucListLevel)228*f5736e95SDavid du Colombier vRestartListValues(USHORT usListIndex, UCHAR ucListLevel)
229*f5736e95SDavid du Colombier {
230*f5736e95SDavid du Colombier 	list_value_type	*pPrev, *pCurr, *pNext;
231*f5736e95SDavid du Colombier 	int		iCounter;
232*f5736e95SDavid du Colombier 
233*f5736e95SDavid du Colombier 	iCounter = 0;
234*f5736e95SDavid du Colombier 	pPrev = NULL;
235*f5736e95SDavid du Colombier 	pCurr = pValues;
236*f5736e95SDavid du Colombier 
237*f5736e95SDavid du Colombier 	while (pCurr != NULL) {
238*f5736e95SDavid du Colombier 		if (pCurr->usListIndex != usListIndex ||
239*f5736e95SDavid du Colombier 		    pCurr->ucListLevel <= ucListLevel) {
240*f5736e95SDavid du Colombier 			pPrev = pCurr;
241*f5736e95SDavid du Colombier 			pCurr = pCurr->pNext;
242*f5736e95SDavid du Colombier 			continue;
243*f5736e95SDavid du Colombier 		}
244*f5736e95SDavid du Colombier 		/* Reset the level by deleting the record */
245*f5736e95SDavid du Colombier 		pNext = pCurr->pNext;
246*f5736e95SDavid du Colombier 		if (pPrev == NULL) {
247*f5736e95SDavid du Colombier 			pValues = pNext;
248*f5736e95SDavid du Colombier 		} else {
249*f5736e95SDavid du Colombier 			pPrev->pNext = pNext;
250*f5736e95SDavid du Colombier 		}
251*f5736e95SDavid du Colombier 		DBG_DEC(pCurr->usListIndex);
252*f5736e95SDavid du Colombier 		DBG_DEC(pCurr->ucListLevel);
253*f5736e95SDavid du Colombier 		pCurr = xfree(pCurr);
254*f5736e95SDavid du Colombier 		pCurr = pNext;
255*f5736e95SDavid du Colombier 		iCounter++;
256*f5736e95SDavid du Colombier 	}
257*f5736e95SDavid du Colombier 	DBG_DEC_C(iCounter > 0, iCounter);
258*f5736e95SDavid du Colombier } /* end of vRestartListValues */
259*f5736e95SDavid du Colombier 
260*f5736e95SDavid du Colombier /*
261*f5736e95SDavid du Colombier  * usGetListValue - Get the current value of the given list
262*f5736e95SDavid du Colombier  *
263*f5736e95SDavid du Colombier  * Returns the value of the given list
264*f5736e95SDavid du Colombier  */
265*f5736e95SDavid du Colombier USHORT
usGetListValue(int iListSeqNumber,int iWordVersion,const style_block_type * pStyle)266*f5736e95SDavid du Colombier usGetListValue(int iListSeqNumber, int iWordVersion,
267*f5736e95SDavid du Colombier 	const style_block_type *pStyle)
268*f5736e95SDavid du Colombier {
269*f5736e95SDavid du Colombier 	list_value_type	*pCurr;
270*f5736e95SDavid du Colombier 	USHORT		usValue;
271*f5736e95SDavid du Colombier 
272*f5736e95SDavid du Colombier 	fail(iListSeqNumber < 0);
273*f5736e95SDavid du Colombier 	fail(iListSeqNumber < iOldListSeqNumber);
274*f5736e95SDavid du Colombier 	fail(iWordVersion < 0);
275*f5736e95SDavid du Colombier 	fail(pStyle == NULL);
276*f5736e95SDavid du Colombier 
277*f5736e95SDavid du Colombier 	if (iListSeqNumber <= 0) {
278*f5736e95SDavid du Colombier 		return 0;
279*f5736e95SDavid du Colombier 	}
280*f5736e95SDavid du Colombier 
281*f5736e95SDavid du Colombier 	if (iWordVersion < 8) {
282*f5736e95SDavid du Colombier 		/* Old style list */
283*f5736e95SDavid du Colombier 		if (iListSeqNumber == iOldListSeqNumber ||
284*f5736e95SDavid du Colombier 		    (iListSeqNumber == iOldListSeqNumber + 1 &&
285*f5736e95SDavid du Colombier 		     eGetNumType(pStyle->ucNumLevel) == level_type_sequence)) {
286*f5736e95SDavid du Colombier 			if (!pStyle->bNumPause) {
287*f5736e95SDavid du Colombier 				usOldListValue++;
288*f5736e95SDavid du Colombier 			}
289*f5736e95SDavid du Colombier 		} else {
290*f5736e95SDavid du Colombier 			usOldListValue = pStyle->usStartAt;
291*f5736e95SDavid du Colombier 		}
292*f5736e95SDavid du Colombier 		iOldListSeqNumber = iListSeqNumber;
293*f5736e95SDavid du Colombier 		return usOldListValue;
294*f5736e95SDavid du Colombier 	}
295*f5736e95SDavid du Colombier 
296*f5736e95SDavid du Colombier 	/* New style list */
297*f5736e95SDavid du Colombier 	if (pStyle->usListIndex == 0 ||
298*f5736e95SDavid du Colombier 	    pStyle->usListIndex - 1 >= usLfoLen ||
299*f5736e95SDavid du Colombier 	    pStyle->ucListLevel > 8) {
300*f5736e95SDavid du Colombier 		/* Out of range; no need to search */
301*f5736e95SDavid du Colombier 		return 0;
302*f5736e95SDavid du Colombier 	}
303*f5736e95SDavid du Colombier 
304*f5736e95SDavid du Colombier 	for (pCurr = pValues; pCurr != NULL; pCurr = pCurr->pNext) {
305*f5736e95SDavid du Colombier 		if (pCurr->usListIndex == pStyle->usListIndex &&
306*f5736e95SDavid du Colombier 		    pCurr->ucListLevel == pStyle->ucListLevel) {
307*f5736e95SDavid du Colombier 			/* Record found; increment and return the value */
308*f5736e95SDavid du Colombier 			pCurr->usValue++;
309*f5736e95SDavid du Colombier 			usValue = pCurr->usValue;
310*f5736e95SDavid du Colombier 			if (!pStyle->bNoRestart) {
311*f5736e95SDavid du Colombier 				vRestartListValues(pStyle->usListIndex,
312*f5736e95SDavid du Colombier 						pStyle->ucListLevel);
313*f5736e95SDavid du Colombier 			}
314*f5736e95SDavid du Colombier 			return usValue;
315*f5736e95SDavid du Colombier 		}
316*f5736e95SDavid du Colombier 	}
317*f5736e95SDavid du Colombier 
318*f5736e95SDavid du Colombier 	/* Record not found; create it and add it to the front of the list */
319*f5736e95SDavid du Colombier 	pCurr = xmalloc(sizeof(list_value_type));
320*f5736e95SDavid du Colombier 	pCurr->usValue = pStyle->usStartAt;
321*f5736e95SDavid du Colombier 	pCurr->usListIndex = pStyle->usListIndex;
322*f5736e95SDavid du Colombier 	pCurr->ucListLevel = pStyle->ucListLevel;
323*f5736e95SDavid du Colombier 	pCurr->pNext = pValues;
324*f5736e95SDavid du Colombier 	pValues = pCurr;
325*f5736e95SDavid du Colombier 	usValue = pCurr->usValue;
326*f5736e95SDavid du Colombier 	if (!pStyle->bNoRestart) {
327*f5736e95SDavid du Colombier 		vRestartListValues(pStyle->usListIndex, pStyle->ucListLevel);
328*f5736e95SDavid du Colombier 	}
329*f5736e95SDavid du Colombier 	return usValue;
330*f5736e95SDavid du Colombier } /* end of usGetListValue */
331