3 * Copyright (C) 2002,2003 A.J. van Os; Released under GPL
6 * Build, read and destroy a list of Word list information
9 * This list only exists when the Word document is saved by Word 8 or later
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
;
23 struct list_desc_tag
*pNext
;
26 typedef struct list_value_tag
{
30 struct list_value_tag
*pNext
;
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
50 vDestroyListInfoList(void)
52 list_desc_type
*pCurr
, *pNext
;
53 list_value_type
*pValueCurr
, *pValueNext
;
55 DBG_MSG("vDestroyListInfoList");
57 /* Free the LFO list */
59 aulLfoList
= xfree(aulLfoList
);
61 /* Free the List Information List */
63 while (pCurr
!= NULL
) {
69 /* Reset all control variables */
72 /* Free the values list */
74 while (pValueCurr
!= NULL
) {
75 pValueNext
= pValueCurr
->pNext
;
76 pValueCurr
= xfree(pValueCurr
);
77 pValueCurr
= pValueNext
;
80 /* Reset the values for the old lists */
81 iOldListSeqNumber
= 0;
83 } /* end of vDestroyListInfoList */
86 * vBuildLfoList - build the LFO list (pllfo)
89 vBuildLfoList(const UCHAR
*aucBuffer
, size_t tBufLen
)
94 fail(aucBuffer
== NULL
);
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 */
104 DBG_DEC(4 + 16 * tRecords
);
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
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
);
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
;
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
;
171 if (usListIndex
== 0) {
174 if (usListIndex
- 1 >= usLfoLen
|| ucListLevel
> 8) {
175 DBG_DEC(usListIndex
);
176 DBG_DEC(ucListLevel
);
179 fail(aulLfoList
== NULL
);
180 ulListID
= aulLfoList
[usListIndex
- 1];
181 NO_DBG_HEX(ulListID
);
184 for (pCurr
= pAnchor
; pCurr
!= NULL
; pCurr
= pCurr
->pNext
) {
185 if (pCurr
->ulListID
!= ulListID
) {
189 if (pCurr
->ucListLevel
== ucListLevel
) {
191 return &pCurr
->tInfo
;
193 if (pCurr
->ucListLevel
== 0) {
195 pNearMatch
= &pCurr
->tInfo
;
198 /* No exact match, use a near match if any */
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
) {
216 for (pCurr
= pAnchor
; pCurr
!= NULL
; pCurr
= pCurr
->pNext
) {
217 if (pCurr
->usIstd
== usIstd
) {
218 return &pCurr
->tInfo
;
222 } /* end of pGetListInfoByIstd */
225 * vRestartListValues - reset the less significant list levels
228 vRestartListValues(USHORT usListIndex
, UCHAR ucListLevel
)
230 list_value_type
*pPrev
, *pCurr
, *pNext
;
237 while (pCurr
!= NULL
) {
238 if (pCurr
->usListIndex
!= usListIndex
||
239 pCurr
->ucListLevel
<= ucListLevel
) {
241 pCurr
= pCurr
->pNext
;
244 /* Reset the level by deleting the record */
245 pNext
= pCurr
->pNext
;
249 pPrev
->pNext
= pNext
;
251 DBG_DEC(pCurr
->usListIndex
);
252 DBG_DEC(pCurr
->ucListLevel
);
253 pCurr
= xfree(pCurr
);
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
266 usGetListValue(int iListSeqNumber
, int iWordVersion
,
267 const style_block_type
*pStyle
)
269 list_value_type
*pCurr
;
272 fail(iListSeqNumber
< 0);
273 fail(iListSeqNumber
< iOldListSeqNumber
);
274 fail(iWordVersion
< 0);
275 fail(pStyle
== NULL
);
277 if (iListSeqNumber
<= 0) {
281 if (iWordVersion
< 8) {
283 if (iListSeqNumber
== iOldListSeqNumber
||
284 (iListSeqNumber
== iOldListSeqNumber
+ 1 &&
285 eGetNumType(pStyle
->ucNumLevel
) == level_type_sequence
)) {
286 if (!pStyle
->bNumPause
) {
290 usOldListValue
= pStyle
->usStartAt
;
292 iOldListSeqNumber
= iListSeqNumber
;
293 return usOldListValue
;
297 if (pStyle
->usListIndex
== 0 ||
298 pStyle
->usListIndex
- 1 >= usLfoLen
||
299 pStyle
->ucListLevel
> 8) {
300 /* Out of range; no need to search */
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 */
309 usValue
= pCurr
->usValue
;
310 if (!pStyle
->bNoRestart
) {
311 vRestartListValues(pStyle
->usListIndex
,
312 pStyle
->ucListLevel
);
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
;
325 usValue
= pCurr
->usValue
;
326 if (!pStyle
->bNoRestart
) {
327 vRestartListValues(pStyle
->usListIndex
, pStyle
->ucListLevel
);
330 } /* end of usGetListValue */