Imported from antiword-0.37.tar.gz.
[antiword.git] / Win32-only / misc.c
blob92714f4ac05c101f7f66e4b57b3736199c075091
1 /*
2 * misc.c
3 * Copyright (C) 1998-2001 A.J. van Os; Released under GPL
5 * Description:
6 * misc. functions
7 */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <time.h>
14 #if defined(__riscos)
15 #include "kernel.h"
16 #include "swis.h"
17 #else
18 #include <errno.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #if defined(__dos)
22 #define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
23 #define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
24 #endif /* __dos */
25 #endif /* __riscos */
26 #if defined(WIN32)
27 #include "windows.h"
28 #endif // WIN32
30 #include "antiword.h"
32 static BOOL bWord6MacFile = FALSE;
35 #if !defined(__riscos)
37 * szGetHomeDirectory - get the name of the home directory
39 const char *
40 szGetHomeDirectory(void)
42 static char homedir[256];
43 const char *szHome;
45 szHome = getenv("HOME");
46 if (szHome == NULL || szHome[0] == '\0') {
47 #if defined(WIN32)
48 (void)GetCurrentDirectory(255, &homedir[0]);
49 szHome = &homedir[0];
50 #else
51 #if defined(__dos)
52 szHome = "C:";
54 #else
55 werr(0, "I can't find the name of your HOME directory");
56 szHome = "";
57 #endif /* __dos */
58 #endif // WIN32
60 return szHome;
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.
68 long
69 lGetFilesize(const char *szFilename)
71 #if defined(__riscos)
72 _kernel_swi_regs regs;
73 _kernel_oserror *e;
75 (void)memset(&regs, 0, sizeof(regs));
76 regs.r[0] = 17;
77 regs.r[1] = (int)szFilename;
78 e = _kernel_swi(OS_File, &regs, &regs);
79 if (e != NULL) {
80 werr(0, "Get Filesize error %d: %s",
81 e->errnum, e->errmess);
82 return -1;
84 if (regs.r[0] != 1) {
85 /* It's not a proper file or the file does not exist */
86 return -1;
88 return (long)regs.r[4];
89 #else
90 struct stat tBuffer;
92 if (stat(szFilename, &tBuffer) != 0) {
93 werr(0, "Get Filesize error %d", errno);
94 return -1;
96 if (!S_ISREG(tBuffer.st_mode)) {
97 /* It's not a regular file */
98 return -1;
100 return (long)tBuffer.st_size;
101 #endif /* __riscos */
102 } /* end of lGetFilesize */
104 #if defined(DEBUG)
105 void
106 vPrintBlock(const char *szFile, int iLine,
107 const unsigned char *aucBlock, size_t tLength)
109 int i, j;
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) {
116 return;
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 */
128 void
129 vPrintUnicode(const char *szFile, int iLine, const char *s)
131 size_t tLen;
132 char *szASCII;
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 */
142 BOOL
143 bCheckDoubleLinkedList(output_type *pAnchor)
145 output_type *pCurr, *pLast;
146 int iInList;
148 pLast = pAnchor;
149 iInList = 0;
150 for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
151 pLast = pCurr;
152 iInList++;
154 NO_DBG_DEC(iInList);
155 for (pCurr = pLast; pCurr != NULL; pCurr = pCurr->pPrev) {
156 pLast = pCurr;
157 iInList--;
159 DBG_DEC_C(iInList != 0, iInList);
160 return pAnchor == pLast && iInList == 0;
161 } /* end of bCheckDoubleLinkedList */
162 #endif /* DEBUG */
165 * bReadBytes
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
170 BOOL
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) {
176 return FALSE;
178 if (fread(aucBytes, sizeof(unsigned char), tMemb, pFile) != tMemb) {
179 return FALSE;
181 return TRUE;
182 } /* end of bReadBytes */
185 * bReadBuffer
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
191 BOOL
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)
196 long lBegin, lIndex;
197 size_t tLen;
199 fail(pFile == NULL);
200 fail(lStartBlock < 0);
201 fail(alBlockDepot == NULL);
202 fail(tBlockSize != BIG_BLOCK_SIZE && tBlockSize != SMALL_BLOCK_SIZE);
203 fail(aucBuffer == NULL);
204 fail(tToRead == 0);
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");
212 } else {
213 werr(1, "The Small Block Depot is corrupt");
216 if (lOffset >= (long)tBlockSize) {
217 lOffset -= (long)tBlockSize;
218 continue;
220 lBegin = lDepotOffset(lIndex, tBlockSize) + lOffset;
221 tLen = min(tBlockSize - (size_t)lOffset, tToRead);
222 lOffset = 0;
223 if (!bReadBytes(aucBuffer, tLen, lBegin, pFile)) {
224 werr(0, "Read big block %ld not possible", lBegin);
225 return FALSE;
227 aucBuffer += tLen;
228 tToRead -= tLen;
230 DBG_DEC_C(tToRead != 0, tToRead);
231 return tToRead == 0;
232 } /* end of bReadBuffer */
235 * Translate a Word colornumber into a true color for use in a drawfile
237 * Returns the true color
239 unsigned int
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.
273 static int
274 iFindSplit(const char *szString, int iStringLen)
276 int iSplit;
278 iSplit = iStringLen - 1;
279 while (iSplit >= 1) {
280 if (szString[iSplit] == ' ' ||
281 (szString[iSplit] == '-' && szString[iSplit - 1] != ' ')) {
282 return iSplit;
284 iSplit--;
286 return -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
294 output_type *
295 pSplitList(output_type *pAnchor)
297 output_type *pCurr, *pLeftOver;
298 int iIndex;
300 fail(pAnchor == NULL);
302 for (pCurr = pAnchor; pCurr->pNext != NULL; pCurr = pCurr->pNext)
303 ; /* EMPTY */
304 iIndex = -1;
305 for (; pCurr != NULL; pCurr = pCurr->pPrev) {
306 iIndex = iFindSplit(pCurr->szStorage, pCurr->iNextFree);
307 if (iIndex >= 0) {
308 break;
312 if (pCurr == NULL || iIndex < 0) {
313 /* No split, no leftover */
314 return NULL;
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,
333 pLeftOver->tFontRef,
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])) {
345 iIndex--;
347 pCurr->iNextFree = iIndex + 1;
348 pCurr->szStorage[pCurr->iNextFree] = '\0';
349 NO_DBG_MSG(pCurr->szStorage);
350 pCurr->lStringWidth = lComputeStringWidth(
351 pCurr->szStorage,
352 pCurr->iNextFree,
353 pCurr->tFontRef,
354 pCurr->sFontsize);
355 pCurr->pNext = NULL;
356 fail(!bCheckDoubleLinkedList(pAnchor));
358 return pLeftOver;
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)
369 char *outp, *p, *q;
370 int iNextVal, iValue;
372 fail(szOutput == NULL);
374 if (iNumber <= 0 || iNumber >= 4000) {
375 szOutput[0] = '\0';
376 return 0;
379 outp = szOutput;
380 p = bUpperCase ? "M\2D\5C\2L\5X\2V\5I" : "m\2d\5c\2l\5x\2v\5i";
381 iValue = 1000;
382 for (;;) {
383 while (iNumber >= iValue) {
384 *outp++ = *p;
385 iNumber -= iValue;
387 if (iNumber <= 0) {
388 *outp = '\0';
389 return outp - szOutput;
391 q = p + 1;
392 iNextVal = iValue / (int)*q;
393 if ((int)*q == 2) { /* magic */
394 iNextVal /= (int)*(q += 2);
396 if (iNumber + iNextVal >= iValue) {
397 *outp++ = *++q;
398 iNumber += iNextVal;
399 } else {
400 p++;
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)
414 char *outp;
415 int iTmp;
417 fail(szOutput == NULL);
419 outp = szOutput;
420 iTmp = bUpperCase ? 'A': 'a';
421 if (iNumber <= 26) {
422 iNumber -= 1;
423 *outp++ = (char)(iTmp + iNumber);
424 } else if (iNumber <= 26 + 26*26) {
425 iNumber -= 26 + 1;
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);
434 *outp = '\0';
435 return outp - szOutput;
436 } /* end of iInteger2Alpha */
439 * unincpy - copy a counted Unicode string to an single-byte string
441 char *
442 unincpy(char *s1, const char *s2, size_t n)
444 char *dest;
445 unsigned long ulChar;
446 size_t len;
447 unsigned short usUni;
449 for (dest = s1, len = 0; len < n; dest++, len++) {
450 usUni = usGetWord(len * 2, s2);
451 if (usUni == 0) {
452 break;
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++) {
461 *dest++ = '\0';
463 return s1;
464 } /* end of unincpy */
467 * unilen - calculate the length of a Unicode string
469 size_t
470 unilen(const char *s)
472 size_t tLen;
473 unsigned short usUni;
475 tLen = 0;
476 for (;;) {
477 usUni = usGetWord(tLen * 2, s);
478 if (usUni == 0) {
479 return tLen;
481 tLen += 2;
483 } /* end of unilen */
486 * szBaseName - get the basename of the given filename
488 const char *
489 szBasename(const char *szFilename)
491 const char *szTmp;
493 fail(szFilename == NULL);
495 if (szFilename == NULL || szFilename[0] == '\0') {
496 return "null";
499 szTmp = strrchr(szFilename, FILE_SEPARATOR[0]);
500 if (szTmp == NULL) {
501 return szFilename;
503 return ++szTmp;
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);
517 DBG_DEC(usFib);
518 if (usFib < 101) {
519 /* This file is from a version of Word older than Word 6 */
520 return -1;
522 usChse = usGetWord(0x14, aucHeader);
523 DBG_DEC(usChse);
524 bWord6MacFile = FALSE;
525 switch (usFib) {
526 case 101:
527 case 102:
528 DBG_MSG("Word 6 for Windows");
529 return 6;
530 case 103:
531 case 104:
532 switch (usChse) {
533 case 0:
534 DBG_MSG("Word 7 for Win95");
535 return 7;
536 case 256:
537 DBG_MSG("Word 6 for Macintosh");
538 bWord6MacFile = TRUE;
539 return 6;
540 default:
541 DBG_FIXME();
542 if (ucGetByte(0x05, aucHeader) == 0xe0) {
543 DBG_MSG("Word 7 for Win95");
544 return 7;
546 DBG_MSG("Word 6 for Macintosh");
547 bWord6MacFile = TRUE;
548 return 6;
550 default:
551 DBG_MSG_C(usChse != 256, "Word97 for Win95/98/NT");
552 DBG_MSG_C(usChse == 256, "Word98 for Macintosh");
553 return 8;
555 } /* end of iGetVersionNumber */
558 * TRUE if the current file was made by Word 6 on an Apple Macintosh,
559 * otherwise FALSE.
560 * This function hides the methode of how to find out from the rest of the
561 * program.
563 BOOL
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
576 long
577 lComputeLeading(int iFontsize)
579 long lLeading;
581 lLeading = iFontsize * 500L;
582 if (iFontsize < 18) { /* Small text: 112% */
583 lLeading *= 112;
584 } else if (iFontsize < 28) { /* Normal text: 124% */
585 lLeading *= 124;
586 } else if (iFontsize < 48) { /* Small headlines: 104% */
587 lLeading *= 104;
588 } else { /* Large headlines: 100% */
589 lLeading *= 100;
591 lLeading = lMilliPoints2DrawUnits(lLeading);
592 lLeading += 50;
593 lLeading /= 100;
594 return lLeading;
595 } /* end of lComputeLeading */