Imported from antiword-0.33.tar.gz.
[antiword.git] / stylelist.c
blobb2cdc926bc6f5defbfcb48b825afb0385c425da8
1 /*
2 * stylelist.c
3 * Copyright (C) 1998-2002 A.J. van Os; Released under GPL
5 * Description:
6 * Build, read and destroy a list of Word style information
7 */
9 #include <stdlib.h>
10 #include <stddef.h>
11 #include <ctype.h>
12 #include "antiword.h"
16 * Private structure to hide the way the information
17 * is stored from the rest of the program
19 typedef struct style_mem_tag {
20 style_block_type tInfo;
21 ULONG ulSequenceNumber;
22 struct style_mem_tag *pNext;
23 } style_mem_type;
25 /* Variables needed to write the Style Information List */
26 static style_mem_type *pAnchor = NULL;
27 static style_mem_type *pStyleLast = NULL;
28 /* Values for efficiency reasons */
29 static const style_mem_type *pMidPtr = NULL;
30 static BOOL bMoveMidPtr = FALSE;
31 static BOOL bInSequence = TRUE;
35 * vDestroyStyleInfoList - destroy the Style Information List
37 void
38 vDestroyStyleInfoList(void)
40 style_mem_type *pCurr, *pNext;
42 DBG_MSG("vDestroyStyleInfoList");
44 /* Free the Style Information List */
45 pCurr = pAnchor;
46 while (pCurr != NULL) {
47 pNext = pCurr->pNext;
48 pCurr = xfree(pCurr);
49 pCurr = pNext;
51 pAnchor = NULL;
52 /* Reset all control variables */
53 pStyleLast = NULL;
54 pMidPtr = NULL;
55 bMoveMidPtr = FALSE;
56 bInSequence = TRUE;
57 } /* end of vDestroyStyleInfoList */
60 * ucChooseListCharacter - choose our list character
62 static UCHAR
63 ucChooseListCharacter(UCHAR ucNFC, UCHAR ucListCharacter)
65 if (isprint(ucListCharacter)) {
66 return ucListCharacter;
68 if (ucNFC == LIST_BULLETS) {
69 switch (ucListCharacter) {
70 case 0x00:
71 case 0xb7:
72 return (UCHAR)OUR_BULLET;
73 case 0xa8:
74 return (UCHAR)OUR_DIAMOND;
75 case 0xde:
76 return (UCHAR)'=';
77 case 0xe0:
78 return (UCHAR)'o';
79 case 0xe1:
80 return (UCHAR)'(';
81 case 0xfe:
82 return (UCHAR)' ';
83 default:
84 DBG_HEX(ucListCharacter);
85 return (UCHAR)OUR_BULLET;
88 return (UCHAR)'.';
89 } /* end of ucChooseListCharacter */
92 * eGetNumType - get level type from level number
94 level_type_enum
95 eGetNumType(UCHAR ucLevelNumber)
97 switch (ucLevelNumber) {
98 case 10:
99 return level_type_numbering;
100 case 11:
101 return level_type_sequence;
102 case 12:
103 return level_type_pause;
104 default:
105 if ((int)ucLevelNumber >= 1 && (int)ucLevelNumber <= 9) {
106 return level_type_outline;
108 return level_type_none;
110 } /* end of eGetNumType */
113 * vCorrectStyleValues - correct style values that Antiword can't use
115 void
116 vCorrectStyleValues(style_block_type *pStyleBlock)
118 if (pStyleBlock->usBeforeIndent > 0x7fff) {
119 pStyleBlock->usBeforeIndent = 0;
120 } else if (pStyleBlock->usBeforeIndent > 2160) {
121 /* 2160 twips = 1.5 inches or 38.1 mm */
122 DBG_DEC(pStyleBlock->usBeforeIndent);
123 pStyleBlock->usBeforeIndent = 2160;
125 if (pStyleBlock->usIstd >= 1 &&
126 pStyleBlock->usIstd <= 9 &&
127 pStyleBlock->usBeforeIndent < HEADING_GAP) {
128 NO_DBG_DEC(pStyleBlock->usBeforeIndent);
129 pStyleBlock->usBeforeIndent = HEADING_GAP;
131 if (pStyleBlock->usAfterIndent > 0x7fff) {
132 pStyleBlock->usAfterIndent = 0;
133 } else if (pStyleBlock->usAfterIndent > 2160) {
134 /* 2160 twips = 1.5 inches or 38.1 mm */
135 DBG_DEC(pStyleBlock->usAfterIndent);
136 pStyleBlock->usAfterIndent = 2160;
138 if (pStyleBlock->usIstd >= 1 &&
139 pStyleBlock->usIstd <= 9 &&
140 pStyleBlock->usAfterIndent < HEADING_GAP) {
141 NO_DBG_DEC(pStyleBlock->usAfterIndent);
142 pStyleBlock->usAfterIndent = HEADING_GAP;
144 if (pStyleBlock->sLeftIndent < 0) {
145 pStyleBlock->sLeftIndent = 0;
147 if (pStyleBlock->sRightIndent > 0) {
148 pStyleBlock->sRightIndent = 0;
150 pStyleBlock->ucListCharacter =
151 ucChooseListCharacter(
152 pStyleBlock->ucNFC,
153 pStyleBlock->ucListCharacter);
154 } /* end of vCorrectStyleValues */
157 * vAdd2StyleInfoList - Add an element to the Style Information List
159 void
160 vAdd2StyleInfoList(const style_block_type *pStyleBlock)
162 style_mem_type *pListMember;
164 fail(pStyleBlock == NULL);
166 NO_DBG_MSG("bAdd2StyleInfoList");
168 if (pStyleBlock->ulFileOffset == FC_INVALID) {
169 NO_DBG_DEC(pStyleBlock->usIstd);
170 return;
173 NO_DBG_HEX(pStyleBlock->ulFileOffset);
174 NO_DBG_DEC_C(pStyleBlock->sLeftIndent != 0,
175 pStyleBlock->sLeftIndent);
176 NO_DBG_DEC_C(pStyleBlock->sRightIndent != 0,
177 pStyleBlock->sRightIndent);
178 NO_DBG_DEC_C(pStyleBlock->bInList, pStyleBlock->bInList);
179 NO_DBG_DEC_C(pStyleBlock->bNumPause, pStyleBlock->bNumPause);
180 NO_DBG_DEC_C(pStyleBlock->usIstd != 0, pStyleBlock->usIstd);
181 NO_DBG_DEC_C(pStyleBlock->usStartAt != 0, pStyleBlock->usStartAt);
182 NO_DBG_DEC_C(pStyleBlock->usAfterIndent != 0,
183 pStyleBlock->usAfterIndent);
184 NO_DBG_DEC_C(pStyleBlock->ucAlignment != 0, pStyleBlock->ucAlignment);
185 NO_DBG_DEC_C(pStyleBlock->bInList, pStyleBlock->ucNFC);
186 NO_DBG_HEX_C(pStyleBlock->bInList, pStyleBlock->ucListCharacter);
187 NO_DBG_DEC_C(pStyleBlock->ucNFC != LIST_BULLETS,
188 pStyleBlock->usStartAt);
190 if (pStyleLast != NULL &&
191 pStyleLast->tInfo.ulFileOffset == pStyleBlock->ulFileOffset) {
193 * If two consecutive styles share the same
194 * offset, remember only the last style
196 fail(pStyleLast->pNext != NULL);
197 pStyleLast->tInfo = *pStyleBlock;
198 return;
201 /* Create list member */
202 pListMember = xmalloc(sizeof(style_mem_type));
203 /* Fill the list member */
204 pListMember->tInfo = *pStyleBlock;
205 pListMember->pNext = NULL;
206 /* Add the sequence number */
207 pListMember->ulSequenceNumber =
208 ulGetSeqNumber(pListMember->tInfo.ulFileOffset);
209 /* Correct the values where needed */
210 vCorrectStyleValues(&pListMember->tInfo);
211 /* Add the new member to the list */
212 if (pAnchor == NULL) {
213 pAnchor = pListMember;
214 /* For efficiency */
215 pMidPtr = pAnchor;
216 bMoveMidPtr = FALSE;
217 bInSequence = TRUE;
218 } else {
219 fail(pStyleLast == NULL);
220 pStyleLast->pNext = pListMember;
221 /* For efficiency */
222 if (bMoveMidPtr) {
223 pMidPtr = pMidPtr->pNext;
224 bMoveMidPtr = FALSE;
225 } else {
226 bMoveMidPtr = TRUE;
228 if (bInSequence) {
229 bInSequence = pListMember->ulSequenceNumber >
230 pStyleLast->ulSequenceNumber;
233 pStyleLast = pListMember;
234 } /* end of vAdd2StyleInfoList */
237 * Get the record that follows the given recored in the Style Information List
239 const style_block_type *
240 pGetNextStyleInfoListItem(const style_block_type *pCurr)
242 const style_mem_type *pRecord;
243 size_t tOffset;
245 if (pCurr == NULL) {
246 if (pAnchor == NULL) {
247 /* There are no records */
248 return NULL;
250 /* The first record is the only one without a predecessor */
251 return &pAnchor->tInfo;
253 tOffset = offsetof(style_mem_type, tInfo);
254 /* Many casts to prevent alignment warnings */
255 pRecord = (style_mem_type *)(void *)((char *)pCurr - tOffset);
256 fail(pCurr != &pRecord->tInfo);
257 if (pRecord->pNext == NULL) {
258 /* The last record has no successor */
259 return NULL;
261 return &pRecord->pNext->tInfo;
262 } /* end of pGetNextStyleInfoListItem */
265 * usGetIstd - get the istd that belongs to the given file offset
267 USHORT
268 usGetIstd(ULONG ulFileOffset)
270 const style_mem_type *pCurr, *pBest, *pStart;
271 ULONG ulSeq, ulBest;
273 ulSeq = ulGetSeqNumber(ulFileOffset);
274 if (ulSeq == FC_INVALID) {
275 return ISTD_NORMAL;
277 NO_DBG_HEX(ulFileOffset);
278 NO_DBG_DEC(ulSeq);
280 if (bInSequence &&
281 pMidPtr != NULL &&
282 ulSeq > pMidPtr->ulSequenceNumber) {
283 /* The istd is in the second half of the chained list */
284 pStart = pMidPtr;
285 } else {
286 pStart = pAnchor;
289 pBest = NULL;
290 ulBest = 0;
291 for (pCurr = pStart; pCurr != NULL; pCurr = pCurr->pNext) {
292 if (pCurr->ulSequenceNumber != FC_INVALID &&
293 (pBest == NULL || pCurr->ulSequenceNumber > ulBest) &&
294 pCurr->ulSequenceNumber <= ulSeq) {
295 pBest = pCurr;
296 ulBest = pCurr->ulSequenceNumber;
298 if (bInSequence && pCurr->ulSequenceNumber > ulSeq) {
299 break;
302 NO_DBG_DEC(ulBest);
304 if (pBest == NULL) {
305 return ISTD_NORMAL;
308 NO_DBG_DEC(pBest->tInfo.usIstd);
309 return pBest->tInfo.usIstd;
310 } /* end of usGetIstd */