3 * Copyright (C) 1998-2001 A.J. van Os; Released under GPL
19 #include <sys/types.h>
22 #define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
23 #define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
32 static BOOL bWord6MacFile
= FALSE
;
35 #if !defined(__riscos)
37 * szGetHomeDirectory - get the name of the home directory
40 szGetHomeDirectory(void)
42 static char homedir
[256];
45 szHome
= getenv("HOME");
46 if (szHome
== NULL
|| szHome
[0] == '\0') {
48 (void)GetCurrentDirectory(255, &homedir
[0]);
55 werr(0, "I can't find the name of your HOME directory");
61 } /* end of szGetHomeDirectory */
62 #endif /* !__riscos */
65 * Get the size of the given file.
66 * Returns -1 if the file does not exist or is not a proper file.
69 lGetFilesize(const char *szFilename
)
72 _kernel_swi_regs regs
;
75 (void)memset(®s
, 0, sizeof(regs
));
77 regs
.r
[1] = (int)szFilename
;
78 e
= _kernel_swi(OS_File
, ®s
, ®s
);
80 werr(0, "Get Filesize error %d: %s",
81 e
->errnum
, e
->errmess
);
85 /* It's not a proper file or the file does not exist */
88 return (long)regs
.r
[4];
92 if (stat(szFilename
, &tBuffer
) != 0) {
93 werr(0, "Get Filesize error %d", errno
);
96 if (!S_ISREG(tBuffer
.st_mode
)) {
97 /* It's not a regular file */
100 return (long)tBuffer
.st_size
;
101 #endif /* __riscos */
102 } /* end of lGetFilesize */
106 vPrintBlock(const char *szFile
, int iLine
,
107 const unsigned char *aucBlock
, size_t tLength
)
111 fail(szFile
== NULL
|| iLine
< 0 || aucBlock
== NULL
);
113 fprintf(stderr
, "%s[%3d]:\n", szFile
, iLine
);
114 for (i
= 0; i
< 32; i
++) {
115 if (16 * i
>= (int)tLength
) {
118 fprintf(stderr
, "%03x: ", 16 * i
);
119 for (j
= 0; j
< 16; j
++) {
120 if (16 * i
+ j
< (int)tLength
) {
121 fprintf(stderr
, "%02x ", aucBlock
[16 * i
+ j
]);
124 fprintf(stderr
, "\n");
126 } /* end of vPrintBlock */
129 vPrintUnicode(const char *szFile
, int iLine
, const char *s
)
134 tLen
= unilen(s
) / 2;
135 szASCII
= xmalloc(tLen
+ 1);
136 (void)unincpy(szASCII
, s
, tLen
);
137 szASCII
[tLen
] = '\0';
138 (void)fprintf(stderr
, "%s[%3d]: %.240s\n", szFile
, iLine
, szASCII
);
139 szASCII
= xfree(szASCII
);
140 } /* end of vPrintUnicode */
143 bCheckDoubleLinkedList(output_type
*pAnchor
)
145 output_type
*pCurr
, *pLast
;
150 for (pCurr
= pAnchor
; pCurr
!= NULL
; pCurr
= pCurr
->pNext
) {
155 for (pCurr
= pLast
; pCurr
!= NULL
; pCurr
= pCurr
->pPrev
) {
159 DBG_DEC_C(iInList
!= 0, iInList
);
160 return pAnchor
== pLast
&& iInList
== 0;
161 } /* end of bCheckDoubleLinkedList */
166 * This function reads the given number of bytes from the given file,
167 * starting from the given offset.
168 * Returns TRUE when successfull, otherwise FALSE
171 bReadBytes(unsigned char *aucBytes
, size_t tMemb
, long lOffset
, FILE *pFile
)
173 fail(aucBytes
== NULL
|| pFile
== NULL
|| lOffset
< 0);
175 if (fseek(pFile
, lOffset
, SEEK_SET
) != 0) {
178 if (fread(aucBytes
, sizeof(unsigned char), tMemb
, pFile
) != tMemb
) {
182 } /* end of bReadBytes */
186 * This function fills the given buffer with the given number of bytes,
187 * starting at the given offset within the Big/Small Block Depot.
189 * Returns TRUE when successful, otherwise FALSE
192 bReadBuffer(FILE *pFile
, long lStartBlock
,
193 const long *alBlockDepot
, size_t tBlockDepotLen
, size_t tBlockSize
,
194 unsigned char *aucBuffer
, long lOffset
, size_t tToRead
)
200 fail(lStartBlock
< 0);
201 fail(alBlockDepot
== NULL
);
202 fail(tBlockSize
!= BIG_BLOCK_SIZE
&& tBlockSize
!= SMALL_BLOCK_SIZE
);
203 fail(aucBuffer
== NULL
);
206 for (lIndex
= lStartBlock
;
207 lIndex
!= END_OF_CHAIN
&& tToRead
!= 0;
208 lIndex
= alBlockDepot
[lIndex
]) {
209 if (lIndex
< 0 || lIndex
>= (long)tBlockDepotLen
) {
210 if (tBlockSize
>= BIG_BLOCK_SIZE
) {
211 werr(1, "The Big Block Depot is corrupt");
213 werr(1, "The Small Block Depot is corrupt");
216 if (lOffset
>= (long)tBlockSize
) {
217 lOffset
-= (long)tBlockSize
;
220 lBegin
= lDepotOffset(lIndex
, tBlockSize
) + lOffset
;
221 tLen
= min(tBlockSize
- (size_t)lOffset
, tToRead
);
223 if (!bReadBytes(aucBuffer
, tLen
, lBegin
, pFile
)) {
224 werr(0, "Read big block %ld not possible", lBegin
);
230 DBG_DEC_C(tToRead
!= 0, tToRead
);
232 } /* end of bReadBuffer */
235 * Translate a Word colornumber into a true color for use in a drawfile
237 * Returns the true color
240 uiColor2Color(int iWordColor
)
242 static const unsigned int auiColorTable
[] = {
243 /* 0 */ 0x00000000U
, /* Automatic */
244 /* 1 */ 0x00000000U
, /* Black */
245 /* 2 */ 0xff000000U
, /* Blue */
246 /* 3 */ 0xffff0000U
, /* Turquoise */
247 /* 4 */ 0x00ff0000U
, /* Bright Green */
248 /* 5 */ 0xff00ff00U
, /* Pink */
249 /* 6 */ 0x0000ff00U
, /* Red */
250 /* 7 */ 0x00ffff00U
, /* Yellow */
251 /* 8 */ 0xffffff00U
, /* White */
252 /* 9 */ 0x80000000U
, /* Dark Blue */
253 /* 10 */ 0x80800000U
, /* Teal */
254 /* 11 */ 0x00800000U
, /* Green */
255 /* 12 */ 0x80008000U
, /* Violet */
256 /* 13 */ 0x00008000U
, /* Dark Red */
257 /* 14 */ 0x00808000U
, /* Dark Yellow */
258 /* 15 */ 0x80808000U
, /* Gray 50% */
259 /* 16 */ 0xc0c0c000U
, /* Gray 25% */
261 if (iWordColor
< 0 ||
262 iWordColor
>= (int)elementsof(auiColorTable
)) {
263 return auiColorTable
[0];
265 return auiColorTable
[iWordColor
];
266 } /* end of uiColor2Color */
269 * iFindSplit - find a place to split the string
271 * returns the index of the split character or -1 if no split found.
274 iFindSplit(const char *szString
, int iStringLen
)
278 iSplit
= iStringLen
- 1;
279 while (iSplit
>= 1) {
280 if (szString
[iSplit
] == ' ' ||
281 (szString
[iSplit
] == '-' && szString
[iSplit
- 1] != ' ')) {
287 } /* end of iFindSplit */
290 * pSplitList - split the given list in a printable part and a leftover part
292 * returns the pointer to the leftover part
295 pSplitList(output_type
*pAnchor
)
297 output_type
*pCurr
, *pLeftOver
;
300 fail(pAnchor
== NULL
);
302 for (pCurr
= pAnchor
; pCurr
->pNext
!= NULL
; pCurr
= pCurr
->pNext
)
305 for (; pCurr
!= NULL
; pCurr
= pCurr
->pPrev
) {
306 iIndex
= iFindSplit(pCurr
->szStorage
, pCurr
->iNextFree
);
312 if (pCurr
== NULL
|| iIndex
< 0) {
313 /* No split, no leftover */
316 /* Split over the iIndex-th character */
317 NO_DBG_MSG("pLeftOver");
318 pLeftOver
= xmalloc(sizeof(*pLeftOver
));
319 pLeftOver
->tStorageSize
= (size_t)(pCurr
->iNextFree
- iIndex
);
320 pLeftOver
->szStorage
= xmalloc(pLeftOver
->tStorageSize
);
321 pLeftOver
->iNextFree
= pCurr
->iNextFree
- iIndex
- 1;
322 (void)strncpy(pLeftOver
->szStorage
,
323 pCurr
->szStorage
+ iIndex
+ 1, (size_t)pLeftOver
->iNextFree
);
324 pLeftOver
->szStorage
[pLeftOver
->iNextFree
] = '\0';
325 NO_DBG_MSG(pLeftOver
->szStorage
);
326 pLeftOver
->iColor
= pCurr
->iColor
;
327 pLeftOver
->ucFontstyle
= pCurr
->ucFontstyle
;
328 pLeftOver
->tFontRef
= pCurr
->tFontRef
;
329 pLeftOver
->sFontsize
= pCurr
->sFontsize
;
330 pLeftOver
->lStringWidth
= lComputeStringWidth(
331 pLeftOver
->szStorage
,
332 pLeftOver
->iNextFree
,
334 pLeftOver
->sFontsize
);
335 pLeftOver
->pPrev
= NULL
;
336 pLeftOver
->pNext
= pCurr
->pNext
;
337 if (pLeftOver
->pNext
!= NULL
) {
338 pLeftOver
->pNext
->pPrev
= pLeftOver
;
340 fail(!bCheckDoubleLinkedList(pLeftOver
));
342 NO_DBG_MSG("pAnchor");
343 NO_DBG_HEX(pCurr
->szStorage
[iIndex
]);
344 while (iIndex
>= 0 && isspace(pCurr
->szStorage
[iIndex
])) {
347 pCurr
->iNextFree
= iIndex
+ 1;
348 pCurr
->szStorage
[pCurr
->iNextFree
] = '\0';
349 NO_DBG_MSG(pCurr
->szStorage
);
350 pCurr
->lStringWidth
= lComputeStringWidth(
356 fail(!bCheckDoubleLinkedList(pAnchor
));
359 } /* end of pSplitList */
362 * iInteger2Roman - convert an integer to Roman Numerals
364 * returns the number of characters written
367 iInteger2Roman(int iNumber
, BOOL bUpperCase
, char *szOutput
)
370 int iNextVal
, iValue
;
372 fail(szOutput
== NULL
);
374 if (iNumber
<= 0 || iNumber
>= 4000) {
380 p
= bUpperCase
? "M\2D\5C\2L\5X\2V\5I" : "m\2d\5c\2l\5x\2v\5i";
383 while (iNumber
>= iValue
) {
389 return outp
- szOutput
;
392 iNextVal
= iValue
/ (int)*q
;
393 if ((int)*q
== 2) { /* magic */
394 iNextVal
/= (int)*(q
+= 2);
396 if (iNumber
+ iNextVal
>= iValue
) {
401 iValue
/= (int)(*p
++);
404 } /* end of iInteger2Roman */
407 * iInteger2Alpha - convert an integer to Alphabetic "numbers"
409 * returns the number of characters written
412 iInteger2Alpha(int iNumber
, BOOL bUpperCase
, char *szOutput
)
417 fail(szOutput
== NULL
);
420 iTmp
= bUpperCase
? 'A': 'a';
423 *outp
++ = (char)(iTmp
+ iNumber
);
424 } else if (iNumber
<= 26 + 26*26) {
426 *outp
++ = (char)(iTmp
+ iNumber
/ 26);
427 *outp
++ = (char)(iTmp
+ iNumber
% 26);
428 } else if (iNumber
<= 26 + 26*26 + 26*26*26) {
429 iNumber
-= 26 + 26*26 + 1;
430 *outp
++ = (char)(iTmp
+ iNumber
/ (26*26));
431 *outp
++ = (char)(iTmp
+ iNumber
/ 26 % 26);
432 *outp
++ = (char)(iTmp
+ iNumber
% 26);
435 return outp
- szOutput
;
436 } /* end of iInteger2Alpha */
439 * unincpy - copy a counted Unicode string to an single-byte string
442 unincpy(char *s1
, const char *s2
, size_t n
)
445 unsigned long ulChar
;
447 unsigned short usUni
;
449 for (dest
= s1
, len
= 0; len
< n
; dest
++, len
++) {
450 usUni
= usGetWord(len
* 2, s2
);
454 ulChar
= ulTranslateCharacters(usUni
, 0, FALSE
, FALSE
);
455 if (ulChar
== IGNORE_CHARACTER
) {
456 ulChar
= (unsigned long)'?';
458 *dest
= (char)ulChar
;
460 for (; len
< n
; len
++) {
464 } /* end of unincpy */
467 * unilen - calculate the length of a Unicode string
470 unilen(const char *s
)
473 unsigned short usUni
;
477 usUni
= usGetWord(tLen
* 2, s
);
483 } /* end of unilen */
486 * szBaseName - get the basename of the given filename
489 szBasename(const char *szFilename
)
493 fail(szFilename
== NULL
);
495 if (szFilename
== NULL
|| szFilename
[0] == '\0') {
499 szTmp
= strrchr(szFilename
, FILE_SEPARATOR
[0]);
504 } /* end of szBasename */
507 * iGetVersionNumber - get the Word version number from the header
509 * Returns the version number or -1 when unknown
512 iGetVersionNumber(const unsigned char *aucHeader
)
514 unsigned short usFib
, usChse
;
516 usFib
= usGetWord(0x02, aucHeader
);
519 /* This file is from a version of Word older than Word 6 */
522 usChse
= usGetWord(0x14, aucHeader
);
524 bWord6MacFile
= FALSE
;
528 DBG_MSG("Word 6 for Windows");
534 DBG_MSG("Word 7 for Win95");
537 DBG_MSG("Word 6 for Macintosh");
538 bWord6MacFile
= TRUE
;
542 if (ucGetByte(0x05, aucHeader
) == 0xe0) {
543 DBG_MSG("Word 7 for Win95");
546 DBG_MSG("Word 6 for Macintosh");
547 bWord6MacFile
= TRUE
;
551 DBG_MSG_C(usChse
!= 256, "Word97 for Win95/98/NT");
552 DBG_MSG_C(usChse
== 256, "Word98 for Macintosh");
555 } /* end of iGetVersionNumber */
558 * TRUE if the current file was made by Word 6 on an Apple Macintosh,
560 * This function hides the methode of how to find out from the rest of the
564 bIsWord6MacFile(void)
566 return bWord6MacFile
;
567 } /* end of bIsWord6MacFile */
570 * lComputeLeading - compute the leading
572 * NOTE: the fontsize is given in half points
574 * Returns the leading in drawunits
577 lComputeLeading(int iFontsize
)
581 lLeading
= iFontsize
* 500L;
582 if (iFontsize
< 18) { /* Small text: 112% */
584 } else if (iFontsize
< 28) { /* Normal text: 124% */
586 } else if (iFontsize
< 48) { /* Small headlines: 104% */
588 } else { /* Large headlines: 100% */
591 lLeading
= lMilliPoints2DrawUnits(lLeading
);
595 } /* end of lComputeLeading */