3 * Copyright (C) 1998-2005 A.J. van Os; Released under GNU GPL
6 * Build, read and destroy a list of Word style information
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
;
25 /* Variables needed to write the Style Information List */
26 static style_mem_type
*pAnchor
= NULL
;
27 static style_mem_type
*pStyleLast
= NULL
;
28 /* The type of conversion */
29 static conversion_type eConversionType
= conversion_unknown
;
30 /* The character set encoding */
31 static encoding_type eEncoding
= encoding_neutral
;
32 /* Values for efficiency reasons */
33 static const style_mem_type
*pMidPtr
= NULL
;
34 static BOOL bMoveMidPtr
= FALSE
;
35 static BOOL bInSequence
= TRUE
;
39 * vDestroyStyleInfoList - destroy the Style Information List
42 vDestroyStyleInfoList(void)
44 style_mem_type
*pCurr
, *pNext
;
46 DBG_MSG("vDestroyStyleInfoList");
48 /* Free the Style Information List */
50 while (pCurr
!= NULL
) {
56 /* Reset all control variables */
61 } /* end of vDestroyStyleInfoList */
64 * vConvertListCharacter - convert the list character
67 vConvertListCharacter(UCHAR ucNFC
, USHORT usListChar
, char *szListChar
)
69 options_type tOptions
;
72 fail(szListChar
== NULL
);
73 fail(szListChar
[0] != '\0');
75 if (usListChar
< 0x80 && isprint((int)usListChar
)) {
76 DBG_CHR_C(isalnum((int)usListChar
), usListChar
);
77 szListChar
[0] = (char)usListChar
;
82 if (ucNFC
!= LIST_SPECIAL
&&
83 ucNFC
!= LIST_SPECIAL2
&&
84 ucNFC
!= LIST_BULLETS
) {
90 if (eConversionType
== conversion_unknown
||
91 eEncoding
== encoding_neutral
) {
92 vGetOptions(&tOptions
);
93 eConversionType
= tOptions
.eConversionType
;
94 eEncoding
= tOptions
.eEncoding
;
98 case 0x0000: case 0x00b7: case 0x00fe: case 0xf021: case 0xf043:
99 case 0xf06c: case 0xf093: case 0xf0b7:
100 usListChar
= 0x2022; /* BULLET */
102 case 0x0096: case 0xf02d:
103 usListChar
= 0x2013; /* EN DASH */
106 usListChar
= 0x2666; /* BLACK DIAMOND SUIT */
109 usListChar
= 0x21d2; /* RIGHTWARDS DOUBLE ARROW */
111 case 0x00e0: case 0xf074:
112 usListChar
= 0x25ca; /* LOZENGE */
115 usListChar
= 0x2329; /* LEFT ANGLE BRACKET */
118 usListChar
= 0x0020; /* SPACE */
121 usListChar
= 0x270c; /* VICTORY HAND */
124 usListChar
= 0x03d5; /* GREEK PHI SYMBOL */
127 usListChar
= 0x25a0; /* BLACK SQUARE */
129 case 0xf06f: case 0xf070: case 0xf0a8:
130 usListChar
= 0x25a1; /* WHITE SQUARE */
133 usListChar
= 0x2751; /* LOWER RIGHT SHADOWED WHITE SQUARE */
135 case 0xf075: case 0xf077:
136 usListChar
= 0x25c6; /* BLACK DIAMOND */
139 usListChar
= 0x2756; /* BLACK DIAMOND MINUS WHITE X */
142 usListChar
= 0x25aa; /* BLACK SMALL SQUARE */
145 usListChar
= 0x27a2; /* RIGHTWARDS ARROWHEAD */
148 usListChar
= 0x2199; /* SOUTH WEST ARROW */
151 usListChar
= 0x21e8; /* RIGHTWARDS WHITE ARROW */
154 usListChar
= 0x2713; /* CHECK MARK */
157 if ((usListChar
>= 0xe000 && usListChar
< 0xf900) ||
158 (usListChar
< 0x80 && !isprint((int)usListChar
))) {
160 * All remaining private area characters and all
161 * remaining non-printable ASCII characters to their
162 * default bullet character
166 if (ucNFC
== LIST_SPECIAL
|| ucNFC
== LIST_SPECIAL2
) {
167 usListChar
= 0x2190; /* LEFTWARDS ARROW */
169 usListChar
= 0x2022; /* BULLET */
175 if (eEncoding
== encoding_utf_8
) {
176 tLen
= tUcs2Utf8(usListChar
, szListChar
, 4);
177 szListChar
[tLen
] = '\0';
179 switch (usListChar
) {
180 case 0x03d5: case 0x25a1: case 0x25c6: case 0x25ca:
184 case 0x2013: case 0x2500:
187 case 0x2190: case 0x2199: case 0x2329:
193 case 0x21e8: case 0x27a2:
196 case 0x25a0: case 0x25aa:
200 szListChar
[0] = OUR_DIAMOND
;
213 vGetBulletValue(eConversionType
, eEncoding
,
219 szListChar
[tLen
] = '\0';
220 } /* end of vConvertListCharacter */
223 * eGetNumType - get the level type from the given level number
225 * Returns the level type
228 eGetNumType(UCHAR ucNumLevel
)
230 switch (ucNumLevel
) {
231 case 1: case 2: case 3: case 4: case 5:
232 case 6: case 7: case 8: case 9:
233 return level_type_outline
;
235 return level_type_numbering
;
237 return level_type_sequence
;
239 return level_type_pause
;
241 return level_type_none
;
243 } /* end of eGetNumType */
246 * vCorrectStyleValues - correct style values that Antiword can't use
249 vCorrectStyleValues(style_block_type
*pStyleBlock
)
251 if (pStyleBlock
->usBeforeIndent
> 0x7fff) {
252 pStyleBlock
->usBeforeIndent
= 0;
253 } else if (pStyleBlock
->usBeforeIndent
> 2160) {
254 /* 2160 twips = 1.5 inches or 38.1 mm */
255 DBG_DEC(pStyleBlock
->usBeforeIndent
);
256 pStyleBlock
->usBeforeIndent
= 2160;
258 if (pStyleBlock
->usIstd
>= 1 &&
259 pStyleBlock
->usIstd
<= 9 &&
260 pStyleBlock
->usBeforeIndent
< HEADING_GAP
) {
261 NO_DBG_DEC(pStyleBlock
->usBeforeIndent
);
262 pStyleBlock
->usBeforeIndent
= HEADING_GAP
;
265 if (pStyleBlock
->usAfterIndent
> 0x7fff) {
266 pStyleBlock
->usAfterIndent
= 0;
267 } else if (pStyleBlock
->usAfterIndent
> 2160) {
268 /* 2160 twips = 1.5 inches or 38.1 mm */
269 DBG_DEC(pStyleBlock
->usAfterIndent
);
270 pStyleBlock
->usAfterIndent
= 2160;
272 if (pStyleBlock
->usIstd
>= 1 &&
273 pStyleBlock
->usIstd
<= 9 &&
274 pStyleBlock
->usAfterIndent
< HEADING_GAP
) {
275 NO_DBG_DEC(pStyleBlock
->usAfterIndent
);
276 pStyleBlock
->usAfterIndent
= HEADING_GAP
;
279 if (pStyleBlock
->sLeftIndent
< 0) {
280 pStyleBlock
->sLeftIndent
= 0;
282 if (pStyleBlock
->sRightIndent
> 0) {
283 pStyleBlock
->sRightIndent
= 0;
285 vConvertListCharacter(pStyleBlock
->ucNFC
,
286 pStyleBlock
->usListChar
,
287 pStyleBlock
->szListChar
);
288 } /* end of vCorrectStyleValues */
291 * vAdd2StyleInfoList - Add an element to the Style Information List
294 vAdd2StyleInfoList(const style_block_type
*pStyleBlock
)
296 style_mem_type
*pListMember
;
298 fail(pStyleBlock
== NULL
);
300 NO_DBG_MSG("bAdd2StyleInfoList");
302 if (pStyleBlock
->ulFileOffset
== FC_INVALID
) {
303 NO_DBG_DEC(pStyleBlock
->usIstd
);
307 NO_DBG_HEX(pStyleBlock
->ulFileOffset
);
308 NO_DBG_DEC_C(pStyleBlock
->sLeftIndent
!= 0,
309 pStyleBlock
->sLeftIndent
);
310 NO_DBG_DEC_C(pStyleBlock
->sRightIndent
!= 0,
311 pStyleBlock
->sRightIndent
);
312 NO_DBG_DEC_C(pStyleBlock
->bNumPause
, pStyleBlock
->bNumPause
);
313 NO_DBG_DEC_C(pStyleBlock
->usIstd
!= 0, pStyleBlock
->usIstd
);
314 NO_DBG_DEC_C(pStyleBlock
->usStartAt
!= 1, pStyleBlock
->usStartAt
);
315 NO_DBG_DEC_C(pStyleBlock
->usAfterIndent
!= 0,
316 pStyleBlock
->usAfterIndent
);
317 NO_DBG_DEC_C(pStyleBlock
->ucAlignment
!= 0, pStyleBlock
->ucAlignment
);
318 NO_DBG_DEC(pStyleBlock
->ucNFC
);
319 NO_DBG_HEX(pStyleBlock
->usListChar
);
321 if (pStyleLast
!= NULL
&&
322 pStyleLast
->tInfo
.ulFileOffset
== pStyleBlock
->ulFileOffset
) {
324 * If two consecutive styles share the same
325 * offset, remember only the last style
327 fail(pStyleLast
->pNext
!= NULL
);
328 pStyleLast
->tInfo
= *pStyleBlock
;
329 /* Correct the values where needed */
330 vCorrectStyleValues(&pStyleLast
->tInfo
);
334 /* Create list member */
335 pListMember
= xmalloc(sizeof(style_mem_type
));
336 /* Fill the list member */
337 pListMember
->tInfo
= *pStyleBlock
;
338 pListMember
->pNext
= NULL
;
339 /* Add the sequence number */
340 pListMember
->ulSequenceNumber
=
341 ulGetSeqNumber(pListMember
->tInfo
.ulFileOffset
);
342 /* Correct the values where needed */
343 vCorrectStyleValues(&pListMember
->tInfo
);
344 /* Add the new member to the list */
345 if (pAnchor
== NULL
) {
346 pAnchor
= pListMember
;
352 fail(pStyleLast
== NULL
);
353 pStyleLast
->pNext
= pListMember
;
356 pMidPtr
= pMidPtr
->pNext
;
362 bInSequence
= pListMember
->ulSequenceNumber
>
363 pStyleLast
->ulSequenceNumber
;
366 pStyleLast
= pListMember
;
367 } /* end of vAdd2StyleInfoList */
370 * Get the record that follows the given recored in the Style Information List
372 const style_block_type
*
373 pGetNextStyleInfoListItem(const style_block_type
*pCurr
)
375 const style_mem_type
*pRecord
;
379 if (pAnchor
== NULL
) {
380 /* There are no records */
383 /* The first record is the only one without a predecessor */
384 return &pAnchor
->tInfo
;
386 tOffset
= offsetof(style_mem_type
, tInfo
);
387 /* Many casts to prevent alignment warnings */
388 pRecord
= (style_mem_type
*)(void *)((char *)pCurr
- tOffset
);
389 fail(pCurr
!= &pRecord
->tInfo
);
390 if (pRecord
->pNext
== NULL
) {
391 /* The last record has no successor */
394 return &pRecord
->pNext
->tInfo
;
395 } /* end of pGetNextStyleInfoListItem */
398 * Get the next text style
400 const style_block_type
*
401 pGetNextTextStyle(const style_block_type
*pCurr
)
403 const style_block_type
*pRecord
;
407 pRecord
= pGetNextStyleInfoListItem(pRecord
);
408 } while (pRecord
!= NULL
&&
409 (pRecord
->eListID
== hdrftr_list
||
410 pRecord
->eListID
== macro_list
||
411 pRecord
->eListID
== annotation_list
));
413 } /* end of pGetNextTextStyle */
416 * usGetIstd - get the istd that belongs to the given file offset
419 usGetIstd(ULONG ulFileOffset
)
421 const style_mem_type
*pCurr
, *pBest
, *pStart
;
424 ulSeq
= ulGetSeqNumber(ulFileOffset
);
425 if (ulSeq
== FC_INVALID
) {
428 NO_DBG_HEX(ulFileOffset
);
433 ulSeq
> pMidPtr
->ulSequenceNumber
) {
434 /* The istd is in the second half of the chained list */
442 for (pCurr
= pStart
; pCurr
!= NULL
; pCurr
= pCurr
->pNext
) {
443 if (pCurr
->ulSequenceNumber
!= FC_INVALID
&&
444 (pBest
== NULL
|| pCurr
->ulSequenceNumber
> ulBest
) &&
445 pCurr
->ulSequenceNumber
<= ulSeq
) {
447 ulBest
= pCurr
->ulSequenceNumber
;
449 if (bInSequence
&& pCurr
->ulSequenceNumber
> ulSeq
) {
459 NO_DBG_DEC(pBest
->tInfo
.usIstd
);
460 return pBest
->tInfo
.usIstd
;
461 } /* end of usGetIstd */
464 * bStyleImpliesList - does style info implies being part of a list
466 * Decide whether the style information implies that the given paragraph is
469 * Returns TRUE when the paragraph is part of a list, otherwise FALSE
472 bStyleImpliesList(const style_block_type
*pStyle
, int iWordVersion
)
474 fail(pStyle
== NULL
);
475 fail(iWordVersion
< 0);
477 if (pStyle
->usIstd
>= 1 && pStyle
->usIstd
<= 9) {
478 /* These are heading levels */
481 if (iWordVersion
< 8) {
482 /* Check for old style lists */
483 return pStyle
->ucNumLevel
!= 0;
485 /* Check for new style lists */
486 return pStyle
->usListIndex
!= 0;
487 } /* end of bStyleImpliesList */