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