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