xref: /plan9/sys/src/cmd/aux/antiword/hdrftrlist.c (revision 25b329d522281a8cdd35da0dcc08c3fc621059a9)
1 /*
2  * hdrftrlist.c
3  * Copyright (C) 2004,2005 A.J. van Os; Released under GNU GPL
4  *
5  * Description:
6  * Build, read and destroy list(s) of Word Header/footer information
7  */
8 
9 #include <string.h>
10 #include "antiword.h"
11 
12 
13 #define HDR_EVEN_PAGES	0
14 #define HDR_ODD_PAGES	1
15 #define FTR_EVEN_PAGES	2
16 #define FTR_ODD_PAGES	3
17 #define HDR_FIRST_PAGE	4
18 #define FTR_FIRST_PAGE	5
19 
20 /*
21  * Private structures to hide the way the information
22  * is stored from the rest of the program
23  */
24 typedef struct hdrftr_local_tag {
25 	hdrftr_block_type	tInfo;
26 	ULONG			ulCharPosStart;
27 	ULONG			ulCharPosNext;
28 	BOOL			bUseful;
29 	BOOL			bTextOriginal;
30 } hdrftr_local_type;
31 typedef struct hdrftr_mem_tag {
32 	hdrftr_local_type	atElement[6];
33 } hdrftr_mem_type;
34 
35 /* Variables needed to write the Header/footer Information List */
36 static hdrftr_mem_type	*pHdrFtrList = NULL;
37 static size_t		tHdrFtrLen = 0;
38 
39 
40 /*
41  * vDestroyHdrFtrInfoList - destroy the Header/footer Information List
42  */
43 void
vDestroyHdrFtrInfoList(void)44 vDestroyHdrFtrInfoList(void)
45 {
46 	hdrftr_mem_type *pRecord;
47 	output_type	*pCurr, *pNext;
48 	size_t		tHdrFtr, tIndex;
49 
50 	DBG_MSG("vDestroyHdrFtrInfoList");
51 
52 	/* Free the Header/footer Information List */
53 	for (tHdrFtr = 0; tHdrFtr < tHdrFtrLen; tHdrFtr++) {
54 		pRecord = pHdrFtrList + tHdrFtr;
55 		for (tIndex = 0;
56 		     tIndex < elementsof(pRecord->atElement);
57 		     tIndex++) {
58 			if (!pRecord->atElement[tIndex].bTextOriginal) {
59 				continue;
60 			}
61 			pCurr = pRecord->atElement[tIndex].tInfo.pText;
62 			while (pCurr != NULL) {
63 				pCurr->szStorage = xfree(pCurr->szStorage);
64 				pNext = pCurr->pNext;
65 				pCurr = xfree(pCurr);
66 				pCurr = pNext;
67 			}
68 		}
69 	}
70 	pHdrFtrList = xfree(pHdrFtrList);
71 	/* Reset all control variables */
72 	tHdrFtrLen = 0;
73 } /* end of vDestroyHdrFtrInfoList */
74 
75 /*
76  * vCreat8HdrFtrInfoList - Create the Header/footer Information List
77  */
78 void
vCreat8HdrFtrInfoList(const ULONG * aulCharPos,size_t tLength)79 vCreat8HdrFtrInfoList(const ULONG *aulCharPos, size_t tLength)
80 {
81 	hdrftr_mem_type	*pListMember;
82 	size_t	tHdrFtr, tIndex, tMainIndex;
83 
84 	fail(aulCharPos == NULL);
85 
86 	DBG_DEC(tLength);
87 	if (tLength <= 1) {
88 		return;
89 	}
90 	tHdrFtrLen = tLength / 12;
91 	if (tLength % 12 != 0 && tLength % 12 != 1) {
92 		tHdrFtrLen++;
93 	}
94 	DBG_DEC(tHdrFtrLen);
95 
96 	pHdrFtrList = xcalloc(tHdrFtrLen, sizeof(hdrftr_mem_type));
97 
98 	for (tHdrFtr = 0; tHdrFtr < tHdrFtrLen; tHdrFtr++) {
99 		pListMember = pHdrFtrList + tHdrFtr;
100 		for (tIndex = 0, tMainIndex = tHdrFtr * 12;
101 		     tIndex < 6 && tMainIndex < tLength;
102 		     tIndex++, tMainIndex++) {
103 			pListMember->atElement[tIndex].tInfo.pText = NULL;
104 			pListMember->atElement[tIndex].ulCharPosStart =
105 						aulCharPos[tMainIndex];
106 			if (tMainIndex + 1 < tLength) {
107 				pListMember->atElement[tIndex].ulCharPosNext =
108 					aulCharPos[tMainIndex + 1];
109 			} else {
110 				pListMember->atElement[tIndex].ulCharPosNext =
111 					aulCharPos[tMainIndex];
112 			}
113 		}
114 	}
115 } /* end of vCreat8HdrFtrInfoList */
116 
117 /*
118  * vCreat6HdrFtrInfoList - Create the Header/footer Information List
119  */
120 void
vCreat6HdrFtrInfoList(const ULONG * aulCharPos,size_t tLength)121 vCreat6HdrFtrInfoList(const ULONG *aulCharPos, size_t tLength)
122 {
123 	static const size_t	atIndex[] =
124 		{ SIZE_T_MAX, SIZE_T_MAX, FTR_FIRST_PAGE, HDR_FIRST_PAGE,
125 		  FTR_ODD_PAGES, FTR_EVEN_PAGES, HDR_ODD_PAGES, HDR_EVEN_PAGES,
126 		};
127 	hdrftr_mem_type	*pListMember;
128 	size_t	tHdrFtr, tTmp, tIndex, tMainIndex, tBit;
129 	UCHAR	ucDopSpecification, ucSepSpecification;
130 
131 	fail(aulCharPos == NULL);
132 
133 	DBG_DEC(tLength);
134 	if (tLength <= 1) {
135 		return;
136 	}
137 	tHdrFtrLen = tGetNumberOfSections();
138 	if (tHdrFtrLen == 0) {
139 		tHdrFtrLen = 1;
140 	}
141 	DBG_DEC(tHdrFtrLen);
142 
143 	pHdrFtrList = xcalloc(tHdrFtrLen, sizeof(hdrftr_mem_type));
144 
145 	/* Get the start index in aulCharPos */
146 	ucDopSpecification = ucGetDopHdrFtrSpecification();
147 	DBG_HEX(ucDopSpecification & 0xe0);
148 	tMainIndex = 0;
149 	for (tBit = 7; tBit >= 5; tBit--) {
150 		if ((ucDopSpecification & BIT(tBit)) != 0) {
151 			tMainIndex++;
152 		}
153 	}
154 	DBG_DEC(tMainIndex);
155 
156 	for (tHdrFtr = 0; tHdrFtr < tHdrFtrLen; tHdrFtr++) {
157 		ucSepSpecification = ucGetSepHdrFtrSpecification(tHdrFtr);
158 		DBG_HEX(ucSepSpecification & 0xfc);
159 		pListMember = pHdrFtrList + tHdrFtr;
160 		for (tTmp = 0;
161 		     tTmp < elementsof(pListMember->atElement);
162 		     tTmp++) {
163 			pListMember->atElement[tTmp].tInfo.pText = NULL;
164 		}
165 		for (tBit = 7; tBit >= 2; tBit--) {
166 			if (tMainIndex >= tLength) {
167 				break;
168 			}
169 			if ((ucSepSpecification & BIT(tBit)) == 0) {
170 				continue;
171 			}
172 			tIndex = atIndex[tBit];
173 			fail(tIndex >= 6);
174 			pListMember->atElement[tIndex].ulCharPosStart =
175 				aulCharPos[tMainIndex];
176 			if (tMainIndex + 1 < tLength) {
177 				pListMember->atElement[tIndex].ulCharPosNext =
178 					aulCharPos[tMainIndex + 1];
179 			} else {
180 				pListMember->atElement[tIndex].ulCharPosNext =
181 					aulCharPos[tMainIndex];
182 			}
183 			tMainIndex++;
184 		}
185 	}
186 } /* end of vCreat6HdrFtrInfoList */
187 
188 /*
189  * vCreat2HdrFtrInfoList - Create the Header/footer Information List
190  */
191 void
vCreat2HdrFtrInfoList(const ULONG * aulCharPos,size_t tLength)192 vCreat2HdrFtrInfoList(const ULONG *aulCharPos, size_t tLength)
193 {
194 	vCreat6HdrFtrInfoList(aulCharPos, tLength);
195 } /* end of vCreat2HdrFtrInfoList */
196 
197 /*
198  * pGetHdrFtrInfo - get the Header/footer information
199  */
200 const hdrftr_block_type *
pGetHdrFtrInfo(int iSectionIndex,BOOL bWantHeader,BOOL bOddPage,BOOL bFirstInSection)201 pGetHdrFtrInfo(int iSectionIndex,
202 	BOOL bWantHeader, BOOL bOddPage, BOOL bFirstInSection)
203 {
204 	hdrftr_mem_type	*pCurr;
205 
206 	fail(iSectionIndex < 0);
207 	fail(pHdrFtrList == NULL && tHdrFtrLen != 0);
208 
209 	if (pHdrFtrList == NULL || tHdrFtrLen == 0) {
210 		/* No information */
211 		return NULL;
212 	}
213 
214 	if (iSectionIndex < 0) {
215 		iSectionIndex = 0;
216 	} else if (iSectionIndex >= (int)tHdrFtrLen) {
217 		iSectionIndex = (int)(tHdrFtrLen - 1);
218 	}
219 
220 	pCurr = pHdrFtrList + iSectionIndex;
221 
222 	if (bFirstInSection) {
223 		if (bWantHeader) {
224 			return &pCurr->atElement[HDR_FIRST_PAGE].tInfo;
225 		} else {
226 			return &pCurr->atElement[FTR_FIRST_PAGE].tInfo;
227 		}
228 	} else {
229 		if (bWantHeader) {
230 			if (bOddPage) {
231 				return &pCurr->atElement[HDR_ODD_PAGES].tInfo;
232 			} else {
233 				return &pCurr->atElement[HDR_EVEN_PAGES].tInfo;
234 			}
235 		} else {
236 			if (bOddPage) {
237 				return &pCurr->atElement[FTR_ODD_PAGES].tInfo;
238 			} else {
239 				return &pCurr->atElement[FTR_EVEN_PAGES].tInfo;
240 			}
241 		}
242 	}
243 } /* end of pGetHdrFtrInfo */
244 
245 /*
246  * lComputeHdrFtrHeight - compute the height of a header or footer
247  *
248  * Returns the height in DrawUnits
249  */
250 static long
lComputeHdrFtrHeight(const output_type * pAnchor)251 lComputeHdrFtrHeight(const output_type *pAnchor)
252 {
253 	const output_type *pCurr;
254 	long	lTotal;
255 	USHORT	usFontSizeMax;
256 
257 	lTotal = 0;
258 	usFontSizeMax = 0;
259 	for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
260 		if (pCurr->tNextFree == 1) {
261 			if (pCurr->szStorage[0] == PAR_END) {
262 				/* End of a paragraph */
263 				lTotal += lComputeLeading(usFontSizeMax);
264 				lTotal += lMilliPoints2DrawUnits(
265 						(long)pCurr->usFontSize * 200);
266 				usFontSizeMax = 0;
267 				continue;
268 			}
269 			if (pCurr->szStorage[0] == HARD_RETURN) {
270 				/* End of a line */
271 				lTotal += lComputeLeading(usFontSizeMax);
272 				usFontSizeMax = 0;
273 				continue;
274 			}
275 		}
276 		if (pCurr->usFontSize > usFontSizeMax) {
277 			usFontSizeMax = pCurr->usFontSize;
278 		}
279 	}
280 	if (usFontSizeMax != 0) {
281 		/* Height of the last paragraph */
282 		lTotal += lComputeLeading(usFontSizeMax);
283 	}
284 	return lTotal;
285 } /* end of lComputeHdrFtrHeight */
286 
287 /*
288  * vPrepareHdrFtrText - prepare the header/footer text
289  */
290 void
vPrepareHdrFtrText(FILE * pFile)291 vPrepareHdrFtrText(FILE *pFile)
292 {
293 	hdrftr_mem_type		*pCurr, *pPrev;
294 	hdrftr_local_type	*pTmp;
295 	output_type		*pText;
296 	size_t		tHdrFtr, tIndex;
297 
298 	fail(pFile == NULL);
299 	fail(pHdrFtrList == NULL && tHdrFtrLen != 0);
300 
301 	if (pHdrFtrList == NULL || tHdrFtrLen == 0) {
302 		/* No information */
303 		return;
304 	}
305 
306 	/* Fill text, text height and useful-ness */
307 	for (tHdrFtr = 0; tHdrFtr < tHdrFtrLen; tHdrFtr++) {
308 		pCurr = pHdrFtrList + tHdrFtr;
309 		for (tIndex = 0;
310 		     tIndex < elementsof(pHdrFtrList->atElement);
311 		     tIndex++) {
312 			pTmp = &pCurr->atElement[tIndex];
313 			pTmp->bUseful =
314 				pTmp->ulCharPosStart != pTmp->ulCharPosNext;
315 			if (pTmp->bUseful) {
316 				pText = pHdrFtrDecryptor(pFile,
317 						pTmp->ulCharPosStart,
318 						pTmp->ulCharPosNext);
319 				pTmp->tInfo.pText = pText;
320 				pTmp->tInfo.lHeight =
321 						lComputeHdrFtrHeight(pText);
322 				pTmp->bTextOriginal = pText != NULL;
323 			} else {
324 				pTmp->tInfo.pText = NULL;
325 				pTmp->tInfo.lHeight = 0;
326 				pTmp->bTextOriginal = FALSE;
327 			}
328 		}
329 	}
330 
331 	/* Replace not-useful records by using inheritance */
332 	if (pHdrFtrList->atElement[HDR_FIRST_PAGE].bUseful) {
333 		pTmp = &pHdrFtrList->atElement[HDR_ODD_PAGES];
334 		if (!pTmp->bUseful) {
335 			*pTmp = pHdrFtrList->atElement[HDR_FIRST_PAGE];
336 			pTmp->bTextOriginal = FALSE;
337 		}
338 		pTmp = &pHdrFtrList->atElement[HDR_EVEN_PAGES];
339 		if (!pTmp->bUseful) {
340 			*pTmp = pHdrFtrList->atElement[HDR_FIRST_PAGE];
341 			pTmp->bTextOriginal = FALSE;
342 		}
343 	}
344 	if (pHdrFtrList->atElement[FTR_FIRST_PAGE].bUseful) {
345 		pTmp = &pHdrFtrList->atElement[FTR_ODD_PAGES];
346 		if (!pTmp->bUseful) {
347 			*pTmp = pHdrFtrList->atElement[FTR_FIRST_PAGE];
348 			pTmp->bTextOriginal = FALSE;
349 		}
350 		pTmp = &pHdrFtrList->atElement[FTR_EVEN_PAGES];
351 		if (!pTmp->bUseful) {
352 			*pTmp = pHdrFtrList->atElement[FTR_FIRST_PAGE];
353 			pTmp->bTextOriginal = FALSE;
354 		}
355 	}
356 	for (tHdrFtr = 1, pCurr = &pHdrFtrList[1];
357 	     tHdrFtr < tHdrFtrLen;
358 	     tHdrFtr++, pCurr++) {
359 		pPrev = pCurr - 1;
360 		for (tIndex = 0;
361 		     tIndex < elementsof(pHdrFtrList->atElement);
362 		     tIndex++) {
363 			if (!pCurr->atElement[tIndex].bUseful &&
364 			    pPrev->atElement[tIndex].bUseful) {
365 				pCurr->atElement[tIndex] =
366 						pPrev->atElement[tIndex];
367 				pCurr->atElement[tIndex].bTextOriginal = FALSE;
368 			}
369 		}
370 	}
371 } /* end of vPrepareHdrFtrText */
372