Imported from antiword-0.37.tar.gz.
[antiword.git] / listlist.c
blobeb86589af3171d65f0f84c878fc8a33c2b4a8fb3
1 /*
2 * listlist.c
3 * Copyright (C) 2002,2003 A.J. van Os; Released under GPL
5 * Description:
6 * Build, read and destroy a list of Word list information
8 * Note:
9 * This list only exists when the Word document is saved by Word 8 or later
12 #include "antiword.h"
15 * Private structure to hide the way the information
16 * is stored from the rest of the program
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;
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;
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;
47 * vDestroyListInfoList - destroy the List Information List
49 void
50 vDestroyListInfoList(void)
52 list_desc_type *pCurr, *pNext;
53 list_value_type *pValueCurr, *pValueNext;
55 DBG_MSG("vDestroyListInfoList");
57 /* Free the LFO list */
58 usLfoLen = 0;
59 aulLfoList = xfree(aulLfoList);
61 /* Free the List Information List */
62 pCurr = pAnchor;
63 while (pCurr != NULL) {
64 pNext = pCurr->pNext;
65 pCurr = xfree(pCurr);
66 pCurr = pNext;
68 pAnchor = NULL;
69 /* Reset all control variables */
70 pBlockLast = NULL;
72 /* Free the values list */
73 pValueCurr = pValues;
74 while (pValueCurr != NULL) {
75 pValueNext = pValueCurr->pNext;
76 pValueCurr = xfree(pValueCurr);
77 pValueCurr = pValueNext;
79 pValues = NULL;
80 /* Reset the values for the old lists */
81 iOldListSeqNumber = 0;
82 usOldListValue = 0;
83 } /* end of vDestroyListInfoList */
86 * vBuildLfoList - build the LFO list (pllfo)
88 void
89 vBuildLfoList(const UCHAR *aucBuffer, size_t tBufLen)
91 size_t tRecords;
92 int iIndex;
94 fail(aucBuffer == NULL);
96 if (tBufLen < 4) {
97 return;
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;
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]);
113 usLfoLen = (USHORT)tRecords;
114 } /* end of vBuildLfoList */
117 * vAdd2ListInfoList - add an element to the List Information list
119 void
120 vAdd2ListInfoList(ULONG ulListID, USHORT usIstd, UCHAR ucListLevel,
121 const list_block_type *pListBlock)
123 list_desc_type *pListMember;
125 fail(pListBlock == NULL);
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);
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;
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;
156 pBlockLast = pListMember;
157 } /* end of vAdd2ListInfoList */
160 * Get a matching record from the List Information List
162 * Returns NULL if no matching records is found
164 const list_block_type *
165 pGetListInfo(USHORT usListIndex, UCHAR ucListLevel)
167 list_desc_type *pCurr;
168 list_block_type *pNearMatch;
169 ULONG ulListID;
171 if (usListIndex == 0) {
172 return NULL;
174 if (usListIndex - 1 >= usLfoLen || ucListLevel > 8) {
175 DBG_DEC(usListIndex);
176 DBG_DEC(ucListLevel);
177 return NULL;
179 fail(aulLfoList == NULL);
180 ulListID = aulLfoList[usListIndex - 1];
181 NO_DBG_HEX(ulListID);
183 pNearMatch = NULL;
184 for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
185 if (pCurr->ulListID != ulListID) {
186 /* No match */
187 continue;
189 if (pCurr->ucListLevel == ucListLevel) {
190 /* Exact match */
191 return &pCurr->tInfo;
193 if (pCurr->ucListLevel == 0) {
194 /* Near match */
195 pNearMatch = &pCurr->tInfo;
198 /* No exact match, use a near match if any */
199 return pNearMatch;
200 } /* end of pGetListInfo */
203 * Get a matching record from the List Information List
205 * Returns NULL if no matching records is found
207 const list_block_type *
208 pGetListInfoByIstd(USHORT usIstd)
210 list_desc_type *pCurr;
212 if (usIstd == ISTD_INVALID || usIstd == STI_NIL || usIstd == STI_USER) {
213 return NULL;
216 for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
217 if (pCurr->usIstd == usIstd) {
218 return &pCurr->tInfo;
221 return NULL;
222 } /* end of pGetListInfoByIstd */
225 * vRestartListValues - reset the less significant list levels
227 static void
228 vRestartListValues(USHORT usListIndex, UCHAR ucListLevel)
230 list_value_type *pPrev, *pCurr, *pNext;
231 int iCounter;
233 iCounter = 0;
234 pPrev = NULL;
235 pCurr = pValues;
237 while (pCurr != NULL) {
238 if (pCurr->usListIndex != usListIndex ||
239 pCurr->ucListLevel <= ucListLevel) {
240 pPrev = pCurr;
241 pCurr = pCurr->pNext;
242 continue;
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;
251 DBG_DEC(pCurr->usListIndex);
252 DBG_DEC(pCurr->ucListLevel);
253 pCurr = xfree(pCurr);
254 pCurr = pNext;
255 iCounter++;
257 DBG_DEC_C(iCounter > 0, iCounter);
258 } /* end of vRestartListValues */
261 * usGetListValue - Get the current value of the given list
263 * Returns the value of the given list
265 USHORT
266 usGetListValue(int iListSeqNumber, int iWordVersion,
267 const style_block_type *pStyle)
269 list_value_type *pCurr;
270 USHORT usValue;
272 fail(iListSeqNumber < 0);
273 fail(iListSeqNumber < iOldListSeqNumber);
274 fail(iWordVersion < 0);
275 fail(pStyle == NULL);
277 if (iListSeqNumber <= 0) {
278 return 0;
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++;
289 } else {
290 usOldListValue = pStyle->usStartAt;
292 iOldListSeqNumber = iListSeqNumber;
293 return usOldListValue;
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;
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);
314 return usValue;
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);
329 return usValue;
330 } /* end of usGetListValue */