summaryrefslogtreecommitdiff
path: root/sys/src/cmd/aux/antiword
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/aux/antiword
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/aux/antiword')
-rwxr-xr-xsys/src/cmd/aux/antiword/antiword.h735
-rwxr-xr-xsys/src/cmd/aux/antiword/asc85enc.c154
-rwxr-xr-xsys/src/cmd/aux/antiword/blocklist.c823
-rwxr-xr-xsys/src/cmd/aux/antiword/chartrans.c720
-rwxr-xr-xsys/src/cmd/aux/antiword/datalist.c374
-rwxr-xr-xsys/src/cmd/aux/antiword/debug.h117
-rwxr-xr-xsys/src/cmd/aux/antiword/depot.c114
-rwxr-xr-xsys/src/cmd/aux/antiword/dib2eps.c509
-rwxr-xr-xsys/src/cmd/aux/antiword/dib2sprt.c597
-rwxr-xr-xsys/src/cmd/aux/antiword/doclist.c75
-rwxr-xr-xsys/src/cmd/aux/antiword/draw.c1047
-rwxr-xr-xsys/src/cmd/aux/antiword/draw.h46
-rwxr-xr-xsys/src/cmd/aux/antiword/drawfile.c422
-rwxr-xr-xsys/src/cmd/aux/antiword/drawfile.h433
-rwxr-xr-xsys/src/cmd/aux/antiword/fail.c26
-rwxr-xr-xsys/src/cmd/aux/antiword/fail.h22
-rwxr-xr-xsys/src/cmd/aux/antiword/finddata.c154
-rwxr-xr-xsys/src/cmd/aux/antiword/findtext.c289
-rwxr-xr-xsys/src/cmd/aux/antiword/fmt_text.c167
-rwxr-xr-xsys/src/cmd/aux/antiword/fontinfo.h2251
-rwxr-xr-xsys/src/cmd/aux/antiword/fontlist.c173
-rwxr-xr-xsys/src/cmd/aux/antiword/fonts.c1018
-rwxr-xr-xsys/src/cmd/aux/antiword/fonts_r.c251
-rwxr-xr-xsys/src/cmd/aux/antiword/fonts_u.c305
-rwxr-xr-xsys/src/cmd/aux/antiword/hdrftrlist.c371
-rwxr-xr-xsys/src/cmd/aux/antiword/icons.c96
-rwxr-xr-xsys/src/cmd/aux/antiword/imgexam.c1044
-rwxr-xr-xsys/src/cmd/aux/antiword/imgtrans.c71
-rwxr-xr-xsys/src/cmd/aux/antiword/jpeg2eps.c74
-rwxr-xr-xsys/src/cmd/aux/antiword/jpeg2sprt.c97
-rwxr-xr-xsys/src/cmd/aux/antiword/listlist.c330
-rwxr-xr-xsys/src/cmd/aux/antiword/main_ros.c520
-rwxr-xr-xsys/src/cmd/aux/antiword/main_u.c321
-rwxr-xr-xsys/src/cmd/aux/antiword/misc.c894
-rwxr-xr-xsys/src/cmd/aux/antiword/mkfile29
-rwxr-xr-xsys/src/cmd/aux/antiword/notes.c876
-rwxr-xr-xsys/src/cmd/aux/antiword/options.c950
-rwxr-xr-xsys/src/cmd/aux/antiword/out2window.c768
-rwxr-xr-xsys/src/cmd/aux/antiword/output.c538
-rwxr-xr-xsys/src/cmd/aux/antiword/pdf.c1148
-rwxr-xr-xsys/src/cmd/aux/antiword/pictlist.c109
-rwxr-xr-xsys/src/cmd/aux/antiword/png2eps.c191
-rwxr-xr-xsys/src/cmd/aux/antiword/png2sprt.c26
-rwxr-xr-xsys/src/cmd/aux/antiword/postscript.c1171
-rwxr-xr-xsys/src/cmd/aux/antiword/prop0.c489
-rwxr-xr-xsys/src/cmd/aux/antiword/prop2.c1067
-rwxr-xr-xsys/src/cmd/aux/antiword/prop6.c1141
-rwxr-xr-xsys/src/cmd/aux/antiword/prop8.c1496
-rwxr-xr-xsys/src/cmd/aux/antiword/properties.c198
-rwxr-xr-xsys/src/cmd/aux/antiword/propmod.c110
-rwxr-xr-xsys/src/cmd/aux/antiword/riscos.c251
-rwxr-xr-xsys/src/cmd/aux/antiword/rowlist.c117
-rwxr-xr-xsys/src/cmd/aux/antiword/saveas.c387
-rwxr-xr-xsys/src/cmd/aux/antiword/sectlist.c165
-rwxr-xr-xsys/src/cmd/aux/antiword/startup.c145
-rwxr-xr-xsys/src/cmd/aux/antiword/stylelist.c487
-rwxr-xr-xsys/src/cmd/aux/antiword/stylesheet.c838
-rwxr-xr-xsys/src/cmd/aux/antiword/summary.c888
-rwxr-xr-xsys/src/cmd/aux/antiword/tabstop.c212
-rwxr-xr-xsys/src/cmd/aux/antiword/text.c182
-rwxr-xr-xsys/src/cmd/aux/antiword/unix.c45
-rwxr-xr-xsys/src/cmd/aux/antiword/utf8.c260
-rwxr-xr-xsys/src/cmd/aux/antiword/version.h37
-rwxr-xr-xsys/src/cmd/aux/antiword/word2text.c1505
-rwxr-xr-xsys/src/cmd/aux/antiword/wordconst.h321
-rwxr-xr-xsys/src/cmd/aux/antiword/worddos.c110
-rwxr-xr-xsys/src/cmd/aux/antiword/wordlib.c359
-rwxr-xr-xsys/src/cmd/aux/antiword/wordmac.c108
-rwxr-xr-xsys/src/cmd/aux/antiword/wordole.c804
-rwxr-xr-xsys/src/cmd/aux/antiword/wordtypes.h317
-rwxr-xr-xsys/src/cmd/aux/antiword/wordwin.c209
-rwxr-xr-xsys/src/cmd/aux/antiword/xmalloc.c136
-rwxr-xr-xsys/src/cmd/aux/antiword/xml.c1438
73 files changed, 34268 insertions, 0 deletions
diff --git a/sys/src/cmd/aux/antiword/antiword.h b/sys/src/cmd/aux/antiword/antiword.h
new file mode 100755
index 000000000..3f4aad5b1
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/antiword.h
@@ -0,0 +1,735 @@
+/*
+ * antiword.h
+ * Copyright (C) 1998-2004 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Generic include file for project 'Antiword'
+ */
+
+#if !defined(__antiword_h)
+#define __antiword_h 1
+
+#if defined(DEBUG) == defined(NDEBUG)
+#error Exactly one of the DEBUG and NDEBUG flags MUST be set
+#endif /* DEBUG == NDEBUG */
+
+#include <stdio.h>
+#include <limits.h>
+#if defined(__riscos)
+#include "DeskLib:Font.h"
+#include "DeskLib:Wimp.h"
+#include "Desklib:Window.h"
+#include "drawfile.h"
+#define window_ANY event_ANY
+#define icon_ANY event_ANY
+#else
+#include <sys/types.h>
+#endif /* __riscos */
+#include "wordconst.h"
+#include "wordtypes.h"
+#include "fail.h"
+#include "debug.h"
+
+/* Constants */
+#if !defined(PATH_MAX)
+ #if defined(__riscos)
+ #define PATH_MAX 255
+ #else
+ #if defined(MAXPATHLEN)
+ #define PATH_MAX MAXPATHLEN
+ #else
+ #define PATH_MAX 1024
+ #endif /* MAXPATHLEN */
+ #endif /* __riscos */
+#endif /* !PATH_MAX */
+
+#if !defined(CHAR_BIT)
+#define CHAR_BIT 8
+#endif /* CHAR_BIT */
+
+#if !defined(TIME_T_MIN)
+#define TIME_T_MIN ((time_t)0 < (time_t)-1 ?\
+ (time_t)0 :\
+ (time_t)1 << (sizeof(time_t) * CHAR_BIT - 1))
+#endif /* TIMER_T_MIN */
+
+#if !defined(TIME_T_MAX)
+#if defined(__TURBOC__) /* Turbo C chokes on the subtraction below */
+#define TIME_T_MAX (LONG_MAX)
+#else /* All others */
+#define TIME_T_MAX (~(time_t)0 - TIME_T_MIN)
+#endif /* __TURBOC__ */
+#endif /* TIME_T_MAX */
+
+#if !defined(SIZE_T_MAX)
+#define SIZE_T_MAX (~(size_t)0)
+#endif /* SIZE_T_MAX */
+
+#if defined(__riscos)
+#define FILE_SEPARATOR "."
+#elif defined(__dos) || defined(__CYGMING__)
+#define FILE_SEPARATOR "\\"
+#else /* All others */
+#define FILE_SEPARATOR "/"
+#endif /* __riscos */
+
+/* PNG chunk names */
+#define PNG_CN_IDAT 0x49444154
+#define PNG_CN_IEND 0x49454e44
+#define PNG_CN_IHDR 0x49484452
+#define PNG_CN_PLTE 0x504c5445
+
+/* The screen width */
+#define MIN_SCREEN_WIDTH 45
+#define DEFAULT_SCREEN_WIDTH 76
+#define MAX_SCREEN_WIDTH 145
+
+#if defined(__riscos)
+/* The scale factors as percentages */
+#define MIN_SCALE_FACTOR 25
+#define DEFAULT_SCALE_FACTOR 100
+#define MAX_SCALE_FACTOR 400
+
+/* Filetypes */
+#define FILETYPE_MSWORD 0xae6
+#define FILETYPE_DRAW 0xaff
+#define FILETYPE_JPEG 0xc85
+#define FILETYPE_POSCRIPT 0xff5
+#define FILETYPE_SPRITE 0xff9
+#define FILETYPE_TEXT 0xfff
+
+/* The button numbers in the choices window */
+#define CHOICES_DEFAULT_BUTTON 3
+#define CHOICES_SAVE_BUTTON 2
+#define CHOICES_CANCEL_BUTTON 1
+#define CHOICES_APPLY_BUTTON 0
+#define CHOICES_BREAK_BUTTON 6
+#define CHOICES_BREAK_WRITEABLE 7
+#define CHOICES_BREAK_UP_BUTTON 8
+#define CHOICES_BREAK_DOWN_BUTTON 9
+#define CHOICES_NO_BREAK_BUTTON 11
+#define CHOICES_AUTOFILETYPE_BUTTON 14
+#define CHOICES_HIDDEN_TEXT_BUTTON 22
+#define CHOICES_WITH_IMAGES_BUTTON 17
+#define CHOICES_NO_IMAGES_BUTTON 18
+#define CHOICES_TEXTONLY_BUTTON 19
+#define CHOICES_SCALE_WRITEABLE 25
+#define CHOICES_SCALE_UP_BUTTON 26
+#define CHOICES_SCALE_DOWN_BUTTON 27
+
+/* The button numbers in the scale view window */
+#define SCALE_CANCEL_BUTTON 1
+#define SCALE_SCALE_BUTTON 0
+#define SCALE_SCALE_WRITEABLE 3
+#define SCALE_50_PCT 5
+#define SCALE_75_PCT 6
+#define SCALE_100_PCT 7
+#define SCALE_150_PCT 8
+
+/* Save menu fields */
+#define SAVEMENU_SCALEVIEW 0
+#define SAVEMENU_SAVEDRAW 1
+#define SAVEMENU_SAVETEXT 2
+#else
+/* Margins for the PostScript version */
+#define PS_LEFT_MARGIN (72 * 640L)
+#define PS_RIGHT_MARGIN (48 * 640L)
+#define PS_TOP_MARGIN (72 * 640L)
+#define PS_BOTTOM_MARGIN (72 * 640L)
+#endif /* __riscos */
+
+/* Macros */
+#define STREQ(x,y) (*(x) == *(y) && strcmp(x,y) == 0)
+#define STRNEQ(x,y,n) (*(x) == *(y) && strncmp(x,y,n) == 0)
+#if defined(__dos) || defined(__EMX__)
+#define STRCEQ(x,y) (stricmp(x,y) == 0)
+#else
+#define STRCEQ(x,y) (strcasecmp(x,y) == 0)
+#endif /* __dos or __EMX__ */
+#define elementsof(a) (sizeof(a) / sizeof(a[0]))
+#define odd(x) (((x)&0x01)!=0)
+#define ROUND4(x) (((x)+3)&~0x03)
+#define ROUND128(x) (((x)+127)&~0x7f)
+#define BIT(x) (1UL << (x))
+#if !defined(max)
+#define max(x,y) ((x)>(y)?(x):(y))
+#endif /* !max */
+#if !defined(min)
+#define min(x,y) ((x)<(y)?(x):(y))
+#endif /* !min */
+
+#if defined(__riscos)
+/* The name of the table font */
+#define TABLE_FONT "Corpus.Medium"
+/* Names of the default fonts */
+#define FONT_MONOSPACED_PLAIN "Corpus.Medium"
+#define FONT_MONOSPACED_BOLD "Corpus.Bold"
+#define FONT_MONOSPACED_ITALIC "Corpus.Medium.Oblique"
+#define FONT_MONOSPACED_BOLDITALIC "Corpus.Bold.Oblique"
+#define FONT_SERIF_PLAIN "Trinity.Medium"
+#define FONT_SERIF_BOLD "Trinity.Bold"
+#define FONT_SERIF_ITALIC "Trinity.Medium.Italic"
+#define FONT_SERIF_BOLDITALIC "Trinity.Bold.Italic"
+#define FONT_SANS_SERIF_PLAIN "Homerton.Medium"
+#define FONT_SANS_SERIF_BOLD "Homerton.Bold"
+#define FONT_SANS_SERIF_ITALIC "Homerton.Medium.Oblique"
+#define FONT_SANS_SERIF_BOLDITALIC "Homerton.Bold.Oblique"
+#else
+/* The name of the table font */
+#define TABLE_FONT "Courier"
+/* Names of the default fonts */
+#define FONT_MONOSPACED_PLAIN "Courier"
+#define FONT_MONOSPACED_BOLD "Courier-Bold"
+#define FONT_MONOSPACED_ITALIC "Courier-Oblique"
+#define FONT_MONOSPACED_BOLDITALIC "Courier-BoldOblique"
+#define FONT_SERIF_PLAIN "Times-Roman"
+#define FONT_SERIF_BOLD "Times-Bold"
+#define FONT_SERIF_ITALIC "Times-Italic"
+#define FONT_SERIF_BOLDITALIC "Times-BoldItalic"
+#define FONT_SANS_SERIF_PLAIN "Helvetica"
+#define FONT_SANS_SERIF_BOLD "Helvetica-Bold"
+#define FONT_SANS_SERIF_ITALIC "Helvetica-Oblique"
+#define FONT_SANS_SERIF_BOLDITALIC "Helvetica-BoldOblique"
+/* The name of the antiword directories and the font information file */
+#if defined(__dos)
+#define GLOBAL_ANTIWORD_DIR "C:\\antiword"
+#define ANTIWORD_DIR "antiword"
+#define FONTNAMES_FILE "fontname.txt"
+#elif defined(__amigaos)
+#define GLOBAL_ANTIWORD_DIR "SYS:.antiword"
+#define ANTIWORD_DIR ".antiword"
+#define FONTNAMES_FILE "fontnames"
+#elif defined(N_PLAT_NLM)
+#define GLOBAL_ANTIWORD_DIR "SYS:/antiword"
+#define ANTIWORD_DIR "antiword"
+#define FONTNAMES_FILE "fontname.txt"
+#elif defined(__vms)
+#define GLOBAL_ANTIWORD_DIR "/usr/share/antiword"
+#define ANTIWORD_DIR "antiword"
+#define FONTNAMES_FILE "fontnames"
+#elif defined(__BEOS__)
+#define GLOBAL_ANTIWORD_DIR "/boot/home/config/apps/antiword"
+#define ANTIWORD_DIR "antiword"
+#define FONTNAMES_FILE "fontnames"
+#elif defined(__CYGMING__)
+#define GLOBAL_ANTIWORD_DIR "C:\\antiword"
+#define ANTIWORD_DIR "antiword"
+#define FONTNAMES_FILE "fontnames"
+#elif defined(__Plan9__)
+#define GLOBAL_ANTIWORD_DIR "/sys/lib/antiword"
+#define ANTIWORD_DIR "lib/antiword"
+#define FONTNAMES_FILE "fontnames"
+#elif defined(__sun__)
+#define GLOBAL_ANTIWORD_DIR "/usr/local/share/antiword"
+#define ANTIWORD_DIR ".antiword"
+#define FONTNAMES_FILE "fontnames"
+#else /* All others */
+#define GLOBAL_ANTIWORD_DIR "/usr/share/antiword"
+#define ANTIWORD_DIR ".antiword"
+#define FONTNAMES_FILE "fontnames"
+#endif /* __dos */
+/* The names of grouped mapping files */
+ /* ASCII */
+#define MAPPING_FILE_CP437 "cp437.txt"
+ /* Latin1 */
+#define MAPPING_FILE_8859_1 "8859-1.txt"
+ /* Latin2 */
+#define MAPPING_FILE_8859_2 "8859-2.txt"
+#define MAPPING_FILE_CP852 "cp852.txt"
+#define MAPPING_FILE_CP1250 "cp1250.txt"
+ /* Cyrillic */
+#define MAPPING_FILE_8859_5 "8859-5.txt"
+#define MAPPING_FILE_KOI8_R "koi8-r.txt"
+#define MAPPING_FILE_KOI8_U "koi8-u.txt"
+#define MAPPING_FILE_CP866 "cp866.txt"
+#define MAPPING_FILE_CP1251 "cp1251.txt"
+ /* Latin9 */
+#define MAPPING_FILE_8859_15 "8859-15.txt"
+ /* UTF-8 */
+#define MAPPING_FILE_UTF_8 "UTF-8.txt"
+#endif /* __riscos */
+
+/* Prototypes */
+
+/* asc85enc.c */
+extern void vASCII85EncodeByte(FILE *, int);
+extern void vASCII85EncodeArray(FILE *, FILE *, size_t);
+extern void vASCII85EncodeFile(FILE *, FILE *, size_t);
+/* blocklist.c */
+extern void vDestroyTextBlockList(void);
+extern BOOL bAdd2TextBlockList(const text_block_type *);
+extern void vSplitBlockList(FILE *, ULONG, ULONG, ULONG, ULONG, ULONG,
+ ULONG, ULONG, ULONG, BOOL);
+extern BOOL bExistsHdrFtr(void);
+extern BOOL bExistsTextBox(void);
+extern BOOL bExistsHdrTextBox(void);
+extern USHORT usNextChar(FILE *, list_id_enum, ULONG *, ULONG *, USHORT *);
+extern USHORT usToHdrFtrPosition(FILE *, ULONG);
+extern USHORT usToFootnotePosition(FILE *, ULONG);
+extern ULONG ulCharPos2FileOffsetX(ULONG, list_id_enum *);
+extern ULONG ulCharPos2FileOffset(ULONG);
+extern ULONG ulHdrFtrOffset2CharPos(ULONG);
+extern ULONG ulGetSeqNumber(ULONG);
+#if defined(__riscos)
+extern ULONG ulGetDocumentLength(void);
+#endif /* __riscos */
+/* chartrans.c */
+extern UCHAR ucGetBulletCharacter(conversion_type, encoding_type);
+extern UCHAR ucGetNbspCharacter(void);
+extern BOOL bReadCharacterMappingTable(FILE *);
+extern ULONG ulTranslateCharacters(USHORT, ULONG, int, conversion_type,
+ encoding_type, BOOL);
+extern ULONG ulToUpper(ULONG);
+/* datalist.c */
+extern void vDestroyDataBlockList(void);
+extern BOOL bAdd2DataBlockList(const data_block_type *);
+extern ULONG ulGetDataOffset(FILE *);
+extern BOOL bSetDataOffset(FILE *, ULONG);
+extern int iNextByte(FILE *);
+extern USHORT usNextWord(FILE *);
+extern ULONG ulNextLong(FILE *);
+extern USHORT usNextWordBE(FILE *);
+extern ULONG ulNextLongBE(FILE *);
+extern size_t tSkipBytes(FILE *, size_t);
+extern ULONG ulDataPos2FileOffset(ULONG);
+/* depot.c */
+extern void vDestroySmallBlockList(void);
+extern BOOL bCreateSmallBlockList(ULONG, const ULONG *, size_t);
+extern ULONG ulDepotOffset(ULONG, size_t);
+/* dib2eps & dib2sprt.c */
+extern BOOL bTranslateDIB(diagram_type *,
+ FILE *, ULONG, const imagedata_type *);
+#if defined(__dos)
+/* dos.c */
+extern int iGetCodepage(void);
+#endif /* __dos */
+/* doclist.c */
+extern void vDestroyDocumentInfoList(void);
+extern void vCreateDocumentInfoList(const document_block_type *);
+extern UCHAR ucGetDopHdrFtrSpecification(void);
+/* draw.c & output.c */
+extern BOOL bAddDummyImage(diagram_type *, const imagedata_type *);
+extern diagram_type *pCreateDiagram(const char *, const char *);
+extern void vPrologue2(diagram_type *, int);
+extern void vMove2NextLine(diagram_type *, drawfile_fontref, USHORT);
+extern void vSubstring2Diagram(diagram_type *,
+ char *, size_t, long, UCHAR, USHORT,
+ drawfile_fontref, USHORT, USHORT);
+extern void vStartOfParagraph1(diagram_type *, long);
+extern void vStartOfParagraph2(diagram_type *);
+extern void vEndOfParagraph(diagram_type *, drawfile_fontref, USHORT, long);
+extern void vEndOfPage(diagram_type *, long, BOOL);
+extern void vSetHeaders(diagram_type *, USHORT);
+extern void vStartOfList(diagram_type *, UCHAR, BOOL);
+extern void vEndOfList(diagram_type *);
+extern void vStartOfListItem(diagram_type *, BOOL);
+extern void vEndOfTable(diagram_type *);
+extern BOOL bAddTableRow(diagram_type *, char **, int,
+ const short *, UCHAR);
+#if defined(__riscos)
+extern BOOL bDestroyDiagram(event_pollblock *, void *);
+extern void vImage2Diagram(diagram_type *, const imagedata_type *,
+ UCHAR *, size_t);
+extern BOOL bVerifyDiagram(diagram_type *);
+extern void vShowDiagram(diagram_type *);
+extern void vMainButtonClick(mouse_block *);
+extern BOOL bMainKeyPressed(event_pollblock *, void *);
+extern BOOL bMainEventHandler(event_pollblock *, void *);
+extern BOOL bRedrawMainWindow(event_pollblock *, void *);
+extern BOOL bScaleOpenAction(event_pollblock *, void *);
+extern void vSetTitle(diagram_type *);
+extern void vScaleButtonClick(mouse_block *, diagram_type *);
+extern BOOL bScaleKeyPressed(event_pollblock *, void *);
+extern BOOL bScaleEventHandler(event_pollblock *, void *);
+#else
+extern void vImagePrologue(diagram_type *, const imagedata_type *);
+extern void vImageEpilogue(diagram_type *);
+extern void vDestroyDiagram(diagram_type *);
+#endif /* __riscos */
+/* finddata.c */
+extern BOOL bAddDataBlocks(ULONG , ULONG, ULONG, const ULONG *, size_t);
+extern BOOL bGet6DocumentData(FILE *, ULONG,
+ const ULONG *, size_t, const UCHAR *);
+/* findtext.c */
+extern BOOL bAddTextBlocks(ULONG , ULONG, BOOL,
+ USHORT, ULONG, const ULONG *, size_t);
+extern BOOL bGet6DocumentText(FILE *, BOOL, ULONG,
+ const ULONG *, size_t, const UCHAR *);
+extern BOOL bGet8DocumentText(FILE *, const pps_info_type *,
+ const ULONG *, size_t, const ULONG *, size_t,
+ const UCHAR *);
+/* fmt_text.c */
+extern void vPrologueFMT(diagram_type *, const options_type *);
+extern void vSubstringFMT(diagram_type *, const char *, size_t, long,
+ USHORT);
+/* fontlist.c */
+extern void vDestroyFontInfoList(void);
+extern void vCorrectFontValues(font_block_type *);
+extern void vAdd2FontInfoList(const font_block_type *);
+extern const font_block_type *pGetNextFontInfoListItem(
+ const font_block_type *);
+/* fonts.c */
+extern int iGetFontByNumber(UCHAR, USHORT);
+extern const char *szGetOurFontname(int);
+extern int iFontname2Fontnumber(const char *, USHORT);
+extern void vCreate0FontTable(void);
+extern void vCreate2FontTable(FILE *, int, const UCHAR *);
+extern void vCreate6FontTable(FILE *, ULONG,
+ const ULONG *, size_t, const UCHAR *);
+extern void vCreate8FontTable(FILE *, const pps_info_type *,
+ const ULONG *, size_t, const ULONG *, size_t,
+ const UCHAR *);
+extern void vDestroyFontTable(void);
+extern const font_table_type *pGetNextFontTableRecord(
+ const font_table_type *);
+extern size_t tGetFontTableLength(void);
+extern void vCorrectFontTable(conversion_type, encoding_type);
+extern long lComputeSpaceWidth(drawfile_fontref, USHORT);
+/* fonts_r.c & fonts_u.c */
+extern FILE *pOpenFontTableFile(void);
+extern void vCloseFont(void);
+extern drawfile_fontref tOpenFont(UCHAR, USHORT, USHORT);
+extern drawfile_fontref tOpenTableFont(USHORT);
+extern long lComputeStringWidth(const char *, size_t, drawfile_fontref, USHORT);
+extern size_t tCountColumns(const char *, size_t);
+extern size_t tGetCharacterLength(const char *);
+/* fonts_u.c */
+#if !defined(__riscos)
+extern const char *szGetFontname(drawfile_fontref);
+#endif /* !__riscos */
+/* hdrftrlist.c */
+extern void vDestroyHdrFtrInfoList(void);
+extern void vCreat8HdrFtrInfoList(const ULONG *, size_t);
+extern void vCreat6HdrFtrInfoList(const ULONG *, size_t);
+extern void vCreat2HdrFtrInfoList(const ULONG *, size_t);
+extern const hdrftr_block_type *pGetHdrFtrInfo(int, BOOL, BOOL, BOOL);
+extern void vPrepareHdrFtrText(FILE *);
+#if defined(__riscos)
+/* icons.c */
+extern void vUpdateIcon(window_handle, icon_block *);
+extern void vUpdateRadioButton(window_handle, icon_handle, BOOL);
+extern void vUpdateWriteable(window_handle, icon_handle, const char *);
+extern void vUpdateWriteableNumber(window_handle, icon_handle, int);
+#endif /* __riscos */
+/* imgexam.c */
+extern image_info_enum eExamineImage(FILE *, ULONG, imagedata_type *);
+/* imgtrans */
+extern BOOL bTranslateImage(diagram_type *,
+ FILE *, BOOL, ULONG, const imagedata_type *);
+/* jpeg2eps.c & jpeg2spr.c */
+extern BOOL bTranslateJPEG(diagram_type *,
+ FILE *, ULONG, size_t, const imagedata_type *);
+/* listlist.c */
+extern void vDestroyListInfoList(void);
+extern void vBuildLfoList(const UCHAR *, size_t);
+extern void vAdd2ListInfoList(ULONG, USHORT, UCHAR,
+ const list_block_type *);
+extern const list_block_type *pGetListInfo(USHORT, UCHAR);
+extern USHORT usGetListValue(int, int, const style_block_type *);
+/* misc.c */
+#if !defined(__riscos)
+extern const char *szGetHomeDirectory(void);
+extern const char *szGetAntiwordDirectory(void);
+#endif /* !__riscos */
+extern long lGetFilesize(const char *);
+#if defined(DEBUG)
+extern void vPrintBlock(const char *, int, const UCHAR *, size_t);
+extern void vPrintUnicode(const char *, int, const UCHAR *, size_t);
+extern BOOL bCheckDoubleLinkedList(output_type *);
+#endif /* DEBUG */
+extern BOOL bReadBytes(UCHAR *, size_t, ULONG, FILE *);
+extern BOOL bReadBuffer(FILE *, ULONG, const ULONG *, size_t, size_t,
+ UCHAR *, ULONG, size_t);
+extern ULONG ulColor2Color(UCHAR);
+extern output_type *pSplitList(output_type *);
+extern size_t tNumber2Roman(UINT, BOOL, char *);
+extern size_t tNumber2Alpha(UINT, BOOL, char *);
+extern char *unincpy(char *, const UCHAR *, size_t);
+extern size_t unilen(const UCHAR *);
+extern const char *szBasename(const char *);
+extern long lComputeLeading(USHORT);
+extern size_t tUcs2Utf8(ULONG, char *, size_t);
+extern void vGetBulletValue(conversion_type, encoding_type, char *, size_t);
+extern BOOL bAllZero(const UCHAR *, size_t);
+extern BOOL bGetNormalizedCodeset(char *, size_t, BOOL *);
+extern const char *szGetDefaultMappingFile(void);
+extern time_t tConvertDTTM(ULONG);
+/* notes.c */
+extern void vDestroyNotesInfoLists(void);
+extern void vGetNotesInfo(FILE *, const pps_info_type *,
+ const ULONG *, size_t, const ULONG *, size_t,
+ const UCHAR *, int);
+extern void vPrepareFootnoteText(FILE *);
+extern const char *szGetFootnootText(UINT);
+extern notetype_enum eGetNotetype(ULONG);
+/* options.c */
+extern int iReadOptions(int, char **);
+extern void vGetOptions(options_type *);
+#if defined(__riscos)
+extern void vChoicesOpenAction(window_handle);
+extern BOOL bChoicesMouseClick(event_pollblock *, void *);
+extern BOOL bChoicesKeyPressed(event_pollblock *, void *);
+#endif /* __riscos */
+/* out2window.c */
+extern void vSetLeftIndentation(diagram_type *, long);
+extern void vAlign2Window(diagram_type *, output_type *,
+ long, UCHAR);
+extern void vJustify2Window(diagram_type *, output_type *,
+ long, long, UCHAR);
+extern void vResetStyles(void);
+extern size_t tStyle2Window(char *, size_t, const style_block_type *,
+ const section_block_type *);
+extern void vTableRow2Window(diagram_type *, output_type *,
+ const row_block_type *, conversion_type, int);
+/* pdf.c */
+extern void vCreateInfoDictionary(diagram_type *, int);
+extern void vProloguePDF(diagram_type *,
+ const char *, const options_type *);
+extern void vEpiloguePDF(diagram_type *);
+extern void vImageProloguePDF(diagram_type *, const imagedata_type *);
+extern void vImageEpiloguePDF(diagram_type *);
+extern BOOL bAddDummyImagePDF(diagram_type *, const imagedata_type *);
+extern void vAddFontsPDF(diagram_type *);
+extern void vMove2NextLinePDF(diagram_type *, USHORT);
+extern void vSubstringPDF(diagram_type *,
+ char *, size_t, long, UCHAR, USHORT,
+ drawfile_fontref, USHORT, USHORT);
+extern void vStartOfParagraphPDF(diagram_type *, long);
+extern void vEndOfParagraphPDF(diagram_type *, USHORT, long);
+extern void vEndOfPagePDF(diagram_type *, BOOL);
+/* pictlist.c */
+extern void vDestroyPictInfoList(void);
+extern void vAdd2PictInfoList(const picture_block_type *);
+extern ULONG ulGetPictInfoListItem(ULONG);
+/* png2eps.c & png2spr.c */
+extern BOOL bTranslatePNG(diagram_type *,
+ FILE *, ULONG, size_t, const imagedata_type *);
+/* postscript.c */
+extern void vProloguePS(diagram_type *,
+ const char *, const char *, const options_type *);
+extern void vEpiloguePS(diagram_type *);
+extern void vImageProloguePS(diagram_type *, const imagedata_type *);
+extern void vImageEpiloguePS(diagram_type *);
+extern BOOL bAddDummyImagePS(diagram_type *, const imagedata_type *);
+extern void vAddFontsPS(diagram_type *);
+extern void vMove2NextLinePS(diagram_type *, USHORT);
+extern void vSubstringPS(diagram_type *,
+ char *, size_t, long, UCHAR, USHORT,
+ drawfile_fontref, USHORT, USHORT);
+extern void vStartOfParagraphPS(diagram_type *, long);
+extern void vEndOfParagraphPS(diagram_type *, USHORT, long);
+extern void vEndOfPagePS(diagram_type *, BOOL);
+/* prop0.c */
+extern void vGet0DopInfo(FILE *, const UCHAR *);
+extern void vGet0SepInfo(FILE *, const UCHAR *);
+extern void vGet0PapInfo(FILE *, const UCHAR *);
+extern void vGet0ChrInfo(FILE *, const UCHAR *);
+/* prop2.c */
+extern void vGet2DopInfo(FILE *, const UCHAR *);
+extern void vGet2SepInfo(FILE *, const UCHAR *);
+extern void vGet2HdrFtrInfo(FILE *, const UCHAR *);
+extern row_info_enum eGet2RowInfo(int,
+ const UCHAR *, int, row_block_type *);
+extern void vGet2StyleInfo(int,
+ const UCHAR *, int, style_block_type *);
+extern void vGet2PapInfo(FILE *, const UCHAR *);
+extern void vGet1FontInfo(int,
+ const UCHAR *, size_t, font_block_type *);
+extern void vGet2FontInfo(int,
+ const UCHAR *, size_t, font_block_type *);
+extern void vGet2ChrInfo(FILE *, int, const UCHAR *);
+/* prop6.c */
+extern void vGet6DopInfo(FILE *, ULONG, const ULONG *, size_t,
+ const UCHAR *);
+extern void vGet6SepInfo(FILE *, ULONG, const ULONG *, size_t,
+ const UCHAR *);
+extern void vGet6HdrFtrInfo(FILE *, ULONG, const ULONG *, size_t,
+ const UCHAR *);
+extern row_info_enum eGet6RowInfo(int,
+ const UCHAR *, int, row_block_type *);
+extern void vGet6StyleInfo(int,
+ const UCHAR *, int, style_block_type *);
+extern void vGet6PapInfo(FILE *, ULONG, const ULONG *, size_t,
+ const UCHAR *);
+extern void vGet6FontInfo(int, USHORT,
+ const UCHAR *, int, font_block_type *);
+extern void vGet6ChrInfo(FILE *, ULONG, const ULONG *, size_t,
+ const UCHAR *);
+/* prop8.c */
+extern void vGet8DopInfo(FILE *, const pps_type *,
+ const ULONG *, size_t, const ULONG *, size_t,
+ const UCHAR *);
+extern void vGet8SepInfo(FILE *, const pps_info_type *,
+ const ULONG *, size_t, const ULONG *, size_t,
+ const UCHAR *);
+extern void vGet8HdrFtrInfo(FILE *, const pps_type *,
+ const ULONG *, size_t, const ULONG *, size_t,
+ const UCHAR *);
+extern row_info_enum eGet8RowInfo(int,
+ const UCHAR *, int, row_block_type *);
+extern void vGet8StyleInfo(int,
+ const UCHAR *, int, style_block_type *);
+extern void vGet8LstInfo(FILE *, const pps_info_type *,
+ const ULONG *, size_t, const ULONG *, size_t,
+ const UCHAR *);
+extern void vGet8PapInfo(FILE *, const pps_info_type *,
+ const ULONG *, size_t, const ULONG *, size_t,
+ const UCHAR *);
+extern void vGet8FontInfo(int, USHORT,
+ const UCHAR *, int, font_block_type *);
+extern void vGet8ChrInfo(FILE *, const pps_info_type *,
+ const ULONG *, size_t, const ULONG *, size_t,
+ const UCHAR *);
+/* properties.c */
+extern void vGetPropertyInfo(FILE *, const pps_info_type *,
+ const ULONG *, size_t, const ULONG *, size_t,
+ const UCHAR *, int);
+extern row_info_enum ePropMod2RowInfo(USHORT, int);
+/* propmod.c */
+extern void vDestroyPropModList(void);
+extern void vAdd2PropModList(const UCHAR *);
+extern const UCHAR *aucReadPropModListItem(USHORT);
+/* rowlist.c */
+extern void vDestroyRowInfoList(void);
+extern void vAdd2RowInfoList(const row_block_type *);
+extern const row_block_type *pGetNextRowInfoListItem(void);
+/* riscos.c */
+#if defined(__riscos)
+extern int iGetFiletype(const char *);
+extern void vSetFiletype(const char *, int);
+extern BOOL bMakeDirectory(const char *);
+extern int iReadCurrentAlphabetNumber(void);
+extern int iGetRiscOsVersion(void);
+extern BOOL bDrawRenderDiag360(void *, size_t,
+ window_redrawblock *, double, os_error *);
+#if defined(DEBUG)
+extern BOOL bGetJpegInfo(UCHAR *, size_t);
+#endif /* DEBUG */
+#endif /* __riscos */
+/* saveas.c */
+#if defined(__riscos)
+extern BOOL bSaveTextfile(event_pollblock *, void *);
+extern BOOL bSaveDrawfile(event_pollblock *, void *);
+#endif /* __riscos */
+/* sectlist.c */
+extern void vDestroySectionInfoList(void);
+extern void vAdd2SectionInfoList(const section_block_type *, ULONG);
+extern void vGetDefaultSection(section_block_type *);
+extern void vDefault2SectionInfoList(ULONG);
+extern const section_block_type *
+ pGetSectionInfo(const section_block_type *, ULONG);
+extern size_t tGetNumberOfSections(void);
+extern UCHAR ucGetSepHdrFtrSpecification(size_t);
+/* stylelist.c */
+extern void vDestroyStyleInfoList(void);
+extern level_type_enum eGetNumType(UCHAR);
+extern void vCorrectStyleValues(style_block_type *);
+extern void vAdd2StyleInfoList(const style_block_type *);
+extern const style_block_type *pGetNextStyleInfoListItem(
+ const style_block_type *);
+extern const style_block_type *pGetNextTextStyle(const style_block_type *);
+extern USHORT usGetIstd(ULONG);
+extern BOOL bStyleImpliesList(const style_block_type *, int);
+/* stylesheet.c */
+extern void vDestroyStylesheetList(void);
+extern USHORT usStc2istd(UCHAR);
+extern void vGet2Stylesheet(FILE *, int, const UCHAR *);
+extern void vGet6Stylesheet(FILE *, ULONG, const ULONG *, size_t,
+ const UCHAR *);
+extern void vGet8Stylesheet(FILE *, const pps_info_type *,
+ const ULONG *, size_t, const ULONG *, size_t,
+ const UCHAR *);
+extern void vFillStyleFromStylesheet(USHORT, style_block_type *);
+extern void vFillFontFromStylesheet(USHORT, font_block_type *);
+/* summary.c */
+extern void vDestroySummaryInfo(void);
+extern void vSet0SummaryInfo(FILE *, const UCHAR *);
+extern void vSet2SummaryInfo(FILE *, int, const UCHAR *);
+extern void vSet6SummaryInfo(FILE *, const pps_info_type *,
+ const ULONG *, size_t, const ULONG *, size_t,
+ const UCHAR *);
+extern void vSet8SummaryInfo(FILE *, const pps_info_type *,
+ const ULONG *, size_t, const ULONG *, size_t,
+ const UCHAR *);
+extern const char *szGetTitle(void);
+extern const char *szGetSubject(void);
+extern const char *szGetAuthor(void);
+extern const char *szGetLastSaveDtm(void);
+extern const char *szGetModDate(void);
+extern const char *szGetCreationDate(void);
+extern const char *szGetCompany(void);
+extern const char *szGetLanguage(void);
+/* tabstop.c */
+extern void vSetDefaultTabWidth(FILE *, const pps_info_type *,
+ const ULONG *, size_t, const ULONG *, size_t,
+ const UCHAR *, int);
+extern long lGetDefaultTabWidth(void);
+/* text.c */
+extern void vPrologueTXT(diagram_type *, const options_type *);
+extern void vEpilogueTXT(FILE *);
+extern void vMove2NextLineTXT(diagram_type *);
+extern void vSubstringTXT(diagram_type *, const char *, size_t, long);
+extern void vStartOfParagraphTXT(diagram_type *, long);
+extern void vEndOfParagraphTXT(diagram_type *, long);
+extern void vEndOfPageTXT(diagram_type *, long);
+/* unix.c */
+extern void werr(int, const char *, ...);
+#if !defined(__riscos)
+extern void Hourglass_On(void);
+extern void Hourglass_Off(void);
+#endif /* !__riscos */
+/* utf8.c */
+#if !defined(__riscos)
+extern long utf8_strwidth(const char *, size_t);
+extern int utf8_chrlength(const char *);
+extern BOOL is_locale_utf8(void);
+#endif /* !__riscos */
+/* word2text.c */
+extern BOOL bOutputContainsText(const output_type *);
+extern BOOL bWordDecryptor(FILE *, long, diagram_type *);
+extern output_type *pHdrFtrDecryptor(FILE *, ULONG, ULONG);
+extern char *szFootnoteDecryptor(FILE *, ULONG, ULONG);
+/* worddos.c */
+extern int iInitDocumentDOS(FILE *, long);
+/* wordlib.c */
+extern BOOL bIsWordForDosFile(FILE *, long);
+extern BOOL bIsRtfFile(FILE *);
+extern BOOL bIsWordPerfectFile(FILE *);
+extern BOOL bIsWinWord12File(FILE *, long);
+extern BOOL bIsMacWord45File(FILE *);
+extern int iGuessVersionNumber(FILE *, long);
+extern int iGetVersionNumber(const UCHAR *);
+extern BOOL bIsOldMacFile(void);
+extern int iInitDocument(FILE *, long);
+extern void vFreeDocument(void);
+/* wordmac.c */
+extern int iInitDocumentMAC(FILE *, long);
+/* wordole.c */
+extern int iInitDocumentOLE(FILE *, long);
+/* wordwin.c */
+extern int iInitDocumentWIN(FILE *, long);
+/* xmalloc.c */
+extern void *xmalloc(size_t);
+extern void *xcalloc(size_t, size_t);
+extern void *xrealloc(void *, size_t);
+extern char *xstrdup(const char *);
+extern void *xfree(void *);
+/* xml.c */
+extern void vCreateBookIntro(diagram_type *, int);
+extern void vPrologueXML(diagram_type *, const options_type *);
+extern void vEpilogueXML(diagram_type *);
+extern void vMove2NextLineXML(diagram_type *);
+extern void vSubstringXML(diagram_type *,
+ const char *, size_t, long, USHORT);
+extern void vStartOfParagraphXML(diagram_type *, UINT);
+extern void vEndOfParagraphXML(diagram_type *, UINT);
+extern void vEndOfPageXML(diagram_type *);
+extern void vSetHeadersXML(diagram_type *, USHORT);
+extern void vStartOfListXML(diagram_type *, UCHAR, BOOL);
+extern void vEndOfListXML(diagram_type *);
+extern void vStartOfListItemXML(diagram_type *, BOOL);
+extern void vEndOfTableXML(diagram_type *);
+extern void vAddTableRowXML(diagram_type *, char **, int,
+ const short *, UCHAR);
+
+#endif /* __antiword_h */
diff --git a/sys/src/cmd/aux/antiword/asc85enc.c b/sys/src/cmd/aux/antiword/asc85enc.c
new file mode 100755
index 000000000..8ff6bc8ce
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/asc85enc.c
@@ -0,0 +1,154 @@
+/*
+ * asc85enc.c
+ * Copyright (C) 2000-2003 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Functions to for ASCII 85 encoding
+ *
+ *====================================================================
+ * This part of the software is based on:
+ * asc85ec.c - ASCII85 and Hex encoding for PostScript Level 2 and PDF
+ * Copyright (C) 1994-99 Thomas Merz (tm@muc.de)
+ *====================================================================
+ * The credit should go to him, but all the bugs are mine.
+ */
+
+#include <stdio.h>
+#include "antiword.h"
+
+static const ULONG aulPower85[5] = {
+ 1UL, 85UL, 85UL * 85, 85UL * 85 * 85, 85UL * 85 * 85 * 85,
+};
+static int iOutBytes = 0; /* Number of characters in an output line */
+static char cCharPrev = '\0';
+
+/*
+ * Two percent characters at the start of a line will cause trouble
+ * with some post-processing software. In order to avoid this, we
+ * simply insert a line break if we encounter two percent characters
+ * at the start of the line. Of course, this rather simplistic
+ * algorithm may lead to a large line count in pathological cases,
+ * but the chance for hitting such a case is very small, and even
+ * so it's only a cosmetic flaw and not a functional restriction.
+ */
+
+/*
+ * vOutputByte - output one byte
+ */
+static void
+vOutputByte(ULONG ulChar, FILE *pOutFile)
+{
+ if (iOutBytes == 1 && cCharPrev == '%' && ulChar == (ULONG)'%') {
+ if (putc('\n', pOutFile) != EOF) {
+ iOutBytes = 0;
+ }
+ }
+ if (putc((int)ulChar, pOutFile) == EOF) {
+ return;
+ }
+ iOutBytes++;
+ if (iOutBytes > 63) {
+ if (putc('\n', pOutFile) != EOF) {
+ iOutBytes = 0;
+ }
+ }
+ cCharPrev = (char)ulChar;
+} /* end of vOutputByte */
+
+/*
+ * vASCII85EncodeByte - ASCII 85 encode a byte
+ */
+void
+vASCII85EncodeByte(FILE *pOutFile, int iByte)
+{
+ static ULONG ulBuffer[4] = { 0, 0, 0, 0 };
+ static int iInBuffer = 0;
+ ULONG ulValue, ulTmp;
+ int iIndex;
+
+ fail(pOutFile == NULL);
+ fail(iInBuffer < 0);
+ fail(iInBuffer > 3);
+
+ if (iByte == EOF) {
+ /* End Of File, time to clean up */
+ if (iInBuffer > 0 && iInBuffer < 4) {
+ /* Encode the remaining bytes */
+ ulValue = 0;
+ for (iIndex = iInBuffer - 1; iIndex >= 0; iIndex--) {
+ ulValue |=
+ ulBuffer[iIndex] << (8 * (3 - iIndex));
+ }
+ for (iIndex = 4; iIndex >= 4 - iInBuffer; iIndex--) {
+ ulTmp = ulValue / aulPower85[iIndex];
+ vOutputByte(ulTmp + '!', pOutFile);
+ ulValue -= ulTmp * aulPower85[iIndex];
+ }
+ }
+ /* Add the End Of Data marker */
+ (void)putc('~', pOutFile);
+ (void)putc('>', pOutFile);
+ (void)putc('\n', pOutFile);
+ /* Reset the control variables */
+ iInBuffer = 0;
+ iOutBytes = 0;
+ cCharPrev = '\0';
+ return;
+ }
+
+ ulBuffer[iInBuffer] = (ULONG)iByte & 0xff;
+ iInBuffer++;
+
+ if (iInBuffer >= 4) {
+ ulValue = (ulBuffer[0] << 24) | (ulBuffer[1] << 16) |
+ (ulBuffer[2] << 8) | ulBuffer[3];
+ if (ulValue == 0) {
+ vOutputByte((ULONG)'z', pOutFile); /* Shortcut for 0 */
+ } else {
+ for (iIndex = 4; iIndex >= 0; iIndex--) {
+ ulTmp = ulValue / aulPower85[iIndex];
+ vOutputByte(ulTmp + '!', pOutFile);
+ ulValue -= ulTmp * aulPower85[iIndex];
+ }
+ }
+ /* Reset the buffer */
+ iInBuffer = 0;
+ }
+} /* end of vASCII85EncodeByte */
+
+/*
+ * vASCII85EncodeArray - ASCII 85 encode a byte array
+ */
+void
+vASCII85EncodeArray(FILE *pInFile, FILE *pOutFile, size_t tLength)
+{
+ size_t tCount;
+ int iByte;
+
+ fail(pInFile == NULL);
+ fail(pOutFile == NULL);
+
+ DBG_DEC(tLength);
+
+ for (tCount = 0; tCount < tLength; tCount++) {
+ iByte = iNextByte(pInFile);
+ if (iByte == EOF) {
+ break;
+ }
+ vASCII85EncodeByte(pOutFile, iByte);
+ }
+} /* end of vASCII85EncodeArray */
+
+/*
+ * vASCII85EncodeFile - ASCII 85 encode part of a file
+ */
+void
+vASCII85EncodeFile(FILE *pInFile, FILE *pOutFile, size_t tLength)
+{
+ fail(pInFile == NULL);
+ fail(pOutFile == NULL);
+ fail(tLength == 0);
+
+ vASCII85EncodeArray(pInFile, pOutFile, tLength);
+ vASCII85EncodeByte(pOutFile, EOF);
+} /* end of vASCII85EncodeFile */
diff --git a/sys/src/cmd/aux/antiword/blocklist.c b/sys/src/cmd/aux/antiword/blocklist.c
new file mode 100755
index 000000000..c847c27e9
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/blocklist.c
@@ -0,0 +1,823 @@
+/*
+ * blocklist.c
+ * Copyright (C) 1998-2005 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Build, read and destroy the lists of Word "text" blocks
+ */
+
+#include <stdlib.h>
+#include "antiword.h"
+
+
+/*
+ * Private structure to hide the way the information
+ * is stored from the rest of the program
+ */
+typedef struct list_mem_tag {
+ text_block_type tInfo;
+ struct list_mem_tag *pNext;
+} list_mem_type;
+
+typedef struct readinfo_tag {
+ list_mem_type *pBlockCurrent;
+ ULONG ulBlockOffset;
+ size_t tByteNext;
+ UCHAR aucBlock[BIG_BLOCK_SIZE];
+} readinfo_type;
+
+/* Variables to describe the start of the block lists */
+static list_mem_type *pTextAnchor = NULL;
+static list_mem_type *pFootnoteAnchor = NULL;
+static list_mem_type *pHdrFtrAnchor = NULL;
+static list_mem_type *pMacroAnchor = NULL;
+static list_mem_type *pAnnotationAnchor = NULL;
+static list_mem_type *pEndnoteAnchor = NULL;
+static list_mem_type *pTextBoxAnchor = NULL;
+static list_mem_type *pHdrTextBoxAnchor = NULL;
+/* Variable needed to build the block list */
+static list_mem_type *pBlockLast = NULL;
+/* Variable needed to read the block lists */
+static readinfo_type tOthers = { NULL, 0, 0, };
+static readinfo_type tHdrFtr = { NULL, 0, 0, };
+static readinfo_type tFootnote = { NULL, 0, 0, };
+
+
+/*
+ * pFreeOneList - free a text block list
+ *
+ * Will always return NULL
+ */
+static list_mem_type *
+pFreeOneList(list_mem_type *pAnchor)
+{
+ list_mem_type *pCurr, *pNext;
+
+ pCurr = pAnchor;
+ while (pCurr != NULL) {
+ pNext = pCurr->pNext;
+ pCurr = xfree(pCurr);
+ pCurr = pNext;
+ }
+ return NULL;
+} /* end of pFreeOneList */
+
+/*
+ * vDestroyTextBlockList - destroy the text block lists
+ */
+void
+vDestroyTextBlockList(void)
+{
+ DBG_MSG("vDestroyTextBlockList");
+
+ /* Free the lists one by one */
+ pTextAnchor = pFreeOneList(pTextAnchor);
+ pFootnoteAnchor = pFreeOneList(pFootnoteAnchor);
+ pHdrFtrAnchor = pFreeOneList(pHdrFtrAnchor);
+ pMacroAnchor = pFreeOneList(pMacroAnchor);
+ pAnnotationAnchor = pFreeOneList(pAnnotationAnchor);
+ pEndnoteAnchor = pFreeOneList(pEndnoteAnchor);
+ pTextBoxAnchor = pFreeOneList(pTextBoxAnchor);
+ pHdrTextBoxAnchor = pFreeOneList(pHdrTextBoxAnchor);
+ /* Reset all the controle variables */
+ pBlockLast = NULL;
+ tOthers.pBlockCurrent = NULL;
+ tHdrFtr.pBlockCurrent = NULL;
+ tFootnote.pBlockCurrent = NULL;
+} /* end of vDestroyTextBlockList */
+
+/*
+ * bAdd2TextBlockList - add an element to the text block list
+ *
+ * returns: TRUE when successful, otherwise FALSE
+ */
+BOOL
+bAdd2TextBlockList(const text_block_type *pTextBlock)
+{
+ list_mem_type *pListMember;
+
+ fail(pTextBlock == NULL);
+ fail(pTextBlock->ulFileOffset == FC_INVALID);
+ fail(pTextBlock->ulCharPos == CP_INVALID);
+ fail(pTextBlock->ulLength == 0);
+ fail(pTextBlock->bUsesUnicode && odd(pTextBlock->ulLength));
+
+ NO_DBG_MSG("bAdd2TextBlockList");
+ NO_DBG_HEX(pTextBlock->ulFileOffset);
+ NO_DBG_HEX(pTextBlock->ulCharPos);
+ NO_DBG_HEX(pTextBlock->ulLength);
+ NO_DBG_DEC(pTextBlock->bUsesUnicode);
+ NO_DBG_DEC(pTextBlock->usPropMod);
+
+ if (pTextBlock->ulFileOffset == FC_INVALID ||
+ pTextBlock->ulCharPos == CP_INVALID ||
+ pTextBlock->ulLength == 0 ||
+ (pTextBlock->bUsesUnicode && odd(pTextBlock->ulLength))) {
+ werr(0, "Software (textblock) error");
+ return FALSE;
+ }
+ /*
+ * Check for continuous blocks of the same character size and
+ * the same properties modifier
+ */
+ if (pBlockLast != NULL &&
+ pBlockLast->tInfo.ulFileOffset +
+ pBlockLast->tInfo.ulLength == pTextBlock->ulFileOffset &&
+ pBlockLast->tInfo.ulCharPos +
+ pBlockLast->tInfo.ulLength == pTextBlock->ulCharPos &&
+ pBlockLast->tInfo.bUsesUnicode == pTextBlock->bUsesUnicode &&
+ pBlockLast->tInfo.usPropMod == pTextBlock->usPropMod) {
+ /* These are continous blocks */
+ pBlockLast->tInfo.ulLength += pTextBlock->ulLength;
+ return TRUE;
+ }
+ /* Make a new block */
+ pListMember = xmalloc(sizeof(list_mem_type));
+ /* Add the block to the list */
+ pListMember->tInfo = *pTextBlock;
+ pListMember->pNext = NULL;
+ if (pTextAnchor == NULL) {
+ pTextAnchor = pListMember;
+ } else {
+ fail(pBlockLast == NULL);
+ pBlockLast->pNext = pListMember;
+ }
+ pBlockLast = pListMember;
+ return TRUE;
+} /* end of bAdd2TextBlockList */
+
+/*
+ * vSpitList - Split the list in two
+ */
+static void
+vSpitList(list_mem_type **ppAnchorCurr, list_mem_type **ppAnchorNext,
+ ULONG ulListLen)
+{
+ list_mem_type *pCurr;
+ long lCharsToGo, lBytesTooFar;
+
+ fail(ppAnchorCurr == NULL);
+ fail(ppAnchorNext == NULL);
+ fail(ulListLen > (ULONG)LONG_MAX);
+
+ pCurr = NULL;
+ lCharsToGo = (long)ulListLen;
+ lBytesTooFar = -1;
+ if (ulListLen != 0) {
+ DBG_DEC(ulListLen);
+ for (pCurr = *ppAnchorCurr;
+ pCurr != NULL;
+ pCurr = pCurr->pNext) {
+ NO_DBG_DEC(pCurr->tInfo.ulLength);
+ fail(pCurr->tInfo.ulLength == 0);
+ fail(pCurr->tInfo.ulLength > (ULONG)LONG_MAX);
+ if (pCurr->tInfo.bUsesUnicode) {
+ fail(odd(pCurr->tInfo.ulLength));
+ lCharsToGo -= (long)(pCurr->tInfo.ulLength / 2);
+ if (lCharsToGo < 0) {
+ lBytesTooFar = -2 * lCharsToGo;
+ }
+ } else {
+ lCharsToGo -= (long)pCurr->tInfo.ulLength;
+ if (lCharsToGo < 0) {
+ lBytesTooFar = -lCharsToGo;
+ }
+ }
+ if (lCharsToGo <= 0) {
+ break;
+ }
+ }
+ }
+/* Split the list */
+ if (ulListLen == 0) {
+ /* Current blocklist is empty */
+ *ppAnchorNext = *ppAnchorCurr;
+ *ppAnchorCurr = NULL;
+ } else if (pCurr == NULL) {
+ /* No blocks for the next list */
+ *ppAnchorNext = NULL;
+ } else if (lCharsToGo == 0) {
+ /* Move the integral number of blocks to the next list */
+ *ppAnchorNext = pCurr->pNext;
+ pCurr->pNext = NULL;
+ } else {
+ /* Split the part current block list, part next block list */
+ DBG_DEC(lBytesTooFar);
+ fail(lBytesTooFar <= 0);
+ *ppAnchorNext = xmalloc(sizeof(list_mem_type));
+ DBG_HEX(pCurr->tInfo.ulFileOffset);
+ (*ppAnchorNext)->tInfo.ulFileOffset =
+ pCurr->tInfo.ulFileOffset +
+ pCurr->tInfo.ulLength -
+ lBytesTooFar;
+ DBG_HEX((*ppAnchorNext)->tInfo.ulFileOffset);
+ DBG_HEX(pCurr->tInfo.ulCharPos);
+ (*ppAnchorNext)->tInfo.ulCharPos =
+ pCurr->tInfo.ulCharPos +
+ pCurr->tInfo.ulLength -
+ lBytesTooFar;
+ DBG_HEX((*ppAnchorNext)->tInfo.ulCharPos);
+ (*ppAnchorNext)->tInfo.ulLength = (ULONG)lBytesTooFar;
+ pCurr->tInfo.ulLength -= (ULONG)lBytesTooFar;
+ (*ppAnchorNext)->tInfo.bUsesUnicode = pCurr->tInfo.bUsesUnicode;
+ (*ppAnchorNext)->tInfo.usPropMod = pCurr->tInfo.usPropMod;
+ /* Move the integral number of blocks to the next list */
+ (*ppAnchorNext)->pNext = pCurr->pNext;
+ pCurr->pNext = NULL;
+ }
+} /* end of vSpitList */
+
+#if defined(DEBUG) || defined(__riscos)
+/*
+ * ulComputeListLength - compute the length of a list
+ *
+ * returns the list length in characters
+ */
+static ULONG
+ulComputeListLength(const list_mem_type *pAnchor)
+{
+ const list_mem_type *pCurr;
+ ULONG ulTotal;
+
+ ulTotal = 0;
+ for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
+ fail(pCurr->tInfo.ulLength == 0);
+ if (pCurr->tInfo.bUsesUnicode) {
+ fail(odd(pCurr->tInfo.ulLength));
+ ulTotal += pCurr->tInfo.ulLength / 2;
+ } else {
+ ulTotal += pCurr->tInfo.ulLength;
+ }
+ }
+ return ulTotal;
+} /* end of ulComputeListLength */
+#endif /* DEBUG || __riscos */
+
+#if defined(DEBUG)
+/*
+ * vCheckList - check the number of bytes in a block list
+ */
+static void
+vCheckList(const list_mem_type *pAnchor, ULONG ulListLen, char *szMsg)
+{
+ ULONG ulTotal;
+
+ ulTotal = ulComputeListLength(pAnchor);
+ DBG_DEC(ulTotal);
+ if (ulTotal != ulListLen) {
+ DBG_DEC(ulListLen);
+ werr(1, szMsg);
+ }
+} /* end of vCheckList */
+#endif /* DEBUG */
+
+/*
+ * bIsEmptyBox - check to see if the given text box is empty
+ */
+static BOOL
+bIsEmptyBox(FILE *pFile, const list_mem_type *pAnchor)
+{
+ const list_mem_type *pCurr;
+ size_t tIndex, tSize;
+ UCHAR *aucBuffer;
+ char cChar;
+
+ fail(pFile == NULL);
+
+ if (pAnchor == NULL) {
+ return TRUE;
+ }
+
+ aucBuffer = NULL;
+ for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
+ fail(pCurr->tInfo.ulLength == 0);
+ tSize = (size_t)pCurr->tInfo.ulLength;
+#if defined(__dos) && !defined(__DJGPP__)
+ if (pCurr->tInfo.ulLength > 0xffffUL) {
+ tSize = 0xffff;
+ }
+#endif /* __dos && !__DJGPP__ */
+ fail(aucBuffer != NULL);
+ aucBuffer = xmalloc(tSize);
+ if (!bReadBytes(aucBuffer, tSize,
+ pCurr->tInfo.ulFileOffset, pFile)) {
+ aucBuffer = xfree(aucBuffer);
+ return FALSE;
+ }
+ for (tIndex = 0; tIndex < tSize; tIndex++) {
+ cChar = (char)aucBuffer[tIndex];
+ switch (cChar) {
+ case '\0': case '\r': case '\n':
+ case '\f': case '\t': case '\v':
+ case ' ':
+ break;
+ default:
+ aucBuffer = xfree(aucBuffer);
+ return FALSE;
+ }
+ }
+ aucBuffer = xfree(aucBuffer);
+ }
+ fail(aucBuffer != NULL);
+ return TRUE;
+} /* end of bIsEmptyBox */
+
+/*
+ * vSplitBlockList - split the block list in the various parts
+ *
+ * Split the blocklist in a Text block list, a Footnote block list, a
+ * HeaderFooter block list, a Macro block list, an Annotation block list,
+ * an Endnote block list, a TextBox list and a HeaderTextBox list.
+ *
+ * NOTE:
+ * The various ul*Len input parameters are given in characters, but the
+ * length of the blocks are in bytes.
+ */
+void
+vSplitBlockList(FILE *pFile, ULONG ulTextLen, ULONG ulFootnoteLen,
+ ULONG ulHdrFtrLen, ULONG ulMacroLen, ULONG ulAnnotationLen,
+ ULONG ulEndnoteLen, ULONG ulTextBoxLen, ULONG ulHdrTextBoxLen,
+ BOOL bMustExtend)
+{
+ list_mem_type *apAnchors[8];
+ list_mem_type *pGarbageAnchor, *pCurr;
+ size_t tIndex;
+
+ DBG_MSG("vSplitBlockList");
+
+ pGarbageAnchor = NULL;
+
+ DBG_MSG_C(ulTextLen != 0, "Text block list");
+ vSpitList(&pTextAnchor, &pFootnoteAnchor, ulTextLen);
+ DBG_MSG_C(ulFootnoteLen != 0, "Footnote block list");
+ vSpitList(&pFootnoteAnchor, &pHdrFtrAnchor, ulFootnoteLen);
+ DBG_MSG_C(ulHdrFtrLen != 0, "Header/Footer block list");
+ vSpitList(&pHdrFtrAnchor, &pMacroAnchor, ulHdrFtrLen);
+ DBG_MSG_C(ulMacroLen != 0, "Macro block list");
+ vSpitList(&pMacroAnchor, &pAnnotationAnchor, ulMacroLen);
+ DBG_MSG_C(ulAnnotationLen != 0, "Annotation block list");
+ vSpitList(&pAnnotationAnchor, &pEndnoteAnchor, ulAnnotationLen);
+ DBG_MSG_C(ulEndnoteLen != 0, "Endnote block list");
+ vSpitList(&pEndnoteAnchor, &pTextBoxAnchor, ulEndnoteLen);
+ DBG_MSG_C(ulTextBoxLen != 0, "Textbox block list");
+ vSpitList(&pTextBoxAnchor, &pHdrTextBoxAnchor, ulTextBoxLen);
+ DBG_MSG_C(ulHdrTextBoxLen != 0, "HeaderTextbox block list");
+ vSpitList(&pHdrTextBoxAnchor, &pGarbageAnchor, ulHdrTextBoxLen);
+
+ /* Free the garbage block list, this should not be needed */
+ DBG_DEC_C(pGarbageAnchor != NULL, pGarbageAnchor->tInfo.ulLength);
+ pGarbageAnchor = pFreeOneList(pGarbageAnchor);
+
+#if defined(DEBUG)
+ vCheckList(pTextAnchor, ulTextLen, "Software error (Text)");
+ vCheckList(pFootnoteAnchor, ulFootnoteLen, "Software error (Footnote)");
+ vCheckList(pHdrFtrAnchor, ulHdrFtrLen, "Software error (Hdr/Ftr)");
+ vCheckList(pMacroAnchor, ulMacroLen, "Software error (Macro)");
+ vCheckList(pAnnotationAnchor, ulAnnotationLen,
+ "Software error (Annotation)");
+ vCheckList(pEndnoteAnchor, ulEndnoteLen, "Software error (Endnote)");
+ vCheckList(pTextBoxAnchor, ulTextBoxLen, "Software error (TextBox)");
+ vCheckList(pHdrTextBoxAnchor, ulHdrTextBoxLen,
+ "Software error (HdrTextBox)");
+#endif /* DEBUG */
+
+ /* Remove the list if the text box is empty */
+ if (bIsEmptyBox(pFile, pTextBoxAnchor)) {
+ pTextBoxAnchor = pFreeOneList(pTextBoxAnchor);
+ }
+ if (bIsEmptyBox(pFile, pHdrTextBoxAnchor)) {
+ pHdrTextBoxAnchor = pFreeOneList(pHdrTextBoxAnchor);
+ }
+
+ if (!bMustExtend) {
+ return;
+ }
+ /*
+ * All blocks (except the last one) must have a length that
+ * is a multiple of the Big Block Size
+ */
+
+ apAnchors[0] = pTextAnchor;
+ apAnchors[1] = pFootnoteAnchor;
+ apAnchors[2] = pHdrFtrAnchor;
+ apAnchors[3] = pMacroAnchor;
+ apAnchors[4] = pAnnotationAnchor;
+ apAnchors[5] = pEndnoteAnchor;
+ apAnchors[6] = pTextBoxAnchor;
+ apAnchors[7] = pHdrTextBoxAnchor;
+
+ for (tIndex = 0; tIndex < elementsof(apAnchors); tIndex++) {
+ for (pCurr = apAnchors[tIndex];
+ pCurr != NULL;
+ pCurr = pCurr->pNext) {
+ if (pCurr->pNext != NULL &&
+ pCurr->tInfo.ulLength % BIG_BLOCK_SIZE != 0) {
+ DBG_DEC(tIndex);
+ DBG_HEX(pCurr->tInfo.ulFileOffset);
+ DBG_HEX(pCurr->tInfo.ulCharPos);
+ DBG_DEC(pCurr->tInfo.ulLength);
+ pCurr->tInfo.ulLength /= BIG_BLOCK_SIZE;
+ pCurr->tInfo.ulLength++;
+ pCurr->tInfo.ulLength *= BIG_BLOCK_SIZE;
+ DBG_DEC(pCurr->tInfo.ulLength);
+ }
+ }
+ }
+} /* end of vSplitBlockList */
+
+#if defined(__riscos)
+/*
+ * ulGetDocumentLength - get the total character length of the printable lists
+ *
+ * returns: The total number of characters
+ */
+ULONG
+ulGetDocumentLength(void)
+{
+ long ulTotal;
+
+ DBG_MSG("ulGetDocumentLength");
+
+ ulTotal = ulComputeListLength(pTextAnchor);
+ ulTotal += ulComputeListLength(pFootnoteAnchor);
+ ulTotal += ulComputeListLength(pEndnoteAnchor);
+ ulTotal += ulComputeListLength(pTextBoxAnchor);
+ ulTotal += ulComputeListLength(pHdrTextBoxAnchor);
+ DBG_DEC(ulTotal);
+ return ulTotal;
+} /* end of ulGetDocumentLength */
+#endif /* __riscos */
+
+#if 0
+/*
+ * bExistsHdrFtr - are there headers and/or footers?
+ */
+BOOL
+bExistsHdrFtr(void)
+{
+ return pHdrFtrAnchor != NULL &&
+ pHdrFtrAnchor->tInfo.ulLength != 0;
+} /* end of bExistsHdrFtr */
+#endif
+
+/*
+ * bExistsTextBox - is there a text box?
+ */
+BOOL
+bExistsTextBox(void)
+{
+ return pTextBoxAnchor != NULL &&
+ pTextBoxAnchor->tInfo.ulLength != 0;
+} /* end of bExistsTextBox */
+
+/*
+ * bExistsHdrTextBox - is there a header text box?
+ */
+BOOL
+bExistsHdrTextBox(void)
+{
+ return pHdrTextBoxAnchor != NULL &&
+ pHdrTextBoxAnchor->tInfo.ulLength != 0;
+} /* end of bExistsHdrTextBox */
+
+/*
+ * usGetNextByte - get the next byte from the specified block list
+ */
+static USHORT
+usGetNextByte(FILE *pFile, readinfo_type *pInfoCurrent, list_mem_type *pAnchor,
+ ULONG *pulFileOffset, ULONG *pulCharPos, USHORT *pusPropMod)
+{
+ ULONG ulReadOff;
+ size_t tReadLen;
+
+ fail(pInfoCurrent == NULL);
+
+ if (pInfoCurrent->pBlockCurrent == NULL ||
+ pInfoCurrent->tByteNext >= sizeof(pInfoCurrent->aucBlock) ||
+ pInfoCurrent->ulBlockOffset + pInfoCurrent->tByteNext >=
+ pInfoCurrent->pBlockCurrent->tInfo.ulLength) {
+ if (pInfoCurrent->pBlockCurrent == NULL) {
+ /* First block, first part */
+ pInfoCurrent->pBlockCurrent = pAnchor;
+ pInfoCurrent->ulBlockOffset = 0;
+ } else if (pInfoCurrent->ulBlockOffset +
+ sizeof(pInfoCurrent->aucBlock) <
+ pInfoCurrent->pBlockCurrent->tInfo.ulLength) {
+ /* Same block, next part */
+ pInfoCurrent->ulBlockOffset +=
+ sizeof(pInfoCurrent->aucBlock);
+ } else {
+ /* Next block, first part */
+ pInfoCurrent->pBlockCurrent =
+ pInfoCurrent->pBlockCurrent->pNext;
+ pInfoCurrent->ulBlockOffset = 0;
+ }
+ if (pInfoCurrent->pBlockCurrent == NULL) {
+ /* Past the last part of the last block */
+ return (USHORT)EOF;
+ }
+ tReadLen = (size_t)
+ (pInfoCurrent->pBlockCurrent->tInfo.ulLength -
+ pInfoCurrent->ulBlockOffset);
+ if (tReadLen > sizeof(pInfoCurrent->aucBlock)) {
+ tReadLen = sizeof(pInfoCurrent->aucBlock);
+ }
+ ulReadOff = pInfoCurrent->pBlockCurrent->tInfo.ulFileOffset +
+ pInfoCurrent->ulBlockOffset;
+ if (!bReadBytes(pInfoCurrent->aucBlock,
+ tReadLen, ulReadOff, pFile)) {
+ /* Don't read from this list any longer */
+ pInfoCurrent->pBlockCurrent = NULL;
+ return (USHORT)EOF;
+ }
+ pInfoCurrent->tByteNext = 0;
+ }
+ if (pulFileOffset != NULL) {
+ *pulFileOffset =
+ pInfoCurrent->pBlockCurrent->tInfo.ulFileOffset +
+ pInfoCurrent->ulBlockOffset +
+ pInfoCurrent->tByteNext;
+ }
+ if (pulCharPos != NULL) {
+ *pulCharPos =
+ pInfoCurrent->pBlockCurrent->tInfo.ulCharPos +
+ pInfoCurrent->ulBlockOffset +
+ pInfoCurrent->tByteNext;
+ }
+ if (pusPropMod != NULL) {
+ *pusPropMod = pInfoCurrent->pBlockCurrent->tInfo.usPropMod;
+ }
+ return (USHORT)pInfoCurrent->aucBlock[pInfoCurrent->tByteNext++];
+} /* end of usGetNextByte */
+
+
+/*
+ * usGetNextChar - get the next character from the specified block list
+ */
+static USHORT
+usGetNextChar(FILE *pFile, list_id_enum eListID,
+ ULONG *pulFileOffset, ULONG *pulCharPos, USHORT *pusPropMod)
+{
+ readinfo_type *pReadinfo;
+ list_mem_type *pAnchor;
+ USHORT usLSB, usMSB;
+
+ switch (eListID) {
+ case text_list:
+ pReadinfo = &tOthers;
+ pAnchor = pTextAnchor;
+ break;
+ case footnote_list:
+ pReadinfo = &tFootnote;
+ pAnchor = pFootnoteAnchor;
+ break;
+ case hdrftr_list:
+ pReadinfo = &tHdrFtr;
+ pAnchor = pHdrFtrAnchor;
+ break;
+ case endnote_list:
+ pReadinfo = &tOthers;
+ pAnchor = pEndnoteAnchor;
+ break;
+ case textbox_list:
+ pReadinfo = &tOthers;
+ pAnchor = pTextBoxAnchor;
+ break;
+ case hdrtextbox_list:
+ pReadinfo = &tOthers;
+ pAnchor = pHdrTextBoxAnchor;
+ break;
+ default:
+ DBG_DEC(eListID);
+ return (USHORT)EOF;
+ }
+
+ usLSB = usGetNextByte(pFile, pReadinfo, pAnchor,
+ pulFileOffset, pulCharPos, pusPropMod);
+ if (usLSB == (USHORT)EOF) {
+ return (USHORT)EOF;
+ }
+ fail(pReadinfo->pBlockCurrent == NULL);
+
+ if (pReadinfo->pBlockCurrent->tInfo.bUsesUnicode) {
+ usMSB = usGetNextByte(pFile,
+ pReadinfo, pAnchor, NULL, NULL, NULL);
+ } else {
+ usMSB = 0x00;
+ }
+ if (usMSB == (USHORT)EOF) {
+ DBG_MSG("usGetNextChar: Unexpected EOF");
+ DBG_HEX_C(pulFileOffset != NULL, *pulFileOffset);
+ DBG_HEX_C(pulCharPos != NULL, *pulCharPos);
+ return (USHORT)EOF;
+ }
+ return (usMSB << 8) | usLSB;
+} /* end of usGetNextChar */
+
+/*
+ * usNextChar - get the next character from the given block list
+ */
+USHORT
+usNextChar(FILE *pFile, list_id_enum eListID,
+ ULONG *pulFileOffset, ULONG *pulCharPos, USHORT *pusPropMod)
+{
+ USHORT usRetVal;
+
+ fail(pFile == NULL);
+
+ usRetVal = usGetNextChar(pFile, eListID,
+ pulFileOffset, pulCharPos, pusPropMod);
+ if (usRetVal == (USHORT)EOF) {
+ if (pulFileOffset != NULL) {
+ *pulFileOffset = FC_INVALID;
+ }
+ if (pulCharPos != NULL) {
+ *pulCharPos = CP_INVALID;
+ }
+ if (pusPropMod != NULL) {
+ *pusPropMod = IGNORE_PROPMOD;
+ }
+ }
+ return usRetVal;
+} /* end of usNextChar */
+
+/*
+ * usToHdrFtrPosition - Go to a character position in header/foorter list
+ *
+ * Returns the character found on the specified character position
+ */
+USHORT
+usToHdrFtrPosition(FILE *pFile, ULONG ulCharPos)
+{
+ ULONG ulCharPosCurr;
+ USHORT usChar;
+
+ tHdrFtr.pBlockCurrent = NULL; /* To reset the header/footer list */
+ do {
+ usChar = usNextChar(pFile,
+ hdrftr_list, NULL, &ulCharPosCurr, NULL);
+ } while (usChar != (USHORT)EOF && ulCharPosCurr != ulCharPos);
+ return usChar;
+} /* end of usToHdrFtrPosition */
+
+/*
+ * usToFootnotePosition - Go to a character position in footnote list
+ *
+ * Returns the character found on the specified character position
+ */
+USHORT
+usToFootnotePosition(FILE *pFile, ULONG ulCharPos)
+{
+ ULONG ulCharPosCurr;
+ USHORT usChar;
+
+ tFootnote.pBlockCurrent = NULL; /* To reset the footnote list */
+ do {
+ usChar = usNextChar(pFile,
+ footnote_list, NULL, &ulCharPosCurr, NULL);
+ } while (usChar != (USHORT)EOF && ulCharPosCurr != ulCharPos);
+ return usChar;
+} /* end of usToFootnotePosition */
+
+/*
+ * Convert a character position to an offset in the file.
+ * Logical to physical offset.
+ *
+ * Returns: FC_INVALID: in case of error
+ * otherwise: the computed file offset
+ */
+ULONG
+ulCharPos2FileOffsetX(ULONG ulCharPos, list_id_enum *peListID)
+{
+ static list_id_enum eListIDs[8] = {
+ text_list, footnote_list, hdrftr_list,
+ macro_list, annotation_list, endnote_list,
+ textbox_list, hdrtextbox_list,
+ };
+ list_mem_type *apAnchors[8];
+ list_mem_type *pCurr;
+ list_id_enum eListGuess;
+ ULONG ulBestGuess;
+ size_t tIndex;
+
+ fail(peListID == NULL);
+
+ if (ulCharPos == CP_INVALID) {
+ *peListID = no_list;
+ return FC_INVALID;
+ }
+
+ apAnchors[0] = pTextAnchor;
+ apAnchors[1] = pFootnoteAnchor;
+ apAnchors[2] = pHdrFtrAnchor;
+ apAnchors[3] = pMacroAnchor;
+ apAnchors[4] = pAnnotationAnchor;
+ apAnchors[5] = pEndnoteAnchor;
+ apAnchors[6] = pTextBoxAnchor;
+ apAnchors[7] = pHdrTextBoxAnchor;
+
+ eListGuess = no_list; /* Best guess is no list */
+ ulBestGuess = FC_INVALID; /* Best guess is "file offset not found" */
+
+ for (tIndex = 0; tIndex < elementsof(apAnchors); tIndex++) {
+ for (pCurr = apAnchors[tIndex];
+ pCurr != NULL;
+ pCurr = pCurr->pNext) {
+ if (ulCharPos == pCurr->tInfo.ulCharPos +
+ pCurr->tInfo.ulLength &&
+ pCurr->pNext != NULL) {
+ /*
+ * The character position is one beyond this
+ * block, so we guess it's the first byte of
+ * the next block (if there is a next block)
+ */
+ eListGuess= eListIDs[tIndex];
+ ulBestGuess = pCurr->pNext->tInfo.ulFileOffset;
+ }
+
+ if (ulCharPos < pCurr->tInfo.ulCharPos ||
+ ulCharPos >= pCurr->tInfo.ulCharPos +
+ pCurr->tInfo.ulLength) {
+ /* Character position is not in this block */
+ continue;
+ }
+
+ /* The character position is in the current block */
+ *peListID = eListIDs[tIndex];
+ return pCurr->tInfo.ulFileOffset +
+ ulCharPos - pCurr->tInfo.ulCharPos;
+ }
+ }
+ /* Passed beyond the end of the last list */
+ NO_DBG_HEX(ulCharPos);
+ NO_DBG_HEX(ulBestGuess);
+ *peListID = eListGuess;
+ return ulBestGuess;
+} /* end of ulCharPos2FileOffsetX */
+
+/*
+ * Convert a character position to an offset in the file.
+ * Logical to physical offset.
+ *
+ * Returns: FC_INVALID: in case of error
+ * otherwise: the computed file offset
+ */
+ULONG
+ulCharPos2FileOffset(ULONG ulCharPos)
+{
+ list_id_enum eListID;
+
+ return ulCharPos2FileOffsetX(ulCharPos, &eListID);
+} /* end of ulCharPos2FileOffset */
+
+/*
+ * Convert an offset in the header/footer list to a character position.
+ *
+ * Returns: CP_INVALID: in case of error
+ * otherwise: the computed character position
+ */
+ULONG
+ulHdrFtrOffset2CharPos(ULONG ulHdrFtrOffset)
+{
+ list_mem_type *pCurr;
+ ULONG ulOffset;
+
+ ulOffset = ulHdrFtrOffset;
+ for (pCurr = pHdrFtrAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
+ if (ulOffset >= pCurr->tInfo.ulLength) {
+ /* The offset is not in this block */
+ ulOffset -= pCurr->tInfo.ulLength;
+ continue;
+ }
+ return pCurr->tInfo.ulCharPos + ulOffset;
+ }
+ return CP_INVALID;
+} /* end of ulHdrFtrOffset2CharPos */
+
+/*
+ * Get the sequence number beloning to the given file offset
+ *
+ * Returns the sequence number
+ */
+ULONG
+ulGetSeqNumber(ULONG ulFileOffset)
+{
+ list_mem_type *pCurr;
+ ULONG ulSeq;
+
+ if (ulFileOffset == FC_INVALID) {
+ return FC_INVALID;
+ }
+
+ ulSeq = 0;
+ for (pCurr = pTextAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
+ if (ulFileOffset >= pCurr->tInfo.ulFileOffset &&
+ ulFileOffset < pCurr->tInfo.ulFileOffset +
+ pCurr->tInfo.ulLength) {
+ /* The file offset is within the current textblock */
+ return ulSeq + ulFileOffset - pCurr->tInfo.ulFileOffset;
+ }
+ ulSeq += pCurr->tInfo.ulLength;
+ }
+ return FC_INVALID;
+} /* end of ulGetSeqNumber */
diff --git a/sys/src/cmd/aux/antiword/chartrans.c b/sys/src/cmd/aux/antiword/chartrans.c
new file mode 100755
index 000000000..5edaae9b4
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/chartrans.c
@@ -0,0 +1,720 @@
+/*
+ * chartrans.c
+ * Copyright (C) 1999-2004 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Translate Word characters to local representation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#if defined(__STDC_ISO_10646__)
+#include <wctype.h>
+#endif /* __STDC_ISO_10646__ */
+#include "antiword.h"
+
+static const USHORT usCp850[] = { /* DOS implementation of Latin1 */
+ 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
+ 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
+ 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
+ 0x00ff, 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x00d8, 0x00d7, 0x0192,
+ 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
+ 0x00bf, 0x00ae, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
+ 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00c1, 0x00c2, 0x00c0,
+ 0x00a9, 0x2563, 0x2551, 0x2557, 0x255d, 0x00a2, 0x00a5, 0x2510,
+ 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x00e3, 0x00c3,
+ 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4,
+ 0x00f0, 0x00d0, 0x00ca, 0x00cb, 0x00c8, 0x0131, 0x00cd, 0x00ce,
+ 0x00cf, 0x2518, 0x250c, 0x2588, 0x2584, 0x00a6, 0x00cc, 0x2580,
+ 0x00d3, 0x00df, 0x00d4, 0x00d2, 0x00f5, 0x00d5, 0x00b5, 0x00fe,
+ 0x00de, 0x00da, 0x00db, 0x00d9, 0x00fd, 0x00dd, 0x00af, 0x00b4,
+ 0x00ad, 0x00b1, 0x2017, 0x00be, 0x00b6, 0x00a7, 0x00f7, 0x00b8,
+ 0x00b0, 0x00a8, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0,
+};
+
+static const USHORT usCp1250[] = { /* Windows implementation of Latin2 */
+ 0x20ac, 0x003f, 0x201a, 0x003f, 0x201e, 0x2026, 0x2020, 0x2021,
+ 0x003f, 0x2030, 0x0160, 0x2039, 0x015a, 0x0164, 0x017d, 0x0179,
+ 0x003f, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
+ 0x003f, 0x2122, 0x0161, 0x203a, 0x015b, 0x0165, 0x017e, 0x017a,
+ 0x00a0, 0x02c7, 0x02d8, 0x0141, 0x00a4, 0x0104, 0x00a6, 0x00a7,
+ 0x00a8, 0x00a9, 0x015e, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x017b,
+ 0x00b0, 0x00b1, 0x02db, 0x0142, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
+ 0x00b8, 0x0105, 0x015f, 0x00bb, 0x013d, 0x02dd, 0x013e, 0x017c,
+ 0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7,
+ 0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e,
+ 0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7,
+ 0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df,
+ 0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7,
+ 0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f,
+ 0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7,
+ 0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9,
+};
+
+static const USHORT usCp1251[] = { /* Windows implementation of Cyrillic */
+ 0x0402, 0x0403, 0x201a, 0x0453, 0x201e, 0x2026, 0x2020, 0x2021,
+ 0x20ac, 0x2030, 0x0409, 0x2039, 0x040a, 0x040c, 0x040b, 0x040f,
+ 0x0452, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
+ 0x00f3, 0x2122, 0x0459, 0x203a, 0x045a, 0x045c, 0x045b, 0x045f,
+ 0x00a0, 0x040e, 0x045e, 0x0408, 0x00a4, 0x0490, 0x00a6, 0x00a7,
+ 0x0401, 0x00a9, 0x0404, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x0407,
+ 0x00b0, 0x00b1, 0x0406, 0x0456, 0x0491, 0x00b5, 0x00b6, 0x00b7,
+ 0x0451, 0x2116, 0x0454, 0x00bb, 0x0458, 0x0405, 0x0455, 0x0457,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f,
+};
+
+static const USHORT usCp1252[] = { /* Windows implementation of Latin1 */
+ 0x20ac, 0x003f, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
+ 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x003f, 0x017d, 0x003f,
+ 0x003f, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
+ 0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x003f, 0x017e, 0x0178,
+ 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
+ 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+ 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
+ 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+ 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
+ 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+ 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
+ 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
+ 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
+ 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+ 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
+ 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff,
+};
+
+static const USHORT usMacRoman[] = { /* Apple implementation of Latin1 */
+ 0x00c4, 0x00c5, 0x00c7, 0x00c9, 0x00d1, 0x00d6, 0x00dc, 0x00e1,
+ 0x00e0, 0x00e2, 0x00e4, 0x00e3, 0x00e5, 0x00e7, 0x00e9, 0x00e8,
+ 0x00ea, 0x00eb, 0x00ed, 0x00ec, 0x00ee, 0x00ef, 0x00f1, 0x00f3,
+ 0x00f2, 0x00f4, 0x00f6, 0x00f5, 0x00fa, 0x00f9, 0x00fb, 0x00fc,
+ 0x2020, 0x00b0, 0x00a2, 0x00a3, 0x00a7, 0x2022, 0x00b6, 0x00df,
+ 0x00ae, 0x00a9, 0x2122, 0x00b4, 0x00a8, 0x2260, 0x00c6, 0x00d8,
+ 0x221e, 0x00b1, 0x2264, 0x2265, 0x00a5, 0x00b5, 0x2202, 0x2211,
+ 0x220f, 0x03c0, 0x222b, 0x00aa, 0x00ba, 0x2126, 0x00e6, 0x00f8,
+ 0x00bf, 0x00a1, 0x00ac, 0x221a, 0x0192, 0x2248, 0x2206, 0x00ab,
+ 0x00bb, 0x2026, 0x00a0, 0x00c0, 0x00c3, 0x00d5, 0x0152, 0x0153,
+ 0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0x00f7, 0x25ca,
+ 0x00ff, 0x0178, 0x2044, 0x00a4, 0x2039, 0x203a, 0xfb01, 0xfb02,
+ 0x2021, 0x00b7, 0x201a, 0x201e, 0x2030, 0x00c2, 0x00ca, 0x00c1,
+ 0x00cb, 0x00c8, 0x00cd, 0x00ce, 0x00cf, 0x00cc, 0x00d3, 0x00d4,
+ 0x003f, 0x00d2, 0x00da, 0x00db, 0x00d9, 0x0131, 0x02c6, 0x02dc,
+ 0x00af, 0x02d8, 0x02d9, 0x02da, 0x00b8, 0x02dd, 0x02db, 0x02c7,
+};
+
+static const USHORT usPrivateArea[] = {
+ 0x0020, 0x0021, 0x2200, 0x0023, 0x2203, 0x0025, 0x0026, 0x220d,
+ 0x0028, 0x0029, 0x2217, 0x002b, 0x002c, 0x2212, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x2019, 0x003e, 0x003f,
+ 0x201d, 0x201c, 0x0392, 0x03a7, 0x0394, 0x0395, 0x03a6, 0x0393,
+ 0x0397, 0x0399, 0x03d1, 0x039a, 0x039b, 0x039c, 0x039d, 0x039f,
+ 0x03a0, 0x0398, 0x03a1, 0x03a3, 0x03a4, 0x03a5, 0x03c2, 0x03a9,
+ 0x039e, 0x03a8, 0x0396, 0x005b, 0x2234, 0x005d, 0x22a5, 0x005f,
+ 0x003f, 0x03b1, 0x03b2, 0x03c7, 0x03b4, 0x03b5, 0x03c6, 0x03b3,
+ 0x03b7, 0x03b9, 0x03d5, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03bf,
+ 0x03c0, 0x03b8, 0x03c1, 0x03c3, 0x03c4, 0x03c5, 0x03d6, 0x03c9,
+ 0x03be, 0x03c8, 0x03b6, 0x007b, 0x007c, 0x007d, 0x223c, 0x003f,
+ 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f,
+ 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f,
+ 0x003f, 0x003f, 0x003f, 0x2022, 0x003f, 0x003f, 0x003f, 0x003f,
+ 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f, 0x003f,
+ 0x20ac, 0x03d2, 0x2032, 0x2264, 0x2044, 0x221e, 0x0192, 0x2663,
+ 0x2666, 0x2665, 0x2660, 0x2194, 0x2190, 0x2191, 0x2192, 0x2193,
+ 0x00b0, 0x00b1, 0x2033, 0x2265, 0x00d7, 0x221d, 0x2202, 0x2022,
+ 0x00f7, 0x2260, 0x2261, 0x2248, 0x2026, 0x007c, 0x23af, 0x21b5,
+ 0x2135, 0x2111, 0x211c, 0x2118, 0x2297, 0x2295, 0x2205, 0x2229,
+ 0x222a, 0x2283, 0x2287, 0x2284, 0x2282, 0x2286, 0x2208, 0x2209,
+ 0x2220, 0x2207, 0x00ae, 0x00a9, 0x2122, 0x220f, 0x221a, 0x22c5,
+ 0x00ac, 0x2227, 0x2228, 0x21d4, 0x21d0, 0x21d1, 0x21d2, 0x21d3,
+ 0x22c4, 0x3008, 0x00ae, 0x00a9, 0x2122, 0x2211, 0x239b, 0x239c,
+ 0x239d, 0x23a1, 0x23a2, 0x23a3, 0x23a7, 0x23a8, 0x23a9, 0x23aa,
+ 0x003f, 0x3009, 0x222b, 0x2320, 0x23ae, 0x2321, 0x239e, 0x239f,
+ 0x23a0, 0x23a4, 0x23a5, 0x23a6, 0x23ab, 0x23ac, 0x23ad, 0x003f,
+};
+
+typedef struct char_table_tag {
+ UCHAR ucLocal;
+ USHORT usUnicode;
+} char_table_type;
+
+static char_table_type atCharTable[256];
+static size_t tNextPosFree = 0;
+
+
+/*
+ * iCompare - compare two records
+ *
+ * Compares two records. For use by qsort(3C) and bsearch(3C).
+ *
+ * returns -1 if rec1 < rec2, 0 if rec1 == rec2, 1 if rec1 > rec2
+ */
+static int
+iCompare(const void *pvRecord1, const void *pvRecord2)
+{
+ USHORT usUnicode1, usUnicode2;
+
+ usUnicode1 = ((char_table_type *)pvRecord1)->usUnicode;
+ usUnicode2 = ((char_table_type *)pvRecord2)->usUnicode;
+
+ if (usUnicode1 < usUnicode2) {
+ return -1;
+ }
+ if (usUnicode1 > usUnicode2) {
+ return 1;
+ }
+ return 0;
+} /* end of iCompare */
+
+/*
+ * pGetCharTableRecord - get the character table record
+ *
+ * returns a pointer to the record when found, otherwise NULL
+ */
+static const char_table_type *
+pGetCharTableRecord(USHORT usUnicode)
+{
+ char_table_type tKey;
+
+ if (tNextPosFree == 0) {
+ return NULL;
+ }
+ tKey.usUnicode = usUnicode;
+ tKey.ucLocal = 0;
+ return (char_table_type *)bsearch(&tKey,
+ atCharTable,
+ tNextPosFree, sizeof(atCharTable[0]),
+ iCompare);
+} /* end of pGetCharTableRecord */
+
+/*
+ * ucGetBulletCharacter - get the local representation of the bullet
+ */
+UCHAR
+ucGetBulletCharacter(conversion_type eConversionType, encoding_type eEncoding)
+{
+#if defined(__riscos)
+ return 0x8f;
+#else
+ const char_table_type *pRec;
+
+ fail(eEncoding == encoding_utf_8);
+
+ if (eEncoding == encoding_latin_1 &&
+ (eConversionType == conversion_ps ||
+ eConversionType == conversion_pdf)) {
+ /* Ugly, but it makes the PostScript and PDF look better */
+ return (UCHAR)143;
+ }
+ if (eConversionType != conversion_text &&
+ eConversionType != conversion_fmt_text) {
+ pRec = pGetCharTableRecord(UNICODE_BULLET);
+ if (pRec != NULL) {
+ return pRec->ucLocal;
+ }
+ pRec = pGetCharTableRecord(UNICODE_BULLET_OPERATOR);
+ if (pRec != NULL) {
+ return pRec->ucLocal;
+ }
+ pRec = pGetCharTableRecord(UNICODE_MIDDLE_DOT);
+ if (pRec != NULL) {
+ return pRec->ucLocal;
+ }
+ }
+ return (UCHAR)'.';
+#endif /* __riscos */
+} /* end of ucGetBulletCharacter */
+
+/*
+ * ucGetNbspCharacter - get the local representation of the non-breaking space
+ */
+UCHAR
+ucGetNbspCharacter(void)
+{
+ const char_table_type *pRec;
+
+ pRec = pGetCharTableRecord(0x00a0); /* Unicode non-breaking space */
+ if (pRec == NULL) {
+ DBG_MSG("Non-breaking space record not found");
+ /* No value found, use the best guess */
+ return (UCHAR)0xa0;
+ }
+ return pRec->ucLocal;
+} /* end of ucGetNbspCharacter */
+
+/*
+ * bReadCharacterMappingTable - read the mapping table
+ *
+ * Read the character mapping table from file and have the contents sorted
+ *
+ * returns TRUE if successful, otherwise FALSE
+ */
+BOOL
+bReadCharacterMappingTable(FILE *pFile)
+{
+ char *pcTmp;
+ ULONG ulUnicode;
+ UINT uiLocal;
+ int iFields;
+ char szLine[81];
+
+ if (pFile == NULL) {
+ return FALSE;
+ }
+
+ /* Clean the table first */
+ (void)memset(atCharTable, 0, sizeof(atCharTable));
+
+ /* Fill the table */
+ while (fgets(szLine, (int)sizeof(szLine), pFile)) {
+ if (szLine[0] == '#' ||
+ szLine[0] == '\r' ||
+ szLine[0] == '\n') {
+ /* Comment or empty line */
+ continue;
+ }
+ iFields = sscanf(szLine, "%x %lx %*s", &uiLocal, &ulUnicode);
+ if (iFields != 2) {
+ pcTmp = strchr(szLine, '\r');
+ if (pcTmp != NULL) {
+ *pcTmp = '\0';
+ }
+ pcTmp = strchr(szLine, '\n');
+ if (pcTmp != NULL) {
+ *pcTmp = '\0';
+ }
+ werr(0, "Syntax error in: '%s'", szLine);
+ continue;
+ }
+ if (uiLocal > 0xff || ulUnicode > 0xffff) {
+ werr(0, "Syntax error in: '%02x %04lx'",
+ uiLocal, ulUnicode);
+ continue;
+ }
+ /* Store only the relevant entries */
+ if (uiLocal != ulUnicode || uiLocal >= 0x80) {
+ atCharTable[tNextPosFree].ucLocal = (UCHAR)uiLocal;
+ atCharTable[tNextPosFree].usUnicode = (USHORT)ulUnicode;
+ tNextPosFree++;
+ }
+ if (tNextPosFree >= elementsof(atCharTable)) {
+ werr(0, "Too many entries in the character mapping "
+ "file. Ignoring the rest.");
+ break;
+ }
+ }
+
+ if (tNextPosFree != 0) {
+ DBG_HEX(atCharTable[0].usUnicode);
+ DBG_HEX(atCharTable[tNextPosFree - 1].usUnicode);
+
+ qsort(atCharTable,
+ tNextPosFree, sizeof(atCharTable[0]),
+ iCompare);
+
+ DBG_HEX(atCharTable[0].usUnicode);
+ DBG_HEX(atCharTable[tNextPosFree - 1].usUnicode);
+ }
+
+ return TRUE;
+} /* end of bReadCharacterMappingTable */
+
+/*
+ * ulTranslateCharacters - Translate characters to local representation
+ *
+ * Translate all characters to local representation
+ *
+ * returns the translated character
+ */
+ULONG
+ulTranslateCharacters(USHORT usChar, ULONG ulFileOffset, int iWordVersion,
+ conversion_type eConversionType, encoding_type eEncoding,
+ BOOL bUseMacCharSet)
+{
+ const char_table_type *pTmp;
+ const USHORT *usCharSet;
+
+ usCharSet = NULL;
+ if (bUseMacCharSet) {
+ /* Macintosh character set */
+ usCharSet = usMacRoman;
+ } else if (iWordVersion == 0) {
+ /* DOS character set */
+ usCharSet = usCp850;
+ } else {
+ /* Windows character set */
+ switch (eEncoding) {
+ case encoding_latin_2:
+ usCharSet = usCp1250;
+ break;
+ case encoding_cyrillic:
+ usCharSet = usCp1251;
+ break;
+ case encoding_latin_1:
+ default:
+ usCharSet = usCp1252;
+ break;
+ }
+ }
+ fail(usCharSet == NULL);
+ if (usChar >= 0x80 && usChar <= 0x9f) {
+ /* Translate implementation defined characters */
+ usChar = usCharSet[usChar - 0x80];
+ } else if (iWordVersion < 8 && usChar >= 0xa0 && usChar <= 0xff) {
+ /* Translate old character set to Unixcode */
+ usChar = usCharSet[usChar - 0x80];
+ }
+
+ /* Microsoft Unicode to real Unicode */
+ if (usChar >= 0xf020 && usChar <= 0xf0ff) {
+ DBG_HEX_C(usPrivateArea[usChar - 0xf020] == 0x003f, usChar);
+ usChar = usPrivateArea[usChar - 0xf020];
+ }
+
+ /* Characters with a special meaning in Word */
+ switch (usChar) {
+ case IGNORE_CHARACTER:
+ case FOOTNOTE_SEPARATOR:
+ case FOOTNOTE_CONTINUATION:
+ case ANNOTATION:
+ case FRAME:
+ case LINE_FEED:
+ case WORD_SOFT_HYPHEN:
+ case UNICODE_HYPHENATION_POINT:
+ return IGNORE_CHARACTER;
+ case PICTURE:
+ case TABLE_SEPARATOR:
+ case TAB:
+ case HARD_RETURN:
+ case PAGE_BREAK:
+ case PAR_END:
+ case COLUMN_FEED:
+ return (ULONG)usChar;
+ case FOOTNOTE_OR_ENDNOTE:
+ NO_DBG_HEX(ulFileOffset);
+ switch (eGetNotetype(ulFileOffset)) {
+ case notetype_is_footnote:
+ return FOOTNOTE_CHAR;
+ case notetype_is_endnote:
+ return ENDNOTE_CHAR;
+ default:
+ return UNKNOWN_NOTE_CHAR;
+ }
+ case WORD_UNBREAKABLE_JOIN:
+ return (ULONG)OUR_UNBREAKABLE_JOIN;
+ default:
+ break;
+ }
+
+ if (eEncoding != encoding_utf_8) {
+ /* Latin characters in an oriental text */
+ if (usChar >= 0xff01 && usChar <= 0xff5e) {
+ usChar -= 0xfee0;
+ }
+ }
+
+ if (eEncoding == encoding_latin_1 &&
+ (eConversionType == conversion_ps ||
+ eConversionType == conversion_pdf)) {
+ /* Ugly, but it makes the PostScript and PDF look better */
+ switch (usChar) {
+ case UNICODE_ELLIPSIS:
+ return 140;
+ case UNICODE_TRADEMARK_SIGN:
+ return 141;
+ case UNICODE_PER_MILLE_SIGN:
+ return 142;
+ case UNICODE_BULLET:
+ case UNICODE_BULLET_OPERATOR:
+ case UNICODE_BLACK_CLUB_SUIT:
+ return 143;
+ case UNICODE_LEFT_SINGLE_QMARK:
+ return 144;
+ case UNICODE_RIGHT_SINGLE_QMARK:
+ return 145;
+ case UNICODE_SINGLE_LEFT_ANGLE_QMARK:
+ return 146;
+ case UNICODE_SINGLE_RIGHT_ANGLE_QMARK:
+ return 147;
+ case UNICODE_LEFT_DOUBLE_QMARK:
+ return 148;
+ case UNICODE_RIGHT_DOUBLE_QMARK:
+ return 149;
+ case UNICODE_DOUBLE_LOW_9_QMARK:
+ return 150;
+ case UNICODE_EN_DASH:
+ return 151;
+ case UNICODE_EM_DASH:
+ return 152;
+ case UNICODE_MINUS_SIGN:
+ return 153;
+ case UNICODE_CAPITAL_LIGATURE_OE:
+ return 154;
+ case UNICODE_SMALL_LIGATURE_OE:
+ return 155;
+ case UNICODE_DAGGER:
+ return 156;
+ case UNICODE_DOUBLE_DAGGER:
+ return 157;
+ case UNICODE_SMALL_LIGATURE_FI:
+ return 158;
+ case UNICODE_SMALL_LIGATURE_FL:
+ return 159;
+ default:
+ break;
+ }
+ }
+
+ if (eConversionType == conversion_pdf) {
+ if (eEncoding == encoding_latin_1) {
+ switch (usChar) {
+ case UNICODE_EURO_SIGN:
+ return 128;
+ default:
+ break;
+ }
+ } else if (eEncoding == encoding_latin_2) {
+ switch (usChar) {
+ case UNICODE_CAPITAL_D_WITH_STROKE:
+ case UNICODE_SMALL_D_WITH_STROKE:
+ return 0x3f;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (usChar < 0x80) {
+ /* US ASCII */
+ if (usChar < 0x20 || usChar == 0x7f) {
+ /* Ignore control characters */
+ DBG_HEX(usChar);
+ DBG_FIXME();
+ return IGNORE_CHARACTER;
+ }
+ return (ULONG)usChar;
+ }
+
+ if (eEncoding == encoding_utf_8) {
+ /* No need to convert Unicode characters */
+ return (ULONG)usChar;
+ }
+
+ /* Unicode to local representation */
+ pTmp = pGetCharTableRecord(usChar);
+ if (pTmp != NULL) {
+ DBG_HEX_C(usChar >= 0x7f && usChar <= 0x9f, usChar);
+ return (ULONG)pTmp->ucLocal;
+ }
+
+ /* Fancy characters to simple US ASCII */
+ switch (usChar) {
+ case UNICODE_SMALL_F_HOOK:
+ return (ULONG)'f';
+ case UNICODE_GREEK_CAPITAL_CHI:
+ return (ULONG)'X';
+ case UNICODE_GREEK_SMALL_UPSILON:
+ return (ULONG)'v';
+ case UNICODE_MODIFIER_CIRCUMFLEX:
+ case UNICODE_UPWARDS_ARROW:
+ return (ULONG)'^';
+ case UNICODE_SMALL_TILDE:
+ case UNICODE_TILDE_OPERATOR:
+ return (ULONG)'~';
+ case UNICODE_EN_QUAD:
+ case UNICODE_EM_QUAD:
+ case UNICODE_EN_SPACE:
+ case UNICODE_EM_SPACE:
+ case UNICODE_THREE_PER_EM_SPACE:
+ case UNICODE_FOUR_PER_EM_SPACE:
+ case UNICODE_SIX_PER_EM_SPACE:
+ case UNICODE_FIGURE_SPACE:
+ case UNICODE_PUNCTUATION_SPACE:
+ case UNICODE_THIN_SPACE:
+ case UNICODE_NARROW_NO_BREAK_SPACE:
+ case UNICODE_LIGHT_SHADE:
+ case UNICODE_MEDIUM_SHADE:
+ case UNICODE_DARK_SHADE:
+ return (ULONG)' ';
+ case UNICODE_LEFT_DOUBLE_QMARK:
+ case UNICODE_RIGHT_DOUBLE_QMARK:
+ case UNICODE_DOUBLE_LOW_9_QMARK:
+ case UNICODE_DOUBLE_HIGH_REV_9_QMARK:
+ case UNICODE_DOUBLE_PRIME:
+ return (ULONG)'"';
+ case UNICODE_LEFT_SINGLE_QMARK:
+ case UNICODE_RIGHT_SINGLE_QMARK:
+ case UNICODE_SINGLE_LOW_9_QMARK:
+ case UNICODE_SINGLE_HIGH_REV_9_QMARK:
+ case UNICODE_PRIME:
+ return (ULONG)'\'';
+ case UNICODE_HYPHEN:
+ case UNICODE_NON_BREAKING_HYPHEN:
+ case UNICODE_FIGURE_DASH:
+ case UNICODE_EN_DASH:
+ case UNICODE_EM_DASH:
+ case UNICODE_HORIZONTAL_BAR:
+ case UNICODE_MINUS_SIGN:
+ case UNICODE_BD_LIGHT_HORIZONTAL:
+ case UNICODE_BD_DOUBLE_HORIZONTAL:
+ return (ULONG)'-';
+ case UNICODE_DOUBLE_VERTICAL_LINE:
+ case UNICODE_BD_LIGHT_VERTICAL:
+ case UNICODE_BD_DOUBLE_VERTICAL:
+ return (ULONG)'|';
+ case UNICODE_DOUBLE_LOW_LINE:
+ return (ULONG)'_';
+ case UNICODE_DAGGER:
+ return (ULONG)'+';
+ case UNICODE_DOUBLE_DAGGER:
+ return (ULONG)'#';
+ case UNICODE_BULLET:
+ case UNICODE_BULLET_OPERATOR:
+ case UNICODE_BLACK_CLUB_SUIT:
+ return (ULONG)ucGetBulletCharacter(eConversionType, eEncoding);
+ case UNICODE_ONE_DOT_LEADER:
+ case UNICODE_TWO_DOT_LEADER:
+ return (ULONG)'.';
+ case UNICODE_ELLIPSIS:
+#if defined(__riscos)
+ return (ULONG)OUR_ELLIPSIS;
+#else
+ if (ulFileOffset == 0) {
+ return (ULONG)OUR_ELLIPSIS;
+ }
+ return UNICODE_ELLIPSIS;
+#endif /* __riscos */
+ case UNICODE_DOUBLE_LEFT_ANGLE_QMARK:
+ case UNICODE_TRIANGULAR_BULLET:
+ case UNICODE_SINGLE_LEFT_ANGLE_QMARK:
+ case UNICODE_LEFTWARDS_ARROW:
+ return (ULONG)'<';
+ case UNICODE_DOUBLE_RIGHT_ANGLE_QMARK:
+ case UNICODE_SINGLE_RIGHT_ANGLE_QMARK:
+ case UNICODE_RIGHTWARDS_ARROW:
+ return (ULONG)'>';
+ case UNICODE_UNDERTIE:
+ return (ULONG)'-';
+ case UNICODE_N_ARY_SUMMATION:
+ return (ULONG)'S';
+ case UNICODE_EURO_SIGN:
+ return (ULONG)'E';
+ case UNICODE_CIRCLE:
+ case UNICODE_SQUARE:
+ return (ULONG)'O';
+ case UNICODE_DIAMOND:
+ return (ULONG)OUR_DIAMOND;
+ case UNICODE_NUMERO_SIGN:
+ return (ULONG)'N';
+ case UNICODE_KELVIN_SIGN:
+ return (ULONG)'K';
+ case UNICODE_DOWNWARDS_ARROW:
+ return (ULONG)'v';
+ case UNICODE_FRACTION_SLASH:
+ case UNICODE_DIVISION_SLASH:
+ return (ULONG)'/';
+ case UNICODE_ASTERISK_OPERATOR:
+ return (ULONG)'*';
+ case UNICODE_RATIO:
+ return (ULONG)':';
+ case UNICODE_BD_LIGHT_DOWN_RIGHT:
+ case UNICODE_BD_LIGHT_DOWN_AND_LEFT:
+ case UNICODE_BD_LIGHT_UP_AND_RIGHT:
+ case UNICODE_BD_LIGHT_UP_AND_LEFT:
+ case UNICODE_BD_LIGHT_VERTICAL_AND_RIGHT:
+ case UNICODE_BD_LIGHT_VERTICAL_AND_LEFT:
+ case UNICODE_BD_LIGHT_DOWN_AND_HORIZONTAL:
+ case UNICODE_BD_LIGHT_UP_AND_HORIZONTAL:
+ case UNICODE_BD_LIGHT_VERTICAL_AND_HORIZONTAL:
+ case UNICODE_BD_DOUBLE_DOWN_AND_RIGHT:
+ case UNICODE_BD_DOUBLE_DOWN_AND_LEFT:
+ case UNICODE_BD_DOUBLE_UP_AND_RIGHT:
+ case UNICODE_BD_DOUBLE_UP_AND_LEFT:
+ case UNICODE_BD_DOUBLE_VERTICAL_AND_RIGHT:
+ case UNICODE_BD_DOUBLE_VERTICAL_AND_LEFT:
+ case UNICODE_BD_DOUBLE_DOWN_AND_HORIZONTAL:
+ case UNICODE_BD_DOUBLE_UP_AND_HORIZONTAL:
+ case UNICODE_BD_DOUBLE_VERTICAL_AND_HORIZONTAL:
+ case UNICODE_BLACK_SQUARE:
+ return (ULONG)'+';
+ case UNICODE_HAIR_SPACE:
+ case UNICODE_ZERO_WIDTH_SPACE:
+ case UNICODE_ZERO_WIDTH_NON_JOINER:
+ case UNICODE_ZERO_WIDTH_JOINER:
+ case UNICODE_LEFT_TO_RIGHT_MARK:
+ case UNICODE_RIGHT_TO_LEFT_MARK:
+ case UNICODE_LEFT_TO_RIGHT_EMBEDDING:
+ case UNICODE_RIGHT_TO_LEFT_EMBEDDING:
+ case UNICODE_POP_DIRECTIONAL_FORMATTING:
+ case UNICODE_LEFT_TO_RIGHT_OVERRIDE:
+ case UNICODE_RIGHT_TO_LEFT_OVERRIDE:
+ case UNICODE_ZERO_WIDTH_NO_BREAK_SPACE:
+ return IGNORE_CHARACTER;
+ default:
+ break;
+ }
+
+ if (usChar == UNICODE_TRADEMARK_SIGN) {
+ /*
+ * No local representation, it doesn't look like anything in
+ * US-ASCII and a question mark does more harm than good.
+ */
+ return IGNORE_CHARACTER;
+ }
+
+ if (usChar >= 0xa0 && usChar <= 0xff) {
+ /* Before Word 97, Word did't use Unicode */
+ return (ULONG)usChar;
+ }
+
+ DBG_HEX_C(usChar < 0x3000 || usChar >= 0xd800, ulFileOffset);
+ DBG_HEX_C(usChar < 0x3000 || usChar >= 0xd800, usChar);
+ DBG_MSG_C(usChar >= 0xe000 && usChar < 0xf900, "Private Use Area");
+
+ /* Untranslated Unicode character */
+ return 0x3f;
+} /* end of ulTranslateCharacters */
+
+/*
+ * ulToUpper - convert letter to upper case
+ *
+ * This function converts a letter to upper case. Unlike toupper(3) this
+ * function is independent from the settings of locale. This comes in handy
+ * for people who have to read Word documents in more than one language or
+ * contain more than one language.
+ *
+ * returns the converted letter, or ulChar if the conversion was not possible.
+ */
+ULONG
+ulToUpper(ULONG ulChar)
+{
+ if (ulChar < 0x80) {
+ /* US ASCII: use standard function */
+ return (ULONG)toupper((int)ulChar);
+ }
+ if (ulChar >= 0xe0 && ulChar <= 0xfe && ulChar != 0xf7) {
+ /*
+ * Lower case accented characters
+ * 0xf7 is Division sign; 0xd7 is Multiplication sign
+ * 0xff is y with diaeresis; 0xdf is Sharp s
+ */
+ return ulChar & ~0x20;
+ }
+#if defined(__STDC_ISO_10646__)
+ /*
+ * If this is ISO C99 and all locales have wchar_t = ISO 10646
+ * (e.g., glibc 2.2 or newer), then use standard function
+ */
+ if (ulChar > 0xff) {
+ return (ULONG)towupper((wint_t)ulChar);
+ }
+#endif /* __STDC_ISO_10646__ */
+ return ulChar;
+} /* end of ulToUpper */
diff --git a/sys/src/cmd/aux/antiword/datalist.c b/sys/src/cmd/aux/antiword/datalist.c
new file mode 100755
index 000000000..564f46980
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/datalist.c
@@ -0,0 +1,374 @@
+/*
+ * datalist.c
+ * Copyright (C) 2000-2002 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Build, read and destroy a list of Word data blocks
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include "antiword.h"
+
+#if defined(__riscos)
+#define EIO 42
+#endif /* __riscos */
+
+
+/*
+ * Private structure to hide the way the information
+ * is stored from the rest of the program
+ */
+typedef struct data_mem_tag {
+ data_block_type tInfo;
+ struct data_mem_tag *pNext;
+} data_mem_type;
+
+/* Variable to describe the start of the data block list */
+static data_mem_type *pAnchor = NULL;
+/* Variable needed to read the data block list */
+static data_mem_type *pBlockLast = NULL;
+/* Variable needed to read the data block list */
+static data_mem_type *pBlockCurrent = NULL;
+static ULONG ulBlockOffset = 0;
+static size_t tByteNext = 0;
+/* Last block read */
+static UCHAR aucBlock[BIG_BLOCK_SIZE];
+
+
+/*
+ * vDestroyDataBlockList - destroy the data block list
+ */
+void
+vDestroyDataBlockList(void)
+{
+ data_mem_type *pCurr, *pNext;
+
+ DBG_MSG("vDestroyDataBlockList");
+
+ pCurr = pAnchor;
+ while (pCurr != NULL) {
+ pNext = pCurr->pNext;
+ pCurr = xfree(pCurr);
+ pCurr = pNext;
+ }
+ pAnchor = NULL;
+ /* Reset all the control variables */
+ pBlockLast = NULL;
+ pBlockCurrent = NULL;
+ ulBlockOffset = 0;
+ tByteNext = 0;
+} /* end of vDestroyDataBlockList */
+
+/*
+ * bAdd2DataBlockList - add an element to the data block list
+ *
+ * Returns TRUE when successful, otherwise FALSE
+ */
+BOOL
+bAdd2DataBlockList(const data_block_type *pDataBlock)
+{
+ data_mem_type *pListMember;
+
+ fail(pDataBlock == NULL);
+ fail(pDataBlock->ulFileOffset == FC_INVALID);
+ fail(pDataBlock->ulDataPos == CP_INVALID);
+ fail(pDataBlock->ulLength == 0);
+
+ NO_DBG_MSG("bAdd2DataBlockList");
+ NO_DBG_HEX(pDataBlock->ulFileOffset);
+ NO_DBG_HEX(pDataBlock->ulDataPos);
+ NO_DBG_HEX(pDataBlock->ulLength);
+
+ if (pDataBlock->ulFileOffset == FC_INVALID ||
+ pDataBlock->ulDataPos == CP_INVALID ||
+ pDataBlock->ulLength == 0) {
+ werr(0, "Software (datablock) error");
+ return FALSE;
+ }
+ /* Check for continuous blocks */
+ if (pBlockLast != NULL &&
+ pBlockLast->tInfo.ulFileOffset +
+ pBlockLast->tInfo.ulLength == pDataBlock->ulFileOffset &&
+ pBlockLast->tInfo.ulDataPos +
+ pBlockLast->tInfo.ulLength == pDataBlock->ulDataPos) {
+ /* These are continous blocks */
+ pBlockLast->tInfo.ulLength += pDataBlock->ulLength;
+ return TRUE;
+ }
+ /* Make a new block */
+ pListMember = xmalloc(sizeof(data_mem_type));
+ /* Add the block to the data list */
+ pListMember->tInfo = *pDataBlock;
+ pListMember->pNext = NULL;
+ if (pAnchor == NULL) {
+ pAnchor = pListMember;
+ } else {
+ fail(pBlockLast == NULL);
+ pBlockLast->pNext = pListMember;
+ }
+ pBlockLast = pListMember;
+ return TRUE;
+} /* end of bAdd2DataBlockList */
+
+/*
+ * ulGetDataOffset - get the offset in the data block list
+ *
+ * Get the fileoffset the current position in the data block list
+ */
+ULONG
+ulGetDataOffset(FILE *pFile)
+{
+ return pBlockCurrent->tInfo.ulFileOffset + ulBlockOffset + tByteNext;
+} /* end of ulGetDataOffset */
+
+/*
+ * bSetDataOffset - set the offset in the data block list
+ *
+ * Make the given fileoffset the current position in the data block list
+ */
+BOOL
+bSetDataOffset(FILE *pFile, ULONG ulFileOffset)
+{
+ data_mem_type *pCurr;
+ size_t tReadLen;
+
+ DBG_HEX(ulFileOffset);
+
+ for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
+ if (ulFileOffset < pCurr->tInfo.ulFileOffset ||
+ ulFileOffset >= pCurr->tInfo.ulFileOffset +
+ pCurr->tInfo.ulLength) {
+ /* The file offset is not in this block */
+ continue;
+ }
+ /* Compute the maximum number of bytes to read */
+ tReadLen = (size_t)(pCurr->tInfo.ulFileOffset +
+ pCurr->tInfo.ulLength -
+ ulFileOffset);
+ /* Compute the real number of bytes to read */
+ if (tReadLen > sizeof(aucBlock)) {
+ tReadLen = sizeof(aucBlock);
+ }
+ /* Read the bytes */
+ if (!bReadBytes(aucBlock, tReadLen, ulFileOffset, pFile)) {
+ return FALSE;
+ }
+ /* Set the control variables */
+ pBlockCurrent = pCurr;
+ ulBlockOffset = ulFileOffset - pCurr->tInfo.ulFileOffset;
+ tByteNext = 0;
+ return TRUE;
+ }
+ return FALSE;
+} /* end of bSetDataOffset */
+
+/*
+ * iNextByte - get the next byte from the data block list
+ */
+int
+iNextByte(FILE *pFile)
+{
+ ULONG ulReadOff;
+ size_t tReadLen;
+
+ fail(pBlockCurrent == NULL);
+
+ if (tByteNext >= sizeof(aucBlock) ||
+ ulBlockOffset + tByteNext >= pBlockCurrent->tInfo.ulLength) {
+ if (ulBlockOffset + sizeof(aucBlock) <
+ pBlockCurrent->tInfo.ulLength) {
+ /* Same block, next part */
+ ulBlockOffset += sizeof(aucBlock);
+ } else {
+ /* Next block, first part */
+ pBlockCurrent = pBlockCurrent->pNext;
+ ulBlockOffset = 0;
+ }
+ if (pBlockCurrent == NULL) {
+ /* Past the last part of the last block */
+ errno = EIO;
+ return EOF;
+ }
+ tReadLen = (size_t)
+ (pBlockCurrent->tInfo.ulLength - ulBlockOffset);
+ if (tReadLen > sizeof(aucBlock)) {
+ tReadLen = sizeof(aucBlock);
+ }
+ ulReadOff = pBlockCurrent->tInfo.ulFileOffset + ulBlockOffset;
+ if (!bReadBytes(aucBlock, tReadLen, ulReadOff, pFile)) {
+ errno = EIO;
+ return EOF;
+ }
+ tByteNext = 0;
+ }
+ return (int)aucBlock[tByteNext++];
+} /* end of iNextByte */
+
+/*
+ * usNextWord - get the next word from the data block list
+ *
+ * Read a two byte value in Little Endian order, that means MSB last
+ *
+ * All return values can be valid so errno is set in case of error
+ */
+USHORT
+usNextWord(FILE *pFile)
+{
+ USHORT usLSB, usMSB;
+
+ usLSB = (USHORT)iNextByte(pFile);
+ if (usLSB == (USHORT)EOF) {
+ errno = EIO;
+ return (USHORT)EOF;
+ }
+ usMSB = (USHORT)iNextByte(pFile);
+ if (usMSB == (USHORT)EOF) {
+ DBG_MSG("usNextWord: Unexpected EOF");
+ errno = EIO;
+ return (USHORT)EOF;
+ }
+ return (usMSB << 8) | usLSB;
+} /* end of usNextWord */
+
+/*
+ * ulNextLong - get the next long from the data block list
+ *
+ * Read a four byte value in Little Endian order, that means MSW last
+ *
+ * All return values can be valid so errno is set in case of error
+ */
+ULONG
+ulNextLong(FILE *pFile)
+{
+ ULONG ulLSW, ulMSW;
+
+ ulLSW = (ULONG)usNextWord(pFile);
+ if (ulLSW == (ULONG)EOF) {
+ errno = EIO;
+ return (ULONG)EOF;
+ }
+ ulMSW = (ULONG)usNextWord(pFile);
+ if (ulMSW == (ULONG)EOF) {
+ DBG_MSG("ulNextLong: Unexpected EOF");
+ errno = EIO;
+ return (ULONG)EOF;
+ }
+ return (ulMSW << 16) | ulLSW;
+} /* end of ulNextLong */
+
+/*
+ * usNextWordBE - get the next two byte value
+ *
+ * Read a two byte value in Big Endian order, that means MSB first
+ *
+ * All return values can be valid so errno is set in case of error
+ */
+USHORT
+usNextWordBE(FILE *pFile)
+{
+ USHORT usLSB, usMSB;
+
+ usMSB = (USHORT)iNextByte(pFile);
+ if (usMSB == (USHORT)EOF) {
+ errno = EIO;
+ return (USHORT)EOF;
+ }
+ usLSB = (USHORT)iNextByte(pFile);
+ if (usLSB == (USHORT)EOF) {
+ DBG_MSG("usNextWordBE: Unexpected EOF");
+ errno = EIO;
+ return (USHORT)EOF;
+ }
+ return (usMSB << 8) | usLSB;
+} /* end of usNextWordBE */
+
+/*
+ * ulNextLongBE - get the next four byte value
+ *
+ * Read a four byte value in Big Endian order, that means MSW first
+ *
+ * All return values can be valid so errno is set in case of error
+ */
+ULONG
+ulNextLongBE(FILE *pFile)
+{
+ ULONG ulLSW, ulMSW;
+
+ ulMSW = (ULONG)usNextWordBE(pFile);
+ if (ulMSW == (ULONG)EOF) {
+ errno = EIO;
+ return (ULONG)EOF;
+ }
+ ulLSW = (ULONG)usNextWordBE(pFile);
+ if (ulLSW == (ULONG)EOF) {
+ DBG_MSG("ulNextLongBE: Unexpected EOF");
+ errno = EIO;
+ return (ULONG)EOF;
+ }
+ return (ulMSW << 16) | ulLSW;
+} /* end of ulNextLongBE */
+
+/*
+ * tSkipBytes - skip over the given number of bytes
+ *
+ * Returns the number of skipped bytes
+ */
+size_t
+tSkipBytes(FILE *pFile, size_t tToSkip)
+{
+ size_t tToGo, tMaxMove, tMove;
+
+ fail(pFile == NULL);
+ fail(pBlockCurrent == NULL);
+
+ tToGo = tToSkip;
+ while (tToGo != 0) {
+ /* Goto the end of the current block */
+ tMaxMove = min(sizeof(aucBlock) - tByteNext,
+ (size_t)(pBlockCurrent->tInfo.ulLength -
+ ulBlockOffset - tByteNext));
+ tMove = min(tMaxMove, tToGo);
+ tByteNext += tMove;
+ tToGo -= tMove;
+ if (tToGo != 0) {
+ /* Goto the next block */
+ if (iNextByte(pFile) == EOF) {
+ return tToSkip - tToGo;
+ }
+ tToGo--;
+ }
+ }
+ return tToSkip;
+} /* end of tSkipBytes */
+
+/*
+ * Translate a data position to an offset in the file.
+ * Logical to physical offset.
+ *
+ * Returns: FC_INVALID: in case of error
+ * otherwise: the computed file offset
+ */
+ULONG
+ulDataPos2FileOffset(ULONG ulDataPos)
+{
+ data_mem_type *pCurr;
+
+ fail(ulDataPos == CP_INVALID);
+
+ for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
+ if (ulDataPos < pCurr->tInfo.ulDataPos ||
+ ulDataPos >= pCurr->tInfo.ulDataPos +
+ pCurr->tInfo.ulLength) {
+ /* The data offset is not in this block, try the next */
+ continue;
+ }
+ /* The data offset is in the current block */
+ return pCurr->tInfo.ulFileOffset +
+ ulDataPos -
+ pCurr->tInfo.ulDataPos;
+ }
+ /* Passed beyond the end of the list */
+ DBG_HEX_C(ulDataPos != 0, ulDataPos);
+ return FC_INVALID;
+} /* end of ulDataPos2FileOffset */
diff --git a/sys/src/cmd/aux/antiword/debug.h b/sys/src/cmd/aux/antiword/debug.h
new file mode 100755
index 000000000..4dee4d43a
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/debug.h
@@ -0,0 +1,117 @@
+/*
+ * debug.h
+ * Copyright (C) 1998-2005 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Macro's for debuging.
+ */
+
+#if !defined(__debug_h)
+#define __debug_h 1
+
+#include <stdio.h>
+#include <ctype.h>
+
+#if defined(DEBUG)
+
+#define DBG_MSG(t) (void)fprintf(stderr,\
+ "%s[%3d]: %.240s\n",\
+ __FILE__, __LINE__, (t))
+
+#define DBG_STRN(t,m) (void)fprintf(stderr,\
+ "%s[%3d]: %d '%.*s'\n",\
+ __FILE__, __LINE__,\
+ (int)(m), (int)(m), (const char *)(t))
+
+#define DBG_CHR(m) (void)fprintf(stderr,\
+ "%s[%3d]: "#m" = %3d 0x%02x '%c'\n",\
+ __FILE__, __LINE__,\
+ (int)(m), (unsigned int)(unsigned char)(m),\
+ isprint((int)(unsigned char)(m))?(char)(m):' ')
+
+#define DBG_DEC(m) (void)fprintf(stderr,\
+ "%s[%3d]: "#m" = %ld\n",\
+ __FILE__, __LINE__, (long)(m))
+
+#define DBG_HEX(m) (void)fprintf(stderr,\
+ "%s[%3d]: "#m" = 0x%02lx\n",\
+ __FILE__, __LINE__, (unsigned long)(m))
+
+#define DBG_FLT(m) (void)fprintf(stderr,\
+ "%s[%3d]: "#m" = %.3f\n",\
+ __FILE__, __LINE__, (double)(m))
+
+#define DBG_FIXME() (void)fprintf(stderr,\
+ "%s[%3d]: FIXME\n",\
+ __FILE__, __LINE__)
+
+#define DBG_PRINT_BLOCK(b,m) vPrintBlock(__FILE__, __LINE__,(b),(m))
+#define DBG_UNICODE(t) vPrintUnicode(__FILE__, __LINE__,\
+ (const UCHAR *)(t),unilen(t))
+#define DBG_UNICODE_N(t,m) vPrintUnicode(__FILE__, __LINE__,\
+ (const UCHAR *)(t),(m))
+
+#define DBG_MSG_C(c,t) do { if (c) DBG_MSG(t); } while(0)
+#define DBG_STRN_C(c,t,m) do { if (c) DBG_STRN(t,m); } while(0)
+#define DBG_CHR_C(c,m) do { if (c) DBG_CHR(m); } while(0)
+#define DBG_DEC_C(c,m) do { if (c) DBG_DEC(m); } while(0)
+#define DBG_HEX_C(c,m) do { if (c) DBG_HEX(m); } while(0)
+#define DBG_FLT_C(c,m) do { if (c) DBG_FLT(m); } while(0)
+
+#else
+
+#define DBG_MSG(t) /* EMPTY */
+#define DBG_STRN(t,m) /* EMPTY */
+#define DBG_CHR(m) /* EMPTY */
+#define DBG_DEC(m) /* EMPTY */
+#define DBG_HEX(m) /* EMPTY */
+#define DBG_FLT(m) /* EMPTY */
+
+#define DBG_FIXME() /* EMPTY */
+#define DBG_PRINT_BLOCK(b,m) /* EMPTY */
+#define DBG_UNICODE(t) /* EMPTY */
+#define DBG_UNICODE_N(t,m) /* EMPTY */
+
+#define DBG_MSG_C(c,t) /* EMPTY */
+#define DBG_STRN_C(c,t,m) /* EMPTY */
+#define DBG_CHR_C(c,m) /* EMPTY */
+#define DBG_DEC_C(c,m) /* EMPTY */
+#define DBG_HEX_C(c,m) /* EMPTY */
+#define DBG_FLT_C(c,m) /* EMPTY */
+
+#endif /* DEBUG */
+
+#define NO_DBG_MSG(t) /* EMPTY */
+#define NO_DBG_STRN(t,m) /* EMPTY */
+#define NO_DBG_CHR(m) /* EMPTY */
+#define NO_DBG_DEC(m) /* EMPTY */
+#define NO_DBG_HEX(m) /* EMPTY */
+#define NO_DBG_FLT(m) /* EMPTY */
+
+#define NO_DBG_PRINT_BLOCK(b,m) /* EMPTY */
+#define NO_DBG_UNICODE(t) /* EMPTY */
+#define NO_DBG_UNICODE_N(t,m) /* EMPTY */
+
+#define NO_DBG_MSG_C(c,t) /* EMPTY */
+#define NO_DBG_STRN_C(c,t,m) /* EMPTY */
+#define NO_DBG_CHR_C(c,m) /* EMPTY */
+#define NO_DBG_DEC_C(c,m) /* EMPTY */
+#define NO_DBG_HEX_C(c,m) /* EMPTY */
+#define NO_DBG_FLT_C(c,m) /* EMPTY */
+
+#if defined(TRACE)
+
+#define TRACE_MSG(t) do {\
+ (void)fprintf(stderr,\
+ "%s[%3d]: TRACE:%.40s\n",\
+ __FILE__, __LINE__, (t));\
+ (void)fflush(stderr);\
+ } while(0)
+
+#else
+
+#define TRACE_MSG(t) /* EMPTY */
+
+#endif /* TRACE */
+
+#endif /* !__debug_h */
diff --git a/sys/src/cmd/aux/antiword/depot.c b/sys/src/cmd/aux/antiword/depot.c
new file mode 100755
index 000000000..295c39d93
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/depot.c
@@ -0,0 +1,114 @@
+/*
+ * depot.c
+ * Copyright (C) 1998-2002 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Functions to compute the depot offset
+ */
+
+#include "antiword.h"
+
+#define SIZE_RATIO (BIG_BLOCK_SIZE/SMALL_BLOCK_SIZE)
+
+static ULONG *aulSmallBlockList = NULL;
+static size_t tSmallBlockListLen = 0;
+
+
+/*
+ * vDestroySmallBlockList - destroy the small block list
+ */
+void
+vDestroySmallBlockList(void)
+{
+ DBG_MSG("vDestroySmallBlockList");
+
+ aulSmallBlockList = xfree(aulSmallBlockList);
+ tSmallBlockListLen = 0;
+} /* end of vDestroySmalBlockList */
+
+/*
+ * vCreateSmallBlockList - create the small block list
+ *
+ * returns: TRUE when successful, otherwise FALSE
+ */
+BOOL
+bCreateSmallBlockList(ULONG ulStartblock, const ULONG *aulBBD, size_t tBBDLen)
+{
+ ULONG ulTmp;
+ size_t tSize;
+ int iIndex;
+
+ fail(aulSmallBlockList != NULL);
+ fail(tSmallBlockListLen != 0);
+ fail(ulStartblock > MAX_BLOCKNUMBER && ulStartblock != END_OF_CHAIN);
+ fail(aulBBD == NULL);
+ fail(tBBDLen == 0);
+
+ /* Find the length of the small block list */
+ for (tSmallBlockListLen = 0, ulTmp = ulStartblock;
+ tSmallBlockListLen < tBBDLen && ulTmp != END_OF_CHAIN;
+ tSmallBlockListLen++, ulTmp = aulBBD[ulTmp]) {
+ if (ulTmp >= (ULONG)tBBDLen) {
+ DBG_DEC(ulTmp);
+ DBG_DEC(tBBDLen);
+ werr(1, "The Big Block Depot is damaged");
+ }
+ }
+ DBG_DEC(tSmallBlockListLen);
+
+ if (tSmallBlockListLen == 0) {
+ /* There is no small block list */
+ fail(ulStartblock != END_OF_CHAIN);
+ aulSmallBlockList = NULL;
+ return TRUE;
+ }
+
+ /* Create the small block list */
+ tSize = tSmallBlockListLen * sizeof(ULONG);
+ aulSmallBlockList = xmalloc(tSize);
+ for (iIndex = 0, ulTmp = ulStartblock;
+ iIndex < (int)tBBDLen && ulTmp != END_OF_CHAIN;
+ iIndex++, ulTmp = aulBBD[ulTmp]) {
+ if (ulTmp >= (ULONG)tBBDLen) {
+ DBG_DEC(ulTmp);
+ DBG_DEC(tBBDLen);
+ werr(1, "The Big Block Depot is damaged");
+ }
+ aulSmallBlockList[iIndex] = ulTmp;
+ NO_DBG_DEC(aulSmallBlockList[iIndex]);
+ }
+ return TRUE;
+} /* end of bCreateSmallBlockList */
+
+/*
+ * ulDepotOffset - get the depot offset the block list
+ */
+ULONG
+ulDepotOffset(ULONG ulIndex, size_t tBlockSize)
+{
+ ULONG ulTmp;
+ size_t tTmp;
+
+ fail(ulIndex >= ULONG_MAX / BIG_BLOCK_SIZE);
+
+ switch (tBlockSize) {
+ case BIG_BLOCK_SIZE:
+ return (ulIndex + 1) * BIG_BLOCK_SIZE;
+ case SMALL_BLOCK_SIZE:
+ tTmp = (size_t)(ulIndex / SIZE_RATIO);
+ ulTmp = ulIndex % SIZE_RATIO;
+ if (aulSmallBlockList == NULL ||
+ tTmp >= tSmallBlockListLen) {
+ DBG_HEX(aulSmallBlockList);
+ DBG_DEC(tSmallBlockListLen);
+ DBG_DEC(tTmp);
+ return 0;
+ }
+ return ((aulSmallBlockList[tTmp] + 1) * SIZE_RATIO +
+ ulTmp) * SMALL_BLOCK_SIZE;
+ default:
+ DBG_DEC(tBlockSize);
+ DBG_FIXME();
+ return 0;
+ }
+} /* end of ulDepotOffset */
diff --git a/sys/src/cmd/aux/antiword/dib2eps.c b/sys/src/cmd/aux/antiword/dib2eps.c
new file mode 100755
index 000000000..2673d38e0
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/dib2eps.c
@@ -0,0 +1,509 @@
+/*
+ * dib2eps.c
+ * Copyright (C) 2000-2003 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Functions to translate dib pictures into eps
+ *
+ *================================================================
+ * This part of the software is based on:
+ * The Windows Bitmap Decoder Class part of paintlib
+ * Paintlib is copyright (c) 1996-2000 Ulrich von Zadow
+ *================================================================
+ * The credit should go to him, but all the bugs are mine.
+ */
+
+#include <stdio.h>
+#include "antiword.h"
+
+
+/*
+ * vDecode1bpp - decode an uncompressed 1 bit per pixel image
+ */
+static void
+vDecode1bpp(FILE *pInFile, FILE *pOutFile, const imagedata_type *pImg)
+{
+ size_t tPadding;
+ int iX, iY, iN, iByte, iTmp, iEighthWidth, iUse;
+
+ DBG_MSG("vDecode1bpp");
+
+ fail(pOutFile == NULL);
+ fail(pImg == NULL);
+ fail(pImg->iColorsUsed < 1 || pImg->iColorsUsed > 2);
+
+ DBG_DEC(pImg->iWidth);
+ DBG_DEC(pImg->iHeight);
+
+ iEighthWidth = (pImg->iWidth + 7) / 8;
+ tPadding = (size_t)(ROUND4(iEighthWidth) - iEighthWidth);
+
+ for (iY = 0; iY < pImg->iHeight; iY++) {
+ for (iX = 0; iX < iEighthWidth; iX++) {
+ iByte = iNextByte(pInFile);
+ if (iByte == EOF) {
+ vASCII85EncodeByte(pOutFile, EOF);
+ return;
+ }
+ if (iX == iEighthWidth - 1 && pImg->iWidth % 8 != 0) {
+ iUse = pImg->iWidth % 8;
+ } else {
+ iUse = 8;
+ }
+ for (iN = 0; iN < iUse; iN++) {
+ switch (iN) {
+ case 0: iTmp = (iByte & 0x80) / 128; break;
+ case 1: iTmp = (iByte & 0x40) / 64; break;
+ case 2: iTmp = (iByte & 0x20) / 32; break;
+ case 3: iTmp = (iByte & 0x10) / 16; break;
+ case 4: iTmp = (iByte & 0x08) / 8; break;
+ case 5: iTmp = (iByte & 0x04) / 4; break;
+ case 6: iTmp = (iByte & 0x02) / 2; break;
+ case 7: iTmp = (iByte & 0x01); break;
+ default: iTmp = 0; break;
+ }
+ vASCII85EncodeByte(pOutFile, iTmp);
+ }
+ }
+ (void)tSkipBytes(pInFile, tPadding);
+ }
+ vASCII85EncodeByte(pOutFile, EOF);
+} /* end of vDecode1bpp */
+
+/*
+ * vDecode4bpp - decode an uncompressed 4 bits per pixel image
+ */
+static void
+vDecode4bpp(FILE *pInFile, FILE *pOutFile, const imagedata_type *pImg)
+{
+ size_t tPadding;
+ int iX, iY, iN, iByte, iTmp, iHalfWidth, iUse;
+
+ DBG_MSG("vDecode4bpp");
+
+ fail(pInFile == NULL);
+ fail(pOutFile == NULL);
+ fail(pImg == NULL);
+ fail(pImg->iColorsUsed < 1 || pImg->iColorsUsed > 16);
+
+ DBG_DEC(pImg->iWidth);
+ DBG_DEC(pImg->iHeight);
+
+ iHalfWidth = (pImg->iWidth + 1) / 2;
+ tPadding = (size_t)(ROUND4(iHalfWidth) - iHalfWidth);
+
+ for (iY = 0; iY < pImg->iHeight; iY++) {
+ for (iX = 0; iX < iHalfWidth; iX++) {
+ iByte = iNextByte(pInFile);
+ if (iByte == EOF) {
+ vASCII85EncodeByte(pOutFile, EOF);
+ return;
+ }
+ if (iX == iHalfWidth - 1 && odd(pImg->iWidth)) {
+ iUse = 1;
+ } else {
+ iUse = 2;
+ }
+ for (iN = 0; iN < iUse; iN++) {
+ if (odd(iN)) {
+ iTmp = iByte & 0x0f;
+ } else {
+ iTmp = (iByte & 0xf0) / 16;
+ }
+ vASCII85EncodeByte(pOutFile, iTmp);
+ }
+ }
+ (void)tSkipBytes(pInFile, tPadding);
+ }
+ vASCII85EncodeByte(pOutFile, EOF);
+} /* end of vDecode4bpp */
+
+/*
+ * vDecode8bpp - decode an uncompressed 8 bits per pixel image
+ */
+static void
+vDecode8bpp(FILE *pInFile, FILE *pOutFile, const imagedata_type *pImg)
+{
+ size_t tPadding;
+ int iX, iY, iByte;
+
+ DBG_MSG("vDecode8bpp");
+
+ fail(pInFile == NULL);
+ fail(pOutFile == NULL);
+ fail(pImg == NULL);
+ fail(pImg->iColorsUsed < 1 || pImg->iColorsUsed > 256);
+
+ DBG_DEC(pImg->iWidth);
+ DBG_DEC(pImg->iHeight);
+
+ tPadding = (size_t)(ROUND4(pImg->iWidth) - pImg->iWidth);
+
+ for (iY = 0; iY < pImg->iHeight; iY++) {
+ for (iX = 0; iX < pImg->iWidth; iX++) {
+ iByte = iNextByte(pInFile);
+ if (iByte == EOF) {
+ vASCII85EncodeByte(pOutFile, EOF);
+ return;
+ }
+ vASCII85EncodeByte(pOutFile, iByte);
+ }
+ (void)tSkipBytes(pInFile, tPadding);
+ }
+ vASCII85EncodeByte(pOutFile, EOF);
+} /* end of vDecode8bpp */
+
+/*
+ * vDecode24bpp - decode an uncompressed 24 bits per pixel image
+ */
+static void
+vDecode24bpp(FILE *pInFile, FILE *pOutFile, const imagedata_type *pImg)
+{
+ size_t tPadding;
+ int iX, iY, iBlue, iGreen, iRed, iTripleWidth;
+
+ DBG_MSG("vDecode24bpp");
+
+ fail(pInFile == NULL);
+ fail(pOutFile == NULL);
+ fail(pImg == NULL);
+ fail(!pImg->bColorImage);
+
+ DBG_DEC(pImg->iWidth);
+ DBG_DEC(pImg->iHeight);
+
+ iTripleWidth = pImg->iWidth * 3;
+ tPadding = (size_t)(ROUND4(iTripleWidth) - iTripleWidth);
+
+ for (iY = 0; iY < pImg->iHeight; iY++) {
+ for (iX = 0; iX < pImg->iWidth; iX++) {
+ /* Change from BGR order to RGB order */
+ iBlue = iNextByte(pInFile);
+ if (iBlue == EOF) {
+ vASCII85EncodeByte(pOutFile, EOF);
+ return;
+ }
+ iGreen = iNextByte(pInFile);
+ if (iGreen == EOF) {
+ vASCII85EncodeByte(pOutFile, EOF);
+ return;
+ }
+ iRed = iNextByte(pInFile);
+ if (iRed == EOF) {
+ vASCII85EncodeByte(pOutFile, EOF);
+ return;
+ }
+ vASCII85EncodeByte(pOutFile, iRed);
+ vASCII85EncodeByte(pOutFile, iGreen);
+ vASCII85EncodeByte(pOutFile, iBlue);
+ }
+ (void)tSkipBytes(pInFile, tPadding);
+ }
+ vASCII85EncodeByte(pOutFile, EOF);
+} /* end of vDecode24bpp */
+
+/*
+ * vDecodeRle4 - decode a RLE compressed 4 bits per pixel image
+ */
+static void
+vDecodeRle4(FILE *pInFile, FILE *pOutFile, const imagedata_type *pImg)
+{
+ int iX, iY, iByte, iTmp, iRunLength, iRun;
+ BOOL bEOF, bEOL;
+
+ DBG_MSG("vDecodeRle4");
+
+ fail(pInFile == NULL);
+ fail(pOutFile == NULL);
+ fail(pImg == NULL);
+ fail(pImg->iColorsUsed < 1 || pImg->iColorsUsed > 16);
+
+ DBG_DEC(pImg->iWidth);
+ DBG_DEC(pImg->iHeight);
+
+ bEOF = FALSE;
+
+ for (iY = 0; iY < pImg->iHeight && !bEOF; iY++) {
+ bEOL = FALSE;
+ iX = 0;
+ while (!bEOL) {
+ iRunLength = iNextByte(pInFile);
+ if (iRunLength == EOF) {
+ vASCII85EncodeByte(pOutFile, EOF);
+ return;
+ }
+ if (iRunLength != 0) {
+ /*
+ * Encoded packet:
+ * RunLength pixels, all the "same" value
+ */
+ iByte = iNextByte(pInFile);
+ if (iByte == EOF) {
+ vASCII85EncodeByte(pOutFile, EOF);
+ return;
+ }
+ for (iRun = 0; iRun < iRunLength; iRun++) {
+ if (odd(iRun)) {
+ iTmp = iByte & 0x0f;
+ } else {
+ iTmp = (iByte & 0xf0) / 16;
+ }
+ if (iX < pImg->iWidth) {
+ vASCII85EncodeByte(pOutFile, iTmp);
+ }
+ iX++;
+ }
+ continue;
+ }
+ /* Literal or escape */
+ iRunLength = iNextByte(pInFile);
+ if (iRunLength == EOF) {
+ vASCII85EncodeByte(pOutFile, EOF);
+ return;
+ }
+ if (iRunLength == 0) { /* End of line escape */
+ bEOL = TRUE;
+ } else if (iRunLength == 1) { /* End of file escape */
+ bEOF = TRUE;
+ bEOL = TRUE;
+ } else if (iRunLength == 2) { /* Delta escape */
+ DBG_MSG("RLE4: encountered delta escape");
+ bEOF = TRUE;
+ bEOL = TRUE;
+ } else { /* Literal packet */
+ iByte = 0;
+ for (iRun = 0; iRun < iRunLength; iRun++) {
+ if (odd(iRun)) {
+ iTmp = iByte & 0x0f;
+ } else {
+ iByte = iNextByte(pInFile);
+ if (iByte == EOF) {
+ vASCII85EncodeByte(pOutFile, EOF);
+ return;
+ }
+ iTmp = (iByte & 0xf0) / 16;
+ }
+ if (iX < pImg->iWidth) {
+ vASCII85EncodeByte(pOutFile, iTmp);
+ }
+ iX++;
+ }
+ /* Padding if the number of bytes is odd */
+ if (odd((iRunLength + 1) / 2)) {
+ (void)tSkipBytes(pInFile, 1);
+ }
+ }
+ }
+ DBG_DEC_C(iX != pImg->iWidth, iX);
+ }
+ vASCII85EncodeByte(pOutFile, EOF);
+} /* end of vDecodeRle4 */
+
+/*
+ * vDecodeRle8 - decode a RLE compressed 8 bits per pixel image
+ */
+static void
+vDecodeRle8(FILE *pInFile, FILE *pOutFile, const imagedata_type *pImg)
+{
+ int iX, iY, iByte, iRunLength, iRun;
+ BOOL bEOF, bEOL;
+
+ DBG_MSG("vDecodeRle8");
+
+ fail(pInFile == NULL);
+ fail(pOutFile == NULL);
+ fail(pImg == NULL);
+ fail(pImg->iColorsUsed < 1 || pImg->iColorsUsed > 256);
+
+ DBG_DEC(pImg->iWidth);
+ DBG_DEC(pImg->iHeight);
+
+ bEOF = FALSE;
+
+ for (iY = 0; iY < pImg->iHeight && !bEOF; iY++) {
+ bEOL = FALSE;
+ iX = 0;
+ while (!bEOL) {
+ iRunLength = iNextByte(pInFile);
+ if (iRunLength == EOF) {
+ vASCII85EncodeByte(pOutFile, EOF);
+ return;
+ }
+ if (iRunLength != 0) {
+ /*
+ * Encoded packet:
+ * RunLength pixels, all the same value
+ */
+ iByte = iNextByte(pInFile);
+ if (iByte == EOF) {
+ vASCII85EncodeByte(pOutFile, EOF);
+ return;
+ }
+ for (iRun = 0; iRun < iRunLength; iRun++) {
+ if (iX < pImg->iWidth) {
+ vASCII85EncodeByte(pOutFile, iByte);
+ }
+ iX++;
+ }
+ continue;
+ }
+ /* Literal or escape */
+ iRunLength = iNextByte(pInFile);
+ if (iRunLength == EOF) {
+ vASCII85EncodeByte(pOutFile, EOF);
+ return;
+ }
+ if (iRunLength == 0) { /* End of line escape */
+ bEOL = TRUE;
+ } else if (iRunLength == 1) { /* End of file escape */
+ bEOF = TRUE;
+ bEOL = TRUE;
+ } else if (iRunLength == 2) { /* Delta escape */
+ DBG_MSG("RLE8: encountered delta escape");
+ bEOF = TRUE;
+ bEOL = TRUE;
+ } else { /* Literal packet */
+ for (iRun = 0; iRun < iRunLength; iRun++) {
+ iByte = iNextByte(pInFile);
+ if (iByte == EOF) {
+ vASCII85EncodeByte(pOutFile, EOF);
+ return;
+ }
+ if (iX < pImg->iWidth) {
+ vASCII85EncodeByte(pOutFile, iByte);
+ }
+ iX++;
+ }
+ /* Padding if the number of bytes is odd */
+ if (odd(iRunLength)) {
+ (void)tSkipBytes(pInFile, 1);
+ }
+ }
+ }
+ DBG_DEC_C(iX != pImg->iWidth, iX);
+ }
+ vASCII85EncodeByte(pOutFile, EOF);
+} /* end of vDecodeRle8 */
+
+/*
+ * vDecodeDIB - decode a dib picture
+ */
+static void
+vDecodeDIB(FILE *pInFile, FILE *pOutFile, const imagedata_type *pImg)
+{
+ size_t tHeaderSize;
+
+ fail(pInFile == NULL);
+ fail(pOutFile == NULL);
+ fail(pImg == NULL);
+
+ /* Skip the bitmap info header */
+ tHeaderSize = (size_t)ulNextLong(pInFile);
+ (void)tSkipBytes(pInFile, tHeaderSize - 4);
+ /* Skip the colortable */
+ if (pImg->uiBitsPerComponent <= 8) {
+ (void)tSkipBytes(pInFile,
+ (size_t)(pImg->iColorsUsed *
+ ((tHeaderSize > 12) ? 4 : 3)));
+ }
+
+ switch (pImg->uiBitsPerComponent) {
+ case 1:
+ fail(pImg->eCompression != compression_none);
+ vDecode1bpp(pInFile, pOutFile, pImg);
+ break;
+ case 4:
+ fail(pImg->eCompression != compression_none &&
+ pImg->eCompression != compression_rle4);
+ if (pImg->eCompression == compression_rle4) {
+ vDecodeRle4(pInFile, pOutFile, pImg);
+ } else {
+ vDecode4bpp(pInFile, pOutFile, pImg);
+ }
+ break;
+ case 8:
+ fail(pImg->eCompression != compression_none &&
+ pImg->eCompression != compression_rle8);
+ if (pImg->eCompression == compression_rle8) {
+ vDecodeRle8(pInFile, pOutFile, pImg);
+ } else {
+ vDecode8bpp(pInFile, pOutFile, pImg);
+ }
+ break;
+ case 24:
+ fail(pImg->eCompression != compression_none);
+ vDecode24bpp(pInFile, pOutFile, pImg);
+ break;
+ default:
+ DBG_DEC(pImg->uiBitsPerComponent);
+ break;
+ }
+} /* end of vDecodeDIB */
+
+#if defined(DEBUG)
+/*
+ * vCopy2File
+ */
+static void
+vCopy2File(FILE *pInFile, ULONG ulFileOffset, size_t tPictureLen)
+{
+ static int iPicCounter = 0;
+ FILE *pOutFile;
+ size_t tIndex;
+ int iTmp;
+ char szFilename[30];
+
+ if (!bSetDataOffset(pInFile, ulFileOffset)) {
+ return;
+ }
+
+ sprintf(szFilename, "/tmp/pic/pic%04d.bmp", ++iPicCounter);
+ pOutFile = fopen(szFilename, "wb");
+ if (pOutFile == NULL) {
+ return;
+ }
+ /* Turn a dib into a bmp by adding a fake 14 byte header */
+ (void)putc('B', pOutFile);
+ (void)putc('M', pOutFile);
+ for (iTmp = 0; iTmp < 12; iTmp++) {
+ if (putc(0, pOutFile) == EOF) {
+ break;
+ }
+ }
+ for (tIndex = 0; tIndex < tPictureLen; tIndex++) {
+ iTmp = iNextByte(pInFile);
+ if (putc(iTmp, pOutFile) == EOF) {
+ break;
+ }
+ }
+ (void)fclose(pOutFile);
+} /* end of vCopy2File */
+#endif /* DEBUG */
+
+/*
+ * bTranslateDIB - translate a DIB picture
+ *
+ * This function translates a picture from dib to eps
+ *
+ * return TRUE when sucessful, otherwise FALSE
+ */
+BOOL
+bTranslateDIB(diagram_type *pDiag, FILE *pInFile,
+ ULONG ulFileOffset, const imagedata_type *pImg)
+{
+#if defined(DEBUG)
+ fail(pImg->tPosition > pImg->tLength);
+ vCopy2File(pInFile, ulFileOffset, pImg->tLength - pImg->tPosition);
+#endif /* DEBUG */
+
+ /* Seek to start position of DIB data */
+ if (!bSetDataOffset(pInFile, ulFileOffset)) {
+ return FALSE;
+ }
+
+ vImagePrologue(pDiag, pImg);
+ vDecodeDIB(pInFile, pDiag->pOutFile, pImg);
+ vImageEpilogue(pDiag);
+
+ return TRUE;
+} /* end of bTranslateDIB */
diff --git a/sys/src/cmd/aux/antiword/dib2sprt.c b/sys/src/cmd/aux/antiword/dib2sprt.c
new file mode 100755
index 000000000..b8fc364dc
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/dib2sprt.c
@@ -0,0 +1,597 @@
+/*
+ * dib2sprt.c
+ * Copyright (C) 2000-2003 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Functions to translate dib pictures into sprites
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "DeskLib:Error.h"
+#include "DeskLib:Sprite.h"
+#include "antiword.h"
+
+#if 0 /* defined(DEBUG) */
+static int iPicCounter = 0;
+#endif /* DEBUG */
+
+
+/*
+ * iGetByteWidth - compute the number of bytes needed for a row of pixels
+ */
+static int
+iGetByteWidth(const imagedata_type *pImg)
+{
+ switch (pImg->uiBitsPerComponent) {
+ case 1:
+ return (pImg->iWidth + 31) / 32 * sizeof(int);
+ case 4:
+ return (pImg->iWidth + 7) / 8 * sizeof(int);
+ case 8:
+ case 24:
+ return (pImg->iWidth + 3) / 4 * sizeof(int);
+ default:
+ DBG_DEC(pImg->uiBitsPerComponent);
+ return 0;
+ }
+} /* end of iGetByteWidth */
+
+/*
+ * pCreateBlankSprite - Create a blank sprite.
+ *
+ * Create a blank sprite and add a palette if needed
+ *
+ * returns a pointer to the sprite when successful, otherwise NULL
+ */
+static sprite_areainfo *
+pCreateBlankSprite(const imagedata_type *pImg, size_t *pSize)
+{
+ sprite_areainfo *pArea;
+ UCHAR *pucTmp;
+ size_t tSize;
+ screen_modeval uMode;
+ int iIndex, iPaletteEntries;
+
+ TRACE_MSG("pCreateBlankSprite");
+
+ fail(pImg == NULL);
+ fail(pSize == NULL);
+
+ switch (pImg->uiBitsPerComponent) {
+ case 1:
+ uMode.screen_mode = 18;
+ iPaletteEntries = 2;
+ break;
+ case 4:
+ uMode.screen_mode = 20;
+ iPaletteEntries = 16;
+ break;
+ case 8:
+ case 24:
+ uMode.screen_mode = 21;
+ iPaletteEntries = 0;
+ break;
+ default:
+ DBG_DEC(pImg->uiBitsPerComponent);
+ return NULL;
+ }
+ fail(iPaletteEntries < 0 || iPaletteEntries > 16);
+
+ /* Get memory for the sprite */
+ tSize = sizeof(sprite_areainfo) +
+ Sprite_MemorySize(pImg->iWidth, pImg->iHeight, uMode,
+ iPaletteEntries > 0 ? sprite_HASPAL : sprite_HASNOMASKPAL);
+ DBG_DEC(tSize);
+ pArea = xmalloc(tSize);
+
+ /* Initialise sprite area */
+ pArea->areasize = tSize;
+ pArea->numsprites = 0;
+ pArea->firstoffset = sizeof(sprite_areainfo);
+ pArea->freeoffset = sizeof(sprite_areainfo);
+
+ /* Create a blank sprite */
+ Error_CheckFatal(Sprite_Create(pArea, "wordimage",
+ iPaletteEntries > 0 ? 1 : 0,
+ pImg->iWidth, pImg->iHeight, uMode));
+
+ /* Add the palette */
+ pucTmp = (UCHAR *)pArea + pArea->firstoffset + sizeof(sprite_header);
+ for (iIndex = 0; iIndex < iPaletteEntries; iIndex++) {
+ /* First color */
+ *pucTmp++ = 0;
+ *pucTmp++ = pImg->aucPalette[iIndex][0];
+ *pucTmp++ = pImg->aucPalette[iIndex][1];
+ *pucTmp++ = pImg->aucPalette[iIndex][2];
+ /* Second color */
+ *pucTmp++ = 0;
+ *pucTmp++ = pImg->aucPalette[iIndex][0];
+ *pucTmp++ = pImg->aucPalette[iIndex][1];
+ *pucTmp++ = pImg->aucPalette[iIndex][2];
+ }
+
+ *pSize = tSize;
+ return pArea;
+} /* end of pCreateBlankSprite */
+
+/*
+ * iReduceColor - reduce from 24 bit to 8 bit color
+ *
+ * Reduce 24 bit true colors to RISC OS default 256 color palette
+ *
+ * returns the resulting color
+ */
+static int
+iReduceColor(int iRed, int iGreen, int iBlue)
+{
+ int iResult;
+
+ iResult = (iBlue & 0x80) ? 0x80 : 0;
+ iResult |= (iGreen & 0x80) ? 0x40 : 0;
+ iResult |= (iGreen & 0x40) ? 0x20 : 0;
+ iResult |= (iRed & 0x80) ? 0x10 : 0;
+ iResult |= (iBlue & 0x40) ? 0x08 : 0;
+ iResult |= (iRed & 0x40) ? 0x04 : 0;
+ iResult |= ((iRed | iGreen | iBlue) & 0x20) ? 0x02 : 0;
+ iResult |= ((iRed | iGreen | iBlue) & 0x10) ? 0x01 : 0;
+ return iResult;
+} /* end of iReduceColor */
+
+/*
+ * vDecode1bpp - decode an uncompressed 1 bit per pixel image
+ */
+static void
+vDecode1bpp(FILE *pFile, UCHAR *pucData, const imagedata_type *pImg)
+{
+ int iX, iY, iByteWidth, iOffset, iTmp, iEighthWidth, iPadding;
+ UCHAR ucTmp;
+
+ DBG_MSG("vDecode1bpp");
+
+ fail(pFile == NULL);
+ fail(pucData == NULL);
+ fail(pImg == NULL);
+ fail(pImg->iColorsUsed < 1 || pImg->iColorsUsed > 2);
+
+ iByteWidth = iGetByteWidth(pImg);
+
+ iEighthWidth = (pImg->iWidth + 7) / 8;
+ iPadding = ROUND4(iEighthWidth) - iEighthWidth;
+
+ for (iY = pImg->iHeight - 1; iY >= 0; iY--) {
+ for (iX = 0; iX < iEighthWidth; iX++) {
+ iTmp = iNextByte(pFile);
+ if (iTmp == EOF) {
+ return;
+ }
+ /* Reverse the bit order */
+ ucTmp = (iTmp & BIT(0)) ? (UCHAR)BIT(7) : 0;
+ ucTmp |= (iTmp & BIT(1)) ? (UCHAR)BIT(6) : 0;
+ ucTmp |= (iTmp & BIT(2)) ? (UCHAR)BIT(5) : 0;
+ ucTmp |= (iTmp & BIT(3)) ? (UCHAR)BIT(4) : 0;
+ ucTmp |= (iTmp & BIT(4)) ? (UCHAR)BIT(3) : 0;
+ ucTmp |= (iTmp & BIT(5)) ? (UCHAR)BIT(2) : 0;
+ ucTmp |= (iTmp & BIT(6)) ? (UCHAR)BIT(1) : 0;
+ ucTmp |= (iTmp & BIT(7)) ? (UCHAR)BIT(0) : 0;
+ iOffset = iY * iByteWidth + iX;
+ *(pucData + iOffset) = ucTmp;
+ }
+ (void)tSkipBytes(pFile, iPadding);
+ }
+} /* end of vDecode1bpp */
+
+/*
+ * vDecode4bpp - decode an uncompressed 4 bits per pixel image
+ */
+static void
+vDecode4bpp(FILE *pFile, UCHAR *pucData, const imagedata_type *pImg)
+{
+ int iX, iY, iByteWidth, iOffset, iTmp, iHalfWidth, iPadding;
+ UCHAR ucTmp;
+
+ DBG_MSG("vDecode4bpp");
+
+ fail(pFile == NULL);
+ fail(pucData == NULL);
+ fail(pImg == NULL);
+ fail(pImg->iColorsUsed < 1 || pImg->iColorsUsed > 16);
+
+ iByteWidth = iGetByteWidth(pImg);
+
+ iHalfWidth = (pImg->iWidth + 1) / 2;
+ iPadding = ROUND4(iHalfWidth) - iHalfWidth;
+
+ for (iY = pImg->iHeight - 1; iY >= 0; iY--) {
+ for (iX = 0; iX < iHalfWidth; iX++) {
+ iTmp = iNextByte(pFile);
+ if (iTmp == EOF) {
+ return;
+ }
+ /* Reverse the nibble order */
+ ucTmp = (iTmp & 0xf0) >> 4;
+ ucTmp |= (iTmp & 0x0f) << 4;
+ iOffset = iY * iByteWidth + iX;
+ *(pucData + iOffset) = ucTmp;
+ }
+ (void)tSkipBytes(pFile, iPadding);
+ }
+} /* end of vDecode4bpp */
+
+/*
+ * vDecode8bpp - decode an uncompressed 8 bits per pixel image
+ */
+static void
+vDecode8bpp(FILE *pFile, UCHAR *pucData, const imagedata_type *pImg)
+{
+ int iX, iY, iByteWidth, iOffset, iIndex, iPadding;
+
+ DBG_MSG("vDecode8bpp");
+
+ fail(pFile == NULL);
+ fail(pucData == NULL);
+ fail(pImg == NULL);
+ fail(pImg->iColorsUsed < 1 || pImg->iColorsUsed > 256);
+
+ iByteWidth = iGetByteWidth(pImg);
+
+ iPadding = ROUND4(pImg->iWidth) - pImg->iWidth;
+
+ for (iY = pImg->iHeight - 1; iY >= 0; iY--) {
+ for (iX = 0; iX < pImg->iWidth; iX++) {
+ iIndex = iNextByte(pFile);
+ if (iIndex == EOF) {
+ return;
+ }
+ iOffset = iY * iByteWidth + iX;
+ *(pucData + iOffset) = iReduceColor(
+ pImg->aucPalette[iIndex][0],
+ pImg->aucPalette[iIndex][1],
+ pImg->aucPalette[iIndex][2]);
+ }
+ (void)tSkipBytes(pFile, iPadding);
+ }
+} /* end of vDecode8bpp */
+
+/*
+ * vDecode24bpp - decode an uncompressed 24 bits per pixel image
+ */
+static void
+vDecode24bpp(FILE *pFile, UCHAR *pucData, const imagedata_type *pImg)
+{
+ int iX, iY, iTripleWidth, iByteWidth, iOffset, iPadding;
+ int iRed, iGreen, iBlue;
+
+ DBG_MSG("vDecode24bpp");
+
+ fail(pFile == NULL);
+ fail(pucData == NULL);
+ fail(pImg == NULL);
+
+ iByteWidth = iGetByteWidth(pImg);
+
+ iTripleWidth = pImg->iWidth * 3;
+ iPadding = ROUND4(iTripleWidth) - iTripleWidth;
+
+ for (iY = pImg->iHeight - 1; iY >= 0; iY--) {
+ for (iX = 0; iX < pImg->iWidth; iX++) {
+ iBlue = iNextByte(pFile);
+ if (iBlue == EOF) {
+ return;
+ }
+ iGreen = iNextByte(pFile);
+ if (iGreen == EOF) {
+ return;
+ }
+ iRed = iNextByte(pFile);
+ if (iRed == EOF) {
+ return;
+ }
+ iOffset = iY * iByteWidth + iX;
+ *(pucData + iOffset) =
+ iReduceColor(iRed, iGreen, iBlue);
+ }
+ (void)tSkipBytes(pFile, iPadding);
+ }
+} /* end of vDecode24bpp */
+
+/*
+ * vDecodeRle4 - decode a RLE compressed 4 bits per pixel image
+ */
+static void
+vDecodeRle4(FILE *pFile, UCHAR *pucData, const imagedata_type *pImg)
+{
+ int iX, iY, iByteWidth, iOffset, iTmp, iHalfWidth;
+ int iRun, iRunLength, iHalfRun;
+ BOOL bEOL;
+ UCHAR ucTmp;
+
+ DBG_MSG("vDecodeRle4");
+
+ fail(pFile == NULL);
+ fail(pucData == NULL);
+ fail(pImg == NULL);
+ fail(pImg->iColorsUsed < 1 || pImg->iColorsUsed > 16);
+
+ DBG_DEC(pImg->iWidth);
+ DBG_DEC(pImg->iHeight);
+
+ iByteWidth = iGetByteWidth(pImg);
+ iHalfWidth = (pImg->iWidth + 1) / 2;
+
+ for (iY = pImg->iHeight - 1; iY >= 0; iY--) {
+ bEOL = FALSE;
+ iX = 0;
+ while (!bEOL) {
+ iRunLength = iNextByte(pFile);
+ if (iRunLength == EOF) {
+ return;
+ }
+ if (iRunLength != 0) {
+ /*
+ * Encoded packet:
+ * RunLength pixels, all the "same" value
+ */
+ iTmp = iNextByte(pFile);
+ if (iTmp == EOF) {
+ return;
+ }
+ /* Reverse the nibble order */
+ ucTmp = (iTmp & 0xf0) >> 4;
+ ucTmp |= (iTmp & 0x0f) << 4;
+ iHalfRun = (iRunLength + 1) / 2;
+ for (iRun = 0; iRun < iHalfRun; iRun++) {
+ if (iX < iHalfWidth) {
+ iOffset = iY * iByteWidth + iX;
+ *(pucData + iOffset) = ucTmp;
+ }
+ iX++;
+ }
+ continue;
+ }
+ /* Literal or escape */
+ iRunLength = iNextByte(pFile);
+ if (iRunLength == EOF) {
+ return;
+ }
+ if (iRunLength == 0) { /* End of line escape */
+ bEOL = TRUE;
+ } else if (iRunLength == 1) { /* End of file escape */
+ return;
+ } else if (iRunLength == 2) { /* Delta escape */
+ DBG_MSG("RLE4: encountered delta escape");
+ return;
+ } else { /* Literal packet */
+ iHalfRun = (iRunLength + 1) / 2;
+ for (iRun = 0; iRun < iHalfRun; iRun++) {
+ iTmp = iNextByte(pFile);
+ if (iTmp == EOF) {
+ return;
+ }
+ /* Reverse the nibble order */
+ ucTmp = (iTmp & 0xf0) >> 4;
+ ucTmp |= (iTmp & 0x0f) << 4;
+ if (iX < iHalfWidth) {
+ iOffset = iY * iByteWidth + iX;
+ *(pucData + iOffset) = ucTmp;
+ }
+ iX++;
+ }
+ /* Padding if the number of bytes is odd */
+ if (odd(iHalfRun)) {
+ (void)tSkipBytes(pFile, 1);
+ }
+ }
+ }
+ DBG_DEC_C(iX != iHalfWidth, iX);
+ }
+} /* end of vDecodeRle4 */
+
+/*
+ * vDecodeRle8 - decode a RLE compressed 8 bits per pixel image
+ */
+static void
+vDecodeRle8(FILE *pFile, UCHAR *pucData, const imagedata_type *pImg)
+{
+ int iX, iY, iRun, iRunLength, iOffset, iIndex, iByteWidth;
+ BOOL bEOL;
+
+ DBG_MSG("vDecodeRle8");
+
+ fail(pFile == NULL);
+ fail(pucData == NULL);
+ fail(pImg == NULL);
+ fail(pImg->iColorsUsed < 1 || pImg->iColorsUsed > 256);
+
+ DBG_DEC(pImg->iWidth);
+ DBG_DEC(pImg->iHeight);
+
+ iByteWidth = iGetByteWidth(pImg);
+
+ for (iY = pImg->iHeight - 1; iY >= 0; iY--) {
+ bEOL = FALSE;
+ iX = 0;
+ while (!bEOL) {
+ iRunLength = iNextByte(pFile);
+ if (iRunLength == EOF) {
+ return;
+ }
+ if (iRunLength != 0) {
+ /*
+ * Encoded packet:
+ * RunLength pixels, all the same value
+ */
+ iIndex = iNextByte(pFile);
+ if (iIndex == EOF) {
+ return;
+ }
+ for (iRun = 0; iRun < iRunLength; iRun++) {
+ if (iX < pImg->iWidth) {
+ iOffset = iY * iByteWidth + iX;
+ *(pucData + iOffset) =
+ iReduceColor(
+ pImg->aucPalette[iIndex][0],
+ pImg->aucPalette[iIndex][1],
+ pImg->aucPalette[iIndex][2]);
+ }
+ iX++;
+ }
+ continue;
+ }
+ /* Literal or escape */
+ iRunLength = iNextByte(pFile);
+ if (iRunLength == EOF) {
+ return;
+ }
+ if (iRunLength == 0) { /* End of line escape */
+ bEOL = TRUE;
+ } else if (iRunLength == 1) { /* End of file escape */
+ return;
+ } else if (iRunLength == 2) { /* Delta escape */
+ DBG_MSG("RLE8: encountered delta escape");
+ return;
+ } else { /* Literal packet */
+ for (iRun = 0; iRun < iRunLength; iRun++) {
+ iIndex = iNextByte(pFile);
+ if (iIndex == EOF) {
+ return;
+ }
+ if (iX < pImg->iWidth) {
+ iOffset = iY * iByteWidth + iX;
+ *(pucData + iOffset) =
+ iReduceColor(
+ pImg->aucPalette[iIndex][0],
+ pImg->aucPalette[iIndex][1],
+ pImg->aucPalette[iIndex][2]);
+ }
+ iX++;
+ }
+ /* Padding if the number of bytes is odd */
+ if (odd(iRunLength)) {
+ (void)tSkipBytes(pFile, 1);
+ }
+ }
+ }
+ DBG_DEC_C(iX != pImg->iWidth, iX);
+ }
+} /* end of vDecodeRle8 */
+
+#if 0 /* defined(DEBUG) */
+static void
+vCopy2File(UCHAR *pucSprite, size_t tSpriteSize)
+{
+ FILE *pOutFile;
+ int iIndex;
+ char szFilename[30];
+
+ sprintf(szFilename, "<Wimp$ScrapDir>.sprt%04d", ++iPicCounter);
+ pOutFile = fopen(szFilename, "wb");
+ if (pOutFile == NULL) {
+ return;
+ }
+ DBG_MSG(szFilename);
+ for (iIndex = 4; iIndex < (int)tSpriteSize; iIndex++) {
+ if (putc(pucSprite[iIndex], pOutFile) == EOF) {
+ break;
+ }
+ }
+ (void)fclose(pOutFile);
+ vSetFiletype(szFilename, FILETYPE_SPRITE);
+} /* end of vCopy2File */
+#endif /* DEBUG */
+
+/*
+ * vDecodeDIB - decode a dib picture
+ */
+static void
+vDecodeDIB(diagram_type *pDiag, FILE *pFile, const imagedata_type *pImg)
+{
+ sprite_areainfo *pSprite;
+ UCHAR *pucPalette, *pucData;
+ size_t tSpriteSize;
+ int iHeaderSize;
+
+ /* Skip the bitmap info header */
+ iHeaderSize = (int)ulNextLong(pFile);
+ (void)tSkipBytes(pFile, iHeaderSize - 4);
+ /* Skip the colortable */
+ if (pImg->uiBitsPerComponent <= 8) {
+ (void)tSkipBytes(pFile,
+ pImg->iColorsUsed * ((iHeaderSize > 12) ? 4 : 3));
+ }
+
+ /* Create an blank sprite */
+ pSprite = pCreateBlankSprite(pImg, &tSpriteSize);
+ pucPalette = (UCHAR *)pSprite +
+ pSprite->firstoffset + sizeof(sprite_header);
+
+ /* Add the pixel information */
+ switch (pImg->uiBitsPerComponent) {
+ case 1:
+ fail(pImg->eCompression != compression_none);
+ pucData = pucPalette + 2 * 8;
+ vDecode1bpp(pFile, pucData, pImg);
+ break;
+ case 4:
+ fail(pImg->eCompression != compression_none &&
+ pImg->eCompression != compression_rle4);
+ pucData = pucPalette + 16 * 8;
+ if (pImg->eCompression == compression_rle4) {
+ vDecodeRle4(pFile, pucData, pImg);
+ } else {
+ vDecode4bpp(pFile, pucData, pImg);
+ }
+ break;
+ case 8:
+ fail(pImg->eCompression != compression_none &&
+ pImg->eCompression != compression_rle8);
+ pucData = pucPalette + 0 * 8;
+ if (pImg->eCompression == compression_rle8) {
+ vDecodeRle8(pFile, pucData, pImg);
+ } else {
+ vDecode8bpp(pFile, pucData, pImg);
+ }
+ break;
+ case 24:
+ fail(pImg->eCompression != compression_none);
+ pucData = pucPalette + 0 * 8;
+ vDecode24bpp(pFile, pucData, pImg);
+ break;
+ default:
+ DBG_DEC(pImg->uiBitsPerComponent);
+ break;
+ }
+
+#if 0 /* defined(DEBUG) */
+ vCopy2File((UCHAR *)pSprite, tSpriteSize);
+#endif /* DEBUG */
+
+ /* Add the sprite to the Draw file */
+ vImage2Diagram(pDiag, pImg,
+ (UCHAR *)pSprite + pSprite->firstoffset,
+ tSpriteSize - pSprite->firstoffset);
+
+ /* Clean up before you leave */
+ pSprite = xfree(pSprite);
+} /* end of vDecodeDIB */
+
+/*
+ * bTranslateDIB - translate a DIB picture
+ *
+ * This function translates a picture from dib to sprite
+ *
+ * return TRUE when sucessful, otherwise FALSE
+ */
+BOOL
+bTranslateDIB(diagram_type *pDiag, FILE *pFile,
+ ULONG ulFileOffset, const imagedata_type *pImg)
+{
+ /* Seek to start position of DIB data */
+ if (!bSetDataOffset(pFile, ulFileOffset)) {
+ return FALSE;
+ }
+
+ vDecodeDIB(pDiag, pFile, pImg);
+
+ return TRUE;
+} /* end of bTranslateDIB */
diff --git a/sys/src/cmd/aux/antiword/doclist.c b/sys/src/cmd/aux/antiword/doclist.c
new file mode 100755
index 000000000..d4ac38026
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/doclist.c
@@ -0,0 +1,75 @@
+/*
+ * doclist.c
+ * Copyright (C) 2004 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Build, read and destroy list(s) of Word document information
+ *
+ * Note:
+ * There is no real list there is always one document per document
+ */
+
+#include "antiword.h"
+
+#define HALF_INCH 36000L /* In millipoints */
+
+/* Variables needed to write the Document Information List */
+static document_block_type *pAnchor = NULL;
+static document_block_type tInfo;
+
+
+/*
+ * vDestroyDocumentInfoList - destroy the Document Information List
+ */
+void
+vDestroyDocumentInfoList(void)
+{
+ DBG_MSG("vDestroyDocumentInfoList");
+
+ pAnchor = NULL;
+} /* end of vDestoryDocumentInfoList */
+
+/*
+ * vCreateDocumentInfoList - create the Document Information List
+ */
+void
+vCreateDocumentInfoList(const document_block_type *pDocument)
+{
+ fail(pDocument == NULL);
+ fail(pAnchor != NULL);
+
+ tInfo = *pDocument;
+ pAnchor = &tInfo;
+} /* end of vCreateDocumentInfoList */
+
+/*
+ * lGetDefaultTabWidth - get the default tabwidth in millipoints
+ */
+long
+lGetDefaultTabWidth(void)
+{
+ long lDefaultTabWidth;
+ USHORT usTmp;
+
+ if (pAnchor == NULL) {
+ DBG_FIXME();
+ return HALF_INCH;
+ }
+ usTmp = pAnchor->usDefaultTabWidth;
+ lDefaultTabWidth = usTmp == 0 ? HALF_INCH : lTwips2MilliPoints(usTmp);
+ NO_DBG_DEC(lDefaultTabWidth);
+ return lDefaultTabWidth;
+} /* end of lGetDefaultTabWidth */
+
+/*
+ * ucGetDopHdrFtrSpecification - get the Heder/footer specification
+ */
+UCHAR
+ucGetDopHdrFtrSpecification(void)
+{
+ if (pAnchor == NULL) {
+ DBG_FIXME();
+ return 0x00;
+ }
+ return pAnchor->ucHdrFtrSpecification;
+} /* end of ucGetDopHdrFtrSpecification */
diff --git a/sys/src/cmd/aux/antiword/draw.c b/sys/src/cmd/aux/antiword/draw.c
new file mode 100755
index 000000000..f833d75ea
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/draw.c
@@ -0,0 +1,1047 @@
+/*
+ * draw.c
+ * Copyright (C) 1998-2005 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Functions to deal with the Draw format
+ */
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include "DeskLib:KeyCodes.h"
+#include "DeskLib:Error.h"
+#include "DeskLib:Menu.h"
+#include "DeskLib:Template.h"
+#include "DeskLib:Window.h"
+#include "DeskLib:EventMsg.h"
+#include "flexlib:flex.h"
+#include "drawfile.h"
+#include "antiword.h"
+
+/* The work area must be a little bit larger than the diagram */
+#define WORKAREA_EXTENSION 5
+/* Diagram memory */
+#define INITIAL_SIZE 32768 /* 32k */
+#define EXTENSION_SIZE 4096 /* 4k */
+/* Main window title */
+#define WINDOW_TITLE_LEN 28
+#define FILENAME_TITLE_LEN (WINDOW_TITLE_LEN - 10)
+
+
+#if !defined(__GNUC__)
+int
+flex_alloc(flex_ptr anchor, int n)
+{
+ void *pvTmp;
+
+ TRACE_MSG("flex_alloc");
+
+ if (anchor == NULL || n < 0) {
+ return 0;
+ }
+ if (n == 0) {
+ n = 1;
+ }
+ pvTmp = malloc(n);
+ if (pvTmp == NULL) {
+ return 0;
+ }
+ *anchor = pvTmp;
+ return 1;
+} /* end of flex_alloc */
+
+void
+flex_free(flex_ptr anchor)
+{
+ TRACE_MSG("flex_free");
+
+ if (anchor == NULL || *anchor == NULL) {
+ return;
+ }
+ free(*anchor);
+ *anchor = NULL;
+} /* end of flex_free */
+
+int
+flex_extend(flex_ptr anchor, int newsize)
+{
+ void *pvTmp;
+
+ TRACE_MSG("flex_extend");
+
+ if (anchor == NULL || newsize < 0) {
+ return 0;
+ }
+ if (newsize == 0) {
+ newsize = 1;
+ }
+ pvTmp = realloc(*anchor, newsize);
+ if (pvTmp == NULL) {
+ return 0;
+ }
+ *anchor = pvTmp;
+ return 1;
+} /* end of flex_extend */
+#endif /* !__GNUC__ */
+
+/*
+ * vCreateMainWindow - create the Main window
+ *
+ * remark: does not return if the Main window can't be created
+ */
+static window_handle
+tCreateMainWindow(void)
+{
+ window_handle tMainWindow;
+
+ TRACE_MSG("tCreateMainWindow");
+
+ tMainWindow = Window_Create("MainWindow", template_TITLEMIN);
+ if (tMainWindow == 0) {
+ werr(1, "I can't find the 'MainWindow' template");
+ }
+ return tMainWindow;
+} /* end of tCreateMainWindow */
+
+/*
+ * vCreateScaleWindow - create the Scale view window
+ *
+ * remark: does not return if the Scale view window can't be created
+ */
+static window_handle
+tCreateScaleWindow(void)
+{
+ window_handle tScaleWindow;
+
+ TRACE_MSG("tCreateScaleWindow");
+
+ tScaleWindow = Window_Create("ScaleView", template_TITLEMIN);
+ if (tScaleWindow == 0) {
+ werr(1, "I can't find the 'ScaleView' template");
+ }
+ return tScaleWindow;
+} /* end of tCreateScaleWindow */
+
+/*
+ * pCreateDiagram - create and initialize a diagram
+ *
+ * remark: does not return if the diagram can't be created
+ */
+diagram_type *
+pCreateDiagram(const char *szTask, const char *szFilename)
+{
+ diagram_type *pDiag;
+ options_type tOptions;
+ window_handle tMainWindow, tScaleWindow;
+ wimp_box tBox;
+
+ TRACE_MSG("pCreateDiagram");
+
+ fail(szTask == NULL || szTask[0] == '\0');
+
+ /* Create the main window */
+ tMainWindow = tCreateMainWindow();
+
+ /* Create the scale view window */
+ tScaleWindow = tCreateScaleWindow();
+
+ /* Get the necessary memory */
+ pDiag = xmalloc(sizeof(diagram_type));
+ if (flex_alloc((flex_ptr)&pDiag->tInfo.data, INITIAL_SIZE) != 1) {
+ werr(1, "Memory allocation failed, unable to continue");
+ }
+
+ /* Initialize the diagram */
+ vGetOptions(&tOptions);
+ pDiag->tMainWindow = tMainWindow;
+ pDiag->tScaleWindow = tScaleWindow;
+ pDiag->iScaleFactorCurr = tOptions.iScaleFactor;
+ pDiag->iScaleFactorTemp = tOptions.iScaleFactor;
+ pDiag->tMemorySize = INITIAL_SIZE;
+ tBox.min.x = 0;
+ tBox.min.y = -(Drawfile_ScreenToDraw(32 + 3) * 8 + 1);
+ tBox.max.x = Drawfile_ScreenToDraw(16) * MIN_SCREEN_WIDTH + 1;
+ tBox.max.y = 0;
+ Error_CheckFatal(Drawfile_CreateDiagram(&pDiag->tInfo,
+ pDiag->tMemorySize, szTask, tBox));
+ DBG_DEC(pDiag->tInfo.length);
+ pDiag->lXleft = 0;
+ pDiag->lYtop = 0;
+ strncpy(pDiag->szFilename,
+ szBasename(szFilename), sizeof(pDiag->szFilename) - 1);
+ pDiag->szFilename[sizeof(pDiag->szFilename) - 1] = '\0';
+ /* Return success */
+ return pDiag;
+} /* end of pCreateDiagram */
+
+/*
+ * bDestroyDiagram - remove a diagram by freeing the memory it uses
+ */
+BOOL
+bDestroyDiagram(event_pollblock *pEvent, void *pvReference)
+{
+ diagram_type *pDiag;
+ window_handle tWindow;
+
+ TRACE_MSG("bDestroyDiagram");
+
+ fail(pEvent == NULL);
+ fail(pvReference == NULL);
+
+ if (pEvent == NULL || pvReference == NULL) {
+ return FALSE;
+ }
+
+ pDiag = (diagram_type *)pvReference;
+
+ switch (pEvent->type) {
+ case event_CLOSE:
+ tWindow = pEvent->data.openblock.window;
+ break;
+ case event_KEY:
+ tWindow = pEvent->data.key.caret.window;
+ break;
+ default:
+ DBG_DEC(pEvent->type);
+ return FALSE;
+ }
+ if (tWindow != pDiag->tMainWindow) {
+ return FALSE;
+ }
+
+ /* Delete the main window */
+ Window_Delete(pDiag->tMainWindow);
+ pDiag->tMainWindow = 0;
+
+ /* Delete the scale window */
+ Window_Delete(pDiag->tScaleWindow);
+ pDiag->tScaleWindow = 0;
+
+#if defined(__GNUC__)
+ /*
+ * Remove all references to the diagram that will be free-ed
+ * by undoing the EventMsg_Claim's from within the Menu_Warn's
+ */
+ while (EventMsg_ReleaseSpecific(message_MENUWARNING, window_ANY,
+ bSaveTextfile, pDiag))
+ ; /* EMPTY */
+ while (EventMsg_ReleaseSpecific(message_MENUWARNING, window_ANY,
+ bSaveDrawfile, pDiag))
+ ; /* EMPTY */
+ while (EventMsg_ReleaseSpecific(message_MENUWARNING, window_ANY,
+ bScaleOpenAction, pDiag))
+ ; /* EMPTY */
+#endif /* __GNUC__ */
+
+ /* Free the memory */
+ if (pDiag->tInfo.data != NULL && pDiag->tMemorySize != 0) {
+ flex_free((flex_ptr)&pDiag->tInfo.data);
+ }
+ /* Just to be on the save side */
+ pDiag->tInfo.data = NULL;
+ pDiag->tInfo.length = 0;
+ pDiag->tMemorySize = 0;
+
+ /* Destroy the diagram itself */
+ pDiag = xfree(pDiag);
+ return TRUE;
+} /* end of bDestroyDiagram */
+
+/*
+ * vExtendDiagramSize - make sure the diagram is big enough
+ */
+static void
+vExtendDiagramSize(diagram_type *pDiag, size_t tSize)
+{
+ TRACE_MSG("vExtendDiagramSize");
+
+ fail(pDiag == NULL || tSize % 4 != 0);
+
+ while (pDiag->tInfo.length + tSize > pDiag->tMemorySize) {
+ if (flex_extend((flex_ptr)&pDiag->tInfo.data,
+ pDiag->tMemorySize + EXTENSION_SIZE) != 1) {
+ werr(1, "Memory extend failed, unable to continue");
+ }
+ pDiag->tMemorySize += EXTENSION_SIZE;
+ NO_DBG_DEC(pDiag->tMemorySize);
+ }
+ TRACE_MSG("end of vExtendDiagramSize");
+} /* end of vExtendDiagramSize */
+
+/*
+ * vPrologue2 - prologue part 2; add a font list to a diagram
+ */
+void
+vPrologue2(diagram_type *pDiag, int iWordVersion)
+{
+ drawfile_object *pNew;
+ const font_table_type *pTmp;
+ char *pcTmp;
+ size_t tRealSize, tSize;
+ int iCount;
+
+ TRACE_MSG("vPrologue2");
+
+ fail(pDiag == NULL);
+
+ if (tGetFontTableLength() == 0) {
+ return;
+ }
+ tRealSize = offsetof(drawfile_object, data);
+ pTmp = NULL;
+ while ((pTmp = pGetNextFontTableRecord(pTmp)) != NULL) {
+ tRealSize += 2 + strlen(pTmp->szOurFontname);
+ }
+ DBG_DEC(tRealSize);
+ tSize = ROUND4(tRealSize);
+ vExtendDiagramSize(pDiag, tSize);
+ pNew = xmalloc(tSize);
+ memset(pNew, 0, tSize);
+ pNew->type = drawfile_TYPE_FONT_TABLE;
+ pNew->size = tSize;
+ pcTmp = (char *)&pNew->data.font_table.font_def[0].font_ref;
+ iCount = 0;
+ pTmp = NULL;
+ while ((pTmp = pGetNextFontTableRecord(pTmp)) != NULL) {
+ *pcTmp = ++iCount;
+ pcTmp++;
+ strcpy(pcTmp, pTmp->szOurFontname);
+ pcTmp += 1 + strlen(pTmp->szOurFontname);
+ }
+ Error_CheckFatal(Drawfile_AppendObject(&pDiag->tInfo,
+ pDiag->tMemorySize, pNew, TRUE));
+ pNew = xfree(pNew);
+} /* end of vPrologue2 */
+
+/*
+ * vSubstring2Diagram - put a sub string into a diagram
+ */
+void
+vSubstring2Diagram(diagram_type *pDiag,
+ char *szString, size_t tStringLength, long lStringWidth,
+ UCHAR ucFontColor, USHORT usFontstyle, drawfile_fontref tFontRef,
+ USHORT usFontSize, USHORT usMaxFontSize)
+{
+ drawfile_object *pNew;
+ long lSizeX, lSizeY, lOffset, l20, lYMove;
+ size_t tRealSize, tSize;
+
+ TRACE_MSG("vSubstring2Diagram");
+
+ fail(pDiag == NULL || szString == NULL);
+ fail(pDiag->lXleft < 0);
+ fail(tStringLength != strlen(szString));
+ fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
+ fail(usMaxFontSize < MIN_FONT_SIZE || usMaxFontSize > MAX_FONT_SIZE);
+ fail(usFontSize > usMaxFontSize);
+
+ if (szString[0] == '\0' || tStringLength == 0) {
+ return;
+ }
+
+ if (tFontRef == 0) {
+ lOffset = Drawfile_ScreenToDraw(2);
+ l20 = Drawfile_ScreenToDraw(32 + 3);
+ lSizeX = Drawfile_ScreenToDraw(16);
+ lSizeY = Drawfile_ScreenToDraw(32);
+ } else {
+ lOffset = lToBaseLine(usMaxFontSize);
+ l20 = lWord2DrawUnits20(usMaxFontSize);
+ lSizeX = lWord2DrawUnits00(usFontSize);
+ lSizeY = lWord2DrawUnits00(usFontSize);
+ }
+
+ lYMove = 0;
+
+ /* Up for superscript */
+ if (bIsSuperscript(usFontstyle)) {
+ lYMove = lMilliPoints2DrawUnits((((long)usFontSize + 1) / 2) * 375);
+ }
+ /* Down for subscript */
+ if (bIsSubscript(usFontstyle)) {
+ lYMove = -lMilliPoints2DrawUnits((long)usFontSize * 125);
+ }
+
+ tRealSize = offsetof(drawfile_object, data);
+ tRealSize += sizeof(drawfile_text) + tStringLength;
+ tSize = ROUND4(tRealSize);
+ vExtendDiagramSize(pDiag, tSize);
+ pNew = xmalloc(tSize);
+ memset(pNew, 0, tSize);
+ pNew->type = drawfile_TYPE_TEXT;
+ pNew->size = tSize;
+ pNew->data.text.bbox.min.x = (int)pDiag->lXleft;
+ pNew->data.text.bbox.min.y = (int)(pDiag->lYtop + lYMove);
+ pNew->data.text.bbox.max.x = (int)(pDiag->lXleft + lStringWidth);
+ pNew->data.text.bbox.max.y = (int)(pDiag->lYtop + l20 + lYMove);
+ pNew->data.text.fill.value = (int)ulColor2Color(ucFontColor);
+ pNew->data.text.bg_hint.value = 0xffffff00; /* White */
+ pNew->data.text.style.font_ref = tFontRef;
+ pNew->data.text.style.reserved[0] = 0;
+ pNew->data.text.style.reserved[1] = 0;
+ pNew->data.text.style.reserved[2] = 0;
+ pNew->data.text.xsize = (int)lSizeX;
+ pNew->data.text.ysize = (int)lSizeY;
+ pNew->data.text.base.x = (int)pDiag->lXleft;
+ pNew->data.text.base.y = (int)(pDiag->lYtop + lOffset + lYMove);
+ strncpy(pNew->data.text.text, szString, tStringLength);
+ pNew->data.text.text[tStringLength] = '\0';
+ Error_CheckFatal(Drawfile_AppendObject(&pDiag->tInfo,
+ pDiag->tMemorySize, pNew, TRUE));
+ pNew = xfree(pNew);
+ /*draw_translateText(&pDiag->tInfo);*/
+ pDiag->lXleft += lStringWidth;
+ TRACE_MSG("leaving vSubstring2Diagram");
+} /* end of vSubstring2Diagram */
+
+/*
+ * vImage2Diagram - put an image into a diagram
+ */
+void
+vImage2Diagram(diagram_type *pDiag, const imagedata_type *pImg,
+ UCHAR *pucImage, size_t tImageSize)
+{
+ drawfile_object *pNew;
+ long lWidth, lHeight;
+ size_t tRealSize, tSize;
+
+ TRACE_MSG("vImage2Diagram");
+
+ fail(pDiag == NULL);
+ fail(pImg == NULL);
+ fail(pDiag->lXleft < 0);
+ fail(pImg->eImageType != imagetype_is_dib &&
+ pImg->eImageType != imagetype_is_jpeg);
+
+ DBG_DEC_C(pDiag->lXleft != 0, pDiag->lXleft);
+
+ lWidth = lPoints2DrawUnits(pImg->iHorSizeScaled);
+ lHeight = lPoints2DrawUnits(pImg->iVerSizeScaled);
+ DBG_DEC(lWidth);
+ DBG_DEC(lHeight);
+
+ pDiag->lYtop -= lHeight;
+
+ tRealSize = offsetof(drawfile_object, data);
+ switch (pImg->eImageType) {
+ case imagetype_is_dib:
+ tRealSize += sizeof(drawfile_sprite) + tImageSize;
+ tSize = ROUND4(tRealSize);
+ vExtendDiagramSize(pDiag, tSize);
+ pNew = xmalloc(tSize);
+ memset(pNew, 0, tSize);
+ pNew->type = drawfile_TYPE_SPRITE;
+ pNew->size = tSize;
+ pNew->data.sprite.bbox.min.x = (int)pDiag->lXleft;
+ pNew->data.sprite.bbox.min.y = (int)pDiag->lYtop;
+ pNew->data.sprite.bbox.max.x = (int)(pDiag->lXleft + lWidth);
+ pNew->data.sprite.bbox.max.y = (int)(pDiag->lYtop + lHeight);
+ memcpy(&pNew->data.sprite.header, pucImage, tImageSize);
+ break;
+ case imagetype_is_jpeg:
+#if defined(DEBUG)
+ (void)bGetJpegInfo(pucImage, tImageSize);
+#endif /* DEBUG */
+ tRealSize += sizeof(drawfile_jpeg) + tImageSize;
+ tSize = ROUND4(tRealSize);
+ vExtendDiagramSize(pDiag, tSize);
+ pNew = xmalloc(tSize);
+ memset(pNew, 0, tSize);
+ pNew->type = drawfile_TYPE_JPEG;
+ pNew->size = tSize;
+ pNew->data.jpeg.bbox.min.x = (int)pDiag->lXleft;
+ pNew->data.jpeg.bbox.min.y = (int)pDiag->lYtop;
+ pNew->data.jpeg.bbox.max.x = (int)(pDiag->lXleft + lWidth);
+ pNew->data.jpeg.bbox.max.y = (int)(pDiag->lYtop + lHeight);
+ pNew->data.jpeg.width = (int)lWidth;
+ pNew->data.jpeg.height = (int)lHeight;
+ pNew->data.jpeg.xdpi = 90;
+ pNew->data.jpeg.ydpi = 90;
+ pNew->data.jpeg.trfm.entries[0][0] = 0x10000;
+ pNew->data.jpeg.trfm.entries[0][1] = 0;
+ pNew->data.jpeg.trfm.entries[1][0] = 0;
+ pNew->data.jpeg.trfm.entries[1][1] = 0x10000;
+ pNew->data.jpeg.trfm.entries[2][0] = (int)pDiag->lXleft;
+ pNew->data.jpeg.trfm.entries[2][1] = (int)pDiag->lYtop;
+ pNew->data.jpeg.len = tImageSize;
+ memcpy(pNew->data.jpeg.data, pucImage, tImageSize);
+ break;
+ default:
+ DBG_DEC(pImg->eImageType);
+ pNew = NULL;
+ break;
+ }
+
+ Error_CheckFatal(Drawfile_AppendObject(&pDiag->tInfo,
+ pDiag->tMemorySize, pNew, TRUE));
+ pNew = xfree(pNew);
+ pDiag->lXleft = 0;
+} /* end of vImage2Diagram */
+
+/*
+ * bAddDummyImage - add a dummy image
+ *
+ * return TRUE when successful, otherwise FALSE
+ */
+BOOL
+bAddDummyImage(diagram_type *pDiag, const imagedata_type *pImg)
+{
+ drawfile_object *pNew;
+ int *piTmp;
+ long lWidth, lHeight;
+ size_t tRealSize, tSize;
+
+ TRACE_MSG("bAddDummyImage");
+
+ fail(pDiag == NULL);
+ fail(pImg == NULL);
+ fail(pDiag->lXleft < 0);
+
+ if (pImg->iVerSizeScaled <= 0 || pImg->iHorSizeScaled <= 0) {
+ return FALSE;
+ }
+
+ DBG_DEC_C(pDiag->lXleft != 0, pDiag->lXleft);
+
+ lWidth = lPoints2DrawUnits(pImg->iHorSizeScaled);
+ lHeight = lPoints2DrawUnits(pImg->iVerSizeScaled);
+
+ pDiag->lYtop -= lHeight;
+
+ tRealSize = offsetof(drawfile_object, data);
+ tRealSize += sizeof(drawfile_path) + (14 - 1) * sizeof(int);
+ tSize = ROUND4(tRealSize);
+ vExtendDiagramSize(pDiag, tSize);
+ pNew = xmalloc(tSize);
+ memset(pNew, 0, tSize);
+ pNew->type = drawfile_TYPE_PATH;
+ pNew->size = tSize;
+ pNew->data.path.bbox.min.x = (int)pDiag->lXleft;
+ pNew->data.path.bbox.min.y = (int)pDiag->lYtop;
+ pNew->data.path.bbox.max.x = (int)(pDiag->lXleft + lWidth);
+ pNew->data.path.bbox.max.y = (int)(pDiag->lYtop + lHeight);
+ pNew->data.path.fill.value = -1;
+ pNew->data.path.outline.value = 0x4d4d4d00; /* Gray 70 percent */
+ pNew->data.path.width = (int)lMilliPoints2DrawUnits(500);
+ pNew->data.path.style.flags = 0;
+ pNew->data.path.style.reserved = 0;
+ pNew->data.path.style.cap_width = 0;
+ pNew->data.path.style.cap_length = 0;
+ piTmp = pNew->data.path.path;
+ *piTmp++ = drawfile_PATH_MOVE_TO;
+ *piTmp++ = pNew->data.path.bbox.min.x;
+ *piTmp++ = pNew->data.path.bbox.min.y;
+ *piTmp++ = drawfile_PATH_LINE_TO;
+ *piTmp++ = pNew->data.path.bbox.min.x;
+ *piTmp++ = pNew->data.path.bbox.max.y;
+ *piTmp++ = drawfile_PATH_LINE_TO;
+ *piTmp++ = pNew->data.path.bbox.max.x;
+ *piTmp++ = pNew->data.path.bbox.max.y;
+ *piTmp++ = drawfile_PATH_LINE_TO;
+ *piTmp++ = pNew->data.path.bbox.max.x;
+ *piTmp++ = pNew->data.path.bbox.min.y;
+ *piTmp++ = drawfile_PATH_CLOSE_LINE;
+ *piTmp++ = drawfile_PATH_END_PATH;
+
+ Error_CheckFatal(Drawfile_AppendObject(&pDiag->tInfo,
+ pDiag->tMemorySize, pNew, TRUE));
+ pNew = xfree(pNew);
+ pDiag->lXleft = 0;
+ return TRUE;
+} /* end of bAddDummyImage */
+
+/*
+ * vMove2NextLine - move to the next line
+ */
+void
+vMove2NextLine(diagram_type *pDiag, drawfile_fontref tFontRef,
+ USHORT usFontSize)
+{
+ long l20;
+
+ TRACE_MSG("vMove2NextLine");
+
+ fail(pDiag == NULL);
+ fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
+
+ if (tFontRef == 0) {
+ l20 = Drawfile_ScreenToDraw(32 + 3);
+ } else {
+ l20 = lWord2DrawUnits20(usFontSize);
+ }
+ pDiag->lYtop -= l20;
+} /* end of vMove2NextLine */
+
+/*
+ * Create an start of paragraph (Phase 1)
+ */
+void
+vStartOfParagraph1(diagram_type *pDiag, long lBeforeIndentation)
+{
+ TRACE_MSG("vStartOfParagraph1");
+
+ fail(pDiag == NULL);
+ fail(lBeforeIndentation < 0);
+
+ pDiag->lXleft = 0;
+ pDiag->lYtop -= lMilliPoints2DrawUnits(lBeforeIndentation);
+} /* end of vStartOfParagraph1 */
+
+/*
+ * Create an start of paragraph (Phase 2)
+ * DUMMY function
+ */
+void
+vStartOfParagraph2(diagram_type *pDiag)
+{
+ TRACE_MSG("vStartOfParagraph2");
+} /* end of vStartOfParagraph2 */
+
+/*
+ * Create an end of paragraph
+ */
+void
+vEndOfParagraph(diagram_type *pDiag,
+ drawfile_fontref tFontRef, USHORT usFontSize, long lAfterIndentation)
+{
+ TRACE_MSG("vEndOfParagraph");
+
+ fail(pDiag == NULL);
+ fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
+ fail(lAfterIndentation < 0);
+
+ pDiag->lXleft = 0;
+ pDiag->lYtop -= lMilliPoints2DrawUnits(lAfterIndentation);
+} /* end of vEndOfParagraph */
+
+/*
+ * Create an end of page
+ */
+void
+vEndOfPage(diagram_type *pDiag, long lAfterIndentation, BOOL bNewSection)
+{
+ TRACE_MSG("vEndOfPage");
+
+ fail(pDiag == NULL);
+ fail(lAfterIndentation < 0);
+
+ pDiag->lXleft = 0;
+ pDiag->lYtop -= lMilliPoints2DrawUnits(lAfterIndentation);
+} /* end of vEndOfPage */
+
+/*
+ * vSetHeaders - set the headers
+ * DUMMY function
+ */
+void
+vSetHeaders(diagram_type *pDiag, USHORT usIstd)
+{
+ TRACE_MSG("vSetHeaders");
+} /* end of vSetHeaders */
+
+/*
+ * Create a start of list
+ * DUMMY function
+ */
+void
+vStartOfList(diagram_type *pDiag, UCHAR ucNFC, BOOL bIsEndOfTable)
+{
+ TRACE_MSG("vStartOfList");
+} /* end of vStartOfList */
+
+/*
+ * Create an end of list
+ * DUMMY function
+ */
+void
+vEndOfList(diagram_type *pDiag)
+{
+ TRACE_MSG("vEndOfList");
+} /* end of vEndOfList */
+
+/*
+ * Create a start of a list item
+ * DUMMY function
+ */
+void
+vStartOfListItem(diagram_type *pDiag, BOOL bNoMarks)
+{
+ TRACE_MSG("vStartOfListItem");
+} /* end of vStartOfListItem */
+
+/*
+ * Create an end of a table
+ * DUMMY function
+ */
+void
+vEndOfTable(diagram_type *pDiag)
+{
+ TRACE_MSG("vEndOfTable");
+} /* end of vEndTable */
+
+/*
+ * Add a table row
+ * DUMMY function
+ *
+ * Returns TRUE when conversion type is XML
+ */
+BOOL
+bAddTableRow(diagram_type *pDiag, char **aszColTxt,
+ int iNbrOfColumns, const short *asColumnWidth, UCHAR ucBorderInfo)
+{
+ TRACE_MSG("bAddTableRow");
+
+ return FALSE;
+} /* end of bAddTableRow */
+
+/*
+ * vForceRedraw - force a redraw of the main window
+ */
+static void
+vForceRedraw(diagram_type *pDiag)
+{
+ window_state tWindowState;
+ window_redrawblock tRedraw;
+ int x0, y0, x1, y1;
+
+ TRACE_MSG("vForceRedraw");
+
+ fail(pDiag == NULL);
+
+ DBG_DEC(pDiag->iScaleFactorCurr);
+
+ /* Read the size of the current diagram */
+ Drawfile_QueryBox(&pDiag->tInfo, &tRedraw.rect, TRUE);
+ /* Adjust the size of the work area */
+ x0 = tRedraw.rect.min.x * pDiag->iScaleFactorCurr / 100 - 1;
+ y0 = tRedraw.rect.min.y * pDiag->iScaleFactorCurr / 100 - 1;
+ x1 = tRedraw.rect.max.x * pDiag->iScaleFactorCurr / 100 + 1;
+ y1 = tRedraw.rect.max.y * pDiag->iScaleFactorCurr / 100 + 1;
+ /* Work area extension */
+ x0 -= WORKAREA_EXTENSION;
+ y0 -= WORKAREA_EXTENSION;
+ x1 += WORKAREA_EXTENSION;
+ y1 += WORKAREA_EXTENSION;
+ Window_SetExtent(pDiag->tMainWindow, x0, y0, x1, y1);
+ /* Widen the box slightly to be sure all the edges are drawn */
+ x0 -= 5;
+ y0 -= 5;
+ x1 += 5;
+ y1 += 5;
+ /* Force the redraw */
+ Window_ForceRedraw(pDiag->tMainWindow, x0, y0, x1, y1);
+ /* Reopen the window to show the correct size */
+ Error_CheckFatal(Wimp_GetWindowState(pDiag->tMainWindow, &tWindowState));
+ tWindowState.openblock.behind = -1;
+ Error_CheckFatal(Wimp_OpenWindow(&tWindowState.openblock));
+} /* end of vForceRedraw */
+
+/*
+ * vShowDiagram - put the diagram on the screen
+ */
+void
+vShowDiagram(diagram_type *pDiag)
+{
+ wimp_box tRect;
+ int x0, y0, x1, y1;
+
+ TRACE_MSG("vShowDiagram");
+
+ fail(pDiag == NULL);
+
+ Window_Show(pDiag->tMainWindow, open_NEARLAST);
+ Drawfile_QueryBox(&pDiag->tInfo, &tRect, TRUE);
+ /* Work area extension */
+ x0 = tRect.min.x - WORKAREA_EXTENSION;
+ y0 = tRect.min.y - WORKAREA_EXTENSION;
+ x1 = tRect.max.x + WORKAREA_EXTENSION;
+ y1 = tRect.max.y + WORKAREA_EXTENSION;
+ Window_SetExtent(pDiag->tMainWindow, x0, y0, x1, y1);
+ vForceRedraw(pDiag);
+} /* end of vShowDiagram */
+
+/*
+ * vMainButtonClick - handle mouse buttons clicks for the main screen
+ */
+void
+vMainButtonClick(mouse_block *pMouse)
+{
+ caret_block tCaret;
+ window_state ws;
+
+ TRACE_MSG("vMainButtonClick");
+
+ fail(pMouse == NULL);
+
+ DBG_DEC(pMouse->button.data.select);
+ DBG_DEC(pMouse->button.data.adjust);
+ DBG_DEC(pMouse->window);
+ DBG_DEC(pMouse->icon);
+
+ if (pMouse->window >= 0 &&
+ pMouse->icon == -1 &&
+ (pMouse->button.data.select || pMouse->button.data.adjust)) {
+ /* Get the input focus */
+ Error_CheckFatal(Wimp_GetWindowState(pMouse->window, &ws));
+ tCaret.window = pMouse->window;
+ tCaret.icon = -1;
+ tCaret.offset.x = pMouse->pos.x - ws.openblock.screenrect.min.x;
+ tCaret.offset.y = pMouse->pos.y - ws.openblock.screenrect.max.y;
+ tCaret.height = (int)BIT(25);
+ tCaret.index = 0;
+ Error_CheckFatal(Wimp_SetCaretPosition(&tCaret));
+ }
+} /* end of vMainButtonClick */
+
+/*
+ * bMainKeyPressed - handle pressed keys for the main window
+ */
+BOOL
+bMainKeyPressed(event_pollblock *pEvent, void *pvReference)
+{
+ diagram_type *pDiag;
+
+ TRACE_MSG("bMainKeyPressed");
+
+ fail(pEvent == NULL);
+ fail(pEvent->type != event_KEY);
+ fail(pvReference == NULL);
+
+ pDiag = (diagram_type *)pvReference;
+
+ fail(pEvent->data.key.caret.window != pDiag->tMainWindow);
+
+
+ switch (pEvent->data.key.code) {
+ case keycode_CTRL_F2: /* Ctrl F2 */
+ bDestroyDiagram(pEvent, pvReference);
+ break;
+ case keycode_F3: /* F3 */
+ bSaveDrawfile(pEvent, pvReference);
+ break;
+ case keycode_SHIFT_F3: /* Shift F3 */
+ bSaveTextfile(pEvent, pvReference);
+ break;
+ default:
+ DBG_DEC(pEvent->data.key.code);
+ Error_CheckFatal(Wimp_ProcessKey(pEvent->data.key.code));
+ }
+ return TRUE;
+} /* end of bMainKeyPressed */
+
+/*
+ * bRedrawMainWindow - redraw the main window
+ */
+BOOL
+bRedrawMainWindow(event_pollblock *pEvent, void *pvReference)
+{
+ window_redrawblock tBlock;
+ diagram_type *pDiag;
+ drawfile_info *pInfo;
+ double dScaleFactor;
+ BOOL bMore;
+
+ TRACE_MSG("bRedrawMainWindow");
+
+ fail(pEvent == NULL);
+ fail(pEvent->type != event_REDRAW);
+ fail(pvReference == NULL);
+
+ pDiag = (diagram_type *)pvReference;
+
+ fail(pDiag->tMainWindow != pEvent->data.openblock.window);
+ fail(pDiag->iScaleFactorCurr < MIN_SCALE_FACTOR);
+ fail(pDiag->iScaleFactorCurr > MAX_SCALE_FACTOR);
+
+ dScaleFactor = (double)pDiag->iScaleFactorCurr / 100.0;
+ pInfo = &pDiag->tInfo;
+
+ tBlock.window = pEvent->data.openblock.window;
+ Error_CheckFatal(Wimp_RedrawWindow(&tBlock, &bMore));
+
+ /* If there is no real diagram just go thru the motions */
+ while (bMore) {
+ if (pInfo->data != NULL && pInfo->length != 0) {
+ Error_CheckFatal(Drawfile_RenderDiagram(pInfo,
+ &tBlock, dScaleFactor));
+ }
+ Error_CheckFatal(Wimp_GetRectangle(&tBlock, &bMore));
+ }
+ return TRUE;
+} /* end of bRedrawMainWindow */
+
+/*
+ * bScaleOpenAction - action to be taken when the Scale view window opens
+ */
+BOOL
+bScaleOpenAction(event_pollblock *pEvent, void *pvReference)
+{
+ window_state tWindowState;
+ diagram_type *pDiag;
+
+ TRACE_MSG("bScaleOpenAction");
+
+ fail(pEvent == NULL);
+ fail(pEvent->type != event_SEND);
+ fail(pEvent->data.message.header.action != message_MENUWARN);
+ fail(pvReference == NULL);
+
+ pDiag = (diagram_type *)pvReference;
+
+ if (menu_currentopen != pDiag->pSaveMenu ||
+ pEvent->data.message.data.menuwarn.selection[0] != SAVEMENU_SCALEVIEW) {
+ return FALSE;
+ }
+
+ Error_CheckFatal(Wimp_GetWindowState(pDiag->tScaleWindow,
+ &tWindowState));
+ if (tWindowState.flags.data.open) {
+ /* The window is already open */
+ return TRUE;
+ }
+
+ DBG_MSG("vScaleOpenAction for real");
+
+ pDiag->iScaleFactorTemp = pDiag->iScaleFactorCurr;
+ vUpdateWriteableNumber(pDiag->tScaleWindow,
+ SCALE_SCALE_WRITEABLE, pDiag->iScaleFactorTemp);
+ Window_Show(pDiag->tScaleWindow, open_UNDERPOINTER);
+ return TRUE;
+} /* end of bScaleOpenAction */
+
+/*
+ * vSetTitle - set the title of a window
+ */
+void
+vSetTitle(diagram_type *pDiag)
+{
+ char szTitle[WINDOW_TITLE_LEN];
+
+ TRACE_MSG("vSetTitle");
+
+ fail(pDiag == NULL);
+ fail(pDiag->szFilename[0] == '\0');
+
+ (void)sprintf(szTitle, "%.*s at %d%%",
+ FILENAME_TITLE_LEN,
+ pDiag->szFilename,
+ pDiag->iScaleFactorCurr % 1000);
+ if (strlen(pDiag->szFilename) > FILENAME_TITLE_LEN) {
+ szTitle[FILENAME_TITLE_LEN - 1] = OUR_ELLIPSIS;
+ }
+
+ Window_SetTitle(pDiag->tMainWindow, szTitle);
+} /* end of vSetTitle */
+
+/*
+ * vScaleButtonClick - handle a mouse button click in the Scale view window
+ */
+void
+vScaleButtonClick(mouse_block *pMouse, diagram_type *pDiag)
+{
+ BOOL bCloseWindow, bRedraw;
+
+ TRACE_MSG("vScaleButtonClick");
+
+ fail(pMouse == NULL || pDiag == NULL);
+ fail(pMouse->window != pDiag->tScaleWindow);
+
+ bCloseWindow = FALSE;
+ bRedraw = FALSE;
+ switch (pMouse->icon) {
+ case SCALE_CANCEL_BUTTON:
+ bCloseWindow = TRUE;
+ pDiag->iScaleFactorTemp = pDiag->iScaleFactorCurr;
+ break;
+ case SCALE_SCALE_BUTTON:
+ bCloseWindow = TRUE;
+ bRedraw = pDiag->iScaleFactorCurr != pDiag->iScaleFactorTemp;
+ pDiag->iScaleFactorCurr = pDiag->iScaleFactorTemp;
+ break;
+ case SCALE_50_PCT:
+ pDiag->iScaleFactorTemp = 50;
+ break;
+ case SCALE_75_PCT:
+ pDiag->iScaleFactorTemp = 75;
+ break;
+ case SCALE_100_PCT:
+ pDiag->iScaleFactorTemp = 100;
+ break;
+ case SCALE_150_PCT:
+ pDiag->iScaleFactorTemp = 150;
+ break;
+ default:
+ DBG_DEC(pMouse->icon);
+ break;
+ }
+ if (bCloseWindow) {
+ /* Close the scale window */
+ Error_CheckFatal(Wimp_CloseWindow(pMouse->window));
+ if (bRedraw) {
+ /* Redraw the main window */
+ vSetTitle(pDiag);
+ vForceRedraw(pDiag);
+ }
+ } else {
+ vUpdateWriteableNumber(pMouse->window,
+ SCALE_SCALE_WRITEABLE,
+ pDiag->iScaleFactorTemp);
+ }
+} /* end of vScaleButtonClick */
+
+/*
+ * bScaleKeyPressed - handle pressed keys for the scale window
+ */
+BOOL
+bScaleKeyPressed(event_pollblock *pEvent, void *pvReference)
+{
+ icon_block tIcon;
+ diagram_type *pDiag;
+ caret_block *pCaret;
+ char *pcChar;
+ int iTmp;
+
+ TRACE_MSG("bScaleKeyPressed");
+
+ fail(pEvent == NULL);
+ fail(pEvent->type != event_KEY);
+ fail(pvReference == NULL);
+
+ pCaret = &pEvent->data.key.caret;
+ pDiag = (diagram_type *)pvReference;
+
+ fail(pEvent->data.key.caret.window != pDiag->tScaleWindow);
+
+ DBG_DEC_C(pCaret->icon != SCALE_SCALE_WRITEABLE, pCaret->icon);
+ DBG_DEC_C(pCaret->icon == SCALE_SCALE_WRITEABLE, pEvent->data.key.code);
+
+ if (pEvent->data.key.code != '\r' ||
+ pCaret->icon != SCALE_SCALE_WRITEABLE) {
+ Error_CheckFatal(Wimp_ProcessKey(pEvent->data.key.code));
+ return TRUE;
+ }
+
+ Error_CheckFatal(Wimp_GetIconState(pCaret->window, pCaret->icon, &tIcon));
+ if (!tIcon.flags.data.text || !tIcon.flags.data.indirected) {
+ werr(1, "Icon %d must be indirected text", (int)pCaret->icon);
+ }
+ iTmp = (int)strtol(tIcon.data.indirecttext.buffer, &pcChar, 10);
+ if (*pcChar != '\0' && *pcChar != '\r') {
+ DBG_DEC(*pcChar);
+ } else if (iTmp < MIN_SCALE_FACTOR) {
+ pDiag->iScaleFactorTemp = MIN_SCALE_FACTOR;
+ } else if (iTmp > MAX_SCALE_FACTOR) {
+ pDiag->iScaleFactorTemp = MAX_SCALE_FACTOR;
+ } else {
+ pDiag->iScaleFactorTemp = iTmp;
+ }
+ pDiag->iScaleFactorCurr = pDiag->iScaleFactorTemp;
+ /* Close the scale window */
+ Error_CheckFatal(Wimp_CloseWindow(pCaret->window));
+ /* Redraw the main window */
+ vSetTitle(pDiag);
+ vForceRedraw(pDiag);
+ return TRUE;
+} /* end of bScaleKeyPressed */
+
diff --git a/sys/src/cmd/aux/antiword/draw.h b/sys/src/cmd/aux/antiword/draw.h
new file mode 100755
index 000000000..839bbf0f3
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/draw.h
@@ -0,0 +1,46 @@
+/*
+ * draw.h
+ * Copyright (C) 2001 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Constants and macros to deal with the Draw format
+ */
+
+#if !defined(__draw_h)
+#define __draw_h 1
+
+#include "drawftypes.h"
+
+typedef struct draw_jpegstrhdr_tag {
+ draw_tagtyp tag; /* 1 word */
+ draw_sizetyp size; /* 1 word */
+ draw_bboxtyp bbox; /* 4 words */
+ int width; /* 1 word */
+ int height; /* 1 word */
+ int xdpi; /* 1 word */
+ int ydpi; /* 1 word */
+ int trfm[6]; /* 6 words */
+ int len; /* 1 word */
+} draw_jpegstrhdr;
+
+typedef struct draw_jpegstr_tag {
+ draw_tagtyp tag; /* 1 word */
+ draw_sizetyp size; /* 1 word */
+ draw_bboxtyp bbox; /* 4 words */
+ int width; /* 1 word */
+ int height; /* 1 word */
+ int xdpi; /* 1 word */
+ int ydpi; /* 1 word */
+ int trfm[6]; /* 6 words */
+ int len; /* 1 word */
+ unsigned char *jpeg;
+} draw_jpegstr;
+
+typedef union draw_imageType_tag {
+ draw_spristr *sprite;
+ draw_jpegstr *jpeg;
+ char *bytep;
+ int *wordp;
+} draw_imageType;
+
+#endif /* !__draw_h */
diff --git a/sys/src/cmd/aux/antiword/drawfile.c b/sys/src/cmd/aux/antiword/drawfile.c
new file mode 100755
index 000000000..596364428
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/drawfile.c
@@ -0,0 +1,422 @@
+/*
+ * drawfile.c
+ * Copyright (C) 2005 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Functions to process with the Draw diagram
+ */
+
+#include <string.h>
+#include "DeskLib:Error.h"
+#include "DeskLib:SWI.h"
+#include "drawfile.h"
+#include "antiword.h"
+
+#define DRAWFILE_OBJECT_TOO_SMALL 200
+#define DRAWFILE_NO_TEXT 201
+#define DRAWFILE_BAD_CHARACTER 202
+#define DRAWFILE_SMALL_MEMORY 203
+#define DRAWFILE_PATH_WITHOUT_LINES 204
+#define DRAWFILE_BAD_PATH_TYPE 205
+#define DRAWFILE_PATH_WITHOUT_END 206
+#define DRAWFILE_BAD_SPRITE_SIZE 207
+#define DRAWFILE_BAD_JPEG_SIZE 208
+#define DRAWFILE_TOO_SMALL 209
+#define DRAWFILE_NOT_A_DRAWFILE 210
+#define DRAWFILE_OBJECT_SIZE 211
+#define DRAWFILE_MANY_FONTTABLES 212
+#define DRAWFILE_TEXT_NO_FONT 213
+#define DRAWFILE_OBJECT_UNEXPECTED 214
+#define DRAWFILE_SIZE_ERROR 215
+
+typedef struct drawfile_error_tag {
+ int iErrorNumber;
+ const char *szErrorText;
+} drawfile_error_type;
+
+static const drawfile_error_type atErrors[] = {
+ { DRAWFILE_OBJECT_TOO_SMALL, "Object too small"},
+ { DRAWFILE_NO_TEXT, "Text object without text"},
+ { DRAWFILE_BAD_CHARACTER, "Bad character in string"},
+ { DRAWFILE_SMALL_MEMORY, "Not enough memory reserved"},
+ { DRAWFILE_PATH_WITHOUT_LINES, "This path has no lines"},
+ { DRAWFILE_BAD_PATH_TYPE, "Bad path-type in path"},
+ { DRAWFILE_PATH_WITHOUT_END, "No end of path seen"},
+ { DRAWFILE_BAD_SPRITE_SIZE, "Bad sprite size"},
+ { DRAWFILE_BAD_JPEG_SIZE, "Bad jpeg size"},
+ { DRAWFILE_TOO_SMALL, "Too small to be a drawfile"},
+ { DRAWFILE_NOT_A_DRAWFILE, "Not a drawfile"},
+ { DRAWFILE_OBJECT_SIZE, "Object with incorrect size"},
+ { DRAWFILE_MANY_FONTTABLES, "More than one font table"},
+ { DRAWFILE_TEXT_NO_FONT, "Text, but no font table seen"},
+ { DRAWFILE_OBJECT_UNEXPECTED, "Unexpected object type"},
+ { DRAWFILE_SIZE_ERROR, "Sizes don't match"},
+};
+
+
+/*
+ * pFillError - error number to error struct
+ */
+static os_error *
+pFillError(int iErrorNumber)
+{
+ static os_error tError;
+ const drawfile_error_type *pTmp;
+ const char *szErrorText;
+
+ szErrorText = "Unknown error";
+ for (pTmp = atErrors; pTmp < atErrors + elementsof(atErrors); pTmp++) {
+ if (iErrorNumber == pTmp->iErrorNumber) {
+ szErrorText = pTmp->szErrorText;
+ break;
+ }
+ }
+ tError.errnum = iErrorNumber;
+ strncpy(tError.errmess, szErrorText, sizeof(tError.errmess) - 1);
+ tError.errmess[sizeof(tError.errmess) - 1] = '\0';
+ DBG_DEC(tError.errnum);
+ DBG_MSG(tError.errmess);
+ return &tError;
+} /* end of pFillError */
+
+/*
+ * Drawfile_BBox - Find the bounding box of a diagram
+ */
+os_error *
+Drawfile_Bbox(drawfile_bbox_flags flags,
+ drawfile_diagram const *diagram,
+ int size,
+ os_trfm const *trfm,
+ wimp_box *bbox)
+{
+ return SWI(5, 0, DrawFile_BBox | XOS_Bit,
+ flags, diagram, size, trfm, bbox);
+} /* end of Drawfile_Bbox */
+
+/*
+ * Drawfile_CreateDiagram - create an empty drawfile diagram
+ */
+os_error *
+Drawfile_CreateDiagram(drawfile_info *pInfo, size_t tMemorySize,
+ const char *szCreator, wimp_box tBbox)
+{
+ drawfile_diagram *pDiag;
+
+ if (tMemorySize < offsetof(drawfile_diagram, objects)) {
+ return pFillError(DRAWFILE_SMALL_MEMORY);
+ }
+ pDiag = (drawfile_diagram *)pInfo->data;
+ strncpy(pDiag->tag, "Draw", 4);
+ pDiag->major_version = 201;
+ pDiag->minor_version = 0;
+ strncpy(pDiag->source, szCreator, sizeof(pDiag->source));
+ pDiag->bbox = tBbox;
+ /* Memory in use */
+ pInfo->length = offsetof(drawfile_diagram, objects);
+ return NULL;
+} /* end of Drawfile_CreateDiagram */
+
+/*
+ * Drawfile_AppendObject - append an object to a diagram
+ */
+os_error *
+Drawfile_AppendObject(drawfile_info *pInfo, size_t tMemorySize,
+ const drawfile_object *pObject, BOOL bRebind)
+{
+ wimp_box *pMainBbox;
+ const wimp_box *pBbox;
+ byte *pAfter;
+
+ if (tMemorySize < pInfo->length + pObject->size) {
+ return pFillError(DRAWFILE_OBJECT_TOO_SMALL);
+ }
+ /* After the last object */
+ pAfter = (byte *)pInfo->data + pInfo->length;
+ /* Copy in the new data */
+ memcpy(pAfter, pObject, pObject->size);
+ /* Rebind if needed */
+ if (bRebind) {
+ pMainBbox = &((drawfile_diagram *)pInfo->data)->bbox;
+ switch (pObject->type) {
+ case drawfile_TYPE_FONT_TABLE:
+ pBbox = NULL;
+ break;
+ case drawfile_TYPE_TEXT:
+ pBbox = &pObject->data.text.bbox;
+ break;
+ case drawfile_TYPE_PATH:
+ pBbox = &pObject->data.path.bbox;
+ break;
+ case drawfile_TYPE_SPRITE:
+ pBbox = &pObject->data.sprite.bbox;
+ break;
+ case drawfile_TYPE_GROUP:
+ pBbox = &pObject->data.group.bbox;
+ break;
+ case drawfile_TYPE_TAGGED:
+ pBbox = &pObject->data.tagged.bbox;
+ break;
+ case drawfile_TYPE_TEXT_AREA:
+ pBbox = &pObject->data.text_area.bbox;
+ break;
+ case drawfile_TYPE_TEXT_COLUMN:
+ pBbox = NULL;
+ break;
+ case drawfile_TYPE_OPTIONS:
+ pBbox = &pObject->data.options.bbox;
+ break;
+ case drawfile_TYPE_TRFM_TEXT:
+ pBbox = &pObject->data.trfm_text.bbox;
+ break;
+ case drawfile_TYPE_TRFM_SPRITE:
+ pBbox = &pObject->data.trfm_sprite.bbox;
+ break;
+ case drawfile_TYPE_JPEG:
+ pBbox = &pObject->data.jpeg.bbox;
+ break;
+ default:
+ pBbox = NULL;
+ break;
+ }
+ if (pBbox != NULL) {
+ if (pBbox->min.x < pMainBbox->min.x) {
+ pMainBbox->min.x = pBbox->min.x;
+ }
+ if (pBbox->min.y < pMainBbox->min.y) {
+ pMainBbox->min.y = pBbox->min.y;
+ }
+ if (pBbox->max.x > pMainBbox->max.x) {
+ pMainBbox->max.x = pBbox->max.x;
+ }
+ if (pBbox->max.y > pMainBbox->max.y) {
+ pMainBbox->max.y = pBbox->max.y;
+ }
+ }
+ }
+ /* Memory in use */
+ pInfo->length += pObject->size;
+ return NULL;
+} /* end of Drawfile_AppendObject */
+
+/*
+ * Replaces the draw_render_diag function from RISC_OSLib
+ */
+os_error *
+Drawfile_RenderDiagram(drawfile_info *pInfo, window_redrawblock *pRedraw,
+ double dScale)
+{
+ int aiTransform[6];
+
+ fail(pInfo == NULL);
+ fail(pInfo->data == NULL);
+ fail(pRedraw == NULL);
+ fail(dScale < 0.01);
+
+ aiTransform[0] = (int)(dScale * 0x10000);
+ aiTransform[1] = 0;
+ aiTransform[2] = 0;
+ aiTransform[3] = (int)(dScale * 0x10000);
+ aiTransform[4] = (pRedraw->rect.min.x - pRedraw->scroll.x) * 256;
+ aiTransform[5] = (pRedraw->rect.max.y - pRedraw->scroll.y) * 256;
+
+ return SWI(6, 0, DrawFile_Render | XOS_Bit,
+ 0, pInfo->data, pInfo->length, aiTransform, &pRedraw->rect, 0);
+} /* end of Drawfile_RenderDiagram */
+
+/*
+ * pVerifyText - verify a text object
+ */
+static os_error *
+pVerifyText(const drawfile_text *pText)
+{
+ const unsigned char *pucTmp;
+
+ if (pText->text[0] == '\0') {
+ return pFillError(DRAWFILE_NO_TEXT);
+ }
+ pucTmp = (const unsigned char *)pText->text;
+ while (*pucTmp != '\0') {
+ if (*pucTmp < 0x20 || *pucTmp == 0x7f) {
+ return pFillError(DRAWFILE_BAD_CHARACTER);
+ }
+ pucTmp++;
+ }
+ return NULL;
+} /* end of pVerifyText */
+
+/*
+ * pVerifyPath - verify a path object
+ */
+static os_error *
+pVerifyPath(const drawfile_path *pPath, int iSize)
+{
+ const int *piTmp;
+ int iElements;
+ BOOL bLine;
+
+ bLine = FALSE;
+ iElements = (iSize - offsetof(drawfile_path, path)) / 4;
+
+ for (piTmp = pPath->path; piTmp < pPath->path + iElements; piTmp++) {
+ switch(*piTmp) {
+ case drawfile_PATH_END_PATH:
+ if (bLine) {
+ return NULL;
+ }
+ return pFillError(DRAWFILE_PATH_WITHOUT_LINES);
+ case drawfile_PATH_LINE_TO:
+ bLine = TRUE;
+ piTmp += 2;
+ break;
+ case drawfile_PATH_MOVE_TO:
+ piTmp += 2;
+ break;
+ case drawfile_PATH_CLOSE_LINE:
+ bLine = TRUE;
+ break;
+ default:
+ return pFillError(DRAWFILE_BAD_PATH_TYPE);
+ }
+ }
+ return pFillError(DRAWFILE_PATH_WITHOUT_END);
+} /* end of pVerifyPath */
+
+/*
+ * pVerifySprite - verify a sprite object
+ */
+static os_error *
+pVerifySprite(const drawfile_sprite *pSprite, int iSize)
+{
+ iSize -= offsetof(drawfile_sprite, header);
+ if (iSize < pSprite->header.offset_next) {
+ DBG_DEC(iSize);
+ DBG_DEC(pSprite->header.offset_next);
+ return pFillError(DRAWFILE_BAD_SPRITE_SIZE);
+ }
+ return NULL;
+} /* end of pVerifySprite */
+
+/*
+ * pVerifyJpeg - verify a jpeg object
+ */
+static os_error *
+pVerifyJpeg(const drawfile_jpeg *pJpeg, int iSize)
+{
+ iSize -= offsetof(drawfile_jpeg, data);
+ if (iSize < pJpeg->len) {
+ DBG_DEC(iSize);
+ DBG_DEC(pJpeg->len);
+ return pFillError(DRAWFILE_BAD_JPEG_SIZE);
+ }
+ return NULL;
+} /* end of pVerifyJpeg */
+
+/*
+ * Drawfile_VerifyDiagram - Verify the diagram generated from the Word file
+ *
+ * returns NULL if the diagram is correct
+ */
+os_error *
+Drawfile_VerifyDiagram(drawfile_info *pInfo)
+{
+ drawfile_diagram *pDiag;
+ drawfile_object *pObj;
+ os_error *pError;
+ const char *pcTmp;
+ int iToGo, iFontTables;
+ BOOL bTypeFontTable;
+
+ TRACE_MSG("Drawfile_VerifyDiagram");
+
+ fail(pInfo == NULL);
+
+ if (pInfo->length < offsetof(drawfile_diagram, objects)) {
+ return pFillError(DRAWFILE_TOO_SMALL);
+ }
+
+ pDiag = (drawfile_diagram *)pInfo->data;
+ if (strncmp(pDiag->tag, "Draw", 4) != 0 ||
+ pDiag->major_version != 201 ||
+ pDiag->minor_version != 0) {
+ return pFillError(DRAWFILE_NOT_A_DRAWFILE);
+ }
+
+ iToGo = pInfo->length - offsetof(drawfile_diagram, objects);
+ pcTmp = (const char *)pInfo->data + offsetof(drawfile_diagram, objects);
+ iFontTables = 0;
+ bTypeFontTable = FALSE;
+
+ while (iToGo > 0) {
+ pObj = (drawfile_object *)pcTmp;
+ if (pObj->size < 0 || pObj->size % 4 != 0) {
+ return pFillError(DRAWFILE_OBJECT_SIZE);
+ }
+ switch (pObj->type) {
+ case drawfile_TYPE_FONT_TABLE:
+ if (bTypeFontTable) {
+ return pFillError(DRAWFILE_MANY_FONTTABLES);
+ }
+ bTypeFontTable = TRUE;
+ break;
+ case drawfile_TYPE_TEXT:
+ if (pObj->data.text.style.font_ref != 0 &&
+ !bTypeFontTable) {
+ return pFillError(DRAWFILE_TEXT_NO_FONT);
+ }
+ pError = pVerifyText(&pObj->data.text);
+ if (pError != NULL) {
+ return pError;
+ }
+ break;
+ case drawfile_TYPE_PATH:
+ pError = pVerifyPath(&pObj->data.path,
+ pObj->size - offsetof(drawfile_object, data));
+ if (pError != NULL) {
+ return pError;
+ }
+ break;
+ case drawfile_TYPE_SPRITE:
+ pError = pVerifySprite(&pObj->data.sprite,
+ pObj->size - offsetof(drawfile_object, data));
+ if (pError != NULL) {
+ return pError;
+ }
+ break;
+ case drawfile_TYPE_JPEG:
+ pError = pVerifyJpeg(&pObj->data.jpeg,
+ pObj->size - offsetof(drawfile_object, data));
+ if (pError != NULL) {
+ return pError;
+ }
+ break;
+ default:
+ DBG_DEC(pObj->type);
+ return pFillError(DRAWFILE_OBJECT_UNEXPECTED);
+ }
+ pcTmp += pObj->size;
+ iToGo -= pObj->size;
+ }
+ if (iToGo < 0) {
+ return pFillError(DRAWFILE_SIZE_ERROR);
+ }
+ return NULL;
+} /* end of Drawfile_VerifyDiagram */
+
+/*
+ * Drawfile_QueryBox - Find the bounding box of a diagram
+ */
+void
+Drawfile_QueryBox(drawfile_info *pInfo, wimp_box *pRect, BOOL bScreenUnits)
+{
+ fail(pInfo == NULL);
+ fail(pRect == NULL);
+
+ Error_CheckFatal(Drawfile_Bbox(0,
+ pInfo->data, pInfo->length, NULL, pRect));
+ if (bScreenUnits) {
+ pRect->min.x = Drawfile_DrawToScreen(pRect->min.x);
+ pRect->min.y = Drawfile_DrawToScreen(pRect->min.y);
+ pRect->max.x = Drawfile_DrawToScreen(pRect->max.x);
+ pRect->max.y = Drawfile_DrawToScreen(pRect->max.y);
+ }
+} /* end of Drawfile_QueryBox */
diff --git a/sys/src/cmd/aux/antiword/drawfile.h b/sys/src/cmd/aux/antiword/drawfile.h
new file mode 100755
index 000000000..c9b76dbcc
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/drawfile.h
@@ -0,0 +1,433 @@
+/*
+ * drawfile.h
+ * Copyright (C) 2005 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Include file to deal with drawfiles
+ *
+ * Based on:
+ * C header file for DrawFile
+ * written by DefMod (May 4 2004) on Tue May 4 13:34:17 2004
+ * Jonathan Coxhead, jonathan@doves.demon.co.uk, 21 Aug 1995
+ * OSLib---efficient, type-safe, transparent, extensible,
+ * register-safe A P I coverage of RISC O S
+ * Copyright (C) 1994 Jonathan Coxhead
+ *
+ * All credit should go to him, but all the bugs are mine
+ */
+
+#if !defined(__drawfile_h)
+#define __drawfile_h
+
+#include "DeskLib:Sprite.h"
+#include "DeskLib:Wimp.h"
+
+#if !defined(BOOL)
+#define BOOL int
+#define TRUE 1
+#define FALSE 0
+#endif /* !BOOL */
+
+/*********************
+ * Conversion macros *
+ *********************/
+#define Drawfile_DrawToScreen(i) ((i) / 256)
+#define Drawfile_ScreenToDraw(i) ((i) * 256)
+
+/**********************************
+ * SWI names and SWI reason codes *
+ **********************************/
+#define DrawFile_Render 0x45540
+#define DrawFile_BBox 0x45541
+#define DrawFile_DeclareFonts 0x45542
+
+/********************
+ * Type definitions *
+ ********************/
+typedef unsigned int bits;
+typedef unsigned char byte;
+
+typedef byte drawfile_fontref;
+
+typedef byte drawfile_path_style_flags;
+
+typedef bits drawfile_text_flags;
+
+typedef bits drawfile_render_flags;
+
+typedef bits drawfile_declare_fonts_flags;
+
+typedef bits drawfile_paper_options;
+
+typedef bits drawfile_entry_mode;
+
+typedef enum {
+ drawfile_TYPE_FONT_TABLE = 0,
+ drawfile_TYPE_TEXT = 1,
+ drawfile_TYPE_PATH = 2,
+ drawfile_TYPE_SPRITE = 5,
+ drawfile_TYPE_GROUP = 6,
+ drawfile_TYPE_TAGGED = 7,
+ drawfile_TYPE_TEXT_AREA = 9,
+ drawfile_TYPE_TEXT_COLUMN = 10,
+ drawfile_TYPE_OPTIONS = 11,
+ drawfile_TYPE_TRFM_TEXT = 12,
+ drawfile_TYPE_TRFM_SPRITE = 13,
+ drawfile_TYPE_JPEG = 16
+} drawfile_type;
+
+typedef enum {
+ drawfile_PATH_END_PATH = 0,
+ drawfile_PATH_CONTINUATION = 1,
+ drawfile_PATH_MOVE_TO = 2,
+ drawfile_PATH_SPECIAL_MOVE_TO = 3,
+ drawfile_PATH_CLOSE_GAP = 4,
+ drawfile_PATH_CLOSE_LINE = 5,
+ drawfile_PATH_BEZIER_TO = 6,
+ drawfile_PATH_GAP_TO = 7,
+ drawfile_PATH_LINE_TO = 8
+} drawfile_path_type;
+
+typedef struct {
+ int start;
+ int element_count;
+ int elements [6];
+} draw_dash_pattern;
+
+typedef struct {
+ int entries [3] [2];
+} os_trfm;
+
+typedef struct {
+ void *data;
+ size_t length;
+} drawfile_info;
+
+typedef struct {
+ drawfile_fontref font_ref;
+ char font_name [1];
+} drawfile_font_def;
+
+typedef struct {
+ drawfile_fontref font_ref;
+ byte reserved [3];
+} drawfile_text_style;
+
+typedef struct {
+ drawfile_path_style_flags flags;
+ byte reserved;
+ byte cap_width;
+ byte cap_length;
+} drawfile_path_style;
+
+typedef struct {
+ drawfile_font_def font_def[1];
+} drawfile_font_table;
+
+typedef struct {
+ wimp_box bbox;
+ palette_entry fill;
+ palette_entry bg_hint;
+ drawfile_text_style style;
+ int xsize;
+ int ysize;
+ wimp_coord base;
+ char text [1];
+} drawfile_text;
+
+typedef struct {
+ wimp_box bbox;
+ palette_entry fill;
+ palette_entry outline;
+ int width;
+ drawfile_path_style style;
+ int path [1];
+} drawfile_path;
+
+typedef struct {
+ wimp_box bbox;
+ palette_entry fill;
+ palette_entry outline;
+ int width;
+ drawfile_path_style style;
+ draw_dash_pattern pattern;
+ int path [1];
+} drawfile_path_with_pattern;
+
+typedef struct {
+ wimp_box bbox;
+ sprite_header header;
+ byte data [1];
+} drawfile_sprite;
+
+typedef struct {
+ wimp_box bbox;
+ char name [12];
+ int objects [1];
+} drawfile_group;
+
+typedef struct {
+ wimp_box bbox;
+ drawfile_type tag;
+ int object [1];
+} drawfile_tagged;
+
+typedef struct {
+ wimp_box box;
+} drawfile_text_column;
+
+typedef struct {
+ struct {
+ drawfile_type type;
+ int size;
+ drawfile_text_column data;
+ } columns [1];
+} drawfile_text_column_list;
+
+typedef struct {
+ drawfile_type type;
+ int reserved [2];
+ palette_entry fill;
+ palette_entry bg_hint;
+ char text [1];
+} drawfile_area_text;
+
+typedef struct {
+ wimp_box bbox;
+ drawfile_text_column_list header;
+ drawfile_area_text area_text;
+} drawfile_text_area;
+
+typedef struct {
+ wimp_box bbox;
+ int paper_size;
+ drawfile_paper_options paper_options;
+ double grid_spacing;
+ int grid_division;
+ BOOL isometric;
+ BOOL auto_adjust;
+ BOOL show;
+ BOOL lock;
+ BOOL cm;
+ int zoom_mul;
+ int zoom_div;
+ BOOL zoom_lock;
+ BOOL toolbox;
+ drawfile_entry_mode entry_mode;
+ int undo_size;
+} drawfile_options;
+
+typedef struct {
+ wimp_box bbox;
+ os_trfm trfm;
+ drawfile_text_flags flags;
+ palette_entry fill;
+ palette_entry bg_hint;
+ drawfile_text_style style;
+ int xsize;
+ int ysize;
+ wimp_coord base;
+ char text [1];
+} drawfile_trfm_text;
+
+typedef struct {
+ wimp_box bbox;
+ os_trfm trfm;
+ sprite_header header;
+ byte data [1];
+} drawfile_trfm_sprite;
+
+typedef struct {
+ wimp_box bbox;
+ int width;
+ int height;
+ int xdpi;
+ int ydpi;
+ os_trfm trfm;
+ int len;
+ byte data [1];
+} drawfile_jpeg;
+
+/* ------------------------------------------------------------------------
+ * Type: drawfile_object
+ *
+ * Description: This type is used to declare pointers rather than objects
+ */
+
+typedef struct {
+ drawfile_type type;
+ int size;
+ union {
+ drawfile_font_table font_table;
+ drawfile_text text;
+ drawfile_path path;
+ drawfile_path_with_pattern path_with_pattern;
+ drawfile_sprite sprite;
+ drawfile_group group;
+ drawfile_tagged tagged;
+ drawfile_text_column text_column;
+ drawfile_text_area text_area;
+ drawfile_options options;
+ drawfile_trfm_text trfm_text;
+ drawfile_trfm_sprite trfm_sprite;
+ drawfile_jpeg jpeg;
+ } data;
+} drawfile_object;
+
+typedef struct {
+ char tag [4];
+ int major_version;
+ int minor_version;
+ char source [12];
+ wimp_box bbox;
+ drawfile_object objects [1];
+} drawfile_diagram;
+
+typedef bits drawfile_bbox_flags;
+
+typedef struct {
+ drawfile_object *object;
+ drawfile_diagram *diagram;
+ drawfile_object *font_table;
+ drawfile_declare_fonts_flags flags;
+ os_error *error;
+} drawfile_declare_fonts_state;
+
+/************************
+ * Constant definitions *
+ ************************/
+#define error_DRAW_FILE_NOT_DRAW 0x20C00u
+#define error_DRAW_FILE_VERSION 0x20C01u
+#define error_DRAW_FILE_FONT_TAB 0x20C02u
+#define error_DRAW_FILE_BAD_FONT_NO 0x20C03u
+#define error_DRAW_FILE_BAD_MODE 0x20C04u
+#define error_DRAW_FILE_BAD_FILE 0x20C05u
+#define error_DRAW_FILE_BAD_GROUP 0x20C06u
+#define error_DRAW_FILE_BAD_TAG 0x20C07u
+#define error_DRAW_FILE_SYNTAX 0x20C08u
+#define error_DRAW_FILE_FONT_NO 0x20C09u
+#define error_DRAW_FILE_AREA_VER 0x20C0Au
+#define error_DRAW_FILE_NO_AREA_VER 0x20C0Bu
+
+#define drawfile_PATH_MITRED ((drawfile_path_style_flags) 0x0u)
+#define drawfile_PATH_ROUND ((drawfile_path_style_flags) 0x1u)
+#define drawfile_PATH_BEVELLED ((drawfile_path_style_flags) 0x2u)
+#define drawfile_PATH_BUTT ((drawfile_path_style_flags) 0x0u)
+#define drawfile_PATH_SQUARE ((drawfile_path_style_flags) 0x2u)
+#define drawfile_PATH_TRIANGLE ((drawfile_path_style_flags) 0x3u)
+#define drawfile_PATH_JOIN_SHIFT 0
+#define drawfile_PATH_JOIN ((drawfile_path_style_flags) 0x3u)
+#define drawfile_PATH_END_SHIFT 2
+#define drawfile_PATH_END ((drawfile_path_style_flags) 0xCu)
+#define drawfile_PATH_START_SHIFT 4
+#define drawfile_PATH_START ((drawfile_path_style_flags) 0x30u)
+#define drawfile_PATH_WINDING_EVEN_ODD ((drawfile_path_style_flags) 0x40u)
+#define drawfile_PATH_DASHED ((drawfile_path_style_flags) 0x80u)
+#define drawfile_PATH_CAP_WIDTH_SHIFT 16
+#define drawfile_PATH_CAP_WIDTH ((drawfile_path_style_flags) 0xFF0000u)
+#define drawfile_PATH_CAP_LENGTH_SHIFT 24
+#define drawfile_PATH_CAP_LENGTH ((drawfile_path_style_flags) 0xFF000000u)
+#define drawfile_TEXT_KERN ((drawfile_text_flags) 0x1u)
+#define drawfile_TEXT_RIGHT_TO_LEFT ((drawfile_text_flags) 0x2u)
+#define drawfile_TEXT_UNDERLINE ((drawfile_text_flags) 0x4u)
+#define drawfile_RENDER_BBOXES ((drawfile_render_flags) 0x1u)
+#define drawfile_RENDER_SUPPRESS ((drawfile_render_flags) 0x2u)
+#define drawfile_RENDER_GIVEN_FLATNESS ((drawfile_render_flags) 0x4u)
+#define drawfile_RENDER_GIVEN_COLOUR_MAPPING ((drawfile_render_flags) 0x8u)
+#define drawfile_NO_DOWNLOAD ((drawfile_declare_fonts_flags) 0x1u)
+#define drawfile_PAPER_SHOW ((drawfile_paper_options) 0x1u)
+#define drawfile_PAPER_LANDSCAPE ((drawfile_paper_options) 0x10u)
+#define drawfile_PAPER_DEFAULT ((drawfile_paper_options) 0x100u)
+#define drawfile_ENTRY_MODE_LINE ((drawfile_entry_mode) 0x1u)
+#define drawfile_ENTRY_MODE_CLOSED_LINE ((drawfile_entry_mode) 0x2u)
+#define drawfile_ENTRY_MODE_CURVE ((drawfile_entry_mode) 0x4u)
+#define drawfile_ENTRY_MODE_CLOSED_CURVE ((drawfile_entry_mode) 0x8u)
+#define drawfile_ENTRY_MODE_RECTANGLE ((drawfile_entry_mode) 0x10u)
+#define drawfile_ENTRY_MODE_ELLIPSE ((drawfile_entry_mode) 0x20u)
+#define drawfile_ENTRY_MODE_TEXT_LINE ((drawfile_entry_mode) 0x40u)
+#define drawfile_ENTRY_MODE_SELECT ((drawfile_entry_mode) 0x80u)
+
+/*************************
+ * Function declarations *
+ *************************/
+
+#if defined(__cplusplus)
+ extern "C" {
+#endif /* __cplusplus */
+
+/* ------------------------------------------------------------------------
+ * Function: drawfile_render()
+ *
+ * Description: Calls SWI 0x45540
+ *
+ * Input: flags - value of R0 on entry
+ * diagram - value of R1 on entry
+ * size - value of R2 on entry
+ * trfm - value of R3 on entry
+ * clip - value of R4 on entry
+ * flatness - value of R5 on entry
+ */
+
+extern os_error *Drawfile_Render (drawfile_render_flags flags,
+ drawfile_diagram const *diagram,
+ int size,
+ os_trfm const *trfm,
+ wimp_box const *clip,
+ int flatness);
+
+/* ------------------------------------------------------------------------
+ * Function: drawfile_bbox()
+ *
+ * Description: Calls SWI 0x45541
+ *
+ * Input: flags - value of R0 on entry
+ * diagram - value of R1 on entry
+ * size - value of R2 on entry
+ * trfm - value of R3 on entry
+ * bbox - value of R4 on entry
+ */
+
+extern os_error *Drawfile_Bbox (drawfile_bbox_flags flags,
+ drawfile_diagram const *diagram,
+ int size,
+ os_trfm const *trfm,
+ wimp_box *bbox);
+
+/* ------------------------------------------------------------------------
+ * Function: Drawfile_DeclareFonts()
+ *
+ * Description: Calls SWI 0x45542
+ *
+ * Input: flags - value of R0 on entry
+ * diagram - value of R1 on entry
+ * size - value of R2 on entry
+ */
+
+extern os_error *Drawfile_DeclareFonts (drawfile_declare_fonts_flags flags,
+ drawfile_diagram const *diagram,
+ int size);
+
+/* ------------------------------------------------------------------------
+ * Function: Drawfile_CreateDiagram()
+ *
+ */
+
+extern os_error * Drawfile_CreateDiagram(drawfile_info *info, size_t memory,
+ const char *creator, wimp_box box);
+
+extern os_error *Drawfile_AppendObject(drawfile_info *info, size_t memory,
+ const drawfile_object *object, BOOL rebind);
+
+extern os_error *Drawfile_RenderDiagram(drawfile_info *info,
+ window_redrawblock *redraw, double scale);
+
+extern os_error *Drawfile_VerifyDiagram(drawfile_info *info);
+
+extern void Drawfile_QueryBox(drawfile_info *info,
+ wimp_box *rect, BOOL screenUnits);
+
+#if defined(__cplusplus)
+ }
+#endif /* __cplusplus */
+
+#endif /* __drawfile.h */
diff --git a/sys/src/cmd/aux/antiword/fail.c b/sys/src/cmd/aux/antiword/fail.c
new file mode 100755
index 000000000..b6c729f19
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/fail.c
@@ -0,0 +1,26 @@
+/*
+ * fail.c
+ * Copyright (C) 1998 A.J. van Os
+ *
+ * Description:
+ * An alternative form of assert()
+ */
+
+#include <stdlib.h>
+#include "antiword.h"
+
+#if !defined(NDEBUG)
+void
+__fail(char *szExpression, char *szFilename, int iLineNumber)
+{
+ if (szExpression == NULL || szFilename == NULL) {
+ werr(1, "Internal error: no expression");
+ }
+#if defined(DEBUG)
+ fprintf(stderr, "%s[%3d]: Internal error in '%s'\n",
+ szFilename, iLineNumber, szExpression);
+#endif /* DEBUG */
+ werr(1, "Internal error in '%s' in file %s at line %d",
+ szExpression, szFilename, iLineNumber);
+} /* end of __fail */
+#endif /* !NDEBUG */
diff --git a/sys/src/cmd/aux/antiword/fail.h b/sys/src/cmd/aux/antiword/fail.h
new file mode 100755
index 000000000..151a26a7e
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/fail.h
@@ -0,0 +1,22 @@
+/*
+ * fail.h
+ * Copyright (C) 1998-2000 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Support for an alternative form of assert()
+ */
+
+#if !defined(__fail_h)
+#define __fail_h 1
+
+#undef fail
+
+#if defined(NDEBUG)
+#define fail(e) ((void)0)
+#else
+#define fail(e) ((e) ? __fail(#e, __FILE__, __LINE__) : (void)0)
+#endif /* NDEBUG */
+
+extern void __fail(char *, char *, int);
+
+#endif /* __fail_h */
diff --git a/sys/src/cmd/aux/antiword/finddata.c b/sys/src/cmd/aux/antiword/finddata.c
new file mode 100755
index 000000000..441030c5a
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/finddata.c
@@ -0,0 +1,154 @@
+/*
+ * finddata.c
+ * Copyright (C) 2000-2002 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Find the blocks that contain the data of MS Word files
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "antiword.h"
+
+
+/*
+ * bAddDataBlocks - Add the blocks to the data block list
+ *
+ * Returns TRUE when successful, otherwise FALSE
+ */
+BOOL
+bAddDataBlocks(ULONG ulDataPosFirst, ULONG ulTotalLength,
+ ULONG ulStartBlock, const ULONG *aulBBD, size_t tBBDLen)
+{
+ data_block_type tDataBlock;
+ ULONG ulDataPos, ulOffset, ulIndex;
+ long lToGo;
+ BOOL bSuccess;
+
+ fail(ulTotalLength > (ULONG)LONG_MAX);
+ fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
+ fail(aulBBD == NULL);
+
+ NO_DBG_HEX(ulDataPosFirst);
+ NO_DBG_DEC(ulTotalLength);
+
+ lToGo = (long)ulTotalLength;
+
+ ulDataPos = ulDataPosFirst;
+ ulOffset = ulDataPosFirst;
+ for (ulIndex = ulStartBlock;
+ ulIndex != END_OF_CHAIN && lToGo > 0;
+ ulIndex = aulBBD[ulIndex]) {
+ if (ulIndex == UNUSED_BLOCK || ulIndex >= (ULONG)tBBDLen) {
+ DBG_DEC(ulIndex);
+ DBG_DEC(tBBDLen);
+ return FALSE;
+ }
+ if (ulOffset >= BIG_BLOCK_SIZE) {
+ ulOffset -= BIG_BLOCK_SIZE;
+ continue;
+ }
+ tDataBlock.ulFileOffset =
+ (ulIndex + 1) * BIG_BLOCK_SIZE + ulOffset;
+ tDataBlock.ulDataPos = ulDataPos;
+ tDataBlock.ulLength = min(BIG_BLOCK_SIZE - ulOffset,
+ (ULONG)lToGo);
+ fail(tDataBlock.ulLength > BIG_BLOCK_SIZE);
+ ulOffset = 0;
+ if (!bAdd2DataBlockList(&tDataBlock)) {
+ DBG_HEX(tDataBlock.ulFileOffset);
+ DBG_HEX(tDataBlock.ulDataPos);
+ DBG_DEC(tDataBlock.ulLength);
+ return FALSE;
+ }
+ ulDataPos += tDataBlock.ulLength;
+ lToGo -= (long)tDataBlock.ulLength;
+ }
+ bSuccess = lToGo == 0 ||
+ (ulTotalLength == (ULONG)LONG_MAX && ulIndex == END_OF_CHAIN);
+ DBG_DEC_C(!bSuccess, lToGo);
+ DBG_DEC_C(!bSuccess, ulTotalLength);
+ DBG_DEC_C(!bSuccess, ulIndex);
+ return bSuccess;
+} /* end of bAddDataBlocks */
+
+/*
+ * bGet6DocumentData - make a list of the data blocks of Word 6/7 files
+ *
+ * Code for "fast saved" files.
+ *
+ * Returns TRUE when successful, otherwise FALSE
+ */
+BOOL
+bGet6DocumentData(FILE *pFile, ULONG ulStartBlock,
+ const ULONG *aulBBD, size_t tBBDLen, const UCHAR *aucHeader)
+{
+ UCHAR *aucBuffer;
+ ULONG ulBeginTextInfo, ulOffset, ulTotLength;
+ size_t tTextInfoLen;
+ int iIndex, iOff, iType, iLen, iPieces;
+
+ DBG_MSG("bGet6DocumentData");
+
+ fail(pFile == NULL);
+ fail(aulBBD == NULL);
+ fail(aucHeader == NULL);
+
+ ulBeginTextInfo = ulGetLong(0x160, aucHeader);
+ DBG_HEX(ulBeginTextInfo);
+ tTextInfoLen = (size_t)ulGetLong(0x164, aucHeader);
+ DBG_DEC(tTextInfoLen);
+
+ aucBuffer = xmalloc(tTextInfoLen);
+ if (!bReadBuffer(pFile, ulStartBlock,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucBuffer, ulBeginTextInfo, tTextInfoLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return FALSE;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tTextInfoLen);
+
+ iOff = 0;
+ while (iOff < (int)tTextInfoLen) {
+ iType = (int)ucGetByte(iOff, aucBuffer);
+ iOff++;
+ if (iType == 0) {
+ iOff++;
+ continue;
+ }
+ iLen = (int)usGetWord(iOff, aucBuffer);
+ iOff += 2;
+ if (iType == 1) {
+ iOff += iLen;
+ continue;
+ }
+ if (iType != 2) {
+ werr(0, "Unknown type of 'fastsaved' format");
+ aucBuffer = xfree(aucBuffer);
+ return FALSE;
+ }
+ /* Type 2 */
+ NO_DBG_DEC(iLen);
+ iOff += 2;
+ iPieces = (iLen - 4) / 12;
+ DBG_DEC(iPieces);
+ for (iIndex = 0; iIndex < iPieces; iIndex++) {
+ ulOffset = ulGetLong(
+ iOff + (iPieces + 1) * 4 + iIndex * 8 + 2,
+ aucBuffer);
+ ulTotLength = ulGetLong(iOff + (iIndex + 1) * 4,
+ aucBuffer) -
+ ulGetLong(iOff + iIndex * 4,
+ aucBuffer);
+ if (!bAddDataBlocks(ulOffset, ulTotLength,
+ ulStartBlock,
+ aulBBD, tBBDLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return FALSE;
+ }
+ }
+ break;
+ }
+ aucBuffer = xfree(aucBuffer);
+ return TRUE;
+} /* end of bGet6DocumentData */
diff --git a/sys/src/cmd/aux/antiword/findtext.c b/sys/src/cmd/aux/antiword/findtext.c
new file mode 100755
index 000000000..20724a5e7
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/findtext.c
@@ -0,0 +1,289 @@
+/*
+ * findtext.c
+ * Copyright (C) 1998-2004 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Find the blocks that contain the text of MS Word files
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "antiword.h"
+
+
+/*
+ * bAddTextBlocks - Add the blocks to the text block list
+ *
+ * Returns TRUE when successful, FALSE if not
+ */
+BOOL
+bAddTextBlocks(ULONG ulCharPosFirst, ULONG ulTotalLength,
+ BOOL bUsesUnicode, USHORT usPropMod,
+ ULONG ulStartBlock, const ULONG *aulBBD, size_t tBBDLen)
+{
+ text_block_type tTextBlock;
+ ULONG ulCharPos, ulOffset, ulIndex;
+ long lToGo;
+
+ fail(ulTotalLength > (ULONG)LONG_MAX / 2);
+ fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
+ fail(aulBBD == NULL);
+
+ NO_DBG_HEX(ulCharPosFirst);
+ NO_DBG_DEC(ulTotalLength);
+
+ if (bUsesUnicode) {
+ /* One character equals two bytes */
+ NO_DBG_MSG("Uses Unicode");
+ lToGo = (long)ulTotalLength * 2;
+ } else {
+ /* One character equals one byte */
+ NO_DBG_MSG("Uses ASCII");
+ lToGo = (long)ulTotalLength;
+ }
+
+ ulCharPos = ulCharPosFirst;
+ ulOffset = ulCharPosFirst;
+ for (ulIndex = ulStartBlock;
+ ulIndex != END_OF_CHAIN && lToGo > 0;
+ ulIndex = aulBBD[ulIndex]) {
+ if (ulIndex >= (ULONG)tBBDLen) {
+ DBG_DEC(ulIndex);
+ DBG_DEC(tBBDLen);
+ werr(1, "The Big Block Depot is damaged");
+ }
+ if (ulOffset >= BIG_BLOCK_SIZE) {
+ ulOffset -= BIG_BLOCK_SIZE;
+ continue;
+ }
+ tTextBlock.ulFileOffset =
+ (ulIndex + 1) * BIG_BLOCK_SIZE + ulOffset;
+ tTextBlock.ulCharPos = ulCharPos;
+ tTextBlock.ulLength = min(BIG_BLOCK_SIZE - ulOffset,
+ (ULONG)lToGo);
+ tTextBlock.bUsesUnicode = bUsesUnicode;
+ tTextBlock.usPropMod = usPropMod;
+ ulOffset = 0;
+ if (!bAdd2TextBlockList(&tTextBlock)) {
+ DBG_HEX(tTextBlock.ulFileOffset);
+ DBG_HEX(tTextBlock.ulCharPos);
+ DBG_DEC(tTextBlock.ulLength);
+ DBG_DEC(tTextBlock.bUsesUnicode);
+ DBG_DEC(tTextBlock.usPropMod);
+ return FALSE;
+ }
+ ulCharPos += tTextBlock.ulLength;
+ lToGo -= (long)tTextBlock.ulLength;
+ }
+ DBG_DEC_C(lToGo != 0, lToGo);
+ return lToGo == 0;
+} /* end of bAddTextBlocks */
+
+/*
+ * bGet6DocumentText - make a list of the text blocks of Word 6/7 files
+ *
+ * Code for "fast saved" files.
+ *
+ * Returns TRUE when successful, FALSE if not
+ */
+BOOL
+bGet6DocumentText(FILE *pFile, BOOL bUsesUnicode, ULONG ulStartBlock,
+ const ULONG *aulBBD, size_t tBBDLen, const UCHAR *aucHeader)
+{
+ UCHAR *aucBuffer;
+ ULONG ulBeginTextInfo, ulTextOffset, ulTotLength;
+ size_t tTextInfoLen;
+ int iIndex, iType, iOff, iLen, iPieces;
+ USHORT usPropMod;
+
+ DBG_MSG("bGet6DocumentText");
+
+ fail(pFile == NULL);
+ fail(aulBBD == NULL);
+ fail(aucHeader == NULL);
+
+ ulBeginTextInfo = ulGetLong(0x160, aucHeader); /* fcClx */
+ DBG_HEX(ulBeginTextInfo);
+ tTextInfoLen = (size_t)ulGetLong(0x164, aucHeader); /* lcbClx */
+ DBG_DEC(tTextInfoLen);
+
+ aucBuffer = xmalloc(tTextInfoLen);
+ if (!bReadBuffer(pFile, ulStartBlock,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucBuffer, ulBeginTextInfo, tTextInfoLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return FALSE;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tTextInfoLen);
+
+ iOff = 0;
+ while ((size_t)iOff < tTextInfoLen) {
+ iType = (int)ucGetByte(iOff, aucBuffer);
+ iOff++;
+ if (iType == 0) {
+ DBG_FIXME();
+ iOff++;
+ continue;
+ }
+ if (iType == 1) {
+ iLen = (int)usGetWord(iOff, aucBuffer);
+ vAdd2PropModList(aucBuffer + iOff);
+ iOff += iLen + 2;
+ continue;
+ }
+ if (iType != 2) {
+ werr(0, "Unknown type of 'fastsaved' format");
+ aucBuffer = xfree(aucBuffer);
+ return FALSE;
+ }
+ /* Type 2 */
+ iLen = (int)usGetWord(iOff, aucBuffer);
+ NO_DBG_DEC(iLen);
+ iOff += 4;
+ iPieces = (iLen - 4) / 12;
+ DBG_DEC(iPieces);
+ for (iIndex = 0; iIndex < iPieces; iIndex++) {
+ ulTextOffset = ulGetLong(
+ iOff + (iPieces + 1) * 4 + iIndex * 8 + 2,
+ aucBuffer);
+ usPropMod = usGetWord(
+ iOff + (iPieces + 1) * 4 + iIndex * 8 + 6,
+ aucBuffer);
+ ulTotLength = ulGetLong(iOff + (iIndex + 1) * 4,
+ aucBuffer) -
+ ulGetLong(iOff + iIndex * 4,
+ aucBuffer);
+ NO_DBG_HEX_C(usPropMod != 0, usPropMod);
+ if (!bAddTextBlocks(ulTextOffset, ulTotLength,
+ bUsesUnicode, usPropMod,
+ ulStartBlock,
+ aulBBD, tBBDLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return FALSE;
+ }
+ }
+ break;
+ }
+ aucBuffer = xfree(aucBuffer);
+ return TRUE;
+} /* end of bGet6DocumentText */
+
+/*
+ * bGet8DocumentText - make a list of the text blocks of Word 8/97 files
+ *
+ * Returns TRUE when successful, FALSE if not
+ */
+BOOL
+bGet8DocumentText(FILE *pFile, const pps_info_type *pPPS,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ const UCHAR *aucHeader)
+{
+ const ULONG *aulBlockDepot;
+ UCHAR *aucBuffer;
+ ULONG ulTextOffset, ulBeginTextInfo;
+ ULONG ulTotLength, ulLen;
+ long lIndex, lPieces, lOff;
+ size_t tTextInfoLen, tBlockDepotLen, tBlockSize;
+ int iType, iLen;
+ BOOL bUsesUnicode;
+ USHORT usPropMod;
+
+ DBG_MSG("bGet8DocumentText");
+
+ fail(pFile == NULL || pPPS == NULL);
+ fail(aulBBD == NULL || aulSBD == NULL);
+ fail(aucHeader == NULL);
+
+ ulBeginTextInfo = ulGetLong(0x1a2, aucHeader); /* fcClx */
+ DBG_HEX(ulBeginTextInfo);
+ tTextInfoLen = (size_t)ulGetLong(0x1a6, aucHeader); /* lcbClx */
+ DBG_DEC(tTextInfoLen);
+
+ DBG_DEC(pPPS->tTable.ulSB);
+ DBG_HEX(pPPS->tTable.ulSize);
+ if (pPPS->tTable.ulSize == 0) {
+ return FALSE;
+ }
+
+ if (pPPS->tTable.ulSize < MIN_SIZE_FOR_BBD_USE) {
+ /* Use the Small Block Depot */
+ aulBlockDepot = aulSBD;
+ tBlockDepotLen = tSBDLen;
+ tBlockSize = SMALL_BLOCK_SIZE;
+ } else {
+ /* Use the Big Block Depot */
+ aulBlockDepot = aulBBD;
+ tBlockDepotLen = tBBDLen;
+ tBlockSize = BIG_BLOCK_SIZE;
+ }
+ aucBuffer = xmalloc(tTextInfoLen);
+ if (!bReadBuffer(pFile, pPPS->tTable.ulSB,
+ aulBlockDepot, tBlockDepotLen, tBlockSize,
+ aucBuffer, ulBeginTextInfo, tTextInfoLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return FALSE;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tTextInfoLen);
+
+ lOff = 0;
+ while (lOff < (long)tTextInfoLen) {
+ iType = (int)ucGetByte(lOff, aucBuffer);
+ lOff++;
+ if (iType == 0) {
+ DBG_FIXME();
+ lOff++;
+ continue;
+ }
+ if (iType == 1) {
+ iLen = (int)usGetWord(lOff, aucBuffer);
+ vAdd2PropModList(aucBuffer + lOff);
+ lOff += (long)iLen + 2;
+ continue;
+ }
+ if (iType != 2) {
+ werr(0, "Unknown type of 'fastsaved' format");
+ aucBuffer = xfree(aucBuffer);
+ return FALSE;
+ }
+ /* Type 2 */
+ ulLen = ulGetLong(lOff, aucBuffer);
+ if (ulLen < 4) {
+ DBG_DEC(ulLen);
+ return FALSE;
+ }
+ lOff += 4;
+ lPieces = (long)((ulLen - 4) / 12);
+ DBG_DEC(lPieces);
+ for (lIndex = 0; lIndex < lPieces; lIndex++) {
+ ulTextOffset = ulGetLong(
+ lOff + (lPieces + 1) * 4 + lIndex * 8 + 2,
+ aucBuffer);
+ usPropMod = usGetWord(
+ lOff + (lPieces + 1) * 4 + lIndex * 8 + 6,
+ aucBuffer);
+ ulTotLength = ulGetLong(lOff + (lIndex + 1) * 4,
+ aucBuffer) -
+ ulGetLong(lOff + lIndex * 4,
+ aucBuffer);
+ if ((ulTextOffset & BIT(30)) == 0) {
+ bUsesUnicode = TRUE;
+ } else {
+ bUsesUnicode = FALSE;
+ ulTextOffset &= ~BIT(30);
+ ulTextOffset /= 2;
+ }
+ NO_DBG_HEX_C(usPropMod != 0, usPropMod);
+ if (!bAddTextBlocks(ulTextOffset, ulTotLength,
+ bUsesUnicode, usPropMod,
+ pPPS->tWordDocument.ulSB,
+ aulBBD, tBBDLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return FALSE;
+ }
+ }
+ break;
+ }
+ aucBuffer = xfree(aucBuffer);
+ return TRUE;
+} /* end of bGet8DocumentText */
diff --git a/sys/src/cmd/aux/antiword/fmt_text.c b/sys/src/cmd/aux/antiword/fmt_text.c
new file mode 100755
index 000000000..db211e943
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/fmt_text.c
@@ -0,0 +1,167 @@
+/*
+ * fmt_text.c
+ * Copyright (C) 2004 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Functions to deal with the Formatted Text format
+ *
+ * Based on patches send by: Ofir Reichenberg <ofir@qlusters.com>
+ *
+ * The credit should go to him, but all the bugs are mine.
+ */
+
+#include <string.h>
+#include "antiword.h"
+
+/* The character set */
+static encoding_type eEncoding = encoding_neutral;
+/* Current vertical position information */
+static long lYtopCurr = 0;
+/* Local representation of the non-breaking space */
+static UCHAR ucNbsp = 0;
+
+
+/*
+ * vPrologueFMT - set options and perform the Formatted Text initialization
+ */
+void
+vPrologueFMT(diagram_type *pDiag, const options_type *pOptions)
+{
+ fail(pDiag == NULL);
+ fail(pOptions == NULL);
+
+ eEncoding = pOptions->eEncoding;
+ pDiag->lXleft = 0;
+ pDiag->lYtop = 0;
+ lYtopCurr = 0;
+} /* end of vPrologueFMT */
+
+/*
+ * vPrintFMT - print a Formatted Text string
+ */
+static void
+vPrintFMT(FILE *pFile,
+ const char *szString, size_t tStringLength, USHORT usFontstyle)
+{
+ const UCHAR *pucByte, *pucStart, *pucLast, *pucNonSpace;
+
+ fail(szString == NULL);
+
+ if (szString == NULL || szString[0] == '\0' || tStringLength == 0) {
+ return;
+ }
+
+ if (eEncoding == encoding_utf_8) {
+ fprintf(pFile, "%.*s", (int)tStringLength, szString);
+ return;
+ }
+
+ if (ucNbsp == 0) {
+ ucNbsp = ucGetNbspCharacter();
+ DBG_HEX_C(ucNbsp != 0xa0, ucNbsp);
+ }
+
+ pucStart = (UCHAR *)szString;
+ pucLast = pucStart + tStringLength - 1;
+ pucNonSpace = pucLast;
+ while ((*pucNonSpace == (UCHAR)' ' || *pucNonSpace == ucNbsp) &&
+ pucNonSpace > pucStart) {
+ pucNonSpace--;
+ }
+
+ /* 1: The spaces at the start */
+ pucByte = pucStart;
+ while ((*pucByte == (UCHAR)' ' || *pucByte == ucNbsp) &&
+ pucByte <= pucLast) {
+ (void)putc(' ', pFile);
+ pucByte++;
+ }
+
+ if (pucByte > pucLast) {
+ /* There is no text, just spaces */
+ return;
+ }
+
+ /* 2: Start the *bold*, /italic/ and _underline_ */
+ if (bIsBold(usFontstyle)) {
+ (void)putc('*', pFile);
+ }
+ if (bIsItalic(usFontstyle)) {
+ (void)putc('/', pFile);
+ }
+ if (bIsUnderline(usFontstyle)) {
+ (void)putc('_', pFile);
+ }
+
+ /* 3: The text itself */
+ while (pucByte <= pucNonSpace) {
+ if (*pucByte == ucNbsp) {
+ (void)putc(' ', pFile);
+ } else {
+ (void)putc((char)*pucByte, pFile);
+ }
+ pucByte++;
+ }
+
+ /* 4: End the *bold*, /italic/ and _underline_ */
+ if (bIsUnderline(usFontstyle)) {
+ (void)putc('_', pFile);
+ }
+ if (bIsItalic(usFontstyle)) {
+ (void)putc('/', pFile);
+ }
+ if (bIsBold(usFontstyle)) {
+ (void)putc('*', pFile);
+ }
+
+ /* 5: The spaces at the end */
+ while (pucByte <= pucLast) {
+ (void)putc(' ', pFile);
+ pucByte++;
+ }
+} /* end of vPrintFMT */
+
+/*
+ * vMoveTo - move to the given X,Y coordinates
+ *
+ * Move the current position of the given diagram to its X,Y coordinates,
+ * start on a new page if needed
+ */
+static void
+vMoveTo(diagram_type *pDiag)
+{
+ int iCount, iNbr;
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+
+ if (pDiag->lYtop != lYtopCurr) {
+ iNbr = iDrawUnits2Char(pDiag->lXleft);
+ for (iCount = 0; iCount < iNbr; iCount++) {
+ (void)putc(FILLER_CHAR, pDiag->pOutFile);
+ }
+ lYtopCurr = pDiag->lYtop;
+ }
+} /* end of vMoveTo */
+
+/*
+ * vSubstringFMT - print a sub string
+ */
+void
+vSubstringFMT(diagram_type *pDiag,
+ const char *szString, size_t tStringLength, long lStringWidth,
+ USHORT usFontstyle)
+{
+ fail(pDiag == NULL || szString == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(pDiag->lXleft < 0);
+ fail(tStringLength != strlen(szString));
+
+ if (szString[0] == '\0' || tStringLength == 0) {
+ return;
+ }
+
+ vMoveTo(pDiag);
+ vPrintFMT(pDiag->pOutFile, szString, tStringLength, usFontstyle);
+ pDiag->lXleft += lStringWidth;
+} /* end of vSubstringFMT */
diff --git a/sys/src/cmd/aux/antiword/fontinfo.h b/sys/src/cmd/aux/antiword/fontinfo.h
new file mode 100755
index 000000000..8538dfa5b
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/fontinfo.h
@@ -0,0 +1,2251 @@
+/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT EDIT! */
+static const char *szFontnames[32] = {
+ "Courier",
+ "Courier-Bold",
+ "Courier-Oblique",
+ "Courier-BoldOblique",
+ "Times-Roman",
+ "Times-Bold",
+ "Times-Italic",
+ "Times-BoldItalic",
+ "Helvetica",
+ "Helvetica-Bold",
+ "Helvetica-Oblique",
+ "Helvetica-BoldOblique",
+ "Palatino-Roman",
+ "Palatino-Bold",
+ "Palatino-Italic",
+ "Palatino-BoldItalic",
+ "Helvetica-Narrow",
+ "Helvetica-Narrow-Bold",
+ "Helvetica-Narrow-Oblique",
+ "Helvetica-Narrow-BoldOblique",
+ "Bookman-Light",
+ "Bookman-Demi",
+ "Bookman-LightItalic",
+ "Bookman-DemiItalic",
+ "AvantGarde-Book",
+ "AvantGarde-Demi",
+ "AvantGarde-BookOblique",
+ "AvantGarde-DemiOblique",
+ "NewCenturySchlbk-Roman",
+ "NewCenturySchlbk-Bold",
+ "NewCenturySchlbk-Italic",
+ "NewCenturySchlbk-BoldItalic",
+};
+static unsigned short ausCharacterWidths1[32][256] = {
+ { /* Courier */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 40 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 48 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 56 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 64 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 72 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 80 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 88 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 96 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 104 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 112 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 120 */ 600, 600, 600, 600, 600, 600, 600, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 600, 600, 600, 600,
+ /* 144 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 152 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 160 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 168 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 176 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 184 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 192 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 200 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 208 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 216 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 224 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 232 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 240 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 248 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ },
+ { /* Courier-Bold */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 40 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 48 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 56 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 64 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 72 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 80 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 88 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 96 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 104 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 112 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 120 */ 600, 600, 600, 600, 600, 600, 600, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 600, 600, 600, 600,
+ /* 144 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 152 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 160 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 168 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 176 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 184 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 192 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 200 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 208 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 216 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 224 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 232 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 240 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 248 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ },
+ { /* Courier-Oblique */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 40 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 48 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 56 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 64 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 72 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 80 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 88 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 96 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 104 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 112 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 120 */ 600, 600, 600, 600, 600, 600, 600, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 600, 600, 600, 600,
+ /* 144 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 152 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 160 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 168 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 176 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 184 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 192 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 200 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 208 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 216 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 224 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 232 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 240 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 248 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ },
+ { /* Courier-BoldOblique */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 40 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 48 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 56 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 64 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 72 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 80 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 88 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 96 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 104 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 112 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 120 */ 600, 600, 600, 600, 600, 600, 600, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 600, 600, 600, 600,
+ /* 144 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 152 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 160 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 168 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 176 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 184 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 192 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 200 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 208 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 216 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 224 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 232 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 240 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 248 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ },
+ { /* Times-Roman */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 250, 333, 408, 500, 500, 833, 778, 333,
+ /* 40 */ 333, 333, 500, 564, 250, 333, 250, 278,
+ /* 48 */ 500, 500, 500, 500, 500, 500, 500, 500,
+ /* 56 */ 500, 500, 278, 278, 564, 564, 564, 444,
+ /* 64 */ 921, 722, 667, 667, 722, 611, 556, 722,
+ /* 72 */ 722, 333, 389, 722, 611, 889, 722, 722,
+ /* 80 */ 556, 722, 667, 556, 611, 722, 722, 944,
+ /* 88 */ 722, 722, 611, 333, 278, 333, 469, 500,
+ /* 96 */ 333, 444, 500, 444, 500, 444, 333, 500,
+ /* 104 */ 500, 278, 278, 500, 278, 778, 500, 500,
+ /* 112 */ 500, 500, 333, 389, 278, 500, 500, 722,
+ /* 120 */ 500, 500, 444, 480, 200, 480, 541, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 980, 1000, 350,
+ /* 144 */ 333, 333, 333, 333, 444, 444, 444, 500,
+ /* 152 */ 1000, 564, 889, 722, 500, 500, 556, 556,
+ /* 160 */ 250, 333, 500, 500, 500, 500, 200, 500,
+ /* 168 */ 333, 760, 276, 500, 564, 333, 760, 333,
+ /* 176 */ 400, 564, 300, 300, 333, 500, 453, 250,
+ /* 184 */ 333, 300, 310, 500, 750, 750, 750, 444,
+ /* 192 */ 722, 722, 722, 722, 722, 722, 889, 667,
+ /* 200 */ 611, 611, 611, 611, 333, 333, 333, 333,
+ /* 208 */ 722, 722, 722, 722, 722, 722, 722, 564,
+ /* 216 */ 722, 722, 722, 722, 722, 722, 556, 500,
+ /* 224 */ 444, 444, 444, 444, 444, 444, 667, 444,
+ /* 232 */ 444, 444, 444, 444, 278, 278, 278, 278,
+ /* 240 */ 500, 500, 500, 500, 500, 500, 500, 564,
+ /* 248 */ 500, 500, 500, 500, 500, 500, 500, 500,
+ },
+ { /* Times-Bold */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 250, 333, 555, 500, 500, 1000, 833, 333,
+ /* 40 */ 333, 333, 500, 570, 250, 333, 250, 278,
+ /* 48 */ 500, 500, 500, 500, 500, 500, 500, 500,
+ /* 56 */ 500, 500, 333, 333, 570, 570, 570, 500,
+ /* 64 */ 930, 722, 667, 722, 722, 667, 611, 778,
+ /* 72 */ 778, 389, 500, 778, 667, 944, 722, 778,
+ /* 80 */ 611, 778, 722, 556, 667, 722, 722, 1000,
+ /* 88 */ 722, 722, 667, 333, 278, 333, 581, 500,
+ /* 96 */ 333, 500, 556, 444, 556, 444, 333, 500,
+ /* 104 */ 556, 278, 333, 556, 278, 833, 556, 500,
+ /* 112 */ 556, 556, 444, 389, 333, 556, 500, 722,
+ /* 120 */ 500, 500, 444, 394, 220, 394, 520, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 1000, 1000, 350,
+ /* 144 */ 333, 333, 333, 333, 500, 500, 500, 500,
+ /* 152 */ 1000, 570, 1000, 722, 500, 500, 556, 556,
+ /* 160 */ 250, 333, 500, 500, 500, 500, 220, 500,
+ /* 168 */ 333, 747, 300, 500, 570, 333, 747, 333,
+ /* 176 */ 400, 570, 300, 300, 333, 556, 540, 250,
+ /* 184 */ 333, 300, 330, 500, 750, 750, 750, 500,
+ /* 192 */ 722, 722, 722, 722, 722, 722, 1000, 722,
+ /* 200 */ 667, 667, 667, 667, 389, 389, 389, 389,
+ /* 208 */ 722, 722, 778, 778, 778, 778, 778, 570,
+ /* 216 */ 778, 722, 722, 722, 722, 722, 611, 556,
+ /* 224 */ 500, 500, 500, 500, 500, 500, 722, 444,
+ /* 232 */ 444, 444, 444, 444, 278, 278, 278, 278,
+ /* 240 */ 500, 556, 500, 500, 500, 500, 500, 570,
+ /* 248 */ 500, 556, 556, 556, 556, 500, 556, 500,
+ },
+ { /* Times-Italic */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 250, 333, 420, 500, 500, 833, 778, 333,
+ /* 40 */ 333, 333, 500, 675, 250, 333, 250, 278,
+ /* 48 */ 500, 500, 500, 500, 500, 500, 500, 500,
+ /* 56 */ 500, 500, 333, 333, 675, 675, 675, 500,
+ /* 64 */ 920, 611, 611, 667, 722, 611, 611, 722,
+ /* 72 */ 722, 333, 444, 667, 556, 833, 667, 722,
+ /* 80 */ 611, 722, 611, 500, 556, 722, 611, 833,
+ /* 88 */ 611, 556, 556, 389, 278, 389, 422, 500,
+ /* 96 */ 333, 500, 500, 444, 500, 444, 278, 500,
+ /* 104 */ 500, 278, 278, 444, 278, 722, 500, 500,
+ /* 112 */ 500, 500, 389, 389, 278, 500, 444, 667,
+ /* 120 */ 444, 444, 389, 400, 275, 400, 541, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 889, 980, 1000, 350,
+ /* 144 */ 333, 333, 333, 333, 556, 556, 556, 500,
+ /* 152 */ 889, 675, 944, 667, 500, 500, 500, 500,
+ /* 160 */ 250, 389, 500, 500, 500, 500, 275, 500,
+ /* 168 */ 333, 760, 276, 500, 675, 333, 760, 333,
+ /* 176 */ 400, 675, 300, 300, 333, 500, 523, 250,
+ /* 184 */ 333, 300, 310, 500, 750, 750, 750, 500,
+ /* 192 */ 611, 611, 611, 611, 611, 611, 889, 667,
+ /* 200 */ 611, 611, 611, 611, 333, 333, 333, 333,
+ /* 208 */ 722, 667, 722, 722, 722, 722, 722, 675,
+ /* 216 */ 722, 722, 722, 722, 722, 556, 611, 500,
+ /* 224 */ 500, 500, 500, 500, 500, 500, 667, 444,
+ /* 232 */ 444, 444, 444, 444, 278, 278, 278, 278,
+ /* 240 */ 500, 500, 500, 500, 500, 500, 500, 675,
+ /* 248 */ 500, 500, 500, 500, 500, 444, 500, 444,
+ },
+ { /* Times-BoldItalic */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 250, 389, 555, 500, 500, 833, 778, 333,
+ /* 40 */ 333, 333, 500, 570, 250, 333, 250, 278,
+ /* 48 */ 500, 500, 500, 500, 500, 500, 500, 500,
+ /* 56 */ 500, 500, 333, 333, 570, 570, 570, 500,
+ /* 64 */ 832, 667, 667, 667, 722, 667, 667, 722,
+ /* 72 */ 778, 389, 500, 667, 611, 889, 722, 722,
+ /* 80 */ 611, 722, 667, 556, 611, 722, 667, 889,
+ /* 88 */ 667, 611, 611, 333, 278, 333, 570, 500,
+ /* 96 */ 333, 500, 500, 444, 500, 444, 333, 500,
+ /* 104 */ 556, 278, 278, 500, 278, 778, 556, 500,
+ /* 112 */ 500, 500, 389, 389, 278, 556, 444, 667,
+ /* 120 */ 500, 444, 389, 348, 220, 348, 570, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 1000, 1000, 350,
+ /* 144 */ 333, 333, 333, 333, 500, 500, 500, 500,
+ /* 152 */ 1000, 606, 944, 722, 500, 500, 556, 556,
+ /* 160 */ 250, 389, 500, 500, 500, 500, 220, 500,
+ /* 168 */ 333, 747, 266, 500, 606, 333, 747, 333,
+ /* 176 */ 400, 570, 300, 300, 333, 576, 500, 250,
+ /* 184 */ 333, 300, 300, 500, 750, 750, 750, 500,
+ /* 192 */ 667, 667, 667, 667, 667, 667, 944, 667,
+ /* 200 */ 667, 667, 667, 667, 389, 389, 389, 389,
+ /* 208 */ 722, 722, 722, 722, 722, 722, 722, 570,
+ /* 216 */ 722, 722, 722, 722, 722, 611, 611, 500,
+ /* 224 */ 500, 500, 500, 500, 500, 500, 722, 444,
+ /* 232 */ 444, 444, 444, 444, 278, 278, 278, 278,
+ /* 240 */ 500, 556, 500, 500, 500, 500, 500, 570,
+ /* 248 */ 500, 556, 556, 556, 556, 444, 500, 444,
+ },
+ { /* Helvetica */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 278, 278, 355, 556, 556, 889, 667, 221,
+ /* 40 */ 333, 333, 389, 584, 278, 333, 278, 278,
+ /* 48 */ 556, 556, 556, 556, 556, 556, 556, 556,
+ /* 56 */ 556, 556, 278, 278, 584, 584, 584, 556,
+ /* 64 */ 1015, 667, 667, 722, 722, 667, 611, 778,
+ /* 72 */ 722, 278, 500, 667, 556, 833, 722, 778,
+ /* 80 */ 667, 778, 722, 667, 611, 722, 667, 944,
+ /* 88 */ 667, 667, 611, 278, 278, 278, 469, 556,
+ /* 96 */ 222, 556, 556, 500, 556, 556, 278, 556,
+ /* 104 */ 556, 222, 222, 500, 222, 833, 556, 556,
+ /* 112 */ 556, 556, 333, 500, 278, 556, 500, 722,
+ /* 120 */ 500, 500, 500, 334, 260, 334, 584, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 1000, 1000, 350,
+ /* 144 */ 222, 221, 333, 333, 333, 333, 333, 556,
+ /* 152 */ 1000, 584, 1000, 944, 556, 556, 500, 500,
+ /* 160 */ 278, 333, 556, 556, 556, 556, 260, 556,
+ /* 168 */ 333, 737, 370, 556, 584, 333, 737, 333,
+ /* 176 */ 606, 584, 351, 351, 333, 556, 537, 278,
+ /* 184 */ 333, 351, 365, 556, 869, 869, 869, 611,
+ /* 192 */ 667, 667, 667, 667, 667, 667, 1000, 722,
+ /* 200 */ 667, 667, 667, 667, 278, 278, 278, 278,
+ /* 208 */ 722, 722, 778, 778, 778, 778, 778, 584,
+ /* 216 */ 778, 722, 722, 722, 722, 666, 666, 611,
+ /* 224 */ 556, 556, 556, 556, 556, 556, 889, 500,
+ /* 232 */ 556, 556, 556, 556, 278, 278, 278, 278,
+ /* 240 */ 556, 556, 556, 556, 556, 556, 556, 584,
+ /* 248 */ 611, 556, 556, 556, 556, 500, 555, 500,
+ },
+ { /* Helvetica-Bold */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 278, 333, 474, 556, 556, 889, 722, 278,
+ /* 40 */ 333, 333, 389, 584, 278, 333, 278, 278,
+ /* 48 */ 556, 556, 556, 556, 556, 556, 556, 556,
+ /* 56 */ 556, 556, 333, 333, 584, 584, 584, 611,
+ /* 64 */ 975, 722, 722, 722, 722, 667, 611, 778,
+ /* 72 */ 722, 278, 556, 722, 611, 833, 722, 778,
+ /* 80 */ 667, 778, 722, 667, 611, 722, 667, 944,
+ /* 88 */ 667, 667, 611, 333, 278, 333, 584, 556,
+ /* 96 */ 278, 556, 611, 556, 611, 556, 333, 611,
+ /* 104 */ 611, 278, 278, 556, 278, 889, 611, 611,
+ /* 112 */ 611, 611, 389, 556, 333, 611, 556, 778,
+ /* 120 */ 556, 556, 500, 389, 280, 389, 584, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 1000, 1000, 350,
+ /* 144 */ 278, 278, 333, 333, 500, 500, 500, 556,
+ /* 152 */ 1000, 584, 1000, 944, 556, 556, 611, 611,
+ /* 160 */ 278, 333, 556, 556, 556, 556, 280, 556,
+ /* 168 */ 333, 737, 370, 556, 584, 333, 737, 333,
+ /* 176 */ 606, 584, 351, 351, 333, 611, 556, 278,
+ /* 184 */ 333, 351, 365, 556, 869, 869, 869, 611,
+ /* 192 */ 722, 722, 722, 722, 722, 722, 1000, 722,
+ /* 200 */ 667, 667, 667, 667, 278, 278, 278, 278,
+ /* 208 */ 722, 722, 778, 778, 778, 778, 778, 584,
+ /* 216 */ 778, 722, 722, 722, 722, 667, 667, 611,
+ /* 224 */ 556, 556, 556, 556, 556, 556, 889, 556,
+ /* 232 */ 556, 556, 556, 556, 278, 278, 278, 278,
+ /* 240 */ 611, 611, 611, 611, 611, 611, 611, 584,
+ /* 248 */ 611, 611, 611, 611, 611, 556, 611, 556,
+ },
+ { /* Helvetica-Oblique */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 278, 278, 355, 556, 556, 889, 667, 222,
+ /* 40 */ 333, 333, 389, 584, 278, 333, 278, 278,
+ /* 48 */ 556, 556, 556, 556, 556, 556, 556, 556,
+ /* 56 */ 556, 556, 278, 278, 584, 584, 584, 556,
+ /* 64 */ 1015, 667, 667, 722, 722, 667, 611, 778,
+ /* 72 */ 722, 278, 500, 667, 556, 833, 722, 778,
+ /* 80 */ 667, 778, 722, 667, 611, 722, 667, 944,
+ /* 88 */ 667, 667, 611, 278, 278, 278, 469, 556,
+ /* 96 */ 222, 556, 556, 500, 556, 556, 278, 556,
+ /* 104 */ 556, 222, 222, 500, 222, 833, 556, 556,
+ /* 112 */ 556, 556, 333, 500, 278, 556, 500, 722,
+ /* 120 */ 500, 500, 500, 334, 260, 334, 584, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 1000, 1000, 350,
+ /* 144 */ 222, 222, 333, 333, 333, 333, 333, 556,
+ /* 152 */ 1000, 584, 1000, 944, 556, 556, 500, 500,
+ /* 160 */ 278, 333, 556, 556, 556, 556, 260, 556,
+ /* 168 */ 333, 737, 370, 556, 584, 333, 737, 333,
+ /* 176 */ 606, 584, 390, 390, 333, 556, 537, 278,
+ /* 184 */ 333, 390, 365, 556, 947, 947, 947, 611,
+ /* 192 */ 667, 667, 667, 667, 667, 667, 1000, 722,
+ /* 200 */ 667, 667, 667, 667, 278, 278, 278, 278,
+ /* 208 */ 722, 722, 778, 778, 778, 778, 778, 584,
+ /* 216 */ 778, 722, 722, 722, 722, 667, 667, 611,
+ /* 224 */ 556, 556, 556, 556, 556, 556, 889, 500,
+ /* 232 */ 556, 556, 556, 556, 278, 278, 278, 278,
+ /* 240 */ 556, 556, 556, 556, 556, 556, 556, 584,
+ /* 248 */ 611, 556, 556, 556, 556, 500, 556, 500,
+ },
+ { /* Helvetica-BoldOblique */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 278, 333, 474, 556, 556, 889, 722, 278,
+ /* 40 */ 333, 333, 389, 584, 278, 333, 278, 278,
+ /* 48 */ 556, 556, 556, 556, 556, 556, 556, 556,
+ /* 56 */ 556, 556, 333, 333, 584, 584, 584, 611,
+ /* 64 */ 975, 722, 722, 722, 722, 667, 611, 778,
+ /* 72 */ 722, 278, 556, 722, 611, 833, 722, 778,
+ /* 80 */ 667, 778, 722, 667, 611, 722, 667, 944,
+ /* 88 */ 667, 667, 611, 333, 278, 333, 584, 556,
+ /* 96 */ 278, 556, 611, 556, 611, 556, 333, 611,
+ /* 104 */ 611, 278, 278, 556, 278, 889, 611, 611,
+ /* 112 */ 611, 611, 389, 556, 333, 611, 556, 778,
+ /* 120 */ 556, 556, 500, 389, 280, 389, 584, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 1000, 1000, 350,
+ /* 144 */ 278, 278, 333, 333, 500, 500, 500, 556,
+ /* 152 */ 1000, 584, 1000, 944, 556, 556, 611, 611,
+ /* 160 */ 278, 333, 556, 556, 556, 556, 280, 556,
+ /* 168 */ 333, 737, 370, 556, 584, 333, 737, 333,
+ /* 176 */ 606, 584, 444, 444, 333, 611, 556, 278,
+ /* 184 */ 333, 444, 365, 556, 1055, 1055, 1055, 611,
+ /* 192 */ 722, 722, 722, 722, 722, 722, 1000, 722,
+ /* 200 */ 667, 667, 667, 667, 278, 278, 278, 278,
+ /* 208 */ 722, 722, 778, 778, 778, 778, 778, 584,
+ /* 216 */ 778, 722, 722, 722, 722, 667, 667, 611,
+ /* 224 */ 556, 556, 556, 556, 556, 556, 889, 556,
+ /* 232 */ 556, 556, 556, 556, 278, 278, 278, 278,
+ /* 240 */ 611, 611, 611, 611, 611, 611, 611, 584,
+ /* 248 */ 611, 611, 611, 611, 611, 556, 611, 556,
+ },
+ { /* Palatino-Roman */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 250, 278, 371, 500, 500, 840, 778, 278,
+ /* 40 */ 333, 333, 389, 606, 250, 333, 250, 606,
+ /* 48 */ 500, 500, 500, 500, 500, 500, 500, 500,
+ /* 56 */ 500, 500, 250, 250, 606, 606, 606, 444,
+ /* 64 */ 747, 778, 611, 709, 774, 611, 556, 763,
+ /* 72 */ 832, 337, 333, 726, 611, 946, 831, 786,
+ /* 80 */ 604, 786, 668, 525, 613, 778, 722, 1000,
+ /* 88 */ 667, 667, 667, 333, 606, 333, 606, 500,
+ /* 96 */ 278, 500, 553, 444, 611, 479, 333, 556,
+ /* 104 */ 582, 291, 234, 556, 291, 883, 582, 546,
+ /* 112 */ 601, 560, 395, 424, 326, 603, 565, 834,
+ /* 120 */ 516, 556, 500, 333, 606, 333, 606, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 979, 1144, 606,
+ /* 144 */ 278, 278, 331, 331, 500, 500, 500, 500,
+ /* 152 */ 1000, 606, 998, 827, 500, 500, 605, 608,
+ /* 160 */ 250, 278, 500, 500, 500, 500, 606, 500,
+ /* 168 */ 333, 747, 333, 500, 606, 333, 747, 333,
+ /* 176 */ 400, 606, 300, 300, 333, 603, 628, 250,
+ /* 184 */ 333, 300, 333, 500, 750, 750, 750, 444,
+ /* 192 */ 778, 778, 778, 778, 778, 778, 944, 709,
+ /* 200 */ 611, 611, 611, 611, 337, 337, 337, 337,
+ /* 208 */ 774, 831, 786, 786, 786, 786, 786, 606,
+ /* 216 */ 833, 778, 778, 778, 778, 667, 604, 556,
+ /* 224 */ 500, 500, 500, 500, 500, 500, 758, 444,
+ /* 232 */ 479, 479, 479, 479, 287, 287, 287, 287,
+ /* 240 */ 546, 582, 546, 546, 546, 546, 546, 606,
+ /* 248 */ 556, 603, 603, 603, 603, 556, 601, 556,
+ },
+ { /* Palatino-Bold */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 250, 278, 402, 500, 500, 889, 833, 278,
+ /* 40 */ 333, 333, 444, 606, 250, 333, 250, 296,
+ /* 48 */ 500, 500, 500, 500, 500, 500, 500, 500,
+ /* 56 */ 500, 500, 250, 250, 606, 606, 606, 444,
+ /* 64 */ 747, 778, 667, 722, 833, 611, 556, 833,
+ /* 72 */ 833, 389, 389, 778, 611, 1000, 833, 833,
+ /* 80 */ 611, 833, 722, 611, 667, 778, 778, 1000,
+ /* 88 */ 667, 667, 667, 333, 606, 333, 606, 500,
+ /* 96 */ 278, 500, 611, 444, 611, 500, 389, 556,
+ /* 104 */ 611, 333, 333, 611, 333, 889, 611, 556,
+ /* 112 */ 611, 611, 389, 444, 333, 611, 556, 833,
+ /* 120 */ 500, 556, 500, 310, 606, 310, 606, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 998, 1000, 606,
+ /* 144 */ 278, 278, 389, 389, 500, 500, 500, 500,
+ /* 152 */ 1000, 606, 1000, 833, 500, 500, 611, 611,
+ /* 160 */ 250, 278, 500, 500, 500, 500, 606, 500,
+ /* 168 */ 333, 747, 438, 500, 606, 333, 747, 333,
+ /* 176 */ 400, 606, 300, 300, 333, 611, 641, 250,
+ /* 184 */ 333, 300, 488, 500, 750, 750, 750, 444,
+ /* 192 */ 778, 778, 778, 778, 778, 778, 1000, 722,
+ /* 200 */ 611, 611, 611, 611, 389, 389, 389, 389,
+ /* 208 */ 833, 833, 833, 833, 833, 833, 833, 606,
+ /* 216 */ 833, 778, 778, 778, 778, 667, 611, 611,
+ /* 224 */ 500, 500, 500, 500, 500, 500, 778, 444,
+ /* 232 */ 500, 500, 500, 500, 333, 333, 333, 333,
+ /* 240 */ 556, 611, 556, 556, 556, 556, 556, 606,
+ /* 248 */ 556, 611, 611, 611, 611, 556, 611, 556,
+ },
+ { /* Palatino-Italic */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 250, 333, 500, 500, 500, 889, 778, 278,
+ /* 40 */ 333, 333, 389, 606, 250, 333, 250, 296,
+ /* 48 */ 500, 500, 500, 500, 500, 500, 500, 500,
+ /* 56 */ 500, 500, 250, 250, 606, 606, 606, 500,
+ /* 64 */ 747, 722, 611, 667, 778, 611, 556, 722,
+ /* 72 */ 778, 333, 333, 667, 556, 944, 778, 778,
+ /* 80 */ 611, 778, 667, 556, 611, 778, 722, 944,
+ /* 88 */ 722, 667, 667, 333, 606, 333, 606, 500,
+ /* 96 */ 278, 444, 463, 407, 500, 389, 278, 500,
+ /* 104 */ 500, 278, 278, 444, 278, 778, 556, 444,
+ /* 112 */ 500, 463, 389, 389, 333, 556, 500, 722,
+ /* 120 */ 500, 500, 444, 333, 606, 333, 606, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 1000, 1000, 500,
+ /* 144 */ 278, 278, 333, 333, 500, 500, 500, 500,
+ /* 152 */ 1000, 606, 1028, 669, 500, 500, 528, 545,
+ /* 160 */ 250, 333, 500, 500, 500, 500, 606, 500,
+ /* 168 */ 333, 747, 333, 500, 606, 333, 747, 333,
+ /* 176 */ 400, 606, 300, 300, 333, 556, 500, 250,
+ /* 184 */ 333, 300, 333, 500, 750, 750, 750, 500,
+ /* 192 */ 722, 722, 722, 722, 722, 722, 941, 667,
+ /* 200 */ 611, 611, 611, 611, 333, 333, 333, 333,
+ /* 208 */ 778, 778, 778, 778, 778, 778, 778, 606,
+ /* 216 */ 778, 778, 778, 778, 778, 667, 611, 500,
+ /* 224 */ 444, 444, 444, 444, 444, 444, 638, 407,
+ /* 232 */ 389, 389, 389, 389, 278, 278, 278, 278,
+ /* 240 */ 444, 556, 444, 444, 444, 444, 444, 606,
+ /* 248 */ 444, 556, 556, 556, 556, 500, 500, 500,
+ },
+ { /* Palatino-BoldItalic */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 250, 333, 500, 500, 500, 889, 833, 278,
+ /* 40 */ 333, 333, 444, 606, 250, 389, 250, 315,
+ /* 48 */ 500, 500, 500, 500, 500, 500, 500, 500,
+ /* 56 */ 500, 500, 250, 250, 606, 606, 606, 444,
+ /* 64 */ 833, 722, 667, 685, 778, 611, 556, 778,
+ /* 72 */ 778, 389, 389, 722, 611, 944, 778, 833,
+ /* 80 */ 667, 833, 722, 556, 611, 778, 667, 1000,
+ /* 88 */ 722, 611, 667, 333, 606, 333, 606, 500,
+ /* 96 */ 278, 556, 537, 444, 556, 444, 333, 500,
+ /* 104 */ 556, 333, 333, 556, 333, 833, 556, 556,
+ /* 112 */ 556, 537, 389, 444, 389, 556, 556, 833,
+ /* 120 */ 500, 556, 500, 333, 606, 333, 606, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 1000, 1000, 606,
+ /* 144 */ 278, 278, 333, 333, 500, 500, 500, 500,
+ /* 152 */ 1000, 606, 944, 778, 556, 556, 611, 611,
+ /* 160 */ 250, 333, 500, 500, 500, 500, 606, 556,
+ /* 168 */ 333, 747, 333, 500, 606, 389, 747, 333,
+ /* 176 */ 400, 606, 300, 300, 333, 556, 556, 250,
+ /* 184 */ 333, 300, 333, 500, 750, 750, 750, 444,
+ /* 192 */ 722, 722, 722, 722, 722, 722, 944, 685,
+ /* 200 */ 611, 611, 611, 611, 389, 389, 389, 389,
+ /* 208 */ 778, 778, 833, 833, 833, 833, 833, 606,
+ /* 216 */ 833, 778, 778, 778, 778, 611, 667, 556,
+ /* 224 */ 556, 556, 556, 556, 556, 556, 738, 444,
+ /* 232 */ 444, 444, 444, 444, 333, 333, 333, 333,
+ /* 240 */ 556, 556, 556, 556, 556, 556, 556, 606,
+ /* 248 */ 556, 556, 556, 556, 556, 556, 556, 556,
+ },
+ { /* Helvetica-Narrow */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 228, 228, 291, 456, 456, 729, 547, 182,
+ /* 40 */ 273, 273, 319, 479, 228, 273, 228, 228,
+ /* 48 */ 456, 456, 456, 456, 456, 456, 456, 456,
+ /* 56 */ 456, 456, 228, 228, 479, 479, 479, 456,
+ /* 64 */ 832, 547, 547, 592, 592, 547, 501, 638,
+ /* 72 */ 592, 228, 410, 547, 456, 683, 592, 638,
+ /* 80 */ 547, 638, 592, 547, 501, 592, 547, 774,
+ /* 88 */ 547, 547, 501, 228, 228, 228, 385, 456,
+ /* 96 */ 182, 456, 456, 410, 456, 456, 228, 456,
+ /* 104 */ 456, 182, 182, 410, 182, 683, 456, 456,
+ /* 112 */ 456, 456, 273, 410, 228, 456, 410, 592,
+ /* 120 */ 410, 410, 410, 274, 213, 274, 479, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 820, 820, 820, 287,
+ /* 144 */ 182, 182, 273, 273, 273, 273, 273, 456,
+ /* 152 */ 820, 479, 820, 774, 456, 456, 410, 410,
+ /* 160 */ 228, 273, 456, 456, 456, 456, 213, 456,
+ /* 168 */ 273, 604, 303, 456, 479, 273, 604, 273,
+ /* 176 */ 328, 479, 273, 273, 273, 456, 440, 228,
+ /* 184 */ 273, 273, 299, 456, 684, 684, 684, 501,
+ /* 192 */ 547, 547, 547, 547, 547, 547, 820, 592,
+ /* 200 */ 547, 547, 547, 547, 228, 228, 228, 228,
+ /* 208 */ 592, 592, 638, 638, 638, 638, 638, 479,
+ /* 216 */ 638, 592, 592, 592, 592, 547, 547, 501,
+ /* 224 */ 456, 456, 456, 456, 456, 456, 729, 410,
+ /* 232 */ 456, 456, 456, 456, 228, 228, 228, 228,
+ /* 240 */ 456, 456, 456, 456, 456, 456, 456, 479,
+ /* 248 */ 501, 456, 456, 456, 456, 410, 456, 410,
+ },
+ { /* Helvetica-Narrow-Bold */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 228, 273, 389, 456, 456, 729, 592, 228,
+ /* 40 */ 273, 273, 319, 479, 228, 273, 228, 228,
+ /* 48 */ 456, 456, 456, 456, 456, 456, 456, 456,
+ /* 56 */ 456, 456, 273, 273, 479, 479, 479, 501,
+ /* 64 */ 800, 592, 592, 592, 592, 547, 501, 638,
+ /* 72 */ 592, 228, 456, 592, 501, 683, 592, 638,
+ /* 80 */ 547, 638, 592, 547, 501, 592, 547, 774,
+ /* 88 */ 547, 547, 501, 273, 228, 273, 479, 456,
+ /* 96 */ 228, 456, 501, 456, 501, 456, 273, 501,
+ /* 104 */ 501, 228, 228, 456, 228, 729, 501, 501,
+ /* 112 */ 501, 501, 319, 456, 273, 501, 456, 638,
+ /* 120 */ 456, 456, 410, 319, 230, 319, 479, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 820, 820, 820, 287,
+ /* 144 */ 228, 228, 273, 273, 410, 410, 410, 456,
+ /* 152 */ 820, 479, 820, 774, 456, 456, 501, 501,
+ /* 160 */ 228, 273, 456, 456, 456, 456, 230, 456,
+ /* 168 */ 273, 604, 303, 456, 479, 273, 604, 273,
+ /* 176 */ 328, 479, 273, 273, 273, 501, 456, 228,
+ /* 184 */ 273, 273, 299, 456, 684, 684, 684, 501,
+ /* 192 */ 592, 592, 592, 592, 592, 592, 820, 592,
+ /* 200 */ 547, 547, 547, 547, 228, 228, 228, 228,
+ /* 208 */ 592, 592, 638, 638, 638, 638, 638, 479,
+ /* 216 */ 638, 592, 592, 592, 592, 547, 547, 501,
+ /* 224 */ 456, 456, 456, 456, 456, 456, 729, 456,
+ /* 232 */ 456, 456, 456, 456, 228, 228, 228, 228,
+ /* 240 */ 501, 501, 501, 501, 501, 501, 501, 479,
+ /* 248 */ 501, 501, 501, 501, 501, 456, 501, 456,
+ },
+ { /* Helvetica-Narrow-Oblique */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 228, 228, 291, 456, 456, 729, 547, 182,
+ /* 40 */ 273, 273, 319, 479, 228, 273, 228, 228,
+ /* 48 */ 456, 456, 456, 456, 456, 456, 456, 456,
+ /* 56 */ 456, 456, 228, 228, 479, 479, 479, 456,
+ /* 64 */ 832, 547, 547, 592, 592, 547, 501, 638,
+ /* 72 */ 592, 228, 410, 547, 456, 683, 592, 638,
+ /* 80 */ 547, 638, 592, 547, 501, 592, 547, 774,
+ /* 88 */ 547, 547, 501, 228, 228, 228, 385, 456,
+ /* 96 */ 182, 456, 456, 410, 456, 456, 228, 456,
+ /* 104 */ 456, 182, 182, 410, 182, 683, 456, 456,
+ /* 112 */ 456, 456, 273, 410, 228, 456, 410, 592,
+ /* 120 */ 410, 410, 410, 274, 213, 274, 479, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 820, 820, 820, 287,
+ /* 144 */ 182, 182, 273, 273, 273, 273, 273, 456,
+ /* 152 */ 820, 479, 820, 774, 456, 456, 410, 410,
+ /* 160 */ 228, 273, 456, 456, 456, 456, 213, 456,
+ /* 168 */ 273, 604, 303, 456, 479, 273, 604, 273,
+ /* 176 */ 328, 479, 273, 273, 273, 456, 440, 228,
+ /* 184 */ 273, 273, 299, 456, 684, 684, 684, 501,
+ /* 192 */ 547, 547, 547, 547, 547, 547, 820, 592,
+ /* 200 */ 547, 547, 547, 547, 228, 228, 228, 228,
+ /* 208 */ 592, 592, 638, 638, 638, 638, 638, 479,
+ /* 216 */ 638, 592, 592, 592, 592, 547, 547, 501,
+ /* 224 */ 456, 456, 456, 456, 456, 456, 729, 410,
+ /* 232 */ 456, 456, 456, 456, 228, 228, 228, 228,
+ /* 240 */ 456, 456, 456, 456, 456, 456, 456, 479,
+ /* 248 */ 501, 456, 456, 456, 456, 410, 456, 410,
+ },
+ { /* Helvetica-Narrow-BoldOblique */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 228, 273, 389, 456, 456, 729, 592, 228,
+ /* 40 */ 273, 273, 319, 479, 228, 273, 228, 228,
+ /* 48 */ 456, 456, 456, 456, 456, 456, 456, 456,
+ /* 56 */ 456, 456, 273, 273, 479, 479, 479, 501,
+ /* 64 */ 800, 592, 592, 592, 592, 547, 501, 638,
+ /* 72 */ 592, 228, 456, 592, 501, 683, 592, 638,
+ /* 80 */ 547, 638, 592, 547, 501, 592, 547, 774,
+ /* 88 */ 547, 547, 501, 273, 228, 273, 479, 456,
+ /* 96 */ 228, 456, 501, 456, 501, 456, 273, 501,
+ /* 104 */ 501, 228, 228, 456, 228, 729, 501, 501,
+ /* 112 */ 501, 501, 319, 456, 273, 501, 456, 638,
+ /* 120 */ 456, 456, 410, 319, 230, 319, 479, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 820, 820, 820, 287,
+ /* 144 */ 228, 228, 273, 273, 410, 410, 410, 456,
+ /* 152 */ 820, 479, 820, 774, 456, 456, 501, 501,
+ /* 160 */ 228, 273, 456, 456, 456, 456, 230, 456,
+ /* 168 */ 273, 604, 303, 456, 479, 273, 604, 273,
+ /* 176 */ 328, 479, 273, 273, 273, 501, 456, 228,
+ /* 184 */ 273, 273, 299, 456, 684, 684, 684, 501,
+ /* 192 */ 592, 592, 592, 592, 592, 592, 820, 592,
+ /* 200 */ 547, 547, 547, 547, 228, 228, 228, 228,
+ /* 208 */ 592, 592, 638, 638, 638, 638, 638, 479,
+ /* 216 */ 638, 592, 592, 592, 592, 547, 547, 501,
+ /* 224 */ 456, 456, 456, 456, 456, 456, 729, 456,
+ /* 232 */ 456, 456, 456, 456, 228, 228, 228, 228,
+ /* 240 */ 501, 501, 501, 501, 501, 501, 501, 479,
+ /* 248 */ 501, 501, 501, 501, 501, 456, 501, 456,
+ },
+ { /* Bookman-Light */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 320, 300, 380, 620, 620, 900, 800, 220,
+ /* 40 */ 300, 300, 440, 600, 320, 400, 320, 600,
+ /* 48 */ 620, 620, 620, 620, 620, 620, 620, 620,
+ /* 56 */ 620, 620, 320, 320, 600, 600, 600, 540,
+ /* 64 */ 820, 680, 740, 740, 800, 720, 640, 800,
+ /* 72 */ 800, 340, 600, 720, 600, 920, 740, 800,
+ /* 80 */ 620, 820, 720, 660, 620, 780, 700, 960,
+ /* 88 */ 720, 640, 640, 300, 600, 300, 600, 500,
+ /* 96 */ 220, 580, 620, 520, 620, 520, 320, 540,
+ /* 104 */ 660, 300, 300, 620, 300, 940, 660, 560,
+ /* 112 */ 620, 580, 440, 520, 380, 680, 520, 780,
+ /* 120 */ 560, 540, 480, 280, 600, 280, 600, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 980, 1280, 460,
+ /* 144 */ 220, 220, 240, 240, 400, 400, 400, 500,
+ /* 152 */ 1000, 600, 1240, 900, 540, 540, 620, 620,
+ /* 160 */ 320, 300, 620, 620, 620, 620, 600, 520,
+ /* 168 */ 420, 740, 420, 360, 600, 400, 740, 440,
+ /* 176 */ 400, 600, 372, 372, 340, 680, 600, 320,
+ /* 184 */ 320, 372, 420, 360, 930, 930, 930, 540,
+ /* 192 */ 680, 680, 680, 680, 680, 680, 1260, 740,
+ /* 200 */ 720, 720, 720, 720, 340, 340, 340, 340,
+ /* 208 */ 800, 740, 800, 800, 800, 800, 800, 600,
+ /* 216 */ 800, 780, 780, 780, 780, 640, 620, 660,
+ /* 224 */ 580, 580, 580, 580, 580, 580, 860, 520,
+ /* 232 */ 520, 520, 520, 520, 300, 300, 300, 300,
+ /* 240 */ 560, 660, 560, 560, 560, 560, 560, 600,
+ /* 248 */ 560, 680, 680, 680, 680, 540, 620, 540,
+ },
+ { /* Bookman-Demi */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 340, 360, 420, 660, 660, 940, 800, 320,
+ /* 40 */ 320, 320, 460, 600, 340, 360, 340, 600,
+ /* 48 */ 660, 660, 660, 660, 660, 660, 660, 660,
+ /* 56 */ 660, 660, 340, 340, 600, 600, 600, 660,
+ /* 64 */ 820, 720, 720, 740, 780, 720, 680, 780,
+ /* 72 */ 820, 400, 640, 800, 640, 940, 740, 800,
+ /* 80 */ 660, 800, 780, 660, 700, 740, 720, 940,
+ /* 88 */ 780, 700, 640, 300, 600, 300, 600, 500,
+ /* 96 */ 320, 580, 600, 580, 640, 580, 380, 580,
+ /* 104 */ 680, 360, 340, 660, 340, 1000, 680, 620,
+ /* 112 */ 640, 620, 460, 520, 460, 660, 600, 800,
+ /* 120 */ 600, 620, 560, 320, 600, 320, 600, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 980, 1360, 460,
+ /* 144 */ 320, 320, 220, 220, 540, 540, 540, 500,
+ /* 152 */ 1000, 600, 1220, 940, 440, 380, 740, 740,
+ /* 160 */ 340, 360, 660, 660, 660, 660, 600, 600,
+ /* 168 */ 500, 740, 400, 400, 600, 360, 740, 460,
+ /* 176 */ 400, 600, 396, 396, 400, 660, 800, 340,
+ /* 184 */ 360, 396, 400, 400, 990, 990, 990, 660,
+ /* 192 */ 720, 720, 720, 720, 720, 720, 1140, 740,
+ /* 200 */ 720, 720, 720, 720, 400, 400, 400, 400,
+ /* 208 */ 780, 740, 800, 800, 800, 800, 800, 600,
+ /* 216 */ 800, 740, 740, 740, 740, 700, 660, 660,
+ /* 224 */ 580, 580, 580, 580, 580, 580, 880, 580,
+ /* 232 */ 580, 580, 580, 580, 360, 360, 360, 360,
+ /* 240 */ 620, 680, 620, 620, 620, 620, 620, 600,
+ /* 248 */ 620, 660, 660, 660, 660, 620, 640, 620,
+ },
+ { /* Bookman-LightItalic */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 300, 320, 360, 620, 620, 800, 820, 280,
+ /* 40 */ 280, 280, 440, 600, 300, 320, 300, 600,
+ /* 48 */ 620, 620, 620, 620, 620, 620, 620, 620,
+ /* 56 */ 620, 620, 300, 300, 600, 600, 600, 540,
+ /* 64 */ 780, 700, 720, 720, 740, 680, 620, 760,
+ /* 72 */ 800, 320, 560, 720, 580, 860, 720, 760,
+ /* 80 */ 600, 780, 700, 640, 600, 720, 680, 960,
+ /* 88 */ 700, 660, 580, 260, 600, 260, 600, 500,
+ /* 96 */ 280, 620, 600, 480, 640, 540, 340, 560,
+ /* 104 */ 620, 280, 280, 600, 280, 880, 620, 540,
+ /* 112 */ 600, 560, 400, 540, 340, 620, 540, 880,
+ /* 120 */ 540, 600, 520, 360, 600, 380, 600, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 980, 1180, 460,
+ /* 144 */ 280, 280, 180, 180, 440, 440, 480, 500,
+ /* 152 */ 1000, 600, 1180, 900, 620, 620, 640, 660,
+ /* 160 */ 300, 320, 620, 620, 620, 620, 600, 620,
+ /* 168 */ 420, 740, 440, 300, 600, 320, 740, 440,
+ /* 176 */ 400, 600, 372, 372, 320, 620, 620, 300,
+ /* 184 */ 320, 372, 400, 300, 930, 930, 930, 540,
+ /* 192 */ 700, 700, 700, 700, 700, 700, 1220, 720,
+ /* 200 */ 680, 680, 680, 680, 320, 320, 320, 320,
+ /* 208 */ 740, 720, 760, 760, 760, 760, 760, 600,
+ /* 216 */ 760, 720, 720, 720, 720, 660, 600, 620,
+ /* 224 */ 620, 620, 620, 620, 620, 620, 880, 480,
+ /* 232 */ 540, 540, 540, 540, 280, 280, 280, 280,
+ /* 240 */ 540, 620, 540, 540, 540, 540, 540, 600,
+ /* 248 */ 540, 620, 620, 620, 620, 600, 600, 600,
+ },
+ { /* Bookman-DemiItalic */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 340, 320, 380, 680, 680, 880, 980, 320,
+ /* 40 */ 260, 260, 460, 600, 340, 280, 340, 360,
+ /* 48 */ 680, 680, 680, 680, 680, 680, 680, 680,
+ /* 56 */ 680, 680, 340, 340, 620, 600, 620, 620,
+ /* 64 */ 780, 720, 720, 700, 760, 720, 660, 760,
+ /* 72 */ 800, 380, 620, 780, 640, 860, 740, 760,
+ /* 80 */ 640, 760, 740, 700, 700, 740, 660, 1000,
+ /* 88 */ 740, 660, 680, 260, 580, 260, 620, 500,
+ /* 96 */ 320, 680, 600, 560, 680, 560, 420, 620,
+ /* 104 */ 700, 380, 320, 700, 380, 960, 680, 600,
+ /* 112 */ 660, 620, 500, 540, 440, 680, 540, 860,
+ /* 120 */ 620, 600, 560, 300, 620, 300, 620, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 940, 1360, 360,
+ /* 144 */ 320, 320, 220, 220, 520, 520, 520, 500,
+ /* 152 */ 1000, 600, 1180, 920, 420, 420, 820, 820,
+ /* 160 */ 340, 320, 680, 680, 680, 680, 620, 620,
+ /* 168 */ 520, 780, 440, 380, 620, 280, 780, 480,
+ /* 176 */ 400, 600, 408, 408, 340, 680, 680, 340,
+ /* 184 */ 360, 408, 440, 380, 1020, 1020, 1020, 620,
+ /* 192 */ 720, 720, 720, 720, 720, 720, 1140, 700,
+ /* 200 */ 720, 720, 720, 720, 380, 380, 380, 380,
+ /* 208 */ 760, 740, 760, 760, 760, 760, 760, 600,
+ /* 216 */ 760, 740, 740, 740, 740, 660, 640, 660,
+ /* 224 */ 680, 680, 680, 680, 680, 680, 880, 560,
+ /* 232 */ 560, 560, 560, 560, 380, 380, 380, 380,
+ /* 240 */ 600, 680, 600, 600, 600, 600, 600, 600,
+ /* 248 */ 600, 680, 680, 680, 680, 600, 660, 600,
+ },
+ { /* AvantGarde-Book */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 277, 295, 309, 554, 554, 775, 757, 351,
+ /* 40 */ 369, 369, 425, 606, 277, 332, 277, 437,
+ /* 48 */ 554, 554, 554, 554, 554, 554, 554, 554,
+ /* 56 */ 554, 554, 277, 277, 606, 606, 606, 591,
+ /* 64 */ 867, 740, 574, 813, 744, 536, 485, 872,
+ /* 72 */ 683, 226, 482, 591, 462, 919, 740, 869,
+ /* 80 */ 592, 871, 607, 498, 426, 655, 702, 960,
+ /* 88 */ 609, 592, 480, 351, 605, 351, 606, 500,
+ /* 96 */ 351, 683, 682, 647, 685, 650, 314, 673,
+ /* 104 */ 610, 200, 203, 502, 200, 938, 610, 655,
+ /* 112 */ 682, 682, 301, 388, 339, 608, 554, 831,
+ /* 120 */ 480, 536, 425, 351, 672, 351, 606, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 1000, 1174, 606,
+ /* 144 */ 351, 351, 251, 251, 502, 484, 502, 500,
+ /* 152 */ 1000, 606, 1194, 1137, 553, 553, 487, 485,
+ /* 160 */ 277, 295, 554, 554, 554, 554, 672, 615,
+ /* 168 */ 369, 747, 369, 425, 606, 332, 747, 485,
+ /* 176 */ 400, 606, 332, 332, 375, 608, 564, 277,
+ /* 184 */ 324, 332, 369, 425, 831, 831, 831, 591,
+ /* 192 */ 740, 740, 740, 740, 740, 740, 992, 813,
+ /* 200 */ 536, 536, 536, 536, 226, 226, 226, 226,
+ /* 208 */ 790, 740, 869, 869, 869, 869, 869, 606,
+ /* 216 */ 868, 655, 655, 655, 655, 592, 592, 554,
+ /* 224 */ 683, 683, 683, 683, 683, 683, 1157, 647,
+ /* 232 */ 650, 650, 650, 650, 200, 200, 200, 200,
+ /* 240 */ 655, 610, 655, 655, 655, 655, 655, 606,
+ /* 248 */ 653, 608, 608, 608, 608, 536, 682, 536,
+ },
+ { /* AvantGarde-Demi */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 280, 280, 360, 560, 560, 860, 680, 280,
+ /* 40 */ 380, 380, 440, 600, 280, 420, 280, 460,
+ /* 48 */ 560, 560, 560, 560, 560, 560, 560, 560,
+ /* 56 */ 560, 560, 280, 280, 600, 600, 600, 560,
+ /* 64 */ 740, 740, 580, 780, 700, 520, 480, 840,
+ /* 72 */ 680, 280, 480, 620, 440, 900, 740, 840,
+ /* 80 */ 560, 840, 580, 520, 420, 640, 700, 900,
+ /* 88 */ 680, 620, 500, 320, 640, 320, 600, 500,
+ /* 96 */ 280, 660, 660, 640, 660, 640, 280, 660,
+ /* 104 */ 600, 240, 260, 580, 240, 940, 600, 640,
+ /* 112 */ 660, 660, 320, 440, 300, 600, 560, 800,
+ /* 120 */ 560, 580, 460, 340, 600, 340, 600, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 1000, 1280, 600,
+ /* 144 */ 280, 280, 240, 240, 480, 480, 480, 500,
+ /* 152 */ 1000, 600, 1060, 1080, 560, 560, 520, 520,
+ /* 160 */ 280, 280, 560, 560, 560, 560, 600, 560,
+ /* 168 */ 500, 740, 360, 460, 600, 420, 740, 420,
+ /* 176 */ 400, 600, 336, 336, 420, 576, 600, 280,
+ /* 184 */ 340, 336, 360, 460, 840, 840, 840, 560,
+ /* 192 */ 740, 740, 740, 740, 740, 740, 900, 780,
+ /* 200 */ 520, 520, 520, 520, 280, 280, 280, 280,
+ /* 208 */ 742, 740, 840, 840, 840, 840, 840, 600,
+ /* 216 */ 840, 640, 640, 640, 640, 620, 560, 600,
+ /* 224 */ 660, 660, 660, 660, 660, 660, 1080, 640,
+ /* 232 */ 640, 640, 640, 640, 240, 240, 240, 240,
+ /* 240 */ 640, 600, 640, 640, 640, 640, 640, 600,
+ /* 248 */ 660, 600, 600, 600, 600, 580, 660, 580,
+ },
+ { /* AvantGarde-BookOblique */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 277, 295, 309, 554, 554, 775, 757, 351,
+ /* 40 */ 369, 369, 425, 606, 277, 332, 277, 437,
+ /* 48 */ 554, 554, 554, 554, 554, 554, 554, 554,
+ /* 56 */ 554, 554, 277, 277, 606, 606, 606, 591,
+ /* 64 */ 867, 740, 574, 813, 744, 536, 485, 872,
+ /* 72 */ 683, 226, 482, 591, 462, 919, 740, 869,
+ /* 80 */ 592, 871, 607, 498, 426, 655, 702, 960,
+ /* 88 */ 609, 592, 480, 351, 605, 351, 606, 500,
+ /* 96 */ 351, 683, 682, 647, 685, 650, 314, 673,
+ /* 104 */ 610, 200, 203, 502, 200, 938, 610, 655,
+ /* 112 */ 682, 682, 301, 388, 339, 608, 554, 831,
+ /* 120 */ 480, 536, 425, 351, 672, 351, 606, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 1000, 1174, 606,
+ /* 144 */ 351, 351, 251, 251, 502, 484, 502, 500,
+ /* 152 */ 1000, 606, 1194, 1137, 553, 553, 487, 485,
+ /* 160 */ 277, 295, 554, 554, 554, 554, 672, 615,
+ /* 168 */ 369, 747, 369, 425, 606, 332, 747, 485,
+ /* 176 */ 400, 606, 332, 332, 375, 608, 564, 277,
+ /* 184 */ 324, 332, 369, 425, 831, 831, 831, 591,
+ /* 192 */ 740, 740, 740, 740, 740, 740, 992, 813,
+ /* 200 */ 536, 536, 536, 536, 226, 226, 226, 226,
+ /* 208 */ 790, 740, 869, 869, 869, 869, 869, 606,
+ /* 216 */ 868, 655, 655, 655, 655, 592, 592, 554,
+ /* 224 */ 683, 683, 683, 683, 683, 683, 1157, 647,
+ /* 232 */ 650, 650, 650, 650, 200, 200, 200, 200,
+ /* 240 */ 655, 610, 655, 655, 655, 655, 655, 606,
+ /* 248 */ 653, 608, 608, 608, 608, 536, 682, 536,
+ },
+ { /* AvantGarde-DemiOblique */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 280, 280, 360, 560, 560, 860, 680, 280,
+ /* 40 */ 380, 380, 440, 600, 280, 420, 280, 460,
+ /* 48 */ 560, 560, 560, 560, 560, 560, 560, 560,
+ /* 56 */ 560, 560, 280, 280, 600, 600, 600, 560,
+ /* 64 */ 740, 740, 580, 780, 700, 520, 480, 840,
+ /* 72 */ 680, 280, 480, 620, 440, 900, 740, 840,
+ /* 80 */ 560, 840, 580, 520, 420, 640, 700, 900,
+ /* 88 */ 680, 620, 500, 320, 640, 320, 600, 500,
+ /* 96 */ 280, 660, 660, 640, 660, 640, 280, 660,
+ /* 104 */ 600, 240, 260, 580, 240, 940, 600, 640,
+ /* 112 */ 660, 660, 320, 440, 300, 600, 560, 800,
+ /* 120 */ 560, 580, 460, 340, 600, 340, 600, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 1000, 1280, 600,
+ /* 144 */ 280, 280, 240, 240, 480, 480, 480, 500,
+ /* 152 */ 1000, 600, 1060, 1080, 560, 560, 520, 520,
+ /* 160 */ 280, 280, 560, 560, 560, 560, 600, 560,
+ /* 168 */ 500, 740, 360, 460, 600, 420, 740, 420,
+ /* 176 */ 400, 600, 336, 336, 420, 576, 600, 280,
+ /* 184 */ 340, 336, 360, 460, 840, 840, 840, 560,
+ /* 192 */ 740, 740, 740, 740, 740, 740, 900, 780,
+ /* 200 */ 520, 520, 520, 520, 280, 280, 280, 280,
+ /* 208 */ 742, 740, 840, 840, 840, 840, 840, 600,
+ /* 216 */ 840, 640, 640, 640, 640, 620, 560, 600,
+ /* 224 */ 660, 660, 660, 660, 660, 660, 1080, 640,
+ /* 232 */ 640, 640, 640, 640, 240, 240, 240, 240,
+ /* 240 */ 640, 600, 640, 640, 640, 640, 640, 600,
+ /* 248 */ 660, 600, 600, 600, 600, 580, 660, 580,
+ },
+ { /* NewCenturySchlbk-Roman */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 278, 296, 389, 556, 556, 833, 815, 204,
+ /* 40 */ 333, 333, 500, 606, 278, 333, 278, 278,
+ /* 48 */ 556, 556, 556, 556, 556, 556, 556, 556,
+ /* 56 */ 556, 556, 278, 278, 606, 606, 606, 444,
+ /* 64 */ 737, 722, 722, 722, 778, 722, 667, 778,
+ /* 72 */ 833, 407, 556, 778, 667, 944, 815, 778,
+ /* 80 */ 667, 778, 722, 630, 667, 815, 722, 981,
+ /* 88 */ 704, 704, 611, 333, 606, 333, 606, 500,
+ /* 96 */ 204, 556, 556, 444, 574, 500, 333, 537,
+ /* 104 */ 611, 315, 296, 593, 315, 889, 611, 500,
+ /* 112 */ 574, 556, 444, 463, 389, 611, 537, 778,
+ /* 120 */ 537, 537, 481, 333, 606, 333, 606, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 1000, 1000, 606,
+ /* 144 */ 204, 204, 259, 259, 389, 389, 389, 556,
+ /* 152 */ 1000, 606, 1000, 833, 500, 500, 611, 611,
+ /* 160 */ 278, 296, 556, 556, 556, 556, 606, 500,
+ /* 168 */ 333, 737, 334, 426, 606, 333, 737, 333,
+ /* 176 */ 400, 606, 333, 333, 333, 611, 606, 278,
+ /* 184 */ 333, 333, 300, 426, 834, 834, 834, 444,
+ /* 192 */ 722, 722, 722, 722, 722, 722, 1000, 722,
+ /* 200 */ 722, 722, 722, 722, 407, 407, 407, 407,
+ /* 208 */ 778, 815, 778, 778, 778, 778, 778, 606,
+ /* 216 */ 778, 815, 815, 815, 815, 704, 667, 574,
+ /* 224 */ 556, 556, 556, 556, 556, 556, 796, 444,
+ /* 232 */ 500, 500, 500, 500, 315, 315, 315, 315,
+ /* 240 */ 500, 611, 500, 500, 500, 500, 500, 606,
+ /* 248 */ 500, 611, 611, 611, 611, 537, 574, 537,
+ },
+ { /* NewCenturySchlbk-Bold */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 287, 296, 333, 574, 574, 833, 852, 241,
+ /* 40 */ 389, 389, 500, 606, 278, 333, 278, 278,
+ /* 48 */ 574, 574, 574, 574, 574, 574, 574, 574,
+ /* 56 */ 574, 574, 278, 278, 606, 606, 606, 500,
+ /* 64 */ 747, 759, 778, 778, 833, 759, 722, 833,
+ /* 72 */ 870, 444, 648, 815, 722, 981, 833, 833,
+ /* 80 */ 759, 833, 815, 667, 722, 833, 759, 981,
+ /* 88 */ 722, 722, 667, 389, 606, 389, 606, 500,
+ /* 96 */ 241, 611, 648, 556, 667, 574, 389, 611,
+ /* 104 */ 685, 370, 352, 667, 352, 963, 685, 611,
+ /* 112 */ 667, 648, 519, 500, 426, 685, 611, 889,
+ /* 120 */ 611, 611, 537, 389, 606, 389, 606, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 1000, 1000, 606,
+ /* 144 */ 241, 241, 333, 333, 481, 481, 481, 500,
+ /* 152 */ 1000, 606, 1000, 907, 500, 500, 685, 685,
+ /* 160 */ 287, 296, 574, 574, 574, 574, 606, 500,
+ /* 168 */ 333, 747, 367, 500, 606, 333, 747, 333,
+ /* 176 */ 400, 606, 344, 344, 333, 685, 747, 278,
+ /* 184 */ 333, 344, 367, 500, 861, 861, 861, 500,
+ /* 192 */ 759, 759, 759, 759, 759, 759, 981, 778,
+ /* 200 */ 759, 759, 759, 759, 444, 444, 444, 444,
+ /* 208 */ 833, 833, 833, 833, 833, 833, 833, 606,
+ /* 216 */ 833, 833, 833, 833, 833, 722, 759, 611,
+ /* 224 */ 611, 611, 611, 611, 611, 611, 870, 556,
+ /* 232 */ 574, 574, 574, 574, 370, 370, 370, 370,
+ /* 240 */ 611, 685, 611, 611, 611, 611, 611, 606,
+ /* 248 */ 611, 685, 685, 685, 685, 611, 667, 611,
+ },
+ { /* NewCenturySchlbk-Italic */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 278, 333, 400, 556, 556, 833, 852, 204,
+ /* 40 */ 333, 333, 500, 606, 278, 333, 278, 606,
+ /* 48 */ 556, 556, 556, 556, 556, 556, 556, 556,
+ /* 56 */ 556, 556, 278, 278, 606, 606, 606, 444,
+ /* 64 */ 747, 704, 722, 722, 778, 722, 667, 778,
+ /* 72 */ 833, 407, 611, 741, 667, 944, 815, 778,
+ /* 80 */ 667, 778, 741, 667, 685, 815, 704, 926,
+ /* 88 */ 704, 685, 667, 333, 606, 333, 606, 500,
+ /* 96 */ 204, 574, 556, 444, 611, 444, 333, 537,
+ /* 104 */ 611, 333, 315, 556, 333, 889, 611, 500,
+ /* 112 */ 574, 556, 444, 444, 352, 611, 519, 778,
+ /* 120 */ 500, 500, 463, 333, 606, 333, 606, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 950, 1000, 606,
+ /* 144 */ 204, 204, 333, 333, 389, 389, 389, 500,
+ /* 152 */ 1000, 606, 981, 778, 500, 500, 611, 611,
+ /* 160 */ 278, 333, 556, 556, 556, 556, 606, 500,
+ /* 168 */ 333, 747, 422, 426, 606, 333, 747, 333,
+ /* 176 */ 400, 606, 333, 333, 333, 611, 650, 278,
+ /* 184 */ 333, 333, 372, 426, 834, 834, 834, 444,
+ /* 192 */ 704, 704, 704, 704, 704, 704, 870, 722,
+ /* 200 */ 722, 722, 722, 722, 407, 407, 407, 407,
+ /* 208 */ 778, 815, 778, 778, 778, 778, 778, 606,
+ /* 216 */ 778, 815, 815, 815, 815, 685, 667, 556,
+ /* 224 */ 574, 574, 574, 574, 574, 574, 722, 444,
+ /* 232 */ 444, 444, 444, 444, 333, 333, 333, 333,
+ /* 240 */ 500, 611, 500, 500, 500, 500, 500, 606,
+ /* 248 */ 500, 611, 611, 611, 611, 500, 574, 500,
+ },
+ { /* NewCenturySchlbk-BoldItalic */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 287, 333, 400, 574, 574, 889, 889, 259,
+ /* 40 */ 407, 407, 500, 606, 287, 333, 287, 278,
+ /* 48 */ 574, 574, 574, 574, 574, 574, 574, 574,
+ /* 56 */ 574, 574, 287, 287, 606, 606, 606, 481,
+ /* 64 */ 747, 741, 759, 759, 833, 741, 704, 815,
+ /* 72 */ 870, 444, 667, 778, 704, 944, 852, 833,
+ /* 80 */ 741, 833, 796, 685, 722, 833, 741, 944,
+ /* 88 */ 741, 704, 704, 407, 606, 407, 606, 500,
+ /* 96 */ 259, 667, 611, 537, 667, 519, 389, 611,
+ /* 104 */ 685, 389, 370, 648, 389, 944, 685, 574,
+ /* 112 */ 648, 630, 519, 481, 407, 685, 556, 833,
+ /* 120 */ 574, 519, 519, 407, 606, 407, 606, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 1000, 950, 1167, 606,
+ /* 144 */ 259, 259, 278, 278, 481, 481, 481, 500,
+ /* 152 */ 1000, 606, 963, 852, 500, 500, 685, 685,
+ /* 160 */ 287, 333, 574, 574, 574, 574, 606, 500,
+ /* 168 */ 333, 747, 412, 481, 606, 333, 747, 333,
+ /* 176 */ 400, 606, 344, 344, 333, 685, 650, 287,
+ /* 184 */ 333, 344, 356, 481, 861, 861, 861, 481,
+ /* 192 */ 741, 741, 741, 741, 741, 741, 889, 759,
+ /* 200 */ 741, 741, 741, 741, 444, 444, 444, 444,
+ /* 208 */ 833, 852, 833, 833, 833, 833, 833, 606,
+ /* 216 */ 833, 833, 833, 833, 833, 704, 741, 574,
+ /* 224 */ 667, 667, 667, 667, 667, 667, 815, 537,
+ /* 232 */ 519, 519, 519, 519, 389, 389, 389, 389,
+ /* 240 */ 574, 685, 574, 574, 574, 574, 574, 606,
+ /* 248 */ 574, 685, 685, 685, 685, 519, 648, 519,
+ },
+};
+static unsigned short ausCharacterWidths2[32][256] = {
+ { /* Courier */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 40 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 48 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 56 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 64 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 72 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 80 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 88 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 96 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 104 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 112 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 120 */ 600, 600, 600, 600, 600, 600, 600, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 168 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 176 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 184 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 192 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 200 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 208 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 216 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 224 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 232 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 240 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 248 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ },
+ { /* Courier-Bold */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 40 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 48 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 56 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 64 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 72 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 80 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 88 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 96 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 104 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 112 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 120 */ 600, 600, 600, 600, 600, 600, 600, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 168 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 176 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 184 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 192 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 200 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 208 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 216 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 224 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 232 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 240 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 248 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ },
+ { /* Courier-Oblique */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 40 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 48 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 56 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 64 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 72 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 80 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 88 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 96 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 104 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 112 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 120 */ 600, 600, 600, 600, 600, 600, 600, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 168 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 176 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 184 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 192 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 200 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 208 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 216 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 224 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 232 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 240 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 248 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ },
+ { /* Courier-BoldOblique */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 40 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 48 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 56 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 64 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 72 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 80 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 88 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 96 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 104 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 112 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 120 */ 600, 600, 600, 600, 600, 600, 600, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 168 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 176 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 184 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 192 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 200 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 208 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 216 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 224 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 232 */ 600, 600, 600, 600, 600, 600, 600, 740,
+ /* 240 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ /* 248 */ 600, 600, 600, 600, 600, 600, 600, 600,
+ },
+ { /* Times-Roman */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 250, 333, 408, 500, 500, 833, 778, 180,
+ /* 40 */ 333, 333, 500, 564, 250, 333, 250, 278,
+ /* 48 */ 500, 500, 500, 500, 500, 500, 500, 500,
+ /* 56 */ 500, 500, 278, 278, 564, 564, 564, 444,
+ /* 64 */ 921, 722, 667, 667, 722, 611, 556, 722,
+ /* 72 */ 722, 333, 389, 722, 611, 889, 722, 722,
+ /* 80 */ 556, 722, 667, 556, 611, 722, 722, 944,
+ /* 88 */ 722, 722, 611, 333, 278, 333, 469, 500,
+ /* 96 */ 333, 444, 500, 444, 500, 444, 333, 500,
+ /* 104 */ 500, 278, 278, 500, 278, 778, 500, 500,
+ /* 112 */ 500, 500, 333, 389, 278, 500, 500, 722,
+ /* 120 */ 500, 500, 444, 480, 200, 480, 541, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 250, 722, 333, 611, 500, 611, 556, 500,
+ /* 168 */ 333, 556, 556, 611, 611, 333, 611, 611,
+ /* 176 */ 333, 444, 333, 278, 333, 348, 389, 333,
+ /* 184 */ 333, 389, 389, 278, 444, 333, 444, 444,
+ /* 192 */ 667, 722, 722, 722, 722, 611, 667, 667,
+ /* 200 */ 667, 611, 611, 611, 611, 333, 333, 722,
+ /* 208 */ 722, 722, 722, 722, 722, 722, 722, 564,
+ /* 216 */ 667, 722, 722, 722, 722, 722, 611, 500,
+ /* 224 */ 333, 444, 444, 444, 444, 278, 444, 444,
+ /* 232 */ 444, 444, 444, 444, 444, 278, 278, 600,
+ /* 240 */ 500, 500, 500, 500, 500, 500, 500, 564,
+ /* 248 */ 333, 500, 500, 500, 500, 500, 278, 333,
+ },
+ { /* Times-Bold */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 250, 333, 555, 500, 500, 1000, 833, 278,
+ /* 40 */ 333, 333, 500, 570, 250, 333, 250, 278,
+ /* 48 */ 500, 500, 500, 500, 500, 500, 500, 500,
+ /* 56 */ 500, 500, 333, 333, 570, 570, 570, 500,
+ /* 64 */ 930, 722, 667, 722, 722, 667, 611, 778,
+ /* 72 */ 778, 389, 500, 778, 667, 944, 722, 778,
+ /* 80 */ 611, 778, 722, 556, 667, 722, 722, 1000,
+ /* 88 */ 722, 722, 667, 333, 278, 333, 581, 500,
+ /* 96 */ 333, 500, 556, 444, 556, 444, 333, 500,
+ /* 104 */ 556, 278, 333, 556, 278, 833, 556, 500,
+ /* 112 */ 556, 556, 444, 389, 333, 556, 500, 722,
+ /* 120 */ 500, 500, 444, 394, 220, 394, 520, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 250, 722, 333, 667, 500, 667, 556, 500,
+ /* 168 */ 333, 556, 556, 667, 667, 333, 667, 667,
+ /* 176 */ 333, 500, 333, 278, 333, 396, 389, 333,
+ /* 184 */ 333, 389, 389, 400, 444, 333, 444, 444,
+ /* 192 */ 722, 722, 722, 722, 722, 667, 722, 722,
+ /* 200 */ 722, 667, 667, 667, 667, 389, 389, 722,
+ /* 208 */ 722, 722, 722, 778, 778, 778, 778, 570,
+ /* 216 */ 722, 722, 722, 722, 722, 722, 667, 556,
+ /* 224 */ 444, 500, 500, 500, 500, 278, 444, 444,
+ /* 232 */ 444, 444, 444, 444, 444, 278, 278, 665,
+ /* 240 */ 556, 556, 556, 500, 500, 500, 500, 570,
+ /* 248 */ 444, 556, 556, 556, 556, 500, 333, 333,
+ },
+ { /* Times-Italic */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 250, 333, 420, 500, 500, 833, 778, 214,
+ /* 40 */ 333, 333, 500, 675, 250, 333, 250, 278,
+ /* 48 */ 500, 500, 500, 500, 500, 500, 500, 500,
+ /* 56 */ 500, 500, 333, 333, 675, 675, 675, 500,
+ /* 64 */ 920, 611, 611, 667, 722, 611, 611, 722,
+ /* 72 */ 722, 333, 444, 667, 556, 833, 667, 722,
+ /* 80 */ 611, 722, 611, 500, 556, 722, 611, 833,
+ /* 88 */ 611, 556, 556, 389, 278, 389, 422, 500,
+ /* 96 */ 333, 500, 500, 444, 500, 444, 278, 500,
+ /* 104 */ 500, 278, 278, 444, 278, 722, 500, 500,
+ /* 112 */ 500, 500, 389, 389, 278, 500, 444, 667,
+ /* 120 */ 444, 444, 389, 400, 275, 400, 541, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 250, 611, 333, 556, 500, 556, 500, 500,
+ /* 168 */ 333, 500, 500, 556, 556, 333, 556, 556,
+ /* 176 */ 333, 500, 333, 278, 333, 278, 389, 333,
+ /* 184 */ 333, 389, 389, 278, 389, 333, 389, 389,
+ /* 192 */ 611, 611, 611, 611, 611, 556, 667, 667,
+ /* 200 */ 667, 611, 611, 611, 611, 333, 333, 722,
+ /* 208 */ 722, 667, 667, 722, 722, 722, 722, 675,
+ /* 216 */ 611, 722, 722, 722, 722, 556, 556, 500,
+ /* 224 */ 389, 500, 500, 500, 500, 278, 444, 444,
+ /* 232 */ 444, 444, 444, 444, 444, 278, 278, 521,
+ /* 240 */ 500, 500, 500, 500, 500, 500, 500, 675,
+ /* 248 */ 389, 500, 500, 500, 500, 444, 278, 333,
+ },
+ { /* Times-BoldItalic */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 250, 389, 555, 500, 500, 833, 778, 278,
+ /* 40 */ 333, 333, 500, 570, 250, 333, 250, 278,
+ /* 48 */ 500, 500, 500, 500, 500, 500, 500, 500,
+ /* 56 */ 500, 500, 333, 333, 570, 570, 570, 500,
+ /* 64 */ 832, 667, 667, 667, 722, 667, 667, 722,
+ /* 72 */ 778, 389, 500, 667, 611, 889, 722, 722,
+ /* 80 */ 611, 722, 667, 556, 611, 722, 667, 889,
+ /* 88 */ 667, 611, 611, 333, 278, 333, 570, 500,
+ /* 96 */ 333, 500, 500, 444, 500, 444, 333, 500,
+ /* 104 */ 556, 278, 278, 500, 278, 778, 556, 500,
+ /* 112 */ 500, 500, 389, 389, 278, 556, 444, 667,
+ /* 120 */ 500, 444, 389, 348, 220, 348, 570, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 250, 667, 333, 611, 500, 611, 556, 500,
+ /* 168 */ 333, 556, 556, 611, 611, 333, 611, 611,
+ /* 176 */ 333, 500, 333, 278, 333, 382, 389, 333,
+ /* 184 */ 333, 389, 389, 345, 389, 333, 389, 389,
+ /* 192 */ 667, 667, 667, 667, 667, 611, 667, 667,
+ /* 200 */ 667, 667, 667, 667, 667, 389, 389, 722,
+ /* 208 */ 722, 722, 722, 722, 722, 722, 722, 570,
+ /* 216 */ 667, 722, 722, 722, 722, 611, 611, 500,
+ /* 224 */ 389, 500, 500, 500, 500, 278, 444, 444,
+ /* 232 */ 444, 444, 444, 444, 444, 278, 278, 600,
+ /* 240 */ 500, 556, 556, 500, 500, 500, 500, 570,
+ /* 248 */ 389, 556, 556, 556, 556, 444, 278, 333,
+ },
+ { /* Helvetica */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 278, 278, 355, 556, 556, 889, 667, 191,
+ /* 40 */ 333, 333, 389, 584, 278, 333, 278, 278,
+ /* 48 */ 556, 556, 556, 556, 556, 556, 556, 556,
+ /* 56 */ 556, 556, 278, 278, 584, 584, 584, 556,
+ /* 64 */ 1015, 667, 667, 722, 722, 667, 611, 778,
+ /* 72 */ 722, 278, 500, 667, 556, 833, 722, 778,
+ /* 80 */ 667, 778, 722, 667, 611, 722, 667, 944,
+ /* 88 */ 667, 667, 611, 278, 278, 278, 469, 556,
+ /* 96 */ 333, 556, 556, 500, 556, 556, 278, 556,
+ /* 104 */ 556, 222, 222, 500, 222, 833, 556, 556,
+ /* 112 */ 556, 556, 333, 500, 278, 556, 500, 722,
+ /* 120 */ 500, 500, 500, 334, 260, 334, 584, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 278, 667, 333, 556, 556, 556, 667, 556,
+ /* 168 */ 333, 667, 667, 611, 611, 333, 611, 611,
+ /* 176 */ 333, 556, 333, 222, 333, 292, 500, 333,
+ /* 184 */ 333, 500, 500, 308, 500, 333, 500, 500,
+ /* 192 */ 722, 667, 667, 667, 667, 556, 722, 722,
+ /* 200 */ 722, 667, 667, 667, 667, 278, 278, 722,
+ /* 208 */ 722, 722, 722, 778, 778, 778, 778, 584,
+ /* 216 */ 722, 722, 722, 722, 722, 666, 611, 611,
+ /* 224 */ 333, 556, 556, 556, 556, 222, 500, 500,
+ /* 232 */ 500, 556, 556, 556, 556, 278, 278, 635,
+ /* 240 */ 556, 556, 556, 556, 556, 556, 556, 584,
+ /* 248 */ 333, 556, 556, 556, 556, 500, 278, 333,
+ },
+ { /* Helvetica-Bold */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 278, 333, 474, 556, 556, 889, 722, 238,
+ /* 40 */ 333, 333, 389, 584, 278, 333, 278, 278,
+ /* 48 */ 556, 556, 556, 556, 556, 556, 556, 556,
+ /* 56 */ 556, 556, 333, 333, 584, 584, 584, 611,
+ /* 64 */ 975, 722, 722, 722, 722, 667, 611, 778,
+ /* 72 */ 722, 278, 556, 722, 611, 833, 722, 778,
+ /* 80 */ 667, 778, 722, 667, 611, 722, 667, 944,
+ /* 88 */ 667, 667, 611, 333, 278, 333, 584, 556,
+ /* 96 */ 333, 556, 611, 556, 611, 556, 333, 611,
+ /* 104 */ 611, 278, 278, 556, 278, 889, 611, 611,
+ /* 112 */ 611, 611, 389, 556, 333, 611, 556, 778,
+ /* 120 */ 556, 556, 500, 389, 280, 389, 584, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 278, 722, 333, 611, 556, 611, 667, 556,
+ /* 168 */ 333, 667, 667, 611, 611, 333, 611, 611,
+ /* 176 */ 333, 556, 333, 278, 333, 369, 556, 333,
+ /* 184 */ 333, 556, 556, 385, 500, 333, 500, 500,
+ /* 192 */ 722, 722, 722, 722, 722, 611, 722, 722,
+ /* 200 */ 722, 667, 667, 667, 667, 278, 278, 722,
+ /* 208 */ 722, 722, 722, 778, 778, 778, 778, 584,
+ /* 216 */ 722, 722, 722, 722, 722, 667, 611, 611,
+ /* 224 */ 389, 556, 556, 556, 556, 278, 556, 556,
+ /* 232 */ 556, 556, 556, 556, 556, 278, 278, 707,
+ /* 240 */ 611, 611, 611, 611, 611, 611, 611, 584,
+ /* 248 */ 389, 611, 611, 611, 611, 556, 333, 333,
+ },
+ { /* Helvetica-Oblique */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 278, 278, 355, 556, 556, 889, 667, 191,
+ /* 40 */ 333, 333, 389, 584, 278, 333, 278, 278,
+ /* 48 */ 556, 556, 556, 556, 556, 556, 556, 556,
+ /* 56 */ 556, 556, 278, 278, 584, 584, 584, 556,
+ /* 64 */ 1015, 667, 667, 722, 722, 667, 611, 778,
+ /* 72 */ 722, 278, 500, 667, 556, 833, 722, 778,
+ /* 80 */ 667, 778, 722, 667, 611, 722, 667, 944,
+ /* 88 */ 667, 667, 611, 278, 278, 278, 469, 556,
+ /* 96 */ 333, 556, 556, 500, 556, 556, 278, 556,
+ /* 104 */ 556, 222, 222, 500, 222, 833, 556, 556,
+ /* 112 */ 556, 556, 333, 500, 278, 556, 500, 722,
+ /* 120 */ 500, 500, 500, 334, 260, 334, 584, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 278, 667, 333, 556, 556, 556, 667, 556,
+ /* 168 */ 333, 667, 667, 611, 611, 333, 611, 611,
+ /* 176 */ 333, 556, 333, 222, 333, 307, 500, 333,
+ /* 184 */ 333, 500, 500, 319, 500, 333, 500, 500,
+ /* 192 */ 722, 667, 667, 667, 667, 556, 722, 722,
+ /* 200 */ 722, 667, 667, 667, 667, 278, 278, 722,
+ /* 208 */ 722, 722, 722, 778, 778, 778, 778, 584,
+ /* 216 */ 722, 722, 722, 722, 722, 667, 611, 611,
+ /* 224 */ 333, 556, 556, 556, 556, 222, 500, 500,
+ /* 232 */ 500, 556, 556, 556, 556, 278, 278, 650,
+ /* 240 */ 556, 556, 556, 556, 556, 556, 556, 584,
+ /* 248 */ 333, 556, 556, 556, 556, 500, 278, 333,
+ },
+ { /* Helvetica-BoldOblique */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 278, 333, 474, 556, 556, 889, 722, 238,
+ /* 40 */ 333, 333, 389, 584, 278, 333, 278, 278,
+ /* 48 */ 556, 556, 556, 556, 556, 556, 556, 556,
+ /* 56 */ 556, 556, 333, 333, 584, 584, 584, 611,
+ /* 64 */ 975, 722, 722, 722, 722, 667, 611, 778,
+ /* 72 */ 722, 278, 556, 722, 611, 833, 722, 778,
+ /* 80 */ 667, 778, 722, 667, 611, 722, 667, 944,
+ /* 88 */ 667, 667, 611, 333, 278, 333, 584, 556,
+ /* 96 */ 333, 556, 611, 556, 611, 556, 333, 611,
+ /* 104 */ 611, 278, 278, 556, 278, 889, 611, 611,
+ /* 112 */ 611, 611, 389, 556, 333, 611, 556, 778,
+ /* 120 */ 556, 556, 500, 389, 280, 389, 584, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 278, 722, 333, 611, 556, 611, 667, 556,
+ /* 168 */ 333, 667, 667, 611, 611, 333, 611, 611,
+ /* 176 */ 333, 556, 333, 278, 333, 384, 556, 333,
+ /* 184 */ 333, 556, 556, 404, 500, 333, 500, 500,
+ /* 192 */ 722, 722, 722, 722, 722, 611, 722, 722,
+ /* 200 */ 722, 667, 667, 667, 667, 278, 278, 722,
+ /* 208 */ 722, 722, 722, 778, 778, 778, 778, 584,
+ /* 216 */ 722, 722, 722, 722, 722, 667, 611, 611,
+ /* 224 */ 389, 556, 556, 556, 556, 278, 556, 556,
+ /* 232 */ 556, 556, 556, 556, 556, 278, 278, 722,
+ /* 240 */ 611, 611, 611, 611, 611, 611, 611, 584,
+ /* 248 */ 389, 611, 611, 611, 611, 556, 333, 333,
+ },
+ { /* Palatino-Roman */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 250, 278, 371, 500, 500, 840, 778, 208,
+ /* 40 */ 333, 333, 389, 606, 250, 333, 250, 606,
+ /* 48 */ 500, 500, 500, 500, 500, 500, 500, 500,
+ /* 56 */ 500, 500, 250, 250, 606, 606, 606, 444,
+ /* 64 */ 747, 778, 611, 709, 774, 611, 556, 763,
+ /* 72 */ 832, 337, 333, 726, 611, 946, 831, 786,
+ /* 80 */ 604, 786, 668, 525, 613, 778, 722, 1000,
+ /* 88 */ 667, 667, 667, 333, 606, 333, 606, 500,
+ /* 96 */ 333, 500, 553, 444, 611, 479, 333, 556,
+ /* 104 */ 582, 291, 234, 556, 291, 883, 582, 546,
+ /* 112 */ 601, 560, 395, 424, 326, 603, 565, 834,
+ /* 120 */ 516, 556, 500, 333, 606, 333, 606, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 250, 778, 333, 611, 500, 611, 525, 500,
+ /* 168 */ 333, 525, 525, 613, 667, 333, 667, 667,
+ /* 176 */ 333, 500, 313, 291, 333, 375, 424, 333,
+ /* 184 */ 333, 424, 424, 375, 500, 380, 500, 500,
+ /* 192 */ 668, 778, 778, 778, 778, 611, 709, 709,
+ /* 200 */ 709, 611, 611, 611, 611, 337, 337, 774,
+ /* 208 */ 774, 831, 831, 786, 786, 786, 786, 606,
+ /* 216 */ 668, 778, 778, 778, 778, 667, 613, 556,
+ /* 224 */ 395, 500, 500, 500, 500, 291, 444, 444,
+ /* 232 */ 444, 479, 479, 479, 479, 287, 287, 671,
+ /* 240 */ 611, 582, 582, 546, 546, 546, 546, 606,
+ /* 248 */ 395, 603, 603, 603, 603, 556, 326, 250,
+ },
+ { /* Palatino-Bold */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 250, 278, 402, 500, 500, 889, 833, 227,
+ /* 40 */ 333, 333, 444, 606, 250, 333, 250, 296,
+ /* 48 */ 500, 500, 500, 500, 500, 500, 500, 500,
+ /* 56 */ 500, 500, 250, 250, 606, 606, 606, 444,
+ /* 64 */ 747, 778, 667, 722, 833, 611, 556, 833,
+ /* 72 */ 833, 389, 389, 778, 611, 1000, 833, 833,
+ /* 80 */ 611, 833, 722, 611, 667, 778, 778, 1000,
+ /* 88 */ 667, 667, 667, 333, 606, 333, 606, 500,
+ /* 96 */ 333, 500, 611, 444, 611, 500, 389, 556,
+ /* 104 */ 611, 333, 333, 611, 333, 889, 611, 556,
+ /* 112 */ 611, 611, 389, 444, 333, 611, 556, 833,
+ /* 120 */ 500, 556, 500, 310, 606, 310, 606, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 250, 778, 333, 611, 500, 611, 611, 500,
+ /* 168 */ 333, 611, 611, 667, 667, 333, 667, 667,
+ /* 176 */ 333, 500, 333, 333, 333, 433, 444, 333,
+ /* 184 */ 333, 444, 444, 402, 500, 333, 500, 500,
+ /* 192 */ 722, 778, 778, 778, 778, 611, 722, 722,
+ /* 200 */ 722, 611, 611, 611, 611, 389, 389, 833,
+ /* 208 */ 833, 833, 833, 833, 833, 833, 833, 606,
+ /* 216 */ 722, 778, 778, 778, 778, 667, 667, 611,
+ /* 224 */ 389, 500, 500, 500, 500, 333, 444, 444,
+ /* 232 */ 444, 500, 500, 500, 500, 333, 333, 711,
+ /* 240 */ 611, 611, 611, 556, 556, 556, 556, 606,
+ /* 248 */ 389, 611, 611, 611, 611, 556, 333, 333,
+ },
+ { /* Palatino-Italic */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 250, 333, 500, 500, 500, 889, 778, 333,
+ /* 40 */ 333, 333, 389, 606, 250, 333, 250, 296,
+ /* 48 */ 500, 500, 500, 500, 500, 500, 500, 500,
+ /* 56 */ 500, 500, 250, 250, 606, 606, 606, 500,
+ /* 64 */ 747, 722, 611, 667, 778, 611, 556, 722,
+ /* 72 */ 778, 333, 333, 667, 556, 944, 778, 778,
+ /* 80 */ 611, 778, 667, 556, 611, 778, 722, 944,
+ /* 88 */ 722, 667, 667, 333, 606, 333, 606, 500,
+ /* 96 */ 333, 444, 463, 407, 500, 389, 278, 500,
+ /* 104 */ 500, 278, 278, 444, 278, 778, 556, 444,
+ /* 112 */ 500, 463, 389, 389, 333, 556, 500, 722,
+ /* 120 */ 500, 500, 444, 333, 606, 333, 606, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 250, 722, 333, 556, 500, 556, 556, 500,
+ /* 168 */ 333, 556, 556, 611, 667, 333, 667, 667,
+ /* 176 */ 333, 444, 333, 278, 333, 346, 389, 333,
+ /* 184 */ 333, 389, 389, 361, 444, 333, 444, 444,
+ /* 192 */ 667, 722, 722, 722, 722, 556, 667, 667,
+ /* 200 */ 667, 611, 611, 611, 611, 333, 333, 778,
+ /* 208 */ 778, 778, 778, 778, 778, 778, 778, 606,
+ /* 216 */ 667, 778, 778, 778, 778, 667, 611, 500,
+ /* 224 */ 389, 444, 444, 444, 444, 278, 407, 407,
+ /* 232 */ 407, 389, 389, 389, 389, 278, 278, 577,
+ /* 240 */ 500, 556, 556, 444, 444, 444, 444, 606,
+ /* 248 */ 389, 556, 556, 556, 556, 500, 333, 333,
+ },
+ { /* Palatino-BoldItalic */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 250, 333, 500, 500, 500, 889, 833, 250,
+ /* 40 */ 333, 333, 444, 606, 250, 389, 250, 315,
+ /* 48 */ 500, 500, 500, 500, 500, 500, 500, 500,
+ /* 56 */ 500, 500, 250, 250, 606, 606, 606, 444,
+ /* 64 */ 833, 722, 667, 685, 778, 611, 556, 778,
+ /* 72 */ 778, 389, 389, 722, 611, 944, 778, 833,
+ /* 80 */ 667, 833, 722, 556, 611, 778, 667, 1000,
+ /* 88 */ 722, 611, 667, 333, 606, 333, 606, 500,
+ /* 96 */ 333, 556, 537, 444, 556, 444, 333, 500,
+ /* 104 */ 556, 333, 333, 556, 333, 833, 556, 556,
+ /* 112 */ 556, 537, 389, 444, 389, 556, 556, 833,
+ /* 120 */ 500, 556, 500, 333, 606, 333, 606, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 250, 722, 333, 611, 500, 611, 556, 556,
+ /* 168 */ 333, 556, 556, 611, 667, 389, 667, 667,
+ /* 176 */ 556, 556, 333, 333, 333, 429, 444, 333,
+ /* 184 */ 333, 444, 444, 389, 500, 333, 500, 500,
+ /* 192 */ 722, 722, 722, 722, 722, 611, 685, 685,
+ /* 200 */ 685, 611, 611, 611, 611, 389, 389, 778,
+ /* 208 */ 778, 778, 778, 833, 833, 833, 833, 606,
+ /* 216 */ 722, 778, 778, 778, 778, 611, 611, 556,
+ /* 224 */ 389, 556, 556, 556, 556, 333, 444, 444,
+ /* 232 */ 444, 444, 444, 444, 444, 333, 333, 667,
+ /* 240 */ 556, 556, 556, 556, 556, 556, 556, 606,
+ /* 248 */ 389, 556, 556, 556, 556, 556, 389, 333,
+ },
+ { /* Helvetica-Narrow */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 228, 228, 291, 456, 456, 729, 547, 157,
+ /* 40 */ 273, 273, 319, 479, 228, 273, 228, 228,
+ /* 48 */ 456, 456, 456, 456, 456, 456, 456, 456,
+ /* 56 */ 456, 456, 228, 228, 479, 479, 479, 456,
+ /* 64 */ 832, 547, 547, 592, 592, 547, 501, 638,
+ /* 72 */ 592, 228, 410, 547, 456, 683, 592, 638,
+ /* 80 */ 547, 638, 592, 547, 501, 592, 547, 774,
+ /* 88 */ 547, 547, 501, 228, 228, 228, 385, 456,
+ /* 96 */ 273, 456, 456, 410, 456, 456, 228, 456,
+ /* 104 */ 456, 182, 182, 410, 182, 683, 456, 456,
+ /* 112 */ 456, 456, 273, 410, 228, 456, 410, 592,
+ /* 120 */ 410, 410, 410, 274, 213, 274, 479, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 228, 547, 273, 456, 456, 456, 547, 456,
+ /* 168 */ 273, 547, 547, 501, 501, 273, 501, 501,
+ /* 176 */ 273, 456, 273, 182, 273, 212, 410, 273,
+ /* 184 */ 273, 410, 410, 248, 410, 273, 410, 410,
+ /* 192 */ 592, 547, 547, 547, 547, 456, 592, 592,
+ /* 200 */ 592, 547, 547, 547, 547, 228, 228, 592,
+ /* 208 */ 592, 592, 592, 638, 638, 638, 638, 479,
+ /* 216 */ 592, 592, 592, 592, 592, 547, 501, 501,
+ /* 224 */ 273, 456, 456, 456, 456, 182, 410, 410,
+ /* 232 */ 410, 456, 456, 456, 456, 228, 228, 496,
+ /* 240 */ 456, 456, 456, 456, 456, 456, 456, 479,
+ /* 248 */ 273, 456, 456, 456, 456, 410, 228, 273,
+ },
+ { /* Helvetica-Narrow-Bold */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 228, 273, 389, 456, 456, 729, 592, 195,
+ /* 40 */ 273, 273, 319, 479, 228, 273, 228, 228,
+ /* 48 */ 456, 456, 456, 456, 456, 456, 456, 456,
+ /* 56 */ 456, 456, 273, 273, 479, 479, 479, 501,
+ /* 64 */ 800, 592, 592, 592, 592, 547, 501, 638,
+ /* 72 */ 592, 228, 456, 592, 501, 683, 592, 638,
+ /* 80 */ 547, 638, 592, 547, 501, 592, 547, 774,
+ /* 88 */ 547, 547, 501, 273, 228, 273, 479, 456,
+ /* 96 */ 273, 456, 501, 456, 501, 456, 273, 501,
+ /* 104 */ 501, 228, 228, 456, 228, 729, 501, 501,
+ /* 112 */ 501, 501, 319, 456, 273, 501, 456, 638,
+ /* 120 */ 456, 456, 410, 319, 230, 319, 479, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 228, 592, 273, 501, 456, 501, 547, 456,
+ /* 168 */ 273, 547, 547, 501, 501, 273, 501, 501,
+ /* 176 */ 273, 456, 273, 228, 273, 280, 456, 273,
+ /* 184 */ 273, 456, 456, 338, 410, 273, 410, 410,
+ /* 192 */ 592, 592, 592, 592, 592, 501, 592, 592,
+ /* 200 */ 592, 547, 547, 547, 547, 228, 228, 592,
+ /* 208 */ 592, 592, 592, 638, 638, 638, 638, 479,
+ /* 216 */ 592, 592, 592, 592, 592, 547, 501, 501,
+ /* 224 */ 319, 456, 456, 456, 456, 228, 456, 456,
+ /* 232 */ 456, 456, 456, 456, 456, 228, 228, 561,
+ /* 240 */ 501, 501, 501, 501, 501, 501, 501, 479,
+ /* 248 */ 319, 501, 501, 501, 501, 456, 273, 273,
+ },
+ { /* Helvetica-Narrow-Oblique */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 228, 228, 291, 456, 456, 729, 547, 157,
+ /* 40 */ 273, 273, 319, 479, 228, 273, 228, 228,
+ /* 48 */ 456, 456, 456, 456, 456, 456, 456, 456,
+ /* 56 */ 456, 456, 228, 228, 479, 479, 479, 456,
+ /* 64 */ 832, 547, 547, 592, 592, 547, 501, 638,
+ /* 72 */ 592, 228, 410, 547, 456, 683, 592, 638,
+ /* 80 */ 547, 638, 592, 547, 501, 592, 547, 774,
+ /* 88 */ 547, 547, 501, 228, 228, 228, 385, 456,
+ /* 96 */ 273, 456, 456, 410, 456, 456, 228, 456,
+ /* 104 */ 456, 182, 182, 410, 182, 683, 456, 456,
+ /* 112 */ 456, 456, 273, 410, 228, 456, 410, 592,
+ /* 120 */ 410, 410, 410, 274, 213, 274, 479, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 228, 547, 273, 456, 456, 456, 547, 456,
+ /* 168 */ 273, 547, 547, 501, 501, 273, 501, 501,
+ /* 176 */ 273, 456, 273, 182, 273, 217, 410, 273,
+ /* 184 */ 273, 410, 410, 254, 410, 273, 410, 410,
+ /* 192 */ 592, 547, 547, 547, 547, 456, 592, 592,
+ /* 200 */ 592, 547, 547, 547, 547, 228, 228, 592,
+ /* 208 */ 592, 592, 592, 638, 638, 638, 638, 479,
+ /* 216 */ 592, 592, 592, 592, 592, 547, 501, 501,
+ /* 224 */ 273, 456, 456, 456, 456, 182, 410, 410,
+ /* 232 */ 410, 456, 456, 456, 456, 228, 228, 503,
+ /* 240 */ 456, 456, 456, 456, 456, 456, 456, 479,
+ /* 248 */ 273, 456, 456, 456, 456, 410, 228, 273,
+ },
+ { /* Helvetica-Narrow-BoldOblique */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 228, 273, 389, 456, 456, 729, 592, 195,
+ /* 40 */ 273, 273, 319, 479, 228, 273, 228, 228,
+ /* 48 */ 456, 456, 456, 456, 456, 456, 456, 456,
+ /* 56 */ 456, 456, 273, 273, 479, 479, 479, 501,
+ /* 64 */ 800, 592, 592, 592, 592, 547, 501, 638,
+ /* 72 */ 592, 228, 456, 592, 501, 683, 592, 638,
+ /* 80 */ 547, 638, 592, 547, 501, 592, 547, 774,
+ /* 88 */ 547, 547, 501, 273, 228, 273, 479, 456,
+ /* 96 */ 273, 456, 501, 456, 501, 456, 273, 501,
+ /* 104 */ 501, 228, 228, 456, 228, 729, 501, 501,
+ /* 112 */ 501, 501, 319, 456, 273, 501, 456, 638,
+ /* 120 */ 456, 456, 410, 319, 230, 319, 479, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 228, 592, 273, 501, 456, 501, 547, 456,
+ /* 168 */ 273, 547, 547, 501, 501, 273, 501, 501,
+ /* 176 */ 273, 456, 273, 228, 273, 283, 456, 273,
+ /* 184 */ 273, 456, 456, 312, 410, 273, 410, 410,
+ /* 192 */ 592, 592, 592, 592, 592, 501, 592, 592,
+ /* 200 */ 592, 547, 547, 547, 547, 228, 228, 592,
+ /* 208 */ 592, 592, 592, 638, 638, 638, 638, 479,
+ /* 216 */ 592, 592, 592, 592, 592, 547, 501, 501,
+ /* 224 */ 319, 456, 456, 456, 456, 228, 456, 456,
+ /* 232 */ 456, 456, 456, 456, 456, 228, 228, 561,
+ /* 240 */ 501, 501, 501, 501, 501, 501, 501, 479,
+ /* 248 */ 319, 501, 501, 501, 501, 456, 273, 273,
+ },
+ { /* Bookman-Light */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 320, 300, 380, 620, 620, 900, 800, 220,
+ /* 40 */ 300, 300, 440, 600, 320, 400, 320, 600,
+ /* 48 */ 620, 620, 620, 620, 620, 620, 620, 620,
+ /* 56 */ 620, 620, 320, 320, 600, 600, 600, 540,
+ /* 64 */ 820, 680, 740, 740, 800, 720, 640, 800,
+ /* 72 */ 800, 340, 600, 720, 600, 920, 740, 800,
+ /* 80 */ 620, 820, 720, 660, 620, 780, 700, 960,
+ /* 88 */ 720, 640, 640, 300, 600, 300, 600, 500,
+ /* 96 */ 340, 580, 620, 520, 620, 520, 320, 540,
+ /* 104 */ 660, 300, 300, 620, 300, 940, 660, 560,
+ /* 112 */ 620, 580, 440, 520, 380, 680, 520, 780,
+ /* 120 */ 560, 540, 480, 280, 600, 280, 600, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 320, 680, 460, 600, 620, 600, 660, 520,
+ /* 168 */ 420, 660, 660, 620, 640, 400, 640, 640,
+ /* 176 */ 320, 580, 320, 320, 340, 336, 520, 420,
+ /* 184 */ 320, 520, 520, 380, 480, 380, 480, 480,
+ /* 192 */ 720, 680, 680, 680, 680, 600, 740, 740,
+ /* 200 */ 740, 720, 720, 720, 720, 340, 340, 800,
+ /* 208 */ 800, 740, 740, 800, 800, 800, 800, 600,
+ /* 216 */ 720, 780, 780, 780, 780, 640, 620, 660,
+ /* 224 */ 440, 580, 580, 580, 580, 300, 520, 520,
+ /* 232 */ 520, 520, 520, 520, 520, 300, 300, 620,
+ /* 240 */ 620, 660, 660, 560, 560, 560, 560, 600,
+ /* 248 */ 440, 680, 680, 680, 680, 540, 380, 260,
+ },
+ { /* Bookman-Demi */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 340, 360, 420, 660, 660, 940, 800, 240,
+ /* 40 */ 320, 320, 460, 600, 340, 360, 340, 600,
+ /* 48 */ 660, 660, 660, 660, 660, 660, 660, 660,
+ /* 56 */ 660, 660, 340, 340, 600, 600, 600, 660,
+ /* 64 */ 820, 720, 720, 740, 780, 720, 680, 780,
+ /* 72 */ 820, 400, 640, 800, 640, 940, 740, 800,
+ /* 80 */ 660, 800, 780, 660, 700, 740, 720, 940,
+ /* 88 */ 780, 700, 640, 300, 600, 300, 600, 500,
+ /* 96 */ 400, 580, 600, 580, 640, 580, 380, 580,
+ /* 104 */ 680, 360, 340, 660, 340, 1000, 680, 620,
+ /* 112 */ 640, 620, 460, 520, 460, 660, 600, 800,
+ /* 120 */ 600, 620, 560, 320, 600, 320, 600, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 340, 720, 500, 640, 660, 640, 660, 600,
+ /* 168 */ 500, 660, 660, 700, 640, 360, 640, 640,
+ /* 176 */ 340, 580, 320, 340, 400, 430, 520, 500,
+ /* 184 */ 360, 520, 520, 470, 560, 440, 560, 560,
+ /* 192 */ 780, 720, 720, 720, 720, 640, 740, 740,
+ /* 200 */ 740, 720, 720, 720, 720, 400, 400, 780,
+ /* 208 */ 780, 740, 740, 800, 800, 800, 800, 600,
+ /* 216 */ 780, 740, 740, 740, 740, 700, 700, 660,
+ /* 224 */ 460, 580, 580, 580, 580, 340, 580, 580,
+ /* 232 */ 580, 580, 580, 580, 580, 360, 360, 720,
+ /* 240 */ 640, 680, 680, 620, 620, 620, 620, 600,
+ /* 248 */ 460, 660, 660, 660, 660, 620, 460, 320,
+ },
+ { /* Bookman-LightItalic */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 300, 320, 360, 620, 620, 800, 820, 200,
+ /* 40 */ 280, 280, 440, 600, 300, 320, 300, 600,
+ /* 48 */ 620, 620, 620, 620, 620, 620, 620, 620,
+ /* 56 */ 620, 620, 300, 300, 600, 600, 600, 540,
+ /* 64 */ 780, 700, 720, 720, 740, 680, 620, 760,
+ /* 72 */ 800, 320, 560, 720, 580, 860, 720, 760,
+ /* 80 */ 600, 780, 700, 640, 600, 720, 680, 960,
+ /* 88 */ 700, 660, 580, 260, 600, 260, 600, 500,
+ /* 96 */ 340, 620, 600, 480, 640, 540, 340, 560,
+ /* 104 */ 620, 280, 280, 600, 280, 880, 620, 540,
+ /* 112 */ 600, 560, 400, 540, 340, 620, 540, 880,
+ /* 120 */ 540, 600, 520, 360, 600, 380, 600, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 300, 700, 440, 580, 620, 580, 640, 620,
+ /* 168 */ 420, 640, 640, 600, 580, 320, 580, 580,
+ /* 176 */ 300, 620, 260, 340, 320, 380, 540, 440,
+ /* 184 */ 320, 540, 540, 340, 520, 340, 520, 520,
+ /* 192 */ 700, 700, 700, 700, 700, 580, 720, 720,
+ /* 200 */ 720, 680, 680, 680, 680, 320, 320, 740,
+ /* 208 */ 740, 720, 720, 760, 760, 760, 760, 600,
+ /* 216 */ 700, 720, 720, 720, 720, 660, 600, 620,
+ /* 224 */ 400, 620, 620, 620, 620, 280, 480, 480,
+ /* 232 */ 480, 540, 540, 540, 540, 280, 280, 730,
+ /* 240 */ 640, 620, 620, 540, 540, 540, 540, 600,
+ /* 248 */ 400, 620, 620, 620, 620, 600, 340, 260,
+ },
+ { /* Bookman-DemiItalic */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 340, 320, 380, 680, 680, 880, 980, 180,
+ /* 40 */ 260, 260, 460, 600, 340, 280, 340, 360,
+ /* 48 */ 680, 680, 680, 680, 680, 680, 680, 680,
+ /* 56 */ 680, 680, 340, 340, 620, 600, 620, 620,
+ /* 64 */ 780, 720, 720, 700, 760, 720, 660, 760,
+ /* 72 */ 800, 380, 620, 780, 640, 860, 740, 760,
+ /* 80 */ 640, 760, 740, 700, 700, 740, 660, 1000,
+ /* 88 */ 740, 660, 680, 260, 580, 260, 620, 500,
+ /* 96 */ 380, 680, 600, 560, 680, 560, 420, 620,
+ /* 104 */ 700, 380, 320, 700, 380, 960, 680, 600,
+ /* 112 */ 660, 620, 500, 540, 440, 680, 540, 860,
+ /* 120 */ 620, 600, 560, 300, 620, 300, 620, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 340, 720, 460, 640, 680, 640, 700, 620,
+ /* 168 */ 520, 700, 700, 700, 680, 280, 680, 680,
+ /* 176 */ 360, 680, 320, 380, 340, 509, 540, 480,
+ /* 184 */ 360, 540, 540, 520, 560, 560, 560, 560,
+ /* 192 */ 740, 720, 720, 720, 720, 640, 700, 700,
+ /* 200 */ 700, 720, 720, 720, 720, 380, 380, 760,
+ /* 208 */ 760, 740, 740, 760, 760, 760, 760, 600,
+ /* 216 */ 740, 740, 740, 740, 740, 660, 700, 660,
+ /* 224 */ 500, 680, 680, 680, 680, 380, 560, 560,
+ /* 232 */ 560, 560, 560, 560, 560, 380, 380, 810,
+ /* 240 */ 680, 680, 680, 600, 600, 600, 600, 600,
+ /* 248 */ 500, 680, 680, 680, 680, 600, 440, 380,
+ },
+ { /* AvantGarde-Book */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 277, 295, 309, 554, 554, 775, 757, 198,
+ /* 40 */ 369, 369, 425, 606, 277, 332, 277, 437,
+ /* 48 */ 554, 554, 554, 554, 554, 554, 554, 554,
+ /* 56 */ 554, 554, 277, 277, 606, 606, 606, 591,
+ /* 64 */ 867, 740, 574, 813, 744, 536, 485, 872,
+ /* 72 */ 683, 226, 482, 591, 462, 919, 740, 869,
+ /* 80 */ 592, 871, 607, 498, 426, 655, 702, 960,
+ /* 88 */ 609, 592, 480, 351, 605, 351, 606, 500,
+ /* 96 */ 378, 683, 682, 647, 685, 650, 314, 673,
+ /* 104 */ 610, 200, 203, 502, 200, 938, 610, 655,
+ /* 112 */ 682, 682, 301, 388, 339, 608, 554, 831,
+ /* 120 */ 480, 536, 425, 351, 672, 351, 606, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 277, 740, 453, 517, 554, 462, 498, 615,
+ /* 168 */ 369, 498, 498, 426, 480, 332, 480, 480,
+ /* 176 */ 332, 683, 302, 300, 375, 245, 388, 502,
+ /* 184 */ 324, 388, 388, 339, 425, 552, 425, 425,
+ /* 192 */ 607, 740, 740, 740, 740, 462, 813, 813,
+ /* 200 */ 813, 536, 536, 536, 536, 226, 226, 744,
+ /* 208 */ 790, 740, 740, 869, 869, 869, 869, 606,
+ /* 216 */ 607, 655, 655, 655, 655, 592, 426, 554,
+ /* 224 */ 301, 683, 683, 683, 683, 200, 647, 647,
+ /* 232 */ 647, 650, 650, 650, 650, 200, 200, 725,
+ /* 240 */ 685, 610, 610, 655, 655, 655, 655, 606,
+ /* 248 */ 301, 608, 608, 608, 608, 536, 339, 222,
+ },
+ { /* AvantGarde-Demi */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 280, 280, 360, 560, 560, 860, 680, 220,
+ /* 40 */ 380, 380, 440, 600, 280, 420, 280, 460,
+ /* 48 */ 560, 560, 560, 560, 560, 560, 560, 560,
+ /* 56 */ 560, 560, 280, 280, 600, 600, 600, 560,
+ /* 64 */ 740, 740, 580, 780, 700, 520, 480, 840,
+ /* 72 */ 680, 280, 480, 620, 440, 900, 740, 840,
+ /* 80 */ 560, 840, 580, 520, 420, 640, 700, 900,
+ /* 88 */ 680, 620, 500, 320, 640, 320, 600, 500,
+ /* 96 */ 420, 660, 660, 640, 660, 640, 280, 660,
+ /* 104 */ 600, 240, 260, 580, 240, 940, 600, 640,
+ /* 112 */ 660, 660, 320, 440, 300, 600, 560, 800,
+ /* 120 */ 560, 580, 460, 340, 600, 340, 600, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 280, 740, 480, 480, 560, 440, 520, 560,
+ /* 168 */ 500, 520, 520, 420, 500, 420, 500, 500,
+ /* 176 */ 360, 660, 340, 320, 420, 330, 440, 540,
+ /* 184 */ 340, 440, 440, 369, 460, 700, 460, 460,
+ /* 192 */ 580, 740, 740, 740, 740, 440, 780, 780,
+ /* 200 */ 780, 520, 520, 520, 520, 280, 280, 700,
+ /* 208 */ 742, 740, 740, 840, 840, 840, 840, 600,
+ /* 216 */ 580, 640, 640, 640, 640, 620, 420, 600,
+ /* 224 */ 320, 660, 660, 660, 660, 240, 640, 640,
+ /* 232 */ 640, 640, 640, 640, 640, 240, 240, 754,
+ /* 240 */ 660, 600, 600, 640, 640, 640, 640, 600,
+ /* 248 */ 320, 600, 600, 600, 600, 580, 300, 280,
+ },
+ { /* AvantGarde-BookOblique */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 277, 295, 309, 554, 554, 775, 757, 198,
+ /* 40 */ 369, 369, 425, 606, 277, 332, 277, 437,
+ /* 48 */ 554, 554, 554, 554, 554, 554, 554, 554,
+ /* 56 */ 554, 554, 277, 277, 606, 606, 606, 591,
+ /* 64 */ 867, 740, 574, 813, 744, 536, 485, 872,
+ /* 72 */ 683, 226, 482, 591, 462, 919, 740, 869,
+ /* 80 */ 592, 871, 607, 498, 426, 655, 702, 960,
+ /* 88 */ 609, 592, 480, 351, 605, 351, 606, 500,
+ /* 96 */ 378, 683, 682, 647, 685, 650, 314, 673,
+ /* 104 */ 610, 200, 203, 502, 200, 938, 610, 655,
+ /* 112 */ 682, 682, 301, 388, 339, 608, 554, 831,
+ /* 120 */ 480, 536, 425, 351, 672, 351, 606, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 277, 740, 453, 517, 554, 462, 498, 615,
+ /* 168 */ 369, 498, 498, 426, 480, 332, 480, 480,
+ /* 176 */ 332, 683, 302, 300, 375, 231, 388, 502,
+ /* 184 */ 324, 388, 388, 339, 425, 552, 425, 425,
+ /* 192 */ 607, 740, 740, 740, 740, 462, 813, 813,
+ /* 200 */ 813, 536, 536, 536, 536, 226, 226, 744,
+ /* 208 */ 790, 740, 740, 869, 869, 869, 869, 606,
+ /* 216 */ 607, 655, 655, 655, 655, 592, 426, 554,
+ /* 224 */ 301, 683, 683, 683, 683, 200, 647, 647,
+ /* 232 */ 647, 650, 650, 650, 650, 200, 200, 714,
+ /* 240 */ 685, 610, 610, 655, 655, 655, 655, 606,
+ /* 248 */ 301, 608, 608, 608, 608, 536, 339, 222,
+ },
+ { /* AvantGarde-DemiOblique */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 280, 280, 360, 560, 560, 860, 680, 220,
+ /* 40 */ 380, 380, 440, 600, 280, 420, 280, 460,
+ /* 48 */ 560, 560, 560, 560, 560, 560, 560, 560,
+ /* 56 */ 560, 560, 280, 280, 600, 600, 600, 560,
+ /* 64 */ 740, 740, 580, 780, 700, 520, 480, 840,
+ /* 72 */ 680, 280, 480, 620, 440, 900, 740, 840,
+ /* 80 */ 560, 840, 580, 520, 420, 640, 700, 900,
+ /* 88 */ 680, 620, 500, 320, 640, 320, 600, 500,
+ /* 96 */ 420, 660, 660, 640, 660, 640, 280, 660,
+ /* 104 */ 600, 240, 260, 580, 240, 940, 600, 640,
+ /* 112 */ 660, 660, 320, 440, 300, 600, 560, 800,
+ /* 120 */ 560, 580, 460, 340, 600, 340, 600, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 280, 740, 480, 480, 560, 440, 520, 560,
+ /* 168 */ 500, 520, 520, 420, 500, 420, 500, 500,
+ /* 176 */ 360, 660, 340, 320, 420, 326, 440, 540,
+ /* 184 */ 340, 440, 440, 364, 460, 700, 460, 460,
+ /* 192 */ 580, 740, 740, 740, 740, 440, 780, 780,
+ /* 200 */ 780, 520, 520, 520, 520, 280, 280, 700,
+ /* 208 */ 742, 740, 740, 840, 840, 840, 840, 600,
+ /* 216 */ 580, 640, 640, 640, 640, 620, 420, 600,
+ /* 224 */ 320, 660, 660, 660, 660, 240, 640, 640,
+ /* 232 */ 640, 640, 640, 640, 640, 240, 240, 752,
+ /* 240 */ 660, 600, 600, 640, 640, 640, 640, 600,
+ /* 248 */ 320, 600, 600, 600, 600, 580, 300, 280,
+ },
+ { /* NewCenturySchlbk-Roman */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 278, 296, 389, 556, 556, 833, 815, 204,
+ /* 40 */ 333, 333, 500, 606, 278, 333, 278, 278,
+ /* 48 */ 556, 556, 556, 556, 556, 556, 556, 556,
+ /* 56 */ 556, 556, 278, 278, 606, 606, 606, 444,
+ /* 64 */ 737, 722, 722, 722, 778, 722, 667, 778,
+ /* 72 */ 833, 407, 556, 778, 667, 944, 815, 778,
+ /* 80 */ 667, 778, 722, 630, 667, 815, 722, 981,
+ /* 88 */ 704, 704, 611, 333, 606, 333, 606, 500,
+ /* 96 */ 333, 556, 556, 444, 574, 500, 333, 537,
+ /* 104 */ 611, 315, 296, 593, 315, 889, 611, 500,
+ /* 112 */ 574, 556, 444, 463, 389, 611, 537, 778,
+ /* 120 */ 537, 537, 481, 333, 606, 333, 606, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 278, 722, 333, 667, 556, 667, 630, 500,
+ /* 168 */ 333, 630, 630, 667, 611, 333, 611, 611,
+ /* 176 */ 333, 556, 333, 315, 333, 339, 463, 333,
+ /* 184 */ 333, 463, 463, 389, 481, 333, 481, 481,
+ /* 192 */ 722, 722, 722, 722, 722, 667, 722, 722,
+ /* 200 */ 722, 722, 722, 722, 722, 407, 407, 778,
+ /* 208 */ 778, 815, 815, 778, 778, 778, 778, 606,
+ /* 216 */ 722, 815, 815, 815, 815, 704, 667, 574,
+ /* 224 */ 444, 556, 556, 556, 556, 315, 444, 444,
+ /* 232 */ 444, 500, 500, 500, 500, 315, 315, 606,
+ /* 240 */ 574, 611, 611, 500, 500, 500, 500, 606,
+ /* 248 */ 444, 611, 611, 611, 611, 537, 389, 333,
+ },
+ { /* NewCenturySchlbk-Bold */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 287, 296, 333, 574, 574, 833, 852, 241,
+ /* 40 */ 389, 389, 500, 606, 278, 333, 278, 278,
+ /* 48 */ 574, 574, 574, 574, 574, 574, 574, 574,
+ /* 56 */ 574, 574, 278, 278, 606, 606, 606, 500,
+ /* 64 */ 747, 759, 778, 778, 833, 759, 722, 833,
+ /* 72 */ 870, 444, 648, 815, 722, 981, 833, 833,
+ /* 80 */ 759, 833, 815, 667, 722, 833, 759, 981,
+ /* 88 */ 722, 722, 667, 389, 606, 389, 606, 500,
+ /* 96 */ 333, 611, 648, 556, 667, 574, 389, 611,
+ /* 104 */ 685, 370, 352, 667, 352, 963, 685, 611,
+ /* 112 */ 667, 648, 519, 500, 426, 685, 611, 889,
+ /* 120 */ 611, 611, 537, 389, 606, 389, 606, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 287, 759, 333, 722, 574, 722, 667, 500,
+ /* 168 */ 333, 667, 667, 722, 667, 333, 667, 667,
+ /* 176 */ 333, 611, 333, 352, 333, 436, 500, 333,
+ /* 184 */ 333, 500, 500, 446, 537, 333, 537, 537,
+ /* 192 */ 815, 759, 759, 759, 759, 722, 778, 778,
+ /* 200 */ 778, 759, 759, 759, 759, 444, 444, 833,
+ /* 208 */ 833, 833, 833, 833, 833, 833, 833, 606,
+ /* 216 */ 815, 833, 833, 833, 833, 722, 722, 611,
+ /* 224 */ 519, 611, 611, 611, 611, 352, 556, 556,
+ /* 232 */ 556, 574, 574, 574, 574, 370, 370, 747,
+ /* 240 */ 667, 685, 685, 611, 611, 611, 611, 606,
+ /* 248 */ 519, 685, 685, 685, 685, 611, 426, 333,
+ },
+ { /* NewCenturySchlbk-Italic */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 278, 333, 400, 556, 556, 833, 852, 278,
+ /* 40 */ 333, 333, 500, 606, 278, 333, 278, 606,
+ /* 48 */ 556, 556, 556, 556, 556, 556, 556, 556,
+ /* 56 */ 556, 556, 278, 278, 606, 606, 606, 444,
+ /* 64 */ 747, 704, 722, 722, 778, 722, 667, 778,
+ /* 72 */ 833, 407, 611, 741, 667, 944, 815, 778,
+ /* 80 */ 667, 778, 741, 667, 685, 815, 704, 926,
+ /* 88 */ 704, 685, 667, 333, 606, 333, 606, 500,
+ /* 96 */ 333, 574, 556, 444, 611, 444, 333, 537,
+ /* 104 */ 611, 333, 315, 556, 333, 889, 611, 500,
+ /* 112 */ 574, 556, 444, 444, 352, 611, 519, 778,
+ /* 120 */ 500, 500, 463, 333, 606, 333, 606, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 278, 704, 333, 667, 556, 667, 667, 500,
+ /* 168 */ 333, 667, 667, 685, 667, 333, 667, 667,
+ /* 176 */ 333, 574, 333, 333, 333, 359, 444, 333,
+ /* 184 */ 333, 444, 444, 368, 463, 333, 463, 463,
+ /* 192 */ 741, 704, 704, 704, 704, 667, 722, 722,
+ /* 200 */ 722, 722, 722, 722, 722, 407, 407, 778,
+ /* 208 */ 778, 815, 815, 778, 778, 778, 778, 606,
+ /* 216 */ 741, 815, 815, 815, 815, 685, 685, 556,
+ /* 224 */ 444, 574, 574, 574, 574, 333, 444, 444,
+ /* 232 */ 444, 444, 444, 444, 444, 333, 333, 651,
+ /* 240 */ 611, 611, 611, 500, 500, 500, 500, 606,
+ /* 248 */ 444, 611, 611, 611, 611, 500, 352, 333,
+ },
+ { /* NewCenturySchlbk-BoldItalic */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 16 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 24 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 32 */ 287, 333, 400, 574, 574, 889, 889, 287,
+ /* 40 */ 407, 407, 500, 606, 287, 333, 287, 278,
+ /* 48 */ 574, 574, 574, 574, 574, 574, 574, 574,
+ /* 56 */ 574, 574, 287, 287, 606, 606, 606, 481,
+ /* 64 */ 747, 741, 759, 759, 833, 741, 704, 815,
+ /* 72 */ 870, 444, 667, 778, 704, 944, 852, 833,
+ /* 80 */ 741, 833, 796, 685, 722, 833, 741, 944,
+ /* 88 */ 741, 704, 704, 407, 606, 407, 606, 500,
+ /* 96 */ 333, 667, 611, 537, 667, 519, 389, 611,
+ /* 104 */ 685, 389, 370, 648, 389, 944, 685, 574,
+ /* 112 */ 648, 630, 519, 481, 407, 685, 556, 833,
+ /* 120 */ 574, 519, 519, 407, 606, 407, 606, 0,
+ /* 128 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 136 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 144 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 152 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 160 */ 287, 741, 333, 704, 574, 704, 685, 500,
+ /* 168 */ 333, 685, 685, 722, 704, 333, 704, 704,
+ /* 176 */ 333, 667, 333, 389, 333, 486, 481, 333,
+ /* 184 */ 333, 481, 481, 483, 519, 333, 519, 519,
+ /* 192 */ 796, 741, 741, 741, 741, 704, 759, 759,
+ /* 200 */ 759, 741, 741, 741, 741, 444, 444, 833,
+ /* 208 */ 833, 852, 852, 833, 833, 833, 833, 606,
+ /* 216 */ 796, 833, 833, 833, 833, 704, 722, 574,
+ /* 224 */ 519, 667, 667, 667, 667, 389, 537, 537,
+ /* 232 */ 537, 519, 519, 519, 519, 389, 389, 780,
+ /* 240 */ 667, 685, 685, 574, 574, 574, 574, 606,
+ /* 248 */ 519, 685, 685, 685, 685, 519, 407, 333,
+ },
+};
+#if 0 /* Until this array is needed */
+static int aiUnderlineInfo[32][2] = {
+ { -100, 50 },
+ { -100, 50 },
+ { -100, 50 },
+ { -100, 50 },
+ { -100, 50 },
+ { -100, 50 },
+ { -100, 50 },
+ { -100, 50 },
+ { -151, 50 },
+ { -155, 69 },
+ { -151, 50 },
+ { -111, 69 },
+ { -100, 50 },
+ { -100, 50 },
+ { -100, 50 },
+ { -100, 50 },
+ { -100, 50 },
+ { -100, 50 },
+ { -100, 50 },
+ { -100, 50 },
+ { -125, 60 },
+ { -125, 60 },
+ { -125, 60 },
+ { -125, 60 },
+ { -96, 58 },
+ { -93, 90 },
+ { -96, 58 },
+ { -93, 90 },
+ { -104, 61 },
+ { -103, 90 },
+ { -102, 42 },
+ { -102, 54 },
+};
+#endif /* 0 */
diff --git a/sys/src/cmd/aux/antiword/fontlist.c b/sys/src/cmd/aux/antiword/fontlist.c
new file mode 100755
index 000000000..d55efbb2e
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/fontlist.c
@@ -0,0 +1,173 @@
+/*
+ * fontlist.c
+ * Copyright (C) 1998-2004 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Build, read and destroy a list of Word font information
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include "antiword.h"
+
+
+/*
+ * Private structure to hide the way the information
+ * is stored from the rest of the program
+ */
+typedef struct font_desc_tag {
+ font_block_type tInfo;
+ struct font_desc_tag *pNext;
+} font_mem_type;
+
+/* Variables needed to write the Font Information List */
+static font_mem_type *pAnchor = NULL;
+static font_mem_type *pFontLast = NULL;
+
+
+/*
+ * vDestroyFontInfoList - destroy the Font Information List
+ */
+void
+vDestroyFontInfoList(void)
+{
+ font_mem_type *pCurr, *pNext;
+
+ DBG_MSG("vDestroyFontInfoList");
+
+ /* Free the Font Information List */
+ pCurr = pAnchor;
+ while (pCurr != NULL) {
+ pNext = pCurr->pNext;
+ pCurr = xfree(pCurr);
+ pCurr = pNext;
+ }
+ pAnchor = NULL;
+ /* Reset all control variables */
+ pFontLast = NULL;
+} /* end of vDestroyFontInfoList */
+
+/*
+ * vCorrectFontValues - correct font values to values Antiword can use
+ */
+void
+vCorrectFontValues(font_block_type *pFontBlock)
+{
+ UINT uiRealSize;
+ USHORT usRealStyle;
+
+ uiRealSize = pFontBlock->usFontSize;
+ usRealStyle = pFontBlock->usFontStyle;
+ if (bIsSmallCapitals(pFontBlock->usFontStyle)) {
+ /* Small capitals become normal capitals in a smaller font */
+ uiRealSize = (uiRealSize * 4 + 2) / 5;
+ usRealStyle &= ~FONT_SMALL_CAPITALS;
+ usRealStyle |= FONT_CAPITALS;
+ }
+ if (bIsSuperscript(pFontBlock->usFontStyle) ||
+ bIsSubscript(pFontBlock->usFontStyle)) {
+ /* Superscript and subscript use a smaller fontsize */
+ uiRealSize = (uiRealSize * 2 + 1) / 3;
+ }
+
+ if (uiRealSize < MIN_FONT_SIZE) {
+ DBG_DEC(uiRealSize);
+ uiRealSize = MIN_FONT_SIZE;
+ } else if (uiRealSize > MAX_FONT_SIZE) {
+ DBG_DEC(uiRealSize);
+ uiRealSize = MAX_FONT_SIZE;
+ }
+
+ pFontBlock->usFontSize = (USHORT)uiRealSize;
+ if (pFontBlock->ucFontColor == 8) {
+ /* White text to light gray text */
+ pFontBlock->ucFontColor = 16;
+ }
+ pFontBlock->usFontStyle = usRealStyle;
+} /* end of vCorrectFontValues */
+
+/*
+ * vAdd2FontInfoList - Add an element to the Font Information List
+ */
+void
+vAdd2FontInfoList(const font_block_type *pFontBlock)
+{
+ font_mem_type *pListMember;
+
+ fail(pFontBlock == NULL);
+
+ NO_DBG_MSG("bAdd2FontInfoList");
+
+ if (pFontBlock->ulFileOffset == FC_INVALID) {
+ /*
+ * This offset is really past the end of the file,
+ * so don't waste any memory by storing it.
+ */
+ return;
+ }
+
+ NO_DBG_HEX(pFontBlock->ulFileOffset);
+ NO_DBG_DEC_C(pFontBlock->ucFontNumber != 0,
+ pFontBlock->ucFontNumber);
+ NO_DBG_DEC_C(pFontBlock->usFontSize != DEFAULT_FONT_SIZE,
+ pFontBlock->usFontSize);
+ NO_DBG_DEC_C(pFontBlock->ucFontColor != 0,
+ pFontBlock->ucFontColor);
+ NO_DBG_HEX_C(pFontBlock->usFontStyle != 0x00,
+ pFontBlock->usFontStyle);
+
+ if (pFontLast != NULL &&
+ pFontLast->tInfo.ulFileOffset == pFontBlock->ulFileOffset) {
+ /*
+ * If two consecutive fonts share the same
+ * offset, remember only the last font
+ */
+ fail(pFontLast->pNext != NULL);
+ pFontLast->tInfo = *pFontBlock;
+ return;
+ }
+
+ /* Create list member */
+ pListMember = xmalloc(sizeof(font_mem_type));
+ /* Fill the list member */
+ pListMember->tInfo = *pFontBlock;
+ pListMember->pNext = NULL;
+ /* Correct the values where needed */
+ vCorrectFontValues(&pListMember->tInfo);
+ /* Add the new member to the list */
+ if (pAnchor == NULL) {
+ pAnchor = pListMember;
+ } else {
+ fail(pFontLast == NULL);
+ pFontLast->pNext = pListMember;
+ }
+ pFontLast = pListMember;
+} /* end of vAdd2FontInfoList */
+
+/*
+ * Get the record that follows the given recored in the Font Information List
+ */
+const font_block_type *
+pGetNextFontInfoListItem(const font_block_type *pCurr)
+{
+ const font_mem_type *pRecord;
+ size_t tOffset;
+
+ if (pCurr == NULL) {
+ if (pAnchor == NULL) {
+ /* There are no records */
+ return NULL;
+ }
+ /* The first record is the only one without a predecessor */
+ return &pAnchor->tInfo;
+ }
+ tOffset = offsetof(font_mem_type, tInfo);
+ /* Many casts to prevent alignment warnings */
+ pRecord = (font_mem_type *)(void *)((char *)pCurr - tOffset);
+ fail(pCurr != &pRecord->tInfo);
+ if (pRecord->pNext == NULL) {
+ /* The last record has no successor */
+ return NULL;
+ }
+ return &pRecord->pNext->tInfo;
+} /* end of pGetNextFontInfoListItem */
diff --git a/sys/src/cmd/aux/antiword/fonts.c b/sys/src/cmd/aux/antiword/fonts.c
new file mode 100755
index 000000000..77fde74ed
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/fonts.c
@@ -0,0 +1,1018 @@
+/*
+ * fonts.c
+ * Copyright (C) 1998-2004 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Functions to deal with fonts (generic)
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include "antiword.h"
+
+/* Maximum line length in the font file */
+#define FONT_LINE_LENGTH 81
+
+/* Pitch */
+#define PITCH_UNKNOWN 0
+#define PITCH_FIXED 1
+#define PITCH_VARIABLE 2
+
+/* Font Family */
+#define FAMILY_UNKNOWN 0
+#define FAMILY_ROMAN 1
+#define FAMILY_SWISS 2
+#define FAMILY_MODERN 3
+#define FAMILY_SCRIPT 4
+#define FAMILY_DECORATIVE 5
+
+/* Font Translation Table */
+static size_t tFontTableRecords = 0;
+static font_table_type *pFontTable = NULL;
+
+/*
+ * Find the given font in the font table
+ *
+ * returns the index into the FontTable, -1 if not found
+ */
+int
+iGetFontByNumber(UCHAR ucWordFontNumber, USHORT usFontStyle)
+{
+ int iIndex;
+
+ for (iIndex = 0; iIndex < (int)tFontTableRecords; iIndex++) {
+ if (ucWordFontNumber == pFontTable[iIndex].ucWordFontNumber &&
+ usFontStyle == pFontTable[iIndex].usFontStyle &&
+ pFontTable[iIndex].szOurFontname[0] != '\0') {
+ return iIndex;
+ }
+ }
+ DBG_DEC(ucWordFontNumber);
+ DBG_HEX(usFontStyle);
+ return -1;
+} /* end of iGetFontByNumber */
+
+/*
+ * szGetOurFontname - Get our font name
+ *
+ * return our font name from the given index, NULL if not found
+ */
+const char *
+szGetOurFontname(int iIndex)
+{
+ if (iIndex < 0 || iIndex >= (int)tFontTableRecords) {
+ return NULL;
+ }
+ return pFontTable[iIndex].szOurFontname;
+} /* end of szGetOurFontname */
+
+/*
+ * Find the given font in the font table
+ *
+ * returns the Word font number, -1 if not found
+ */
+int
+iFontname2Fontnumber(const char *szOurFontname, USHORT usFontStyle)
+{
+ int iIndex;
+
+ for (iIndex = 0; iIndex < (int)tFontTableRecords; iIndex++) {
+ if (pFontTable[iIndex].usFontStyle == usFontStyle &&
+ STREQ(pFontTable[iIndex].szOurFontname, szOurFontname)) {
+ return (int)pFontTable[iIndex].ucWordFontNumber;
+ }
+ }
+ return -1;
+} /* end of iFontname2Fontnumber */
+
+/*
+ * szGetDefaultFont - get the default font that matches the parameters
+ */
+static const char *
+szGetDefaultFont(UCHAR ucFFN, int iEmphasis)
+{
+ UCHAR ucPrq, ucFf;
+
+ fail(iEmphasis < 0 || iEmphasis > 3);
+
+ ucPrq = ucFFN & 0x03;
+ ucFf = (ucFFN & 0x70) >> 4;
+ NO_DBG_DEC(ucPrq);
+ NO_DBG_DEC(ucFf);
+ if (ucPrq == PITCH_FIXED) {
+ /* Set to the default monospaced font */
+ switch (iEmphasis) {
+ case 1: return FONT_MONOSPACED_BOLD;
+ case 2: return FONT_MONOSPACED_ITALIC;
+ case 3: return FONT_MONOSPACED_BOLDITALIC;
+ default: return FONT_MONOSPACED_PLAIN;
+ }
+ } else if (ucFf == FAMILY_ROMAN) {
+ /* Set to the default serif font */
+ switch (iEmphasis) {
+ case 1: return FONT_SERIF_BOLD;
+ case 2: return FONT_SERIF_ITALIC;
+ case 3: return FONT_SERIF_BOLDITALIC;
+ default: return FONT_SERIF_PLAIN;
+ }
+ } else if (ucFf == FAMILY_SWISS) {
+ /* Set to the default sans serif font */
+ switch (iEmphasis) {
+ case 1: return FONT_SANS_SERIF_BOLD;
+ case 2: return FONT_SANS_SERIF_ITALIC;
+ case 3: return FONT_SANS_SERIF_BOLDITALIC;
+ default: return FONT_SANS_SERIF_PLAIN;
+ }
+ } else {
+ /* Set to the default default font */
+ switch (iEmphasis) {
+ case 1: return FONT_SERIF_BOLD;
+ case 2: return FONT_SERIF_ITALIC;
+ case 3: return FONT_SERIF_BOLDITALIC;
+ default: return FONT_SERIF_PLAIN;
+ }
+ }
+} /* end of szGetDefaultFont */
+
+/*
+ * See if the fontname from the Word file matches the fontname from the
+ * font translation file.
+ * If iBytesPerChar is one than aucWord is in ISO-8859-x (Word 2/6/7),
+ * if iBytesPerChar is two than aucWord is in Unicode (Word 8/9/10).
+ */
+static BOOL
+bFontEqual(const UCHAR *aucWord, const char *szTable, int iBytesPerChar)
+{
+ const UCHAR *pucTmp;
+ const char *pcTmp;
+
+ fail(aucWord == NULL || szTable == NULL);
+ fail(iBytesPerChar != 1 && iBytesPerChar != 2);
+
+ for (pucTmp = aucWord, pcTmp = szTable;
+ *pucTmp != 0;
+ pucTmp += iBytesPerChar, pcTmp++) {
+ if (ulToUpper((ULONG)*pucTmp) !=
+ ulToUpper((ULONG)(UCHAR)*pcTmp)) {
+ return FALSE;
+ }
+ }
+ return *pcTmp == '\0';
+} /* end of bFontEqual */
+
+/*
+ * vFontname2Table - add fontnames to the font table
+ */
+static void
+vFontname2Table(const UCHAR *aucFont, const UCHAR *aucAltFont,
+ int iBytesPerChar, int iEmphasis, UCHAR ucFFN,
+ const char *szWordFont, const char *szOurFont,
+ font_table_type *pFontTableRecord)
+{
+ BOOL bMatchFound;
+
+ fail(aucFont == NULL || aucFont[0] == 0);
+ fail(aucAltFont != NULL && aucAltFont[0] == 0);
+ fail(iBytesPerChar != 1 && iBytesPerChar != 2);
+ fail(iEmphasis < 0 || iEmphasis > 3);
+ fail(szWordFont == NULL || szWordFont[0] == '\0');
+ fail(szOurFont == NULL || szOurFont[0] == '\0');
+ fail(pFontTableRecord == NULL);
+
+ bMatchFound = bFontEqual(aucFont, szWordFont, iBytesPerChar);
+
+ if (!bMatchFound && aucAltFont != NULL) {
+ bMatchFound = bFontEqual(aucAltFont, szWordFont, iBytesPerChar);
+ }
+
+ if (!bMatchFound &&
+ pFontTableRecord->szWordFontname[0] == '\0' &&
+ szWordFont[0] == '*' &&
+ szWordFont[1] == '\0') {
+ /*
+ * szWordFont contains a "*", so szOurFont will contain the
+ * "default default" font. See if we can do better than that.
+ */
+ szOurFont = szGetDefaultFont(ucFFN, iEmphasis);
+ bMatchFound = TRUE;
+ }
+
+ if (bMatchFound) {
+ switch (iBytesPerChar) {
+ case 1:
+ (void)strncpy(pFontTableRecord->szWordFontname,
+ (const char *)aucFont,
+ sizeof(pFontTableRecord->szWordFontname) - 1);
+ break;
+ case 2:
+ (void)unincpy(pFontTableRecord->szWordFontname,
+ aucFont,
+ sizeof(pFontTableRecord->szWordFontname) - 1);
+ break;
+ default:
+ DBG_FIXME();
+ pFontTableRecord->szWordFontname[0] = '\0';
+ break;
+ }
+ pFontTableRecord->szWordFontname[
+ sizeof(pFontTableRecord->szWordFontname) - 1] = '\0';
+ (void)strncpy(pFontTableRecord->szOurFontname, szOurFont,
+ sizeof(pFontTableRecord->szOurFontname) - 1);
+ pFontTableRecord->szOurFontname[
+ sizeof(pFontTableRecord->szOurFontname) - 1] = '\0';
+ NO_DBG_MSG(pFontTableRecord->szWordFontname);
+ NO_DBG_MSG(pFontTableRecord->szOurFontname);
+ pFontTableRecord->ucFFN = ucFFN;
+ pFontTableRecord->ucEmphasis = (UCHAR)iEmphasis;
+ }
+} /* end of vFontname2Table */
+
+/*
+ * vCreateFontTable - Create and initialize the internal font table
+ */
+static void
+vCreateFontTable(void)
+{
+ font_table_type *pTmp;
+ int iNbr;
+
+ if (tFontTableRecords == 0) {
+ pFontTable = xfree(pFontTable);
+ return;
+ }
+
+ /* Create the font table */
+ pFontTable = xcalloc(tFontTableRecords, sizeof(*pFontTable));
+
+ /* Initialize the font table */
+ for (iNbr = 0, pTmp = pFontTable;
+ pTmp < pFontTable + tFontTableRecords;
+ iNbr++, pTmp++) {
+ pTmp->ucWordFontNumber = (UCHAR)(iNbr / 4);
+ switch (iNbr % 4) {
+ case 0:
+ pTmp->usFontStyle = FONT_REGULAR;
+ break;
+ case 1:
+ pTmp->usFontStyle = FONT_BOLD;
+ break;
+ case 2:
+ pTmp->usFontStyle = FONT_ITALIC;
+ break;
+ case 3:
+ pTmp->usFontStyle = FONT_BOLD|FONT_ITALIC;
+ break;
+ default:
+ DBG_DEC(iNbr);
+ break;
+ }
+ }
+} /* end of vCreateFontTable */
+
+/*
+ * vMinimizeFontTable - make the font table as small as possible
+ */
+static void
+vMinimizeFontTable(void)
+{
+ font_block_type tFontNext;
+ const style_block_type *pStyle;
+ const font_block_type *pFont;
+ font_table_type *pTmp;
+ int iUnUsed;
+ BOOL bMustAddTableFont;
+
+ NO_DBG_MSG("vMinimizeFontTable");
+
+ if (tFontTableRecords == 0) {
+ pFontTable = xfree(pFontTable);
+ return;
+ }
+
+ /* See if we must add a font for our tables */
+ bMustAddTableFont = TRUE;
+
+#if 0
+ DBG_MSG("Before");
+ DBG_DEC(tFontTableRecords);
+ for (pTmp = pFontTable;
+ pTmp < pFontTable + tFontTableRecords;
+ pTmp++) {
+ DBG_DEC(pTmp->ucWordFontNumber);
+ DBG_HEX(pTmp->usFontStyle);
+ DBG_MSG(pTmp->szWordFontname);
+ DBG_MSG(pTmp->szOurFontname);
+ }
+#endif /* DEBUG */
+
+ /* See which fonts/styles we really need */
+
+ /* Default font/style is by definition in use */
+ pFontTable[0].ucInUse = 1;
+
+ /* Make InUse 1 for all the fonts/styles that WILL be used */
+ pFont = NULL;
+ while((pFont = pGetNextFontInfoListItem(pFont)) != NULL) {
+ pTmp = pFontTable + 4 * (int)pFont->ucFontNumber;
+ if (bIsBold(pFont->usFontStyle)) {
+ pTmp++;
+ }
+ if (bIsItalic(pFont->usFontStyle)) {
+ pTmp += 2;
+ }
+ if (pTmp >= pFontTable + tFontTableRecords) {
+ continue;
+ }
+ if (STREQ(pTmp->szOurFontname, TABLE_FONT)) {
+ /* The table font is already present */
+ bMustAddTableFont = FALSE;
+ }
+ pTmp->ucInUse = 1;
+ }
+
+ /* Make InUse 1 for all the fonts/styles that MIGHT be used */
+ pStyle = NULL;
+ while((pStyle = pGetNextStyleInfoListItem(pStyle)) != NULL) {
+ vFillFontFromStylesheet(pStyle->usIstdNext, &tFontNext);
+ vCorrectFontValues(&tFontNext);
+ pTmp = pFontTable + 4 * (int)tFontNext.ucFontNumber;
+ if (bIsBold(tFontNext.usFontStyle)) {
+ pTmp++;
+ }
+ if (bIsItalic(tFontNext.usFontStyle)) {
+ pTmp += 2;
+ }
+ if (pTmp >= pFontTable + tFontTableRecords) {
+ continue;
+ }
+ if (STREQ(pTmp->szOurFontname, TABLE_FONT)) {
+ /* The table font is already present */
+ bMustAddTableFont = FALSE;
+ }
+ pTmp->ucInUse = 1;
+ }
+
+ /* Remove the unused font entries from the font table */
+ iUnUsed = 0;
+ for (pTmp = pFontTable;
+ pTmp < pFontTable + tFontTableRecords;
+ pTmp++) {
+ if (pTmp->ucInUse == 0) {
+ iUnUsed++;
+ continue;
+ }
+ if (iUnUsed > 0) {
+ fail(pTmp - iUnUsed <= pFontTable);
+ *(pTmp - iUnUsed) = *pTmp;
+ }
+ }
+ fail(iUnUsed < 0);
+ fail(tFontTableRecords <= (size_t)iUnUsed);
+ tFontTableRecords -= (size_t)iUnUsed;
+
+ if (bMustAddTableFont) {
+ pTmp = pFontTable + tFontTableRecords;
+ fail(pTmp <= pFontTable);
+ pTmp->ucWordFontNumber = (pTmp - 1)->ucWordFontNumber + 1;
+ pTmp->usFontStyle = FONT_REGULAR;
+ pTmp->ucInUse = 1;
+ strcpy(pTmp->szWordFontname, "Extra Table Font");
+ strcpy(pTmp->szOurFontname, TABLE_FONT);
+ tFontTableRecords++;
+ iUnUsed--;
+ }
+ if (iUnUsed > 0) {
+ /* Resize the font table */
+ pFontTable = xrealloc(pFontTable,
+ tFontTableRecords * sizeof(*pFontTable));
+ }
+#if defined(DEBUG)
+ DBG_MSG("After");
+ DBG_DEC(tFontTableRecords);
+ for (pTmp = pFontTable;
+ pTmp < pFontTable + tFontTableRecords;
+ pTmp++) {
+ DBG_DEC(pTmp->ucWordFontNumber);
+ DBG_HEX(pTmp->usFontStyle);
+ DBG_MSG(pTmp->szWordFontname);
+ DBG_MSG(pTmp->szOurFontname);
+ }
+#endif /* DEBUG */
+} /* end of vMinimizeFontTable */
+
+/*
+ * bReadFontFile - read and check a line from the font translation file
+ *
+ * returns TRUE when a correct line has been read, otherwise FALSE
+ */
+static BOOL
+bReadFontFile(FILE *pFontTableFile, char *szWordFont,
+ int *piItalic, int *piBold, char *szOurFont, int *piSpecial)
+{
+ char *pcTmp;
+ int iFields;
+ char szLine[FONT_LINE_LENGTH];
+
+ fail(szWordFont == NULL || szOurFont == NULL);
+ fail(piItalic == NULL || piBold == NULL || piSpecial == NULL);
+
+ while (fgets(szLine, (int)sizeof(szLine), pFontTableFile) != NULL) {
+ if (szLine[0] == '#' ||
+ szLine[0] == '\n' ||
+ szLine[0] == '\r') {
+ continue;
+ }
+ iFields = sscanf(szLine, "%[^,],%d,%d,%1s%[^,],%d",
+ szWordFont, piItalic, piBold,
+ &szOurFont[0], &szOurFont[1], piSpecial);
+ if (iFields != 6) {
+ pcTmp = strchr(szLine, '\r');
+ if (pcTmp != NULL) {
+ *pcTmp = '\0';
+ }
+ pcTmp = strchr(szLine, '\n');
+ if (pcTmp != NULL) {
+ *pcTmp = '\0';
+ }
+ DBG_DEC(iFields);
+ werr(0, "Syntax error in: '%s'", szLine);
+ continue;
+ }
+ if (strlen(szWordFont) >=
+ sizeof(pFontTable[0].szWordFontname)) {
+ werr(0, "Word fontname too long: '%s'", szWordFont);
+ continue;
+ }
+ if (strlen(szOurFont) >=
+ sizeof(pFontTable[0].szOurFontname)) {
+ werr(0, "Local fontname too long: '%s'", szOurFont);
+ continue;
+ }
+ /* The current line passed all the tests */
+ return TRUE;
+ }
+ return FALSE;
+} /* end of bReadFontFile */
+
+/*
+ * vCreate0FontTable - create a font table from Word for DOS
+ */
+void
+vCreate0FontTable(void)
+{
+ FILE *pFontTableFile;
+ font_table_type *pTmp;
+ UCHAR *aucFont;
+ int iBold, iItalic, iSpecial, iEmphasis, iFtc;
+ UCHAR ucPrq, ucFf, ucFFN;
+ char szWordFont[FONT_LINE_LENGTH], szOurFont[FONT_LINE_LENGTH];
+
+ tFontTableRecords = 0;
+ pFontTable = xfree(pFontTable);
+
+ pFontTableFile = pOpenFontTableFile();
+ if (pFontTableFile == NULL) {
+ /* No translation table file, no translation table */
+ return;
+ }
+
+ /* Get the maximum number of entries in the font table */
+ tFontTableRecords = 64;
+ tFontTableRecords *= 4; /* Plain, Bold, Italic and Bold/italic */
+ tFontTableRecords++; /* One extra for the table-font */
+ vCreateFontTable();
+
+ /* Read the font translation file */
+ iItalic = 0;
+ iBold = 0;
+ iSpecial = 0;
+ while (bReadFontFile(pFontTableFile, szWordFont,
+ &iItalic, &iBold, szOurFont, &iSpecial)) {
+ iEmphasis = 0;
+ if (iBold != 0) {
+ iEmphasis++;
+ }
+ if (iItalic != 0) {
+ iEmphasis += 2;
+ }
+ for (iFtc = 0, pTmp = pFontTable + iEmphasis;
+ pTmp < pFontTable + tFontTableRecords;
+ iFtc++, pTmp += 4) {
+ if (iFtc >= 16 && iFtc <= 55) {
+ ucPrq = PITCH_VARIABLE;
+ ucFf = FAMILY_ROMAN;
+ aucFont = (UCHAR *)"Times";
+ } else {
+ ucPrq = PITCH_FIXED;
+ ucFf = FAMILY_MODERN;
+ aucFont = (UCHAR *)"Courier";
+ }
+ ucFFN = (ucFf << 4) | ucPrq;
+ vFontname2Table(aucFont, NULL, 1, iEmphasis,
+ ucFFN, szWordFont, szOurFont, pTmp);
+ }
+ }
+ (void)fclose(pFontTableFile);
+ vMinimizeFontTable();
+} /* end of vCreate0FontTable */
+
+/*
+ * vCreate2FontTable - create a font table from WinWord 1/2
+ */
+void
+vCreate2FontTable(FILE *pFile, int iWordVersion, const UCHAR *aucHeader)
+{
+ FILE *pFontTableFile;
+ font_table_type *pTmp;
+ UCHAR *aucFont;
+ UCHAR *aucBuffer;
+ ULONG ulBeginFontInfo;
+ size_t tFontInfoLen;
+ int iPos, iOff, iRecLen;
+ int iBold, iItalic, iSpecial, iEmphasis;
+ UCHAR ucFFN;
+ char szWordFont[FONT_LINE_LENGTH], szOurFont[FONT_LINE_LENGTH];
+
+ fail(pFile == NULL || aucHeader == NULL);
+ fail(iWordVersion != 1 && iWordVersion != 2);
+
+ tFontTableRecords = 0;
+ pFontTable = xfree(pFontTable);
+
+ pFontTableFile = pOpenFontTableFile();
+ if (pFontTableFile == NULL) {
+ /* No translation table file, no translation table */
+ return;
+ }
+
+ ulBeginFontInfo = ulGetLong(0xb2, aucHeader); /* fcSttbfffn */
+ DBG_HEX(ulBeginFontInfo);
+ tFontInfoLen = (size_t)usGetWord(0xb6, aucHeader); /* cbSttbfffn */
+ DBG_DEC(tFontInfoLen);
+
+ if (ulBeginFontInfo > (ULONG)LONG_MAX || tFontInfoLen == 0) {
+ /* Don't ask me why this is needed */
+ DBG_HEX_C(tFontInfoLen != 0, ulBeginFontInfo);
+ (void)fclose(pFontTableFile);
+ return;
+ }
+
+ aucBuffer = xmalloc(tFontInfoLen);
+ if (!bReadBytes(aucBuffer, tFontInfoLen, ulBeginFontInfo, pFile)) {
+ aucBuffer = xfree(aucBuffer);
+ (void)fclose(pFontTableFile);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tFontInfoLen);
+ DBG_DEC(usGetWord(0, aucBuffer));
+
+ /* Compute the maximum number of entries in the font table */
+ if (iWordVersion == 1) {
+ fail(tFontInfoLen < 2);
+ /* WinWord 1 has three implicit fonts */
+ tFontTableRecords = 3;
+ iOff = 2;
+ } else {
+ fail(tFontInfoLen < 6);
+ /* WinWord 2 and up have no implicit fonts */
+ tFontTableRecords = 0;
+ iOff = 3;
+ }
+ iPos = 2;
+ while (iPos + iOff < (int)tFontInfoLen) {
+ iRecLen = (int)ucGetByte(iPos, aucBuffer);
+ NO_DBG_DEC(iRecLen);
+ NO_DBG_MSG(aucBuffer + iPos + iOff);
+ iPos += iRecLen + 1;
+ tFontTableRecords++;
+ }
+ tFontTableRecords *= 4; /* Plain, Bold, Italic and Bold/Italic */
+ tFontTableRecords++; /* One extra for the table-font */
+ vCreateFontTable();
+
+ /* Add the tree implicit fonts (in four variations) */
+ if (iWordVersion == 1) {
+ fail(tFontTableRecords < 13);
+ vFontname2Table((UCHAR *)"Tms Rmn", NULL, 1, 0,
+ (UCHAR)((FAMILY_ROMAN << 4) | PITCH_VARIABLE),
+ "*", "Times-Roman", pFontTable + 0);
+ vFontname2Table((UCHAR *)"Tms Rmn", NULL, 1, 1,
+ (UCHAR)((FAMILY_ROMAN << 4) | PITCH_VARIABLE),
+ "*", "Times-Bold", pFontTable + 1);
+ vFontname2Table((UCHAR *)"Tms Rmn", NULL, 1, 2,
+ (UCHAR)((FAMILY_ROMAN << 4) | PITCH_VARIABLE),
+ "*", "Times-Italic", pFontTable + 2);
+ vFontname2Table((UCHAR *)"Tms Rmn", NULL, 1, 3,
+ (UCHAR)((FAMILY_ROMAN << 4) | PITCH_VARIABLE),
+ "*", "Times-BoldItalic", pFontTable + 3);
+ vFontname2Table((UCHAR *)"Symbol", NULL, 1, 0,
+ (UCHAR)((FAMILY_ROMAN << 4) | PITCH_VARIABLE),
+ "*", "Times-Roman", pFontTable + 4);
+ vFontname2Table((UCHAR *)"Symbol", NULL, 1, 1,
+ (UCHAR)((FAMILY_ROMAN << 4) | PITCH_VARIABLE),
+ "*", "Times-Bold", pFontTable + 5);
+ vFontname2Table((UCHAR *)"Symbol", NULL, 1, 2,
+ (UCHAR)((FAMILY_ROMAN << 4) | PITCH_VARIABLE),
+ "*", "Times-Italic", pFontTable + 6);
+ vFontname2Table((UCHAR *)"Symbol", NULL, 1, 3,
+ (UCHAR)((FAMILY_ROMAN << 4) | PITCH_VARIABLE),
+ "*", "Times-BoldItalic", pFontTable + 7);
+ vFontname2Table((UCHAR *)"Helv", NULL, 1, 0,
+ (UCHAR)((FAMILY_SWISS << 4) | PITCH_VARIABLE),
+ "*", "Helvetica", pFontTable + 8);
+ vFontname2Table((UCHAR *)"Helv", NULL, 1, 1,
+ (UCHAR)((FAMILY_SWISS << 4) | PITCH_VARIABLE),
+ "*", "Helvetica-Bold", pFontTable + 9);
+ vFontname2Table((UCHAR *)"Helv", NULL, 1, 2,
+ (UCHAR)((FAMILY_SWISS << 4) | PITCH_VARIABLE),
+ "*", "Helvetica-Oblique", pFontTable + 10);
+ vFontname2Table((UCHAR *)"Helv", NULL, 1, 3,
+ (UCHAR)((FAMILY_SWISS << 4) | PITCH_VARIABLE),
+ "*", "Helvetica-BoldOblique", pFontTable + 11);
+ }
+
+ /* Read the font translation file */
+ iItalic = 0;
+ iBold = 0;
+ iSpecial = 0;
+ while (bReadFontFile(pFontTableFile, szWordFont,
+ &iItalic, &iBold, szOurFont, &iSpecial)) {
+ iEmphasis = 0;
+ if (iBold != 0) {
+ iEmphasis++;
+ }
+ if (iItalic != 0) {
+ iEmphasis += 2;
+ }
+ pTmp = pFontTable + iEmphasis;
+ iPos = 2;
+ while (iPos + iOff < (int)tFontInfoLen) {
+ iRecLen = (int)ucGetByte(iPos, aucBuffer);
+ ucFFN = ucGetByte(iPos + 1, aucBuffer);
+ aucFont = aucBuffer + iPos + iOff;
+ vFontname2Table(aucFont, NULL, 1, iEmphasis,
+ ucFFN, szWordFont, szOurFont, pTmp);
+ pTmp += 4;
+ iPos += iRecLen + 1;
+ }
+ }
+ (void)fclose(pFontTableFile);
+ aucBuffer = xfree(aucBuffer);
+ vMinimizeFontTable();
+} /* end of vCreate2FontTable */
+
+/*
+ * vCreate6FontTable - create a font table from Word 6/7
+ */
+void
+vCreate6FontTable(FILE *pFile, ULONG ulStartBlock,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const UCHAR *aucHeader)
+{
+ FILE *pFontTableFile;
+ font_table_type *pTmp;
+ UCHAR *aucFont, *aucAltFont;
+ UCHAR *aucBuffer;
+ ULONG ulBeginFontInfo;
+ size_t tFontInfoLen;
+ int iPos, iRecLen, iOffsetAltName;
+ int iBold, iItalic, iSpecial, iEmphasis;
+ UCHAR ucFFN;
+ char szWordFont[FONT_LINE_LENGTH], szOurFont[FONT_LINE_LENGTH];
+
+ fail(pFile == NULL || aucHeader == NULL);
+ fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
+ fail(aulBBD == NULL);
+
+ tFontTableRecords = 0;
+ pFontTable = xfree(pFontTable);
+
+ pFontTableFile = pOpenFontTableFile();
+ if (pFontTableFile == NULL) {
+ /* No translation table file, no translation table */
+ return;
+ }
+
+ ulBeginFontInfo = ulGetLong(0xd0, aucHeader); /* fcSttbfffn */
+ DBG_HEX(ulBeginFontInfo);
+ tFontInfoLen = (size_t)ulGetLong(0xd4, aucHeader); /* lcbSttbfffn */
+ DBG_DEC(tFontInfoLen);
+ fail(tFontInfoLen < 9);
+
+ aucBuffer = xmalloc(tFontInfoLen);
+ if (!bReadBuffer(pFile, ulStartBlock,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucBuffer, ulBeginFontInfo, tFontInfoLen)) {
+ aucBuffer = xfree(aucBuffer);
+ (void)fclose(pFontTableFile);
+ return;
+ }
+ DBG_DEC(usGetWord(0, aucBuffer));
+
+ /* Compute the maximum number of entries in the font table */
+ tFontTableRecords = 0;
+ iPos = 2;
+ while (iPos + 6 < (int)tFontInfoLen) {
+ iRecLen = (int)ucGetByte(iPos, aucBuffer);
+ NO_DBG_DEC(iRecLen);
+ iOffsetAltName = (int)ucGetByte(iPos + 5, aucBuffer);
+ NO_DBG_MSG(aucBuffer + iPos + 6);
+ NO_DBG_MSG_C(iOffsetAltName > 0,
+ aucBuffer + iPos + 6 + iOffsetAltName);
+ iPos += iRecLen + 1;
+ tFontTableRecords++;
+ }
+ tFontTableRecords *= 4; /* Plain, Bold, Italic and Bold/italic */
+ tFontTableRecords++; /* One extra for the table-font */
+ vCreateFontTable();
+
+ /* Read the font translation file */
+ iItalic = 0;
+ iBold = 0;
+ iSpecial = 0;
+ while (bReadFontFile(pFontTableFile, szWordFont,
+ &iItalic, &iBold, szOurFont, &iSpecial)) {
+ iEmphasis = 0;
+ if (iBold != 0) {
+ iEmphasis++;
+ }
+ if (iItalic != 0) {
+ iEmphasis += 2;
+ }
+ pTmp = pFontTable + iEmphasis;
+ iPos = 2;
+ while (iPos + 6 < (int)tFontInfoLen) {
+ iRecLen = (int)ucGetByte(iPos, aucBuffer);
+ ucFFN = ucGetByte(iPos + 1, aucBuffer);
+ aucFont = aucBuffer + iPos + 6;
+ iOffsetAltName = (int)ucGetByte(iPos + 5, aucBuffer);
+ if (iOffsetAltName <= 0) {
+ aucAltFont = NULL;
+ } else {
+ aucAltFont = aucFont + iOffsetAltName;
+ NO_DBG_MSG(aucFont);
+ NO_DBG_MSG(aucAltFont);
+ }
+ vFontname2Table(aucFont, aucAltFont, 1, iEmphasis,
+ ucFFN, szWordFont, szOurFont, pTmp);
+ pTmp += 4;
+ iPos += iRecLen + 1;
+ }
+ }
+ (void)fclose(pFontTableFile);
+ aucBuffer = xfree(aucBuffer);
+ vMinimizeFontTable();
+} /* end of vCreate6FontTable */
+
+/*
+ * vCreate8FontTable - create a font table from Word 8/9/10
+ */
+void
+vCreate8FontTable(FILE *pFile, const pps_info_type *pPPS,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ const UCHAR *aucHeader)
+{
+ FILE *pFontTableFile;
+ font_table_type *pTmp;
+ const ULONG *aulBlockDepot;
+ UCHAR *aucFont, *aucAltFont;
+ UCHAR *aucBuffer;
+ ULONG ulBeginFontInfo;
+ size_t tFontInfoLen, tBlockDepotLen, tBlockSize;
+ int iPos, iRecLen, iOffsetAltName;
+ int iBold, iItalic, iSpecial, iEmphasis;
+ UCHAR ucFFN;
+ char szWordFont[FONT_LINE_LENGTH], szOurFont[FONT_LINE_LENGTH];
+
+ fail(pFile == NULL || pPPS == NULL || aucHeader == NULL);
+ fail(aulBBD == NULL || aulSBD == NULL);
+
+ tFontTableRecords = 0;
+ pFontTable = xfree(pFontTable);
+
+ pFontTableFile = pOpenFontTableFile();
+ if (pFontTableFile == NULL) {
+ /* No translation table file, no translation table */
+ return;
+ }
+
+ ulBeginFontInfo = ulGetLong(0x112, aucHeader); /* fcSttbfffn */
+ DBG_HEX(ulBeginFontInfo);
+ tFontInfoLen = (size_t)ulGetLong(0x116, aucHeader); /* lcbSttbfffn */
+ DBG_DEC(tFontInfoLen);
+ fail(tFontInfoLen < 46);
+
+ DBG_DEC(pPPS->tTable.ulSB);
+ DBG_HEX(pPPS->tTable.ulSize);
+ if (pPPS->tTable.ulSize == 0) {
+ DBG_MSG("No fontname table");
+ (void)fclose(pFontTableFile);
+ return;
+ }
+
+ if (pPPS->tTable.ulSize < MIN_SIZE_FOR_BBD_USE) {
+ /* Use the Small Block Depot */
+ aulBlockDepot = aulSBD;
+ tBlockDepotLen = tSBDLen;
+ tBlockSize = SMALL_BLOCK_SIZE;
+ } else {
+ /* Use the Big Block Depot */
+ aulBlockDepot = aulBBD;
+ tBlockDepotLen = tBBDLen;
+ tBlockSize = BIG_BLOCK_SIZE;
+ }
+ aucBuffer = xmalloc(tFontInfoLen);
+ if (!bReadBuffer(pFile, pPPS->tTable.ulSB,
+ aulBlockDepot, tBlockDepotLen, tBlockSize,
+ aucBuffer, ulBeginFontInfo, tFontInfoLen)) {
+ aucBuffer = xfree(aucBuffer);
+ (void)fclose(pFontTableFile);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tFontInfoLen);
+
+ /* Get the maximum number of entries in the font table */
+ tFontTableRecords = (size_t)usGetWord(0, aucBuffer);
+ tFontTableRecords *= 4; /* Plain, Bold, Italic and Bold/italic */
+ tFontTableRecords++; /* One extra for the table-font */
+ vCreateFontTable();
+
+ /* Read the font translation file */
+ iItalic = 0;
+ iBold = 0;
+ iSpecial = 0;
+ while (bReadFontFile(pFontTableFile, szWordFont,
+ &iItalic, &iBold, szOurFont, &iSpecial)) {
+ iEmphasis = 0;
+ if (iBold != 0) {
+ iEmphasis++;
+ }
+ if (iItalic != 0) {
+ iEmphasis += 2;
+ }
+ pTmp = pFontTable + iEmphasis;
+ iPos = 4;
+ while (iPos + 40 < (int)tFontInfoLen) {
+ iRecLen = (int)ucGetByte(iPos, aucBuffer);
+ ucFFN = ucGetByte(iPos + 1, aucBuffer);
+ aucFont = aucBuffer + iPos + 40;
+ iOffsetAltName = (int)unilen(aucFont);
+ if (iPos + 40 + iOffsetAltName + 4 >= iRecLen) {
+ aucAltFont = NULL;
+ } else {
+ aucAltFont = aucFont + iOffsetAltName + 2;
+ NO_DBG_UNICODE(aucFont);
+ NO_DBG_UNICODE(aucAltFont);
+ }
+ vFontname2Table(aucFont, aucAltFont, 2, iEmphasis,
+ ucFFN, szWordFont, szOurFont, pTmp);
+ pTmp += 4;
+ iPos += iRecLen + 1;
+ }
+ }
+ (void)fclose(pFontTableFile);
+ aucBuffer = xfree(aucBuffer);
+ vMinimizeFontTable();
+} /* end of vCreate8FontTable */
+
+/*
+ * Destroy the internal font table by freeing its memory
+ */
+void
+vDestroyFontTable(void)
+{
+ DBG_MSG("vDestroyFontTable");
+
+ tFontTableRecords = 0;
+ pFontTable = xfree(pFontTable);
+} /* end of vDestroyFontTable */
+
+/*
+ * pGetNextFontTableRecord
+ *
+ * returns the next record in the table or NULL if there is no next record
+ */
+const font_table_type *
+pGetNextFontTableRecord(const font_table_type *pRecordCurr)
+{
+ size_t tIndexCurr;
+
+ if (pRecordCurr == NULL) {
+ /* No current record, so start with the first one */
+ return &pFontTable[0];
+ }
+
+ if (pRecordCurr < pFontTable ||
+ pRecordCurr >= pFontTable + tFontTableRecords) {
+ /* Not a pointer in the array */
+ DBG_HEX(pRecordCurr);
+ DBG_HEX(pFontTable);
+ return NULL;
+ }
+
+ tIndexCurr = (size_t)(pRecordCurr - pFontTable);
+ if (tIndexCurr + 1 < tFontTableRecords) {
+ /* There is a next record, so return it */
+ return &pFontTable[tIndexCurr + 1];
+ }
+ /* There is no next record */
+ return NULL;
+} /* end of pGetNextFontTableRecord */
+
+/*
+ * tGetFontTableLength
+ *
+ * returns the number of records in the internal font table
+ */
+size_t
+tGetFontTableLength(void)
+{
+ return tFontTableRecords;
+} /* end of tGetFontTableLength */
+
+#if !defined(__riscos)
+/*
+ * vCorrect4PDF - only include PDF default fonts
+ */
+static void
+vCorrect4PDF(void)
+{
+ font_table_type *pTmp;
+ const char *szOurFont;
+
+ for (pTmp = pFontTable; pTmp < pFontTable + tFontTableRecords; pTmp++) {
+ if (STRCEQ(pTmp->szOurFontname, FONT_MONOSPACED_PLAIN) ||
+ STRCEQ(pTmp->szOurFontname, FONT_MONOSPACED_BOLD) ||
+ STRCEQ(pTmp->szOurFontname, FONT_MONOSPACED_ITALIC) ||
+ STRCEQ(pTmp->szOurFontname, FONT_MONOSPACED_BOLDITALIC) ||
+ STRCEQ(pTmp->szOurFontname, FONT_SERIF_PLAIN) ||
+ STRCEQ(pTmp->szOurFontname, FONT_SERIF_BOLD) ||
+ STRCEQ(pTmp->szOurFontname, FONT_SERIF_ITALIC) ||
+ STRCEQ(pTmp->szOurFontname, FONT_SERIF_BOLDITALIC) ||
+ STRCEQ(pTmp->szOurFontname, FONT_SANS_SERIF_PLAIN) ||
+ STRCEQ(pTmp->szOurFontname, FONT_SANS_SERIF_BOLD) ||
+ STRCEQ(pTmp->szOurFontname, FONT_SANS_SERIF_ITALIC) ||
+ STRCEQ(pTmp->szOurFontname, FONT_SANS_SERIF_BOLDITALIC)) {
+ /* Already a default font */
+ continue;
+ }
+ szOurFont =
+ szGetDefaultFont(pTmp->ucFFN, (int)pTmp->ucEmphasis);
+ (void)strncpy(pTmp->szOurFontname, szOurFont,
+ sizeof(pTmp->szOurFontname) - 1);
+ pTmp->szOurFontname[sizeof(pTmp->szOurFontname) - 1] = '\0';
+ }
+} /* end of vCorrect4PDF */
+
+/*
+ * vCorrect4CyrPS - only include monospaced fonts
+ */
+static void
+vCorrect4CyrPS(void)
+{
+ font_table_type *pTmp;
+ const char *szOurFont;
+ UCHAR ucFFN;
+
+ ucFFN = (FAMILY_UNKNOWN << 4) | PITCH_FIXED;
+ for (pTmp = pFontTable; pTmp < pFontTable + tFontTableRecords; pTmp++) {
+ szOurFont = szGetDefaultFont(ucFFN, (int)pTmp->ucEmphasis);
+ (void)strncpy(pTmp->szOurFontname, szOurFont,
+ sizeof(pTmp->szOurFontname) - 1);
+ pTmp->szOurFontname[sizeof(pTmp->szOurFontname) - 1] = '\0';
+ }
+} /* end of vCorrect4CyrPS */
+#endif /* __riscos */
+
+/*
+ * vCorrectFontTable - correct the font table in special cases
+ */
+void
+vCorrectFontTable(conversion_type eConversionType, encoding_type eEncoding)
+{
+#if !defined(__riscos)
+ if (eConversionType == conversion_pdf) {
+ vCorrect4PDF();
+ }
+ if (eConversionType == conversion_ps &&
+ eEncoding == encoding_cyrillic) {
+ vCorrect4CyrPS();
+ }
+#endif /* __riscos */
+} /* end of vCorrectFontTable */
+
+/*
+ * lComputeSpaceWidth - compute the width of a space character
+ *
+ * Returns the space width in millipoints
+ */
+long
+lComputeSpaceWidth(drawfile_fontref tFontRef, USHORT usFontSize)
+{
+ char szSpace[] = " ";
+
+ fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
+
+ return lComputeStringWidth(szSpace, 1, tFontRef, usFontSize);
+} /* end of lComputeSpaceWidth */
diff --git a/sys/src/cmd/aux/antiword/fonts_r.c b/sys/src/cmd/aux/antiword/fonts_r.c
new file mode 100755
index 000000000..0898d4f37
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/fonts_r.c
@@ -0,0 +1,251 @@
+/*
+ * fonts_r.c
+ * Copyright (C) 1999-2002 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Functions to deal with fonts (RiscOs version)
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "DeskLib:Font.h"
+#include "drawfile.h"
+#include "antiword.h"
+
+static font_handle tFontCurr = (font_handle)-1;
+
+/*
+ * pOpenFontTableFile - open the Font translation file
+ * Copy the file to the proper place if necessary.
+ *
+ * Returns the file pointer or NULL
+ */
+FILE *
+pOpenFontTableFile(void)
+{
+ FILE *pFileR, *pFileW;
+ char *szFontNamesFile;
+ size_t tSize;
+ BOOL bFailed;
+ char acBuffer[256];
+
+ pFileR = fopen("<AntiWord$FontNamesFile>", "r");
+ if (pFileR != NULL) {
+ /* The font table is already in the right directory */
+ return pFileR;
+ }
+
+ szFontNamesFile = getenv("AntiWord$FontNamesSave");
+ if (szFontNamesFile == NULL) {
+ werr(0, "Warning: Name of the FontNames file not found");
+ return NULL;
+ }
+ DBG_MSG(szFontNamesFile);
+
+ pFileR = fopen("<AntiWord$Dir>.Resources.Default", "r");
+ if (pFileR == NULL) {
+ werr(0, "I can't find 'Resources.Default'");
+ return NULL;
+ }
+ /* Here the default font translation table is known to exist */
+
+ if (!bMakeDirectory(szFontNamesFile)) {
+ werr(0,
+ "I can't make a directory for the FontNames file");
+ return NULL;
+ }
+ /* Here the proper directory is known to exist */
+
+ pFileW = fopen(szFontNamesFile, "w");
+ if (pFileW == NULL) {
+ (void)fclose(pFileR);
+ werr(0, "I can't create a default FontNames file");
+ return NULL;
+ }
+ /* Here the proper directory is known to be writeable */
+
+ /* Copy the default FontNames file */
+ bFailed = FALSE;
+ while (!feof(pFileR)) {
+ tSize = fread(acBuffer, 1, sizeof(acBuffer), pFileR);
+ if (ferror(pFileR)) {
+ DBG_MSG("Read error");
+ bFailed = TRUE;
+ break;
+ }
+ if (fwrite(acBuffer, 1, tSize, pFileW) != tSize) {
+ DBG_MSG("Write error");
+ bFailed = TRUE;
+ break;
+ }
+ }
+ (void)fclose(pFileW);
+ (void)fclose(pFileR);
+ if (bFailed) {
+ DBG_MSG("Copying the FontNames file failed");
+ (void)remove(szFontNamesFile);
+ return NULL;
+ }
+ return fopen(szFontNamesFile, "r");
+} /* end of pOpenFontTableFile */
+
+/*
+ * vCloseFont - close the current font, if any
+ */
+void
+vCloseFont(void)
+{
+ os_error *e;
+
+ NO_DBG_MSG("vCloseFont");
+
+ if (tFontCurr == (font_handle)-1) {
+ return;
+ }
+ e = Font_LoseFont(tFontCurr);
+ if (e != NULL) {
+ werr(0, "Close font error %d: %s", e->errnum, e->errmess);
+ }
+ tFontCurr = (font_handle)-1;
+} /* end of vCloseFont */
+
+/*
+ * tOpenFont - make the specified font the current font
+ *
+ * Returns the font reference number for use in a draw file
+ */
+drawfile_fontref
+tOpenFont(UCHAR ucWordFontNumber, USHORT usFontStyle, USHORT usWordFontSize)
+{
+ os_error *e;
+ const char *szOurFontname;
+ font_handle tFont;
+ int iFontnumber;
+
+ NO_DBG_MSG("tOpenFont");
+ NO_DBG_DEC(ucWordFontNumber);
+ NO_DBG_HEX(usFontStyle);
+ NO_DBG_DEC(usWordFontSize);
+
+ /* Keep the relevant bits */
+ usFontStyle &= FONT_BOLD|FONT_ITALIC;
+ NO_DBG_HEX(usFontStyle);
+
+ iFontnumber = iGetFontByNumber(ucWordFontNumber, usFontStyle);
+ szOurFontname = szGetOurFontname(iFontnumber);
+ if (szOurFontname == NULL || szOurFontname[0] == '\0') {
+ tFontCurr = (font_handle)-1;
+ return (byte)0;
+ }
+ NO_DBG_MSG(szOurFontname);
+ e = Font_FindFont(&tFont, (char *)szOurFontname,
+ (int)usWordFontSize * 8, (int)usWordFontSize * 8,
+ 0, 0);
+ if (e != NULL) {
+ switch (e->errnum) {
+ case 523:
+ werr(0, "%s", e->errmess);
+ break;
+ default:
+ werr(0, "Open font error %d: %s",
+ e->errnum, e->errmess);
+ break;
+ }
+ tFontCurr = (font_handle)-1;
+ return (drawfile_fontref)0;
+ }
+ tFontCurr = tFont;
+ NO_DBG_DEC(tFontCurr);
+ return (drawfile_fontref)(iFontnumber + 1);
+} /* end of tOpenFont */
+
+/*
+ * tOpenTableFont - make the table font the current font
+ *
+ * Returns the font reference number for use in a draw file
+ */
+drawfile_fontref
+tOpenTableFont(USHORT usWordFontSize)
+{
+ int iWordFontnumber;
+
+ NO_DBG_MSG("tOpenTableFont");
+
+ iWordFontnumber = iFontname2Fontnumber(TABLE_FONT, FONT_REGULAR);
+ if (iWordFontnumber < 0 || iWordFontnumber > (int)UCHAR_MAX) {
+ DBG_DEC(iWordFontnumber);
+ tFontCurr = (font_handle)-1;
+ return (drawfile_fontref)0;
+ }
+
+ return tOpenFont((UCHAR)iWordFontnumber, FONT_REGULAR, usWordFontSize);
+} /* end of tOpenTableFont */
+
+/*
+ * lComputeStringWidth - compute the string width
+ *
+ * Returns the string width in millipoints
+ */
+long
+lComputeStringWidth(const char *szString, size_t tStringLength,
+ drawfile_fontref tFontRef, USHORT usFontSize)
+{
+ font_string tStr;
+ os_error *e;
+
+ fail(szString == NULL);
+ fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
+
+ if (szString[0] == '\0' || tStringLength == 0) {
+ /* Empty string */
+ return 0;
+ }
+ if (tStringLength == 1 && szString[0] == TABLE_SEPARATOR) {
+ /* Font_strwidth doesn't like control characters */
+ return 0;
+ }
+ if (tFontCurr == (font_handle)-1) {
+ /* No current font, use systemfont */
+ return lChar2MilliPoints(tStringLength);
+ }
+ tStr.s = (char *)szString;
+ tStr.x = INT_MAX;
+ tStr.y = INT_MAX;
+ tStr.split = -1;
+ tStr.term = tStringLength;
+ e = Font_StringWidth(&tStr);
+ if (e == NULL) {
+ return (long)tStr.x;
+ }
+ DBG_DEC(e->errnum);
+ DBG_MSG(e->errmess);
+ DBG_DEC(tStringLength);
+ DBG_MSG(szString);
+ werr(0, "String width error %d: %s", e->errnum, e->errmess);
+ return lChar2MilliPoints(tStringLength);
+} /* end of lComputeStringWidth */
+
+/*
+ * tCountColumns - count the number of columns in a string
+ *
+ * Returns the number of columns
+ */
+size_t
+tCountColumns(const char *szString, size_t tLength)
+{
+ fail(szString == NULL);
+
+ /* One byte, one character, one column */
+ return tLength;
+} /* end of tCountColumns */
+
+/*
+ * tGetCharacterLength - the length of the specified character in bytes
+ *
+ * Returns the length in bytes
+ */
+size_t
+tGetCharacterLength(const char *szString)
+{
+ return 1;
+} /* end of tGetCharacterLength */
diff --git a/sys/src/cmd/aux/antiword/fonts_u.c b/sys/src/cmd/aux/antiword/fonts_u.c
new file mode 100755
index 000000000..a99f7d2e6
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/fonts_u.c
@@ -0,0 +1,305 @@
+/*
+ * fonts_u.c
+ * Copyright (C) 1999-2004 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Functions to deal with fonts (Unix version)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "antiword.h"
+#include "fontinfo.h"
+
+/* Don't use fonts, just plain text */
+static BOOL bUsePlainText = TRUE;
+/* Which character set should be used */
+static encoding_type eEncoding = encoding_neutral;
+
+
+/*
+ * pOpenFontTableFile - open the Font translation file
+ *
+ * Returns the file pointer or NULL
+ */
+FILE *
+pOpenFontTableFile(void)
+{
+ FILE *pFile;
+ const char *szHome, *szAntiword, *szGlobalFile;
+ char szEnvironmentFile[PATH_MAX+1];
+ char szLocalFile[PATH_MAX+1];
+
+ szEnvironmentFile[0] = '\0';
+ szLocalFile[0] = '\0';
+
+ /* Try the environment version of the fontnames file */
+ szAntiword = szGetAntiwordDirectory();
+ if (szAntiword != NULL && szAntiword[0] != '\0') {
+ if (strlen(szAntiword) +
+ sizeof(FILE_SEPARATOR FONTNAMES_FILE) >=
+ sizeof(szEnvironmentFile)) {
+ werr(0,
+ "The name of your ANTIWORDHOME directory is too long");
+ return NULL;
+ }
+ sprintf(szEnvironmentFile, "%s%s",
+ szAntiword,
+ FILE_SEPARATOR FONTNAMES_FILE);
+ DBG_MSG(szEnvironmentFile);
+
+ pFile = fopen(szEnvironmentFile, "r");
+ if (pFile != NULL) {
+ return pFile;
+ }
+ }
+
+ /* Try the local version of the fontnames file */
+ szHome = szGetHomeDirectory();
+ if (strlen(szHome) +
+ sizeof(FILE_SEPARATOR ANTIWORD_DIR FILE_SEPARATOR FONTNAMES_FILE) >=
+ sizeof(szLocalFile)) {
+ werr(0, "The name of your HOME directory is too long");
+ return NULL;
+ }
+
+ sprintf(szLocalFile, "%s%s",
+ szHome,
+ FILE_SEPARATOR ANTIWORD_DIR FILE_SEPARATOR FONTNAMES_FILE);
+ DBG_MSG(szLocalFile);
+
+ pFile = fopen(szLocalFile, "r");
+ if (pFile != NULL) {
+ return pFile;
+ }
+
+ /* Try the global version of the fontnames file */
+ szGlobalFile = GLOBAL_ANTIWORD_DIR FILE_SEPARATOR FONTNAMES_FILE;
+ DBG_MSG(szGlobalFile);
+
+ pFile = fopen(szGlobalFile, "r");
+ if (pFile != NULL) {
+ return pFile;
+ }
+
+ if (szEnvironmentFile[0] != '\0') {
+ werr(0, "I can not open your fontnames file.\n"
+ "Neither '%s' nor\n"
+ "'%s' nor\n"
+ "'%s' can be opened for reading.",
+ szEnvironmentFile, szLocalFile, szGlobalFile);
+ } else {
+ werr(0, "I can not open your fontnames file.\n"
+ "Neither '%s' nor\n"
+ "'%s' can be opened for reading.",
+ szLocalFile, szGlobalFile);
+ }
+ return NULL;
+} /* end of pOpenFontTableFile */
+
+/*
+ * vCloseFont - close the current font, if any
+ */
+void
+vCloseFont(void)
+{
+ NO_DBG_MSG("vCloseFont");
+ /* For safety: to be overwritten at the next call of tOpenfont() */
+ eEncoding = encoding_neutral;
+ bUsePlainText = TRUE;
+} /* end of vCloseFont */
+
+/*
+ * tOpenFont - make the specified font the current font
+ *
+ * Returns the font reference number
+ */
+drawfile_fontref
+tOpenFont(UCHAR ucWordFontNumber, USHORT usFontStyle, USHORT usWordFontSize)
+{
+ options_type tOptions;
+ const char *szOurFontname;
+ size_t tIndex;
+ int iFontnumber;
+
+ NO_DBG_MSG("tOpenFont");
+ NO_DBG_DEC(ucWordFontNumber);
+ NO_DBG_HEX(usFontStyle);
+ NO_DBG_DEC(usWordFontSize);
+
+ /* Keep the relevant bits */
+ usFontStyle &= FONT_BOLD|FONT_ITALIC;
+ NO_DBG_HEX(usFontStyle);
+
+ vGetOptions(&tOptions);
+ eEncoding = tOptions.eEncoding;
+ bUsePlainText = tOptions.eConversionType != conversion_draw &&
+ tOptions.eConversionType != conversion_ps &&
+ tOptions.eConversionType != conversion_pdf;
+
+ if (bUsePlainText) {
+ /* Plain text, no fonts */
+ return (drawfile_fontref)0;
+ }
+
+ iFontnumber = iGetFontByNumber(ucWordFontNumber, usFontStyle);
+ szOurFontname = szGetOurFontname(iFontnumber);
+ if (szOurFontname == NULL || szOurFontname[0] == '\0') {
+ DBG_DEC(iFontnumber);
+ return (drawfile_fontref)0;
+ }
+ NO_DBG_MSG(szOurFontname);
+
+ for (tIndex = 0; tIndex < elementsof(szFontnames); tIndex++) {
+ if (STREQ(szFontnames[tIndex], szOurFontname)) {
+ NO_DBG_DEC(tIndex);
+ return (drawfile_fontref)tIndex;
+ }
+ }
+ return (drawfile_fontref)0;
+} /* end of tOpenFont */
+
+/*
+ * tOpenTableFont - make the table font the current font
+ *
+ * Returns the font reference number
+ */
+drawfile_fontref
+tOpenTableFont(USHORT usWordFontSize)
+{
+ options_type tOptions;
+ int iWordFontnumber;
+
+ NO_DBG_MSG("tOpenTableFont");
+
+ vGetOptions(&tOptions);
+ eEncoding = tOptions.eEncoding;
+ bUsePlainText = tOptions.eConversionType != conversion_draw &&
+ tOptions.eConversionType != conversion_ps &&
+ tOptions.eConversionType != conversion_pdf;
+
+ if (bUsePlainText) {
+ /* Plain text, no fonts */
+ return (drawfile_fontref)0;
+ }
+
+ iWordFontnumber = iFontname2Fontnumber(TABLE_FONT, FONT_REGULAR);
+ if (iWordFontnumber < 0 || iWordFontnumber > (int)UCHAR_MAX) {
+ DBG_DEC(iWordFontnumber);
+ return (drawfile_fontref)0;
+ }
+
+ return tOpenFont((UCHAR)iWordFontnumber, FONT_REGULAR, usWordFontSize);
+} /* end of tOpenTableFont */
+
+/*
+ * szGetFontname - get the fontname
+ */
+const char *
+szGetFontname(drawfile_fontref tFontRef)
+{
+ fail((size_t)(UCHAR)tFontRef >= elementsof(szFontnames));
+ return szFontnames[(int)(UCHAR)tFontRef];
+} /* end of szGetFontname */
+
+/*
+ * lComputeStringWidth - compute the string width
+ *
+ * Note: the fontsize is specified in half-points!
+ * the stringlength is specified in bytes, not characters!
+ *
+ * Returns the string width in millipoints
+ */
+long
+lComputeStringWidth(const char *szString, size_t tStringLength,
+ drawfile_fontref tFontRef, USHORT usFontSize)
+{
+ USHORT *ausCharWidths;
+ UCHAR *pucChar;
+ long lRelWidth;
+ size_t tIndex;
+ int iFontRef;
+
+ fail(szString == NULL);
+ fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
+
+ if (szString[0] == '\0' || tStringLength == 0) {
+ /* Empty string */
+ return 0;
+ }
+
+ if (eEncoding == encoding_utf_8) {
+ fail(!bUsePlainText);
+ return lChar2MilliPoints(
+ utf8_strwidth(szString, tStringLength));
+ }
+
+ if (bUsePlainText) {
+ /* No current font, use "systemfont" */
+ return lChar2MilliPoints(tStringLength);
+ }
+
+ if (eEncoding == encoding_cyrillic) {
+ /* FIXME: until the character tables are available */
+ return (tStringLength * 600L * (long)usFontSize + 1) / 2;
+ }
+
+ DBG_DEC_C(eEncoding != encoding_latin_1 &&
+ eEncoding != encoding_latin_2, eEncoding);
+ fail(eEncoding != encoding_latin_1 &&
+ eEncoding != encoding_latin_2);
+
+ /* Compute the relative string width */
+ iFontRef = (int)(UCHAR)tFontRef;
+ if (eEncoding == encoding_latin_2) {
+ ausCharWidths = ausCharacterWidths2[iFontRef];
+ } else {
+ ausCharWidths = ausCharacterWidths1[iFontRef];
+ }
+ lRelWidth = 0;
+ for (tIndex = 0, pucChar = (UCHAR *)szString;
+ tIndex < tStringLength;
+ tIndex++, pucChar++) {
+ lRelWidth += (long)ausCharWidths[(int)*pucChar];
+ }
+
+ /* Compute the absolute string width */
+ return (lRelWidth * (long)usFontSize + 1) / 2;
+} /* end of lComputeStringWidth */
+
+/*
+ * tCountColumns - count the number of columns in a string
+ *
+ * Note: the length is specified in bytes!
+ * A UTF-8 a character can be 0, 1 or 2 columns wide.
+ *
+ * Returns the number of columns
+ */
+size_t
+tCountColumns(const char *szString, size_t tLength)
+{
+ fail(szString == NULL);
+
+ if (eEncoding != encoding_utf_8) {
+ /* One byte, one character, one column */
+ return tLength;
+ }
+ return (size_t)utf8_strwidth(szString, tLength);
+} /* end of tCountColumns */
+
+/*
+ * tGetCharacterLength - the length of the specified character in bytes
+ *
+ * Returns the length in bytes
+ */
+size_t
+tGetCharacterLength(const char *szString)
+{
+ fail(szString == NULL);
+
+ if (eEncoding != encoding_utf_8) {
+ return 1;
+ }
+ return (size_t)utf8_chrlength(szString);
+} /* end of tGetCharacterLength */
diff --git a/sys/src/cmd/aux/antiword/hdrftrlist.c b/sys/src/cmd/aux/antiword/hdrftrlist.c
new file mode 100755
index 000000000..c16418882
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/hdrftrlist.c
@@ -0,0 +1,371 @@
+/*
+ * hdrftrlist.c
+ * Copyright (C) 2004,2005 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Build, read and destroy list(s) of Word Header/footer information
+ */
+
+#include <string.h>
+#include "antiword.h"
+
+
+#define HDR_EVEN_PAGES 0
+#define HDR_ODD_PAGES 1
+#define FTR_EVEN_PAGES 2
+#define FTR_ODD_PAGES 3
+#define HDR_FIRST_PAGE 4
+#define FTR_FIRST_PAGE 5
+
+/*
+ * Private structures to hide the way the information
+ * is stored from the rest of the program
+ */
+typedef struct hdrftr_local_tag {
+ hdrftr_block_type tInfo;
+ ULONG ulCharPosStart;
+ ULONG ulCharPosNext;
+ BOOL bUseful;
+ BOOL bTextOriginal;
+} hdrftr_local_type;
+typedef struct hdrftr_mem_tag {
+ hdrftr_local_type atElement[6];
+} hdrftr_mem_type;
+
+/* Variables needed to write the Header/footer Information List */
+static hdrftr_mem_type *pHdrFtrList = NULL;
+static size_t tHdrFtrLen = 0;
+
+
+/*
+ * vDestroyHdrFtrInfoList - destroy the Header/footer Information List
+ */
+void
+vDestroyHdrFtrInfoList(void)
+{
+ hdrftr_mem_type *pRecord;
+ output_type *pCurr, *pNext;
+ size_t tHdrFtr, tIndex;
+
+ DBG_MSG("vDestroyHdrFtrInfoList");
+
+ /* Free the Header/footer Information List */
+ for (tHdrFtr = 0; tHdrFtr < tHdrFtrLen; tHdrFtr++) {
+ pRecord = pHdrFtrList + tHdrFtr;
+ for (tIndex = 0;
+ tIndex < elementsof(pRecord->atElement);
+ tIndex++) {
+ if (!pRecord->atElement[tIndex].bTextOriginal) {
+ continue;
+ }
+ pCurr = pRecord->atElement[tIndex].tInfo.pText;
+ while (pCurr != NULL) {
+ pCurr->szStorage = xfree(pCurr->szStorage);
+ pNext = pCurr->pNext;
+ pCurr = xfree(pCurr);
+ pCurr = pNext;
+ }
+ }
+ }
+ pHdrFtrList = xfree(pHdrFtrList);
+ /* Reset all control variables */
+ tHdrFtrLen = 0;
+} /* end of vDestroyHdrFtrInfoList */
+
+/*
+ * vCreat8HdrFtrInfoList - Create the Header/footer Information List
+ */
+void
+vCreat8HdrFtrInfoList(const ULONG *aulCharPos, size_t tLength)
+{
+ hdrftr_mem_type *pListMember;
+ size_t tHdrFtr, tIndex, tMainIndex;
+
+ fail(aulCharPos == NULL);
+
+ DBG_DEC(tLength);
+ if (tLength <= 1) {
+ return;
+ }
+ tHdrFtrLen = tLength / 12;
+ if (tLength % 12 != 0 && tLength % 12 != 1) {
+ tHdrFtrLen++;
+ }
+ DBG_DEC(tHdrFtrLen);
+
+ pHdrFtrList = xcalloc(tHdrFtrLen, sizeof(hdrftr_mem_type));
+
+ for (tHdrFtr = 0; tHdrFtr < tHdrFtrLen; tHdrFtr++) {
+ pListMember = pHdrFtrList + tHdrFtr;
+ for (tIndex = 0, tMainIndex = tHdrFtr * 12;
+ tIndex < 6 && tMainIndex < tLength;
+ tIndex++, tMainIndex++) {
+ pListMember->atElement[tIndex].tInfo.pText = NULL;
+ pListMember->atElement[tIndex].ulCharPosStart =
+ aulCharPos[tMainIndex];
+ if (tMainIndex + 1 < tLength) {
+ pListMember->atElement[tIndex].ulCharPosNext =
+ aulCharPos[tMainIndex + 1];
+ } else {
+ pListMember->atElement[tIndex].ulCharPosNext =
+ aulCharPos[tMainIndex];
+ }
+ }
+ }
+} /* end of vCreat8HdrFtrInfoList */
+
+/*
+ * vCreat6HdrFtrInfoList - Create the Header/footer Information List
+ */
+void
+vCreat6HdrFtrInfoList(const ULONG *aulCharPos, size_t tLength)
+{
+ static const size_t atIndex[] =
+ { SIZE_T_MAX, SIZE_T_MAX, FTR_FIRST_PAGE, HDR_FIRST_PAGE,
+ FTR_ODD_PAGES, FTR_EVEN_PAGES, HDR_ODD_PAGES, HDR_EVEN_PAGES,
+ };
+ hdrftr_mem_type *pListMember;
+ size_t tHdrFtr, tTmp, tIndex, tMainIndex, tBit;
+ UCHAR ucDopSpecification, ucSepSpecification;
+
+ fail(aulCharPos == NULL);
+
+ DBG_DEC(tLength);
+ if (tLength <= 1) {
+ return;
+ }
+ tHdrFtrLen = tGetNumberOfSections();
+ if (tHdrFtrLen == 0) {
+ tHdrFtrLen = 1;
+ }
+ DBG_DEC(tHdrFtrLen);
+
+ pHdrFtrList = xcalloc(tHdrFtrLen, sizeof(hdrftr_mem_type));
+
+ /* Get the start index in aulCharPos */
+ ucDopSpecification = ucGetDopHdrFtrSpecification();
+ DBG_HEX(ucDopSpecification & 0xe0);
+ tMainIndex = 0;
+ for (tBit = 7; tBit >= 5; tBit--) {
+ if ((ucDopSpecification & BIT(tBit)) != 0) {
+ tMainIndex++;
+ }
+ }
+ DBG_DEC(tMainIndex);
+
+ for (tHdrFtr = 0; tHdrFtr < tHdrFtrLen; tHdrFtr++) {
+ ucSepSpecification = ucGetSepHdrFtrSpecification(tHdrFtr);
+ DBG_HEX(ucSepSpecification & 0xfc);
+ pListMember = pHdrFtrList + tHdrFtr;
+ for (tTmp = 0;
+ tTmp < elementsof(pListMember->atElement);
+ tTmp++) {
+ pListMember->atElement[tTmp].tInfo.pText = NULL;
+ }
+ for (tBit = 7; tBit >= 2; tBit--) {
+ if (tMainIndex >= tLength) {
+ break;
+ }
+ if ((ucSepSpecification & BIT(tBit)) == 0) {
+ continue;
+ }
+ tIndex = atIndex[tBit];
+ fail(tIndex >= 6);
+ pListMember->atElement[tIndex].ulCharPosStart =
+ aulCharPos[tMainIndex];
+ if (tMainIndex + 1 < tLength) {
+ pListMember->atElement[tIndex].ulCharPosNext =
+ aulCharPos[tMainIndex + 1];
+ } else {
+ pListMember->atElement[tIndex].ulCharPosNext =
+ aulCharPos[tMainIndex];
+ }
+ tMainIndex++;
+ }
+ }
+} /* end of vCreat6HdrFtrInfoList */
+
+/*
+ * vCreat2HdrFtrInfoList - Create the Header/footer Information List
+ */
+void
+vCreat2HdrFtrInfoList(const ULONG *aulCharPos, size_t tLength)
+{
+ vCreat6HdrFtrInfoList(aulCharPos, tLength);
+} /* end of vCreat2HdrFtrInfoList */
+
+/*
+ * pGetHdrFtrInfo - get the Header/footer information
+ */
+const hdrftr_block_type *
+pGetHdrFtrInfo(int iSectionIndex,
+ BOOL bWantHeader, BOOL bOddPage, BOOL bFirstInSection)
+{
+ hdrftr_mem_type *pCurr;
+
+ fail(iSectionIndex < 0);
+ fail(pHdrFtrList == NULL && tHdrFtrLen != 0);
+
+ if (pHdrFtrList == NULL || tHdrFtrLen == 0) {
+ /* No information */
+ return NULL;
+ }
+
+ if (iSectionIndex < 0) {
+ iSectionIndex = 0;
+ } else if (iSectionIndex >= (int)tHdrFtrLen) {
+ iSectionIndex = (int)(tHdrFtrLen - 1);
+ }
+
+ pCurr = pHdrFtrList + iSectionIndex;
+
+ if (bFirstInSection) {
+ if (bWantHeader) {
+ return &pCurr->atElement[HDR_FIRST_PAGE].tInfo;
+ } else {
+ return &pCurr->atElement[FTR_FIRST_PAGE].tInfo;
+ }
+ } else {
+ if (bWantHeader) {
+ if (bOddPage) {
+ return &pCurr->atElement[HDR_ODD_PAGES].tInfo;
+ } else {
+ return &pCurr->atElement[HDR_EVEN_PAGES].tInfo;
+ }
+ } else {
+ if (bOddPage) {
+ return &pCurr->atElement[FTR_ODD_PAGES].tInfo;
+ } else {
+ return &pCurr->atElement[FTR_EVEN_PAGES].tInfo;
+ }
+ }
+ }
+} /* end of pGetHdrFtrInfo */
+
+/*
+ * lComputeHdrFtrHeight - compute the height of a header or footer
+ *
+ * Returns the height in DrawUnits
+ */
+static long
+lComputeHdrFtrHeight(const output_type *pAnchor)
+{
+ const output_type *pCurr;
+ long lTotal;
+ USHORT usFontSizeMax;
+
+ lTotal = 0;
+ usFontSizeMax = 0;
+ for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
+ if (pCurr->tNextFree == 1) {
+ if (pCurr->szStorage[0] == PAR_END) {
+ /* End of a paragraph */
+ lTotal += lComputeLeading(usFontSizeMax);
+ lTotal += lMilliPoints2DrawUnits(
+ (long)pCurr->usFontSize * 200);
+ usFontSizeMax = 0;
+ continue;
+ }
+ if (pCurr->szStorage[0] == HARD_RETURN) {
+ /* End of a line */
+ lTotal += lComputeLeading(usFontSizeMax);
+ usFontSizeMax = 0;
+ continue;
+ }
+ }
+ if (pCurr->usFontSize > usFontSizeMax) {
+ usFontSizeMax = pCurr->usFontSize;
+ }
+ }
+ if (usFontSizeMax != 0) {
+ /* Height of the last paragraph */
+ lTotal += lComputeLeading(usFontSizeMax);
+ }
+ return lTotal;
+} /* end of lComputeHdrFtrHeight */
+
+/*
+ * vPrepareHdrFtrText - prepare the header/footer text
+ */
+void
+vPrepareHdrFtrText(FILE *pFile)
+{
+ hdrftr_mem_type *pCurr, *pPrev;
+ hdrftr_local_type *pTmp;
+ output_type *pText;
+ size_t tHdrFtr, tIndex;
+
+ fail(pFile == NULL);
+ fail(pHdrFtrList == NULL && tHdrFtrLen != 0);
+
+ if (pHdrFtrList == NULL || tHdrFtrLen == 0) {
+ /* No information */
+ return;
+ }
+
+ /* Fill text, text height and useful-ness */
+ for (tHdrFtr = 0; tHdrFtr < tHdrFtrLen; tHdrFtr++) {
+ pCurr = pHdrFtrList + tHdrFtr;
+ for (tIndex = 0;
+ tIndex < elementsof(pHdrFtrList->atElement);
+ tIndex++) {
+ pTmp = &pCurr->atElement[tIndex];
+ pTmp->bUseful =
+ pTmp->ulCharPosStart != pTmp->ulCharPosNext;
+ if (pTmp->bUseful) {
+ pText = pHdrFtrDecryptor(pFile,
+ pTmp->ulCharPosStart,
+ pTmp->ulCharPosNext);
+ pTmp->tInfo.pText = pText;
+ pTmp->tInfo.lHeight =
+ lComputeHdrFtrHeight(pText);
+ pTmp->bTextOriginal = pText != NULL;
+ } else {
+ pTmp->tInfo.pText = NULL;
+ pTmp->tInfo.lHeight = 0;
+ pTmp->bTextOriginal = FALSE;
+ }
+ }
+ }
+
+ /* Replace not-useful records by using inheritance */
+ if (pHdrFtrList->atElement[HDR_FIRST_PAGE].bUseful) {
+ pTmp = &pHdrFtrList->atElement[HDR_ODD_PAGES];
+ if (!pTmp->bUseful) {
+ *pTmp = pHdrFtrList->atElement[HDR_FIRST_PAGE];
+ pTmp->bTextOriginal = FALSE;
+ }
+ pTmp = &pHdrFtrList->atElement[HDR_EVEN_PAGES];
+ if (!pTmp->bUseful) {
+ *pTmp = pHdrFtrList->atElement[HDR_FIRST_PAGE];
+ pTmp->bTextOriginal = FALSE;
+ }
+ }
+ if (pHdrFtrList->atElement[FTR_FIRST_PAGE].bUseful) {
+ pTmp = &pHdrFtrList->atElement[FTR_ODD_PAGES];
+ if (!pTmp->bUseful) {
+ *pTmp = pHdrFtrList->atElement[FTR_FIRST_PAGE];
+ pTmp->bTextOriginal = FALSE;
+ }
+ pTmp = &pHdrFtrList->atElement[FTR_EVEN_PAGES];
+ if (!pTmp->bUseful) {
+ *pTmp = pHdrFtrList->atElement[FTR_FIRST_PAGE];
+ pTmp->bTextOriginal = FALSE;
+ }
+ }
+ for (tHdrFtr = 1, pCurr = &pHdrFtrList[1];
+ tHdrFtr < tHdrFtrLen;
+ tHdrFtr++, pCurr++) {
+ pPrev = pCurr - 1;
+ for (tIndex = 0;
+ tIndex < elementsof(pHdrFtrList->atElement);
+ tIndex++) {
+ if (!pCurr->atElement[tIndex].bUseful &&
+ pPrev->atElement[tIndex].bUseful) {
+ pCurr->atElement[tIndex] =
+ pPrev->atElement[tIndex];
+ pCurr->atElement[tIndex].bTextOriginal = FALSE;
+ }
+ }
+ }
+} /* end of vPrepareHdrFtrText */
diff --git a/sys/src/cmd/aux/antiword/icons.c b/sys/src/cmd/aux/antiword/icons.c
new file mode 100755
index 000000000..dd88c0053
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/icons.c
@@ -0,0 +1,96 @@
+/*
+ * icons.c
+ * Copyright (C) 1998-2001 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Update window icons
+ */
+
+#include <string.h>
+#include "DeskLib:Error.h"
+#include "DeskLib:WimpSWIs.h"
+#include "antiword.h"
+
+void
+vUpdateIcon(window_handle tWindow, icon_block *pIcon)
+{
+ window_redrawblock tRedraw;
+ BOOL bMore;
+
+ tRedraw.window = tWindow;
+ tRedraw.rect = pIcon->workarearect;
+ Error_CheckFatal(Wimp_UpdateWindow(&tRedraw, &bMore));
+ while (bMore) {
+ Error_CheckFatal(Wimp_PlotIcon(pIcon));
+ Error_CheckFatal(Wimp_GetRectangle(&tRedraw, &bMore));
+ }
+} /* end of vUpdateIcon */
+
+void
+vUpdateRadioButton(window_handle tWindow, icon_handle tIconNumber,
+ BOOL bSelected)
+{
+ icon_block tIcon;
+
+ Error_CheckFatal(Wimp_GetIconState(tWindow, tIconNumber, &tIcon));
+ DBG_DEC(tIconNumber);
+ DBG_HEX(tIcon.flags.data.selected);
+ if (bSelected == (tIcon.flags.data.selected == 1)) {
+ /* No update needed */
+ return;
+ }
+ Error_CheckFatal(Wimp_SetIconState(tWindow, tIconNumber,
+ bSelected ? 0x00200000 : 0, 0x00200000));
+ vUpdateIcon(tWindow, &tIcon);
+} /* end of vUpdateRadioButton */
+
+/*
+ * vUpdateWriteable - update a writeable icon with a string
+ */
+void
+vUpdateWriteable(window_handle tWindow, icon_handle tIconNumber,
+ const char *szString)
+{
+ icon_block tIcon;
+ caret_block tCaret;
+ int iLen;
+
+ fail(szString == NULL);
+
+ NO_DBG_DEC(tIconNumber);
+ NO_DBG_MSG(szString);
+
+ Error_CheckFatal(Wimp_GetIconState(tWindow, tIconNumber, &tIcon));
+ NO_DBG_HEX(tIcon.flags);
+ if (!tIcon.flags.data.text || !tIcon.flags.data.indirected) {
+ werr(1, "Icon %d must be indirected text", (int)tIconNumber);
+ return;
+ }
+ strncpy(tIcon.data.indirecttext.buffer,
+ szString,
+ tIcon.data.indirecttext.bufflen - 1);
+ /* Ensure the caret is behind the last character of the text */
+ Error_CheckFatal(Wimp_GetCaretPosition(&tCaret));
+ if (tCaret.window == tWindow && tCaret.icon == tIconNumber) {
+ iLen = strlen(tIcon.data.indirecttext.buffer);
+ if (tCaret.index != iLen) {
+ tCaret.index = iLen;
+ Error_CheckFatal(Wimp_SetCaretPosition(&tCaret));
+ }
+ }
+ Error_CheckFatal(Wimp_SetIconState(tWindow, tIconNumber, 0, 0));
+ vUpdateIcon(tWindow, &tIcon);
+} /* end of vUpdateWriteable */
+
+/*
+ * vUpdateWriteableNumber - update a writeable icon with a number
+ */
+void
+vUpdateWriteableNumber(window_handle tWindow, icon_handle tIconNumber,
+ int iNumber)
+{
+ char szTmp[1+3*sizeof(int)+1];
+
+ (void)sprintf(szTmp, "%d", iNumber);
+ vUpdateWriteable(tWindow, tIconNumber, szTmp);
+} /* end of vUpdateWriteableNumber */
diff --git a/sys/src/cmd/aux/antiword/imgexam.c b/sys/src/cmd/aux/antiword/imgexam.c
new file mode 100755
index 000000000..2b8384af8
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/imgexam.c
@@ -0,0 +1,1044 @@
+/*
+ * imgexam.c
+ * Copyright (C) 2000-2004 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Functions to examine image headers
+ *
+ *================================================================
+ * Part of this software is based on:
+ * jpeg2ps - convert JPEG compressed images to PostScript Level 2
+ * Copyright (C) 1994-99 Thomas Merz (tm@muc.de)
+ *================================================================
+ * The credit should go to him, but all the bugs are mine.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "antiword.h"
+
+/* BMP compression types */
+#define BI_RGB 0
+#define BI_RLE8 1
+#define BI_RLE4 2
+
+/* PNG colortype bits */
+#define PNG_CB_PALETTE 0x01
+#define PNG_CB_COLOR 0x02
+#define PNG_CB_ALPHA 0x04
+
+/* Instance signature */
+#define MSOBI_WMF 0x0216
+#define MSOBI_EMF 0x03d4
+#define MSOBI_PICT 0x0542
+#define MSOBI_PNG 0x06e0
+#define MSOBI_JPEG 0x046a
+#define MSOBI_DIB 0x07a8
+
+/* The following enum is stolen from the IJG JPEG library */
+typedef enum { /* JPEG marker codes */
+ M_SOF0 = 0xc0, /* baseline DCT */
+ M_SOF1 = 0xc1, /* extended sequential DCT */
+ M_SOF2 = 0xc2, /* progressive DCT */
+ M_SOF3 = 0xc3, /* lossless (sequential) */
+
+ M_SOF5 = 0xc5, /* differential sequential DCT */
+ M_SOF6 = 0xc6, /* differential progressive DCT */
+ M_SOF7 = 0xc7, /* differential lossless */
+
+ M_JPG = 0xc8, /* JPEG extensions */
+ M_SOF9 = 0xc9, /* extended sequential DCT */
+ M_SOF10 = 0xca, /* progressive DCT */
+ M_SOF11 = 0xcb, /* lossless (sequential) */
+
+ M_SOF13 = 0xcd, /* differential sequential DCT */
+ M_SOF14 = 0xce, /* differential progressive DCT */
+ M_SOF15 = 0xcf, /* differential lossless */
+
+ M_DHT = 0xc4, /* define Huffman tables */
+
+ M_DAC = 0xcc, /* define arithmetic conditioning table */
+
+ M_RST0 = 0xd0, /* restart */
+ M_RST1 = 0xd1, /* restart */
+ M_RST2 = 0xd2, /* restart */
+ M_RST3 = 0xd3, /* restart */
+ M_RST4 = 0xd4, /* restart */
+ M_RST5 = 0xd5, /* restart */
+ M_RST6 = 0xd6, /* restart */
+ M_RST7 = 0xd7, /* restart */
+
+ M_SOI = 0xd8, /* start of image */
+ M_EOI = 0xd9, /* end of image */
+ M_SOS = 0xda, /* start of scan */
+ M_DQT = 0xdb, /* define quantization tables */
+ M_DNL = 0xdc, /* define number of lines */
+ M_DRI = 0xdd, /* define restart interval */
+ M_DHP = 0xde, /* define hierarchical progression */
+ M_EXP = 0xdf, /* expand reference image(s) */
+
+ M_APP0 = 0xe0, /* application marker, used for JFIF */
+ M_APP1 = 0xe1, /* application marker */
+ M_APP2 = 0xe2, /* application marker */
+ M_APP3 = 0xe3, /* application marker */
+ M_APP4 = 0xe4, /* application marker */
+ M_APP5 = 0xe5, /* application marker */
+ M_APP6 = 0xe6, /* application marker */
+ M_APP7 = 0xe7, /* application marker */
+ M_APP8 = 0xe8, /* application marker */
+ M_APP9 = 0xe9, /* application marker */
+ M_APP10 = 0xea, /* application marker */
+ M_APP11 = 0xeb, /* application marker */
+ M_APP12 = 0xec, /* application marker */
+ M_APP13 = 0xed, /* application marker */
+ M_APP14 = 0xee, /* application marker, used by Adobe */
+ M_APP15 = 0xef, /* application marker */
+
+ M_JPG0 = 0xf0, /* reserved for JPEG extensions */
+ M_JPG13 = 0xfd, /* reserved for JPEG extensions */
+ M_COM = 0xfe, /* comment */
+
+ M_TEM = 0x01 /* temporary use */
+} JPEG_MARKER;
+
+
+/*
+ * bFillPaletteDIB - fill the palette part of the imagesdata
+ *
+ * returns TRUE if the images must be a color image, otherwise FALSE;
+ */
+static BOOL
+bFillPaletteDIB(FILE *pFile, imagedata_type *pImg, BOOL bNewFormat)
+{
+ int iIndex;
+ BOOL bIsColorPalette;
+
+ fail(pFile == NULL);
+ fail(pImg == NULL);
+
+ if (pImg->uiBitsPerComponent > 8) {
+ /* No palette, image uses more than 256 colors */
+ return TRUE;
+ }
+
+ if (pImg->iColorsUsed <= 0) {
+ /* Not specified, so compute the number of colors used */
+ pImg->iColorsUsed = 1 << pImg->uiBitsPerComponent;
+ }
+
+ fail(pImg->iColorsUsed > 256);
+ if (pImg->iColorsUsed > 256) {
+ pImg->iColorsUsed = 256;
+ }
+
+ bIsColorPalette = FALSE;
+ for (iIndex = 0; iIndex < pImg->iColorsUsed; iIndex++) {
+ /* From BGR order to RGB order */
+ pImg->aucPalette[iIndex][2] = (UCHAR)iNextByte(pFile);
+ pImg->aucPalette[iIndex][1] = (UCHAR)iNextByte(pFile);
+ pImg->aucPalette[iIndex][0] = (UCHAR)iNextByte(pFile);
+ if (bNewFormat) {
+ (void)iNextByte(pFile);
+ }
+ NO_DBG_PRINT_BLOCK(pImg->aucPalette[iIndex], 3);
+ if (pImg->aucPalette[iIndex][0] !=
+ pImg->aucPalette[iIndex][1] ||
+ pImg->aucPalette[iIndex][1] !=
+ pImg->aucPalette[iIndex][2]) {
+ bIsColorPalette = TRUE;
+ }
+ }
+
+ return bIsColorPalette;
+} /* end of bFillPaletteDIB */
+
+/*
+ * bExamineDIB - Examine a DIB header
+ *
+ * return TRUE if successful, otherwise FALSE
+ */
+static BOOL
+bExamineDIB(FILE *pFile, imagedata_type *pImg)
+{
+ size_t tHeaderSize;
+ int iPlanes, iCompression;
+
+ tHeaderSize = (size_t)ulNextLong(pFile);
+ switch (tHeaderSize) {
+ case 12:
+ pImg->iWidth = (int)usNextWord(pFile);
+ pImg->iHeight = (int)usNextWord(pFile);
+ iPlanes = (int)usNextWord(pFile);
+ pImg->uiBitsPerComponent = (UINT)usNextWord(pFile);
+ iCompression = BI_RGB;
+ pImg->iColorsUsed = 0;
+ break;
+ case 40:
+ case 64:
+ pImg->iWidth = (int)ulNextLong(pFile);
+ pImg->iHeight = (int)ulNextLong(pFile);
+ iPlanes = (int)usNextWord(pFile);
+ pImg->uiBitsPerComponent = (UINT)usNextWord(pFile);
+ iCompression = (int)ulNextLong(pFile);
+ (void)tSkipBytes(pFile, 12);
+ pImg->iColorsUsed = (int)ulNextLong(pFile);
+ (void)tSkipBytes(pFile, tHeaderSize - 36);
+ break;
+ default:
+ DBG_DEC(tHeaderSize);
+ return FALSE;
+ }
+ DBG_DEC(pImg->iWidth);
+ DBG_DEC(pImg->iHeight);
+ DBG_DEC(pImg->uiBitsPerComponent);
+ DBG_DEC(iCompression);
+ DBG_DEC(pImg->iColorsUsed);
+
+ /* Do some sanity checks with the parameters */
+ if (iPlanes != 1) {
+ DBG_DEC(iPlanes);
+ return FALSE;
+ }
+ if (pImg->iWidth <= 0 || pImg->iHeight <= 0) {
+ DBG_DEC(pImg->iWidth);
+ DBG_DEC(pImg->iHeight);
+ return FALSE;
+ }
+ if (pImg->uiBitsPerComponent != 1 && pImg->uiBitsPerComponent != 4 &&
+ pImg->uiBitsPerComponent != 8 && pImg->uiBitsPerComponent != 24) {
+ DBG_DEC(pImg->uiBitsPerComponent);
+ return FALSE;
+ }
+ if (iCompression != BI_RGB &&
+ (pImg->uiBitsPerComponent == 1 || pImg->uiBitsPerComponent == 24)) {
+ return FALSE;
+ }
+ if (iCompression == BI_RLE8 && pImg->uiBitsPerComponent == 4) {
+ return FALSE;
+ }
+ if (iCompression == BI_RLE4 && pImg->uiBitsPerComponent == 8) {
+ return FALSE;
+ }
+
+ switch (iCompression) {
+ case BI_RGB:
+ pImg->eCompression = compression_none;
+ break;
+ case BI_RLE4:
+ pImg->eCompression = compression_rle4;
+ break;
+ case BI_RLE8:
+ pImg->eCompression = compression_rle8;
+ break;
+ default:
+ DBG_DEC(iCompression);
+ return FALSE;
+ }
+
+ pImg->bColorImage = bFillPaletteDIB(pFile, pImg, tHeaderSize > 12);
+
+ if (pImg->uiBitsPerComponent <= 8) {
+ pImg->iComponents = 1;
+ } else {
+ pImg->iComponents = (int)(pImg->uiBitsPerComponent / 8);
+ }
+
+ return TRUE;
+} /* end of bExamineDIB */
+
+/*
+ * iNextMarker - read the next JPEG marker
+ */
+static int
+iNextMarker(FILE *pFile)
+{
+ int iMarker;
+
+ do {
+ do {
+ iMarker = iNextByte(pFile);
+ } while (iMarker != 0xff && iMarker != EOF);
+ if (iMarker == EOF) {
+ return EOF;
+ }
+ do {
+ iMarker = iNextByte(pFile);
+ } while (iMarker == 0xff);
+ } while (iMarker == 0x00); /* repeat if ff/00 */
+
+ return iMarker;
+} /* end of iNextMarker */
+
+/*
+ * bExamineJPEG - Examine a JPEG header
+ *
+ * return TRUE if successful, otherwise FALSE
+ */
+static BOOL
+bExamineJPEG(FILE *pFile, imagedata_type *pImg)
+{
+ size_t tLength;
+ int iMarker, iIndex;
+ char appstring[10];
+ BOOL bSOFDone;
+
+ tLength = 0;
+ bSOFDone = FALSE;
+
+ /* process JPEG markers */
+ while (!bSOFDone && (iMarker = iNextMarker(pFile)) != (int)M_EOI) {
+ switch (iMarker) {
+ case EOF:
+ DBG_MSG("Error: unexpected end of JPEG file");
+ return FALSE;
+ /* The following are not officially supported in PostScript level 2 */
+ case M_SOF2:
+ case M_SOF3:
+ case M_SOF5:
+ case M_SOF6:
+ case M_SOF7:
+ case M_SOF9:
+ case M_SOF10:
+ case M_SOF11:
+ case M_SOF13:
+ case M_SOF14:
+ case M_SOF15:
+ DBG_HEX(iMarker);
+ return FALSE;
+ case M_SOF0:
+ case M_SOF1:
+ tLength = (size_t)usNextWordBE(pFile);
+ pImg->uiBitsPerComponent = (UINT)iNextByte(pFile);
+ pImg->iHeight = (int)usNextWordBE(pFile);
+ pImg->iWidth = (int)usNextWordBE(pFile);
+ pImg->iComponents = iNextByte(pFile);
+ bSOFDone = TRUE;
+ break;
+ case M_APP14:
+ /*
+ * Check for Adobe application marker. It is known (per Adobe's
+ * TN5116) to contain the string "Adobe" at the start of the
+ * APP14 marker.
+ */
+ tLength = (size_t)usNextWordBE(pFile);
+ if (tLength < 12) {
+ (void)tSkipBytes(pFile, tLength - 2);
+ } else {
+ for (iIndex = 0; iIndex < 5; iIndex++) {
+ appstring[iIndex] =
+ (char)iNextByte(pFile);
+ }
+ appstring[5] = '\0';
+ if (STREQ(appstring, "Adobe")) {
+ pImg->bAdobe = TRUE;
+ }
+ (void)tSkipBytes(pFile, tLength - 7);
+ }
+ break;
+ case M_SOI: /* ignore markers without parameters */
+ case M_EOI:
+ case M_TEM:
+ case M_RST0:
+ case M_RST1:
+ case M_RST2:
+ case M_RST3:
+ case M_RST4:
+ case M_RST5:
+ case M_RST6:
+ case M_RST7:
+ break;
+ default: /* skip variable length markers */
+ tLength = (size_t)usNextWordBE(pFile);
+ (void)tSkipBytes(pFile, tLength - 2);
+ break;
+ }
+ }
+
+ DBG_DEC(pImg->iWidth);
+ DBG_DEC(pImg->iHeight);
+ DBG_DEC(pImg->uiBitsPerComponent);
+ DBG_DEC(pImg->iComponents);
+
+ /* Do some sanity checks with the parameters */
+ if (pImg->iHeight <= 0 ||
+ pImg->iWidth <= 0 ||
+ pImg->iComponents <= 0) {
+ DBG_DEC(pImg->iHeight);
+ DBG_DEC(pImg->iWidth);
+ DBG_DEC(pImg->iComponents);
+ return FALSE;
+ }
+
+ /* Some broken JPEG files have this but they print anyway... */
+ if (pImg->iComponents * 3 + 8 != (int)tLength) {
+ DBG_MSG("Warning: SOF marker has incorrect length - ignored");
+ }
+
+ if (pImg->uiBitsPerComponent != 8) {
+ DBG_DEC(pImg->uiBitsPerComponent);
+ DBG_MSG("Not supported in PostScript level 2");
+ return FALSE;
+ }
+
+ if (pImg->iComponents != 1 &&
+ pImg->iComponents != 3 &&
+ pImg->iComponents != 4) {
+ DBG_DEC(pImg->iComponents);
+ return FALSE;
+ }
+
+ pImg->bColorImage = pImg->iComponents >= 3;
+ pImg->iColorsUsed = 0;
+ pImg->eCompression = compression_jpeg;
+
+ return TRUE;
+} /* end of bExamineJPEG */
+
+/*
+ * bFillPalettePNG - fill the palette part of the imagesdata
+ *
+ * returns TRUE if sucessful, otherwise FALSE;
+ */
+static BOOL
+bFillPalettePNG(FILE *pFile, imagedata_type *pImg, size_t tLength)
+{
+ int iIndex, iEntries;
+
+ fail(pFile == NULL);
+ fail(pImg == NULL);
+
+ if (pImg->uiBitsPerComponent > 8) {
+ /* No palette, image uses more than 256 colors */
+ return TRUE;
+ }
+
+ if (!pImg->bColorImage) {
+ /* Only color images can have a palette */
+ return FALSE;
+ }
+
+ if (tLength % 3 != 0) {
+ /* Each palette entry takes three bytes */
+ DBG_DEC(tLength);
+ return FALSE;
+ }
+
+ iEntries = (int)(tLength / 3);
+ DBG_DEC(iEntries);
+ pImg->iColorsUsed = 1 << pImg->uiBitsPerComponent;
+ DBG_DEC(pImg->iColorsUsed);
+
+ if (iEntries > 256) {
+ DBG_DEC(iEntries);
+ return FALSE;
+ }
+
+ for (iIndex = 0; iIndex < iEntries; iIndex++) {
+ pImg->aucPalette[iIndex][0] = (UCHAR)iNextByte(pFile);
+ pImg->aucPalette[iIndex][1] = (UCHAR)iNextByte(pFile);
+ pImg->aucPalette[iIndex][2] = (UCHAR)iNextByte(pFile);
+ NO_DBG_PRINT_BLOCK(pImg->aucPalette[iIndex], 3);
+ }
+ for (;iIndex < pImg->iColorsUsed; iIndex++) {
+ pImg->aucPalette[iIndex][0] = 0;
+ pImg->aucPalette[iIndex][1] = 0;
+ pImg->aucPalette[iIndex][2] = 0;
+ }
+
+ return TRUE;
+} /* end of bFillPalettePNG */
+
+/*
+ * bExaminePNG - Examine a PNG header
+ *
+ * return TRUE if successful, otherwise FALSE
+ */
+static BOOL
+bExaminePNG(FILE *pFile, imagedata_type *pImg)
+{
+ size_t tLength;
+ ULONG ulLong1, ulLong2, ulName;
+ int iIndex, iTmp;
+ int iCompressionMethod, iFilterMethod, iInterlaceMethod;
+ int iColor, iIncrement;
+ BOOL bHasPalette, bHasAlpha;
+ UCHAR aucBuf[4];
+
+ /* Check signature */
+ ulLong1 = ulNextLongBE(pFile);
+ ulLong2 = ulNextLongBE(pFile);
+ if (ulLong1 != 0x89504e47UL || ulLong2 != 0x0d0a1a0aUL) {
+ DBG_HEX(ulLong1);
+ DBG_HEX(ulLong2);
+ return FALSE;
+ }
+
+ ulName = 0x00;
+ bHasPalette = FALSE;
+
+ /* Examine chunks */
+ while (ulName != PNG_CN_IEND) {
+ tLength = (size_t)ulNextLongBE(pFile);
+ ulName = 0x00;
+ for (iIndex = 0; iIndex < (int)elementsof(aucBuf); iIndex++) {
+ aucBuf[iIndex] = (UCHAR)iNextByte(pFile);
+ if (!isalpha(aucBuf[iIndex])) {
+ DBG_HEX(aucBuf[iIndex]);
+ return FALSE;
+ }
+ ulName <<= 8;
+ ulName |= aucBuf[iIndex];
+ }
+
+ switch (ulName) {
+ case PNG_CN_IHDR:
+ /* Header chunck */
+ if (tLength < 13) {
+ DBG_DEC(tLength);
+ return FALSE;
+ }
+ pImg->iWidth = (int)ulNextLongBE(pFile);
+ pImg->iHeight = (int)ulNextLongBE(pFile);
+ pImg->uiBitsPerComponent = (UINT)iNextByte(pFile);
+ iTmp = iNextByte(pFile);
+ NO_DBG_HEX(iTmp);
+ pImg->bColorImage = (iTmp & PNG_CB_COLOR) != 0;
+ bHasPalette = (iTmp & PNG_CB_PALETTE) != 0;
+ bHasAlpha = (iTmp & PNG_CB_ALPHA) != 0;
+ if (bHasPalette && pImg->uiBitsPerComponent > 8) {
+ /* This should not happen */
+ return FALSE;
+ }
+ pImg->iComponents =
+ (bHasPalette || !pImg->bColorImage) ? 1 : 3;
+ if (bHasAlpha) {
+ pImg->iComponents++;
+ }
+ iCompressionMethod = iNextByte(pFile);
+ if (iCompressionMethod != 0) {
+ DBG_DEC(iCompressionMethod);
+ return FALSE;
+ }
+ iFilterMethod = iNextByte(pFile);
+ if (iFilterMethod != 0) {
+ DBG_DEC(iFilterMethod);
+ return FALSE;
+ }
+ iInterlaceMethod = iNextByte(pFile);
+ if (iInterlaceMethod != 0) {
+ DBG_DEC(iInterlaceMethod);
+ return FALSE;
+ }
+ pImg->iColorsUsed = 0;
+ (void)tSkipBytes(pFile, tLength - 13 + 4);
+ break;
+ case PNG_CN_PLTE:
+ if (!bHasPalette) {
+ return FALSE;
+ }
+ if (!bFillPalettePNG(pFile, pImg, tLength)) {
+ return FALSE;
+ }
+ (void)tSkipBytes(pFile, 4);
+ break;
+ default:
+ (void)tSkipBytes(pFile, tLength + 4);
+ break;
+ }
+ }
+
+ DBG_DEC(pImg->iWidth);
+ DBG_DEC(pImg->iHeight);
+ DBG_DEC(pImg->uiBitsPerComponent);
+ DBG_DEC(pImg->iColorsUsed);
+ DBG_DEC(pImg->iComponents);
+
+ /* Do some sanity checks with the parameters */
+ if (pImg->iWidth <= 0 || pImg->iHeight <= 0) {
+ return FALSE;
+ }
+
+ if (pImg->uiBitsPerComponent != 1 && pImg->uiBitsPerComponent != 2 &&
+ pImg->uiBitsPerComponent != 4 && pImg->uiBitsPerComponent != 8 &&
+ pImg->uiBitsPerComponent != 16) {
+ DBG_DEC(pImg->uiBitsPerComponent);
+ return FALSE;
+ }
+
+ if (pImg->iComponents != 1 && pImg->iComponents != 3) {
+ /* Not supported */
+ DBG_DEC(pImg->iComponents);
+ return FALSE;
+ }
+
+ if (pImg->uiBitsPerComponent > 8) {
+ /* Not supported */
+ DBG_DEC(pImg->uiBitsPerComponent);
+ return FALSE;
+ }
+
+ if (pImg->iColorsUsed == 0 &&
+ pImg->iComponents == 1 &&
+ pImg->uiBitsPerComponent <= 4) {
+ /*
+ * No palette is supplied, but PostScript needs one in these
+ * cases, so we add a default palette here
+ */
+ pImg->iColorsUsed = 1 << pImg->uiBitsPerComponent;
+ iIncrement = 0xff / (pImg->iColorsUsed - 1);
+ for (iIndex = 0, iColor = 0x00;
+ iIndex < pImg->iColorsUsed;
+ iIndex++, iColor += iIncrement) {
+ pImg->aucPalette[iIndex][0] = (UCHAR)iColor;
+ pImg->aucPalette[iIndex][1] = (UCHAR)iColor;
+ pImg->aucPalette[iIndex][2] = (UCHAR)iColor;
+ }
+ /* Just to be sure */
+ pImg->bColorImage = FALSE;
+ }
+
+ pImg->eCompression = compression_zlib;
+
+ return TRUE;
+} /* end of bExaminePNG */
+
+/*
+ * bExamineWMF - Examine a WMF header
+ *
+ * return TRUE if successful, otherwise FALSE
+ */
+static BOOL
+bExamineWMF(FILE *pFile, imagedata_type *pImg)
+{
+ ULONG ulFileSize, ulMaxRecord, ulMagic;
+ USHORT usType, usHeaderSize, usVersion, usNoObjects;
+
+ usType = usNextWord(pFile);
+ usHeaderSize = usNextWord(pFile);
+ ulMagic = ((ULONG)usHeaderSize << 16) | (ULONG)usType;
+ usVersion = usNextWord(pFile);
+ ulFileSize = ulNextLong(pFile);
+ usNoObjects = usNextWord(pFile);
+ ulMaxRecord = ulNextLong(pFile);
+
+ DBG_HEX(ulMagic);
+ DBG_DEC(usType);
+ DBG_DEC(usHeaderSize);
+ DBG_HEX(usVersion);
+ DBG_DEC(ulFileSize);
+ DBG_DEC(usNoObjects);
+ DBG_DEC(ulMaxRecord);
+
+ return FALSE;
+} /* end of bExamineWMF */
+
+#if !defined(__riscos)
+/*
+ * vImage2Papersize - make sure the image fits on the paper
+ *
+ * This function should not be needed if Word would do a proper job
+ */
+static void
+vImage2Papersize(imagedata_type *pImg)
+{
+ static int iNetPageHeight = -1;
+ static int iNetPageWidth = -1;
+ options_type tOptions;
+ double dVerFactor, dHorFactor, dFactor;
+
+ DBG_MSG("vImage2Papersize");
+
+ fail(pImg == NULL);
+
+ if (iNetPageHeight < 0 || iNetPageWidth < 0) {
+ /* Get the page dimensions from the options */
+ vGetOptions(&tOptions);
+ /* Add 999 to err on the save side */
+ iNetPageHeight = tOptions.iPageHeight -
+ (lDrawUnits2MilliPoints(
+ PS_TOP_MARGIN + PS_BOTTOM_MARGIN) +
+ 999) / 1000;
+ iNetPageWidth = tOptions.iPageWidth -
+ (lDrawUnits2MilliPoints(
+ PS_LEFT_MARGIN + PS_RIGHT_MARGIN) +
+ 999) / 1000;
+ DBG_DEC(iNetPageHeight);
+ DBG_DEC(iNetPageWidth);
+ }
+
+ if (pImg->iVerSizeScaled < iNetPageHeight &&
+ pImg->iHorSizeScaled < iNetPageWidth) {
+ /* The image fits on the paper */
+ return;
+ }
+
+ dVerFactor = (double)iNetPageHeight / (double)pImg->iVerSizeScaled;
+ dHorFactor = (double)iNetPageWidth / (double)pImg->iHorSizeScaled;
+ dFactor = min(dVerFactor, dHorFactor);
+ DBG_FLT(dFactor);
+ /* Round down, just to be on the save side */
+ pImg->iVerSizeScaled = (int)(pImg->iVerSizeScaled * dFactor);
+ pImg->iHorSizeScaled = (int)(pImg->iHorSizeScaled * dFactor);
+} /* end of vImage2Papersize */
+#endif /* !__riscos */
+
+/*
+ * tFind6Image - skip until the image is found
+ *
+ * Find the image in Word 6/7 files
+ *
+ * returns the new position when a image is found, otherwise -1
+ */
+static size_t
+tFind6Image(FILE *pFile, size_t tPosition, size_t tLength,
+ imagetype_enum *peImageType)
+{
+ ULONG ulMarker;
+ size_t tRecordLength, tToSkip;
+ USHORT usMarker;
+
+ fail(pFile == NULL);
+ fail(peImageType == NULL);
+
+ *peImageType = imagetype_is_unknown;
+ if (tPosition + 18 >= tLength) {
+ return (size_t)-1;
+ }
+
+ ulMarker = ulNextLong(pFile);
+ if (ulMarker != 0x00090001) {
+ DBG_HEX(ulMarker);
+ return (size_t)-1;
+ }
+ usMarker = usNextWord(pFile);
+ if (usMarker != 0x0300) {
+ DBG_HEX(usMarker);
+ return (size_t)-1;
+ }
+ (void)tSkipBytes(pFile, 10);
+ usMarker = usNextWord(pFile);
+ if (usMarker != 0x0000) {
+ DBG_HEX(usMarker);
+ return (size_t)-1;
+ }
+ tPosition += 18;
+
+ while (tPosition + 6 <= tLength) {
+ tRecordLength = (size_t)ulNextLong(pFile);
+ usMarker = usNextWord(pFile);
+ tPosition += 6;
+ NO_DBG_DEC(tRecordLength);
+ NO_DBG_HEX(usMarker);
+ switch (usMarker) {
+ case 0x0000:
+ DBG_HEX(ulGetDataOffset(pFile));
+ return (size_t)-1;
+ case 0x0b41:
+ DBG_MSG("DIB");
+ *peImageType = imagetype_is_dib;
+ tPosition += tSkipBytes(pFile, 20);
+ return tPosition;
+ case 0x0f43:
+ DBG_MSG("DIB");
+ *peImageType = imagetype_is_dib;
+ tPosition += tSkipBytes(pFile, 22);
+ return tPosition;
+ default:
+ if (tRecordLength < 3) {
+ break;
+ }
+ if (tRecordLength > SIZE_T_MAX / 2) {
+ /*
+ * No need to compute the number of bytes
+ * to skip
+ */
+ DBG_DEC(tRecordLength);
+ DBG_HEX(tRecordLength);
+ DBG_FIXME();
+ return (size_t)-1;
+ }
+ tToSkip = tRecordLength * 2 - 6;
+ if (tToSkip > tLength - tPosition) {
+ /* You can't skip this number of bytes */
+ DBG_DEC(tToSkip);
+ DBG_DEC(tLength - tPosition);
+ return (size_t)-1;
+ }
+ tPosition += tSkipBytes(pFile, tToSkip);
+ break;
+ }
+ }
+
+ return (size_t)-1;
+} /* end of tFind6Image */
+
+/*
+ * tFind8Image - skip until the image is found
+ *
+ * Find the image in Word 8/9/10 files
+ *
+ * returns the new position when a image is found, otherwise -1
+ */
+static size_t
+tFind8Image(FILE *pFile, size_t tPosition, size_t tLength,
+ imagetype_enum *peImageType)
+{
+ size_t tRecordLength, tNameLen;
+ USHORT usRecordVersion, usRecordType, usRecordInstance;
+ USHORT usTmp;
+
+ fail(pFile == NULL);
+ fail(peImageType == NULL);
+
+ *peImageType = imagetype_is_unknown;
+ while (tPosition + 8 <= tLength) {
+ usTmp = usNextWord(pFile);
+ usRecordVersion = usTmp & 0x000f;
+ usRecordInstance = usTmp >> 4;
+ usRecordType = usNextWord(pFile);
+ tRecordLength = (size_t)ulNextLong(pFile);
+ tPosition += 8;
+ NO_DBG_HEX(usRecordVersion);
+ NO_DBG_HEX(usRecordInstance);
+ NO_DBG_HEX(usRecordType);
+ NO_DBG_DEC(tRecordLength);
+ switch (usRecordType) {
+ case 0xf000: case 0xf001: case 0xf002: case 0xf003:
+ case 0xf004: case 0xf005:
+ break;
+ case 0xf007:
+ tPosition += tSkipBytes(pFile, 33);
+ tNameLen = (size_t)iNextByte(pFile);
+ tPosition++;
+ DBG_DEC_C(tNameLen != 0, tNameLen);
+ tPosition += tSkipBytes(pFile, 2 + tNameLen * 2);
+ break;
+ case 0xf008:
+ tPosition += tSkipBytes(pFile, 8);
+ break;
+ case 0xf009:
+ tPosition += tSkipBytes(pFile, 16);
+ break;
+ case 0xf006: case 0xf00a: case 0xf00b: case 0xf00d:
+ case 0xf00e: case 0xf00f: case 0xf010: case 0xf011:
+ case 0xf122:
+ tPosition += tSkipBytes(pFile, tRecordLength);
+ break;
+ case 0xf01a:
+ DBG_MSG("EMF");
+ *peImageType = imagetype_is_emf;
+ tPosition += tSkipBytes(pFile, 50);
+ if ((usRecordInstance ^ MSOBI_EMF) == 1) {
+ tPosition += tSkipBytes(pFile, 16);
+ }
+ return tPosition;
+ case 0xf01b:
+ DBG_MSG("WMF");
+ *peImageType = imagetype_is_wmf;
+ tPosition += tSkipBytes(pFile, 50);
+ if ((usRecordInstance ^ MSOBI_WMF) == 1) {
+ tPosition += tSkipBytes(pFile, 16);
+ }
+ return tPosition;
+ case 0xf01c:
+ DBG_MSG("PICT");
+ *peImageType = imagetype_is_pict;
+ tPosition += tSkipBytes(pFile, 50);
+ if ((usRecordInstance ^ MSOBI_PICT) == 1) {
+ tPosition += tSkipBytes(pFile, 16);
+ }
+ return tPosition;
+ case 0xf01d:
+ DBG_MSG("JPEG");
+ *peImageType = imagetype_is_jpeg;
+ tPosition += tSkipBytes(pFile, 17);
+ if ((usRecordInstance ^ MSOBI_JPEG) == 1) {
+ tPosition += tSkipBytes(pFile, 16);
+ }
+ return tPosition;
+ case 0xf01e:
+ DBG_MSG("PNG");
+ *peImageType = imagetype_is_png;
+ tPosition += tSkipBytes(pFile, 17);
+ if ((usRecordInstance ^ MSOBI_PNG) == 1) {
+ tPosition += tSkipBytes(pFile, 16);
+ }
+ return tPosition;
+ case 0xf01f:
+ DBG_MSG("DIB");
+ /* DIB is a BMP minus its 14 byte header */
+ *peImageType = imagetype_is_dib;
+ tPosition += tSkipBytes(pFile, 17);
+ if ((usRecordInstance ^ MSOBI_DIB) == 1) {
+ tPosition += tSkipBytes(pFile, 16);
+ }
+ return tPosition;
+ case 0xf00c:
+ default:
+ DBG_HEX(usRecordType);
+ DBG_DEC_C(tRecordLength % 4 != 0, tRecordLength);
+ DBG_FIXME();
+ return (size_t)-1;
+ }
+ }
+
+ return (size_t)-1;
+} /* end of tFind8Image */
+
+/*
+ * eExamineImage - Examine the image
+ *
+ * Returns an indication of the amount of information found
+ */
+image_info_enum
+eExamineImage(FILE *pFile, ULONG ulFileOffsetImage, imagedata_type *pImg)
+{
+ long lTmp;
+ size_t tWordHeaderLen, tLength, tPos;
+ int iType, iHorSize, iVerSize;
+ USHORT usHorScalingFactor, usVerScalingFactor;
+
+ if (ulFileOffsetImage == FC_INVALID) {
+ return image_no_information;
+ }
+ DBG_HEX(ulFileOffsetImage);
+
+ if (!bSetDataOffset(pFile, ulFileOffsetImage)) {
+ return image_no_information;
+ }
+
+ tLength = (size_t)ulNextLong(pFile);
+ DBG_DEC(tLength);
+ if (tLength < 46) {
+ /* Smaller than the smallest known header */
+ DBG_FIXME();
+ return image_no_information;
+ }
+ tWordHeaderLen = (size_t)usNextWord(pFile);
+ DBG_DEC(tWordHeaderLen);
+ fail(tWordHeaderLen != 46 &&
+ tWordHeaderLen != 58 &&
+ tWordHeaderLen != 68);
+
+ if (tLength < tWordHeaderLen) {
+ /* Smaller than the current header */
+ return image_no_information;
+ }
+ iType = (int)usNextWord(pFile);
+ DBG_DEC(iType);
+ (void)tSkipBytes(pFile, 28 - 8);
+
+ lTmp = lTwips2MilliPoints(usNextWord(pFile));
+ iHorSize = (int)(lTmp / 1000);
+ if (lTmp % 1000 != 0) {
+ iHorSize++;
+ }
+ DBG_DEC(iHorSize);
+ lTmp = lTwips2MilliPoints(usNextWord(pFile));
+ iVerSize = (int)(lTmp / 1000);
+ if (lTmp % 1000 != 0) {
+ iVerSize++;
+ }
+ DBG_DEC(iVerSize);
+
+ usHorScalingFactor = usNextWord(pFile);
+ DBG_DEC(usHorScalingFactor);
+ usVerScalingFactor = usNextWord(pFile);
+ DBG_DEC(usVerScalingFactor);
+
+ /* Sanity checks */
+ lTmp = (long)iHorSize * (long)usHorScalingFactor;
+ if (lTmp < 2835) {
+ /* This image would be less than 1 millimeter wide */
+ DBG_DEC(lTmp);
+ return image_no_information;
+ }
+ lTmp = (long)iVerSize * (long)usVerScalingFactor;
+ if (lTmp < 2835) {
+ /* This image would be less than 1 millimeter high */
+ DBG_DEC(lTmp);
+ return image_no_information;
+ }
+
+ /* Skip the rest of the header */
+ (void)tSkipBytes(pFile, tWordHeaderLen - 36);
+ tPos = tWordHeaderLen;
+
+ (void)memset(pImg, 0, sizeof(*pImg));
+
+ switch (iType) {
+ case 7:
+ case 8:
+ tPos = tFind6Image(pFile, tPos, tLength, &pImg->eImageType);
+ if (tPos == (size_t)-1) {
+ /* No image found */
+ return image_no_information;
+ }
+ DBG_HEX(tPos);
+ break;
+ case 94: /* Word 6/7, no image just a pathname */
+ pImg->eImageType = imagetype_is_external;
+ DBG_HEX(ulFileOffsetImage + tPos);
+ break;
+ case 100:
+ tPos = tFind8Image(pFile, tPos, tLength, &pImg->eImageType);
+ if (tPos == (size_t)-1) {
+ /* No image found */
+ return image_no_information;
+ }
+ DBG_HEX(tPos);
+ break;
+ case 102: /* Word 8/9/10, no image just a pathname or URL */
+ pImg->eImageType = imagetype_is_external;
+ DBG_HEX(ulFileOffsetImage + tPos);
+ break;
+ default:
+ DBG_DEC(iType);
+ DBG_HEX(ulFileOffsetImage + tPos);
+ DBG_FIXME();
+ return image_no_information;
+ }
+
+ /* Minimal information is now available */
+ pImg->tLength = tLength;
+ pImg->tPosition = tPos;
+ pImg->iHorSizeScaled =
+ (int)(((long)iHorSize * (long)usHorScalingFactor + 500) / 1000);
+ pImg->iVerSizeScaled =
+ (int)(((long)iVerSize * (long)usVerScalingFactor + 500) / 1000);
+#if !defined(__riscos)
+ vImage2Papersize(pImg);
+#endif /* !__riscos */
+
+ /* Image type specific examinations */
+ switch (pImg->eImageType) {
+ case imagetype_is_dib:
+ if (bExamineDIB(pFile, pImg)) {
+ return image_full_information;
+ }
+ return image_minimal_information;
+ case imagetype_is_jpeg:
+ if (bExamineJPEG(pFile, pImg)) {
+ return image_full_information;
+ }
+ return image_minimal_information;
+ case imagetype_is_png:
+ if (bExaminePNG(pFile, pImg)) {
+ return image_full_information;
+ }
+ return image_minimal_information;
+ case imagetype_is_wmf:
+ if (bExamineWMF(pFile, pImg)) {
+ return image_full_information;
+ }
+ return image_minimal_information;
+ case imagetype_is_emf:
+ case imagetype_is_pict:
+ case imagetype_is_external:
+ return image_minimal_information;
+ case imagetype_is_unknown:
+ default:
+ return image_no_information;
+ }
+} /* end of eExamineImage */
diff --git a/sys/src/cmd/aux/antiword/imgtrans.c b/sys/src/cmd/aux/antiword/imgtrans.c
new file mode 100755
index 000000000..1b284c4e3
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/imgtrans.c
@@ -0,0 +1,71 @@
+/*
+ * imgtrans.c
+ * Copyright (C) 2000-2002 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Generic functions to translate Word images
+ */
+
+#include <stdio.h>
+#include "antiword.h"
+
+
+/*
+ * bTranslateImage - translate the image
+ *
+ * This function reads the type of the given image and and gets it translated.
+ *
+ * return TRUE when sucessful, otherwise FALSE
+ */
+BOOL
+bTranslateImage(diagram_type *pDiag, FILE *pFile, BOOL bMinimalInformation,
+ ULONG ulFileOffsetImage, const imagedata_type *pImg)
+{
+ options_type tOptions;
+
+ DBG_MSG("bTranslateImage");
+
+ fail(pDiag == NULL);
+ fail(pFile == NULL);
+ fail(ulFileOffsetImage == FC_INVALID);
+ fail(pImg == NULL);
+ fail(pImg->iHorSizeScaled <= 0);
+ fail(pImg->iVerSizeScaled <= 0);
+
+ vGetOptions(&tOptions);
+ fail(tOptions.eImageLevel == level_no_images);
+
+ if (bMinimalInformation) {
+ return bAddDummyImage(pDiag, pImg);
+ }
+
+ switch (pImg->eImageType) {
+ case imagetype_is_dib:
+ return bTranslateDIB(pDiag, pFile,
+ ulFileOffsetImage + pImg->tPosition,
+ pImg);
+ case imagetype_is_jpeg:
+ return bTranslateJPEG(pDiag, pFile,
+ ulFileOffsetImage + pImg->tPosition,
+ pImg->tLength - pImg->tPosition,
+ pImg);
+ case imagetype_is_png:
+ if (tOptions.eImageLevel == level_ps_2) {
+ return bAddDummyImage(pDiag, pImg);
+ }
+ return bTranslatePNG(pDiag, pFile,
+ ulFileOffsetImage + pImg->tPosition,
+ pImg->tLength - pImg->tPosition,
+ pImg);
+ case imagetype_is_emf:
+ case imagetype_is_wmf:
+ case imagetype_is_pict:
+ case imagetype_is_external:
+ /* FIXME */
+ return bAddDummyImage(pDiag, pImg);
+ case imagetype_is_unknown:
+ default:
+ DBG_DEC(pImg->eImageType);
+ return bAddDummyImage(pDiag, pImg);
+ }
+} /* end of bTranslateImage */
diff --git a/sys/src/cmd/aux/antiword/jpeg2eps.c b/sys/src/cmd/aux/antiword/jpeg2eps.c
new file mode 100755
index 000000000..ee438cec4
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/jpeg2eps.c
@@ -0,0 +1,74 @@
+/*
+ * jpeg2eps.c
+ * Copyright (C) 2000-2002 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Functions to translate jpeg pictures into eps
+ *
+ */
+
+#include <stdio.h>
+#include "antiword.h"
+
+#if defined(DEBUG)
+static int iPicCounter = 0;
+#endif /* DEBUG */
+
+
+#if defined(DEBUG)
+/*
+ * vCopy2File
+ */
+static void
+vCopy2File(FILE *pFile, ULONG ulFileOffset, size_t tPictureLen)
+{
+ FILE *pOutFile;
+ size_t tIndex;
+ int iTmp;
+ char szFilename[30];
+
+ if (!bSetDataOffset(pFile, ulFileOffset)) {
+ return;
+ }
+
+ sprintf(szFilename, "/tmp/pic/pic%04d.jpg", ++iPicCounter);
+ pOutFile = fopen(szFilename, "wb");
+ if (pOutFile == NULL) {
+ return;
+ }
+ for (tIndex = 0; tIndex < tPictureLen; tIndex++) {
+ iTmp = iNextByte(pFile);
+ if (putc(iTmp, pOutFile) == EOF) {
+ break;
+ }
+ }
+ (void)fclose(pOutFile);
+} /* end of vCopy2File */
+#endif /* DEBUG */
+
+/*
+ * bTranslateJPEG - translate a JPEG picture
+ *
+ * This function translates a picture from jpeg to eps
+ *
+ * return TRUE when sucessful, otherwise FALSE
+ */
+BOOL
+bTranslateJPEG(diagram_type *pDiag, FILE *pFile,
+ ULONG ulFileOffset, size_t tPictureLen, const imagedata_type *pImg)
+{
+#if defined(DEBUG)
+ vCopy2File(pFile, ulFileOffset, tPictureLen);
+#endif /* DEBUG */
+
+ /* Seek to start position of JPEG data */
+ if (!bSetDataOffset(pFile, ulFileOffset)) {
+ return FALSE;
+ }
+
+ vImagePrologue(pDiag, pImg);
+ vASCII85EncodeFile(pFile, pDiag->pOutFile, tPictureLen);
+ vImageEpilogue(pDiag);
+
+ return TRUE;
+} /* end of bTranslateJPEG */
diff --git a/sys/src/cmd/aux/antiword/jpeg2sprt.c b/sys/src/cmd/aux/antiword/jpeg2sprt.c
new file mode 100755
index 000000000..28bd6cdaa
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/jpeg2sprt.c
@@ -0,0 +1,97 @@
+/*
+ * jpeg2sprt.c
+ * Copyright (C) 2000-2002 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Functions to translate jpeg pictures into sprites
+ */
+
+#include <stdio.h>
+#include "antiword.h"
+
+#if 0 /* defined(DEBUG) */
+static int iPicCounter = 0;
+#endif /* DEBUG */
+
+
+#if 0 /* defined(DEBUG) */
+static void
+vCopy2File(UCHAR *pucJpeg, size_t tJpegSize)
+{
+ FILE *pOutFile;
+ size_t tIndex;
+ char szFilename[30];
+
+ sprintf(szFilename, "<Wimp$ScrapDir>.jpeg%04d", ++iPicCounter);
+ pOutFile = fopen(szFilename, "wb");
+ if (pOutFile == NULL) {
+ return;
+ }
+ DBG_MSG(szFilename);
+ for (tIndex = 0; tIndex < tJpegSize; tIndex++) {
+ if (putc(pucJpeg[tIndex], pOutFile) == EOF) {
+ break;
+ }
+ }
+ (void)fclose(pOutFile);
+ vSetFiletype(szFilename, FILETYPE_JPEG);
+} /* end of vCopy2File */
+#endif /* DEBUG */
+
+/*
+ * bSave2Draw - save the JPEG picture to the Draw file
+ *
+ * This function puts a JPEG picture in a Draw file
+ *
+ * return TRUE when sucessful, otherwise FALSE
+ */
+BOOL
+bSave2Draw(diagram_type *pDiag, FILE *pFile,
+ size_t tJpegSize, const imagedata_type *pImg)
+{
+ UCHAR *pucJpeg, *pucTmp;
+ size_t tLen;
+ int iByte;
+
+ pucJpeg = xmalloc(tJpegSize);
+ for (pucTmp = pucJpeg, tLen = 0; tLen < tJpegSize; pucTmp++, tLen++) {
+ iByte = iNextByte(pFile);
+ if (iByte == EOF) {
+ return FALSE;
+ }
+ *pucTmp = (UCHAR)iByte;
+ }
+
+#if 0 /* defined(DEBUG) */
+ vCopy2File(pucJpeg, tJpegSize);
+#endif /* DEBUG */
+
+ /* Add the JPEG to the Draw file */
+ vImage2Diagram(pDiag, pImg, pucJpeg, tJpegSize);
+
+ xfree(pucJpeg);
+ return TRUE;
+} /* end of bSave2Draw */
+
+/*
+ * bTranslateJPEG - translate a JPEG picture
+ *
+ * This function translates a picture from jpeg to sprite
+ *
+ * return TRUE when sucessful, otherwise FALSE
+ */
+BOOL
+bTranslateJPEG(diagram_type *pDiag, FILE *pFile,
+ ULONG ulFileOffset, size_t tPictureLen, const imagedata_type *pImg)
+{
+ /* Seek to start position of JPEG data */
+ if (!bSetDataOffset(pFile, ulFileOffset)) {
+ return FALSE;
+ }
+
+ if (iGetRiscOsVersion() >= 360) {
+ return bSave2Draw(pDiag, pFile, tPictureLen, pImg);
+ }
+ /* JPEG is not supported until RISC OS 3.6 */
+ return bAddDummyImage(pDiag, pImg);
+} /* end of bTranslateJPEG */
diff --git a/sys/src/cmd/aux/antiword/listlist.c b/sys/src/cmd/aux/antiword/listlist.c
new file mode 100755
index 000000000..eb86589af
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/listlist.c
@@ -0,0 +1,330 @@
+/*
+ * listlist.c
+ * Copyright (C) 2002,2003 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Build, read and destroy a list of Word list information
+ *
+ * Note:
+ * This list only exists when the Word document is saved by Word 8 or later
+ */
+
+#include "antiword.h"
+
+/*
+ * Private structure to hide the way the information
+ * is stored from the rest of the program
+ */
+typedef struct list_desc_tag {
+ list_block_type tInfo;
+ ULONG ulListID;
+ USHORT usIstd;
+ UCHAR ucListLevel;
+ struct list_desc_tag *pNext;
+} list_desc_type;
+
+typedef struct list_value_tag {
+ USHORT usValue;
+ USHORT usListIndex;
+ UCHAR ucListLevel;
+ struct list_value_tag *pNext;
+} list_value_type;
+
+/* Variables needed to describe the LFO list (pllfo) */
+static ULONG *aulLfoList = NULL;
+static USHORT usLfoLen = 0;
+/* Variables needed to write the List Information List */
+static list_desc_type *pAnchor = NULL;
+static list_desc_type *pBlockLast = NULL;
+/* Variable needed for numbering new lists */
+static list_value_type *pValues = NULL;
+/* Variables needed for numbering old lists */
+static int iOldListSeqNumber = 0;
+static USHORT usOldListValue = 0;
+
+
+/*
+ * vDestroyListInfoList - destroy the List Information List
+ */
+void
+vDestroyListInfoList(void)
+{
+ list_desc_type *pCurr, *pNext;
+ list_value_type *pValueCurr, *pValueNext;
+
+ DBG_MSG("vDestroyListInfoList");
+
+ /* Free the LFO list */
+ usLfoLen = 0;
+ aulLfoList = xfree(aulLfoList);
+
+ /* Free the List Information List */
+ pCurr = pAnchor;
+ while (pCurr != NULL) {
+ pNext = pCurr->pNext;
+ pCurr = xfree(pCurr);
+ pCurr = pNext;
+ }
+ pAnchor = NULL;
+ /* Reset all control variables */
+ pBlockLast = NULL;
+
+ /* Free the values list */
+ pValueCurr = pValues;
+ while (pValueCurr != NULL) {
+ pValueNext = pValueCurr->pNext;
+ pValueCurr = xfree(pValueCurr);
+ pValueCurr = pValueNext;
+ }
+ pValues = NULL;
+ /* Reset the values for the old lists */
+ iOldListSeqNumber = 0;
+ usOldListValue = 0;
+} /* end of vDestroyListInfoList */
+
+/*
+ * vBuildLfoList - build the LFO list (pllfo)
+ */
+void
+vBuildLfoList(const UCHAR *aucBuffer, size_t tBufLen)
+{
+ size_t tRecords;
+ int iIndex;
+
+ fail(aucBuffer == NULL);
+
+ if (tBufLen < 4) {
+ return;
+ }
+ tRecords = (size_t)ulGetLong(0, aucBuffer);
+ NO_DBG_DEC(tRecords);
+ if (4 + 16 * tRecords > tBufLen || tRecords >= 0x7fff) {
+ /* Just a sanity check */
+ DBG_DEC(tRecords);
+ DBG_DEC(4 + 16 * tRecords);
+ DBG_DEC(tBufLen);
+ return;
+ }
+ aulLfoList = xcalloc(tRecords, sizeof(ULONG));
+ for (iIndex = 0; iIndex < (int)tRecords; iIndex++) {
+ aulLfoList[iIndex] = ulGetLong(4 + 16 * iIndex, aucBuffer);
+ NO_DBG_HEX(aulLfoList[iIndex]);
+ }
+ usLfoLen = (USHORT)tRecords;
+} /* end of vBuildLfoList */
+
+/*
+ * vAdd2ListInfoList - add an element to the List Information list
+ */
+void
+vAdd2ListInfoList(ULONG ulListID, USHORT usIstd, UCHAR ucListLevel,
+ const list_block_type *pListBlock)
+{
+ list_desc_type *pListMember;
+
+ fail(pListBlock == NULL);
+
+ NO_DBG_HEX(ulListID);
+ NO_DBG_DEC(usIstd);
+ NO_DBG_DEC(ucListLevel);
+ NO_DBG_DEC(pListBlock->ulStartAt);
+ NO_DBG_DEC(pListBlock->bNoRestart);
+ NO_DBG_DEC(pListBlock->sLeftIndent);
+ NO_DBG_HEX(pListBlock->ucNFC);
+ NO_DBG_HEX(pListBlock->usListChar);
+
+ /* Create list member */
+ pListMember = xmalloc(sizeof(list_desc_type));
+ /* Fill the list member */
+ pListMember->tInfo = *pListBlock;
+ pListMember->ulListID = ulListID;
+ pListMember->usIstd = usIstd;
+ pListMember->ucListLevel = ucListLevel;
+ pListMember->pNext = NULL;
+ /* Correct the values where needed */
+ if (pListMember->tInfo.ulStartAt > 0xffff) {
+ DBG_DEC(pListMember->tInfo.ulStartAt);
+ pListMember->tInfo.ulStartAt = 1;
+ }
+ /* Add the new member to the list */
+ if (pAnchor == NULL) {
+ pAnchor = pListMember;
+ } else {
+ fail(pBlockLast == NULL);
+ pBlockLast->pNext = pListMember;
+ }
+ pBlockLast = pListMember;
+} /* end of vAdd2ListInfoList */
+
+/*
+ * Get a matching record from the List Information List
+ *
+ * Returns NULL if no matching records is found
+ */
+const list_block_type *
+pGetListInfo(USHORT usListIndex, UCHAR ucListLevel)
+{
+ list_desc_type *pCurr;
+ list_block_type *pNearMatch;
+ ULONG ulListID;
+
+ if (usListIndex == 0) {
+ return NULL;
+ }
+ if (usListIndex - 1 >= usLfoLen || ucListLevel > 8) {
+ DBG_DEC(usListIndex);
+ DBG_DEC(ucListLevel);
+ return NULL;
+ }
+ fail(aulLfoList == NULL);
+ ulListID = aulLfoList[usListIndex - 1];
+ NO_DBG_HEX(ulListID);
+
+ pNearMatch = NULL;
+ for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
+ if (pCurr->ulListID != ulListID) {
+ /* No match */
+ continue;
+ }
+ if (pCurr->ucListLevel == ucListLevel) {
+ /* Exact match */
+ return &pCurr->tInfo;
+ }
+ if (pCurr->ucListLevel == 0) {
+ /* Near match */
+ pNearMatch = &pCurr->tInfo;
+ }
+ }
+ /* No exact match, use a near match if any */
+ return pNearMatch;
+} /* end of pGetListInfo */
+
+/*
+ * Get a matching record from the List Information List
+ *
+ * Returns NULL if no matching records is found
+ */
+const list_block_type *
+pGetListInfoByIstd(USHORT usIstd)
+{
+ list_desc_type *pCurr;
+
+ if (usIstd == ISTD_INVALID || usIstd == STI_NIL || usIstd == STI_USER) {
+ return NULL;
+ }
+
+ for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
+ if (pCurr->usIstd == usIstd) {
+ return &pCurr->tInfo;
+ }
+ }
+ return NULL;
+} /* end of pGetListInfoByIstd */
+
+/*
+ * vRestartListValues - reset the less significant list levels
+ */
+static void
+vRestartListValues(USHORT usListIndex, UCHAR ucListLevel)
+{
+ list_value_type *pPrev, *pCurr, *pNext;
+ int iCounter;
+
+ iCounter = 0;
+ pPrev = NULL;
+ pCurr = pValues;
+
+ while (pCurr != NULL) {
+ if (pCurr->usListIndex != usListIndex ||
+ pCurr->ucListLevel <= ucListLevel) {
+ pPrev = pCurr;
+ pCurr = pCurr->pNext;
+ continue;
+ }
+ /* Reset the level by deleting the record */
+ pNext = pCurr->pNext;
+ if (pPrev == NULL) {
+ pValues = pNext;
+ } else {
+ pPrev->pNext = pNext;
+ }
+ DBG_DEC(pCurr->usListIndex);
+ DBG_DEC(pCurr->ucListLevel);
+ pCurr = xfree(pCurr);
+ pCurr = pNext;
+ iCounter++;
+ }
+ DBG_DEC_C(iCounter > 0, iCounter);
+} /* end of vRestartListValues */
+
+/*
+ * usGetListValue - Get the current value of the given list
+ *
+ * Returns the value of the given list
+ */
+USHORT
+usGetListValue(int iListSeqNumber, int iWordVersion,
+ const style_block_type *pStyle)
+{
+ list_value_type *pCurr;
+ USHORT usValue;
+
+ fail(iListSeqNumber < 0);
+ fail(iListSeqNumber < iOldListSeqNumber);
+ fail(iWordVersion < 0);
+ fail(pStyle == NULL);
+
+ if (iListSeqNumber <= 0) {
+ return 0;
+ }
+
+ if (iWordVersion < 8) {
+ /* Old style list */
+ if (iListSeqNumber == iOldListSeqNumber ||
+ (iListSeqNumber == iOldListSeqNumber + 1 &&
+ eGetNumType(pStyle->ucNumLevel) == level_type_sequence)) {
+ if (!pStyle->bNumPause) {
+ usOldListValue++;
+ }
+ } else {
+ usOldListValue = pStyle->usStartAt;
+ }
+ iOldListSeqNumber = iListSeqNumber;
+ return usOldListValue;
+ }
+
+ /* New style list */
+ if (pStyle->usListIndex == 0 ||
+ pStyle->usListIndex - 1 >= usLfoLen ||
+ pStyle->ucListLevel > 8) {
+ /* Out of range; no need to search */
+ return 0;
+ }
+
+ for (pCurr = pValues; pCurr != NULL; pCurr = pCurr->pNext) {
+ if (pCurr->usListIndex == pStyle->usListIndex &&
+ pCurr->ucListLevel == pStyle->ucListLevel) {
+ /* Record found; increment and return the value */
+ pCurr->usValue++;
+ usValue = pCurr->usValue;
+ if (!pStyle->bNoRestart) {
+ vRestartListValues(pStyle->usListIndex,
+ pStyle->ucListLevel);
+ }
+ return usValue;
+ }
+ }
+
+ /* Record not found; create it and add it to the front of the list */
+ pCurr = xmalloc(sizeof(list_value_type));
+ pCurr->usValue = pStyle->usStartAt;
+ pCurr->usListIndex = pStyle->usListIndex;
+ pCurr->ucListLevel = pStyle->ucListLevel;
+ pCurr->pNext = pValues;
+ pValues = pCurr;
+ usValue = pCurr->usValue;
+ if (!pStyle->bNoRestart) {
+ vRestartListValues(pStyle->usListIndex, pStyle->ucListLevel);
+ }
+ return usValue;
+} /* end of usGetListValue */
diff --git a/sys/src/cmd/aux/antiword/main_ros.c b/sys/src/cmd/aux/antiword/main_ros.c
new file mode 100755
index 000000000..8f4f3161e
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/main_ros.c
@@ -0,0 +1,520 @@
+/*
+ * main_ros.c
+ *
+ * Released under GPL
+ *
+ * Copyright (C) 1998-2005 A.J. van Os
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Description:
+ * The main program of !Antiword (RISC OS version)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "DeskLib:Dialog2.h"
+#include "DeskLib:Error.h"
+#include "DeskLib:Event.h"
+#include "DeskLib:EventMsg.h"
+#include "DeskLib:Handler.h"
+#include "DeskLib:Menu.h"
+#include "DeskLib:Resource.h"
+#include "DeskLib:Screen.h"
+#include "DeskLib:Template.h"
+#include "DeskLib:Window.h"
+#if defined(__GNUC__)
+#include "flexlib:flex.h"
+#endif /* __GNUC__ */
+#include "version.h"
+#include "antiword.h"
+
+
+/* The name of this program */
+static char *szTask = "!Antiword";
+
+/* The window handle of the choices window */
+static window_handle tChoicesWindow = 0;
+
+/* Dummy diagram with the iconbar menu pointer */
+static diagram_type tDummyDiagram;
+
+/* Program information Box */
+static dialog2_block *pInfoBox = NULL;
+
+/* Info box fields */
+#define PURPOSE_INFO_FIELD 2
+#define AUTHOR_INFO_FIELD 3
+#define VERSION_INFO_FIELD 4
+#define STATUS_INFO_FIELD 5
+
+/* Iconbar menu fields */
+#define ICONBAR_INFO_FIELD 0
+#define ICONBAR_CHOICES_FIELD 1
+#define ICONBAR_QUIT_FIELD 2
+
+
+/*
+ * bBarInfo - Show iconbar information
+ */
+static BOOL
+bBarInfo(event_pollblock *pEvent, void *pvReference)
+{
+ diagram_type *pDiag;
+
+ TRACE_MSG("bBarInfo");
+
+ fail(pEvent == NULL);
+ fail(pEvent->type != event_SEND);
+ fail(pEvent->data.message.header.action != message_MENUWARN);
+ fail(pvReference == NULL);
+
+ pDiag = (diagram_type *)pvReference;
+
+ if (menu_currentopen != pDiag->pSaveMenu ||
+ pEvent->data.message.data.menuwarn.selection[0] != ICONBAR_INFO_FIELD) {
+ return FALSE;
+ }
+
+ Dialog2_OpenDialogMenuLeaf(pEvent, pInfoBox);
+ return TRUE;
+} /* end of bBarInfo */
+
+/*
+ * vBarInfoSetText - Set the iconbar infobox text
+ */
+static void
+vBarInfoSetText(dialog2_block *pBox)
+{
+ TRACE_MSG("vBarInfoSetText");
+
+ fail(pBox == NULL);
+ fail(pBox != pInfoBox);
+
+ Icon_SetText(pBox->window, PURPOSE_INFO_FIELD, PURPOSESTRING);
+ Icon_SetText(pBox->window, AUTHOR_INFO_FIELD, AUTHORSTRING);
+ Icon_SetText(pBox->window, VERSION_INFO_FIELD, VERSIONSTRING);
+ Icon_SetText(pBox->window, STATUS_INFO_FIELD, STATUSSTRING);
+} /* end of vBarInfoSetText */
+
+/*
+ * bMouseButtonClick - respond to mouse button click
+ */
+static BOOL
+bMouseButtonClick(event_pollblock *pEvent, void *pvReference)
+{
+ diagram_type *pDiag;
+ menu_ptr pMenu;
+ int iPosY;
+
+ TRACE_MSG("bMouseButtonClick");
+
+ fail(pEvent == NULL);
+ fail(pEvent->type != event_CLICK);
+ fail(pvReference == NULL);
+
+ pDiag = (diagram_type *)pvReference;
+
+ if (pEvent->data.mouse.button.data.menu) {
+ pMenu = pDiag->pSaveMenu;
+ iPosY = (pMenu == tDummyDiagram.pSaveMenu) ?
+ -1 : pEvent->data.mouse.pos.y;
+ Menu_Show(pMenu, pEvent->data.mouse.pos.x, iPosY);
+ return TRUE;
+ }
+ if (pEvent->data.mouse.window == pDiag->tMainWindow &&
+ pEvent->data.mouse.icon == -1) {
+ vMainButtonClick(&pEvent->data.mouse);
+ return TRUE;
+ }
+ if (pEvent->data.mouse.window == pDiag->tScaleWindow &&
+ pEvent->data.mouse.icon >= 0) {
+ vScaleButtonClick(&pEvent->data.mouse, pDiag);
+ return TRUE;
+ }
+ return FALSE;
+} /* end of bMouseButtonClick */
+
+/*
+ * bAutoRedrawWindow - the redraw is handled by the WIMP
+ */
+static BOOL
+bAutoRedrawWindow(event_pollblock *pEvent, void *pvReference)
+{
+ return TRUE;
+} /* end of bAutoRedrawWindow */
+
+static BOOL
+bSaveSelect(event_pollblock *pEvent, void *pvReference)
+{
+ TRACE_MSG("bSaveSelect");
+
+ fail(pEvent == NULL);
+ fail(pEvent->type != event_MENU);
+ fail(pvReference == NULL);
+
+ DBG_DEC(pEvent->data.selection[0]);
+
+ switch (pEvent->data.selection[0]) {
+ case SAVEMENU_SCALEVIEW:
+ return bScaleOpenAction(pEvent, pvReference);
+ case SAVEMENU_SAVEDRAW:
+ return bSaveDrawfile(pEvent, pvReference);
+ case SAVEMENU_SAVETEXT:
+ return bSaveTextfile(pEvent, pvReference);
+ default:
+ DBG_DEC(pEvent->data.selection[0]);
+ return FALSE;
+ }
+} /* end of bSaveSelect */
+
+/*
+ * Create the window for the text from the given file
+ */
+static diagram_type *
+pCreateTextWindow(const char *szFilename)
+{
+ diagram_type *pDiag;
+
+ TRACE_MSG("pCreateTextWindow");
+
+ fail(szFilename == NULL || szFilename[0] == '\0');
+
+ /* Create the diagram */
+ pDiag = pCreateDiagram(szTask+1, szFilename);
+ if (pDiag == NULL) {
+ werr(0, "Sorry, no new diagram object");
+ return NULL;
+ }
+
+ /* Prepare a save menu for this diagram */
+ pDiag->pSaveMenu = Menu_New(szTask+1,
+ ">Scale view,"
+ ">Save (Drawfile) F3,"
+ ">Save (Text only) \213F3");
+ if (pDiag->pSaveMenu == NULL) {
+ werr(1, "Sorry, no Savemenu object");
+ }
+ Menu_Warn(pDiag->pSaveMenu, SAVEMENU_SCALEVIEW,
+ TRUE, bScaleOpenAction, pDiag);
+ Menu_Warn(pDiag->pSaveMenu, SAVEMENU_SAVEDRAW,
+ TRUE, bSaveDrawfile, pDiag);
+ Menu_Warn(pDiag->pSaveMenu, SAVEMENU_SAVETEXT,
+ TRUE, bSaveTextfile, pDiag);
+
+ /* Claim events for the main window */
+ Event_Claim(event_REDRAW, pDiag->tMainWindow, icon_ANY,
+ bRedrawMainWindow, pDiag);
+ Event_Claim(event_CLOSE, pDiag->tMainWindow, icon_ANY,
+ bDestroyDiagram, pDiag);
+ Event_Claim(event_CLICK, pDiag->tMainWindow, icon_ANY,
+ bMouseButtonClick, pDiag);
+ Event_Claim(event_KEY, pDiag->tMainWindow, icon_ANY,
+ bMainKeyPressed, pDiag);
+
+ /* Claim events for the scale window */
+ Event_Claim(event_REDRAW, pDiag->tScaleWindow, icon_ANY,
+ bAutoRedrawWindow, NULL);
+ Event_Claim(event_CLICK, pDiag->tScaleWindow, icon_ANY,
+ bMouseButtonClick, pDiag);
+ Event_Claim(event_KEY, pDiag->tScaleWindow, icon_ANY,
+ bScaleKeyPressed, pDiag);
+
+ /* Set the window title */
+ vSetTitle(pDiag);
+ return pDiag;
+} /* end of pCreateTextWindow */
+
+/*
+ * vProcessFile - process one file
+ */
+static void
+vProcessFile(const char *szFilename, int iFiletype)
+{
+ options_type tOptions;
+ FILE *pFile;
+ diagram_type *pDiag;
+ long lFilesize;
+ int iWordVersion;
+
+ TRACE_MSG("vProcessFile");
+
+ fail(szFilename == NULL || szFilename[0] == '\0');
+
+ DBG_MSG(szFilename);
+
+ pFile = fopen(szFilename, "rb");
+ if (pFile == NULL) {
+ werr(0, "I can't open '%s' for reading", szFilename);
+ return;
+ }
+
+ lFilesize = lGetFilesize(szFilename);
+ if (lFilesize < 0) {
+ (void)fclose(pFile);
+ werr(0, "I can't get the size of '%s'", szFilename);
+ return;
+ }
+
+ iWordVersion = iGuessVersionNumber(pFile, lFilesize);
+ if (iWordVersion < 0 || iWordVersion == 3) {
+ if (bIsRtfFile(pFile)) {
+ werr(0, "%s is not a Word Document."
+ " It is probably a Rich Text Format file",
+ szFilename);
+ } if (bIsWordPerfectFile(pFile)) {
+ werr(0, "%s is not a Word Document."
+ " It is probably a Word Perfect file",
+ szFilename);
+ } else {
+ werr(0, "%s is not a Word Document.", szFilename);
+ }
+ (void)fclose(pFile);
+ return;
+ }
+ /* Reset any reading done during file-testing */
+ rewind(pFile);
+
+ if (iFiletype != FILETYPE_MSWORD) {
+ vGetOptions(&tOptions);
+ if (tOptions.bAutofiletypeAllowed) {
+ vSetFiletype(szFilename, FILETYPE_MSWORD);
+ }
+ }
+
+ pDiag = pCreateTextWindow(szFilename);
+ if (pDiag == NULL) {
+ (void)fclose(pFile);
+ return;
+ }
+
+ (void)bWordDecryptor(pFile, lFilesize, pDiag);
+ Error_CheckFatal(Drawfile_VerifyDiagram(&pDiag->tInfo));
+ vShowDiagram(pDiag);
+ TRACE_MSG("After vShowDiagram");
+
+ TRACE_MSG("before debug print");
+ DBG_HEX(pFile);
+ TRACE_MSG("before fclose");
+ (void)fclose(pFile);
+ TRACE_MSG("after fclose");
+} /* end of vProcessFile */
+
+/*
+ * vSendAck - send an acknowledge
+ */
+static void
+vSendAck(event_pollblock *pEvent)
+{
+ message_block tMessage;
+
+ TRACE_MSG("vSendAck");
+
+ fail(pEvent == NULL);
+ fail(pEvent->type != event_SEND && pEvent->type != event_SENDWANTACK);
+ fail(pEvent->data.message.header.action != message_DATALOAD &&
+ pEvent->data.message.header.action != message_DATAOPEN);
+
+ tMessage.header.action = message_DATALOADACK;
+ tMessage.header.size = sizeof(tMessage);
+ tMessage.header.yourref = pEvent->data.message.header.myref;
+ Error_CheckFatal(Wimp_SendMessage(event_SEND, &tMessage,
+ pEvent->data.message.header.sender, 0));
+} /* end of vSendAck */
+
+static BOOL
+bEventMsgHandler(event_pollblock *pEvent, void *pvReference)
+{
+ TRACE_MSG("bEventMsgHandler");
+
+ fail(pEvent == NULL);
+
+ switch (pEvent->type) {
+ case event_SEND:
+ case event_SENDWANTACK:
+ switch (pEvent->data.message.header.action) {
+ case message_CLOSEDOWN:
+ exit(EXIT_SUCCESS);
+ break;
+ case message_DATALOAD:
+ case message_DATAOPEN:
+ vProcessFile(
+ pEvent->data.message.data.dataload.filename,
+ pEvent->data.message.data.dataload.filetype);
+ vSendAck(pEvent);
+ break;
+ default:
+ DBG_DEC(pEvent->data.message.header.action);
+ break;
+ }
+ return TRUE;
+ default:
+ DBG_DEC(pEvent->type);
+ return FALSE;
+ }
+} /* end of bEventMsgHandler */
+
+/*
+ * bMenuSelect - select from the iconbar menu
+ */
+static BOOL
+bMenuSelect(event_pollblock *pEvent, void *pvReference)
+{
+ TRACE_MSG("bMenuSelect");
+
+ fail(pEvent == NULL);
+ fail(pEvent->type != event_MENU);
+
+ DBG_DEC(pEvent->data.selection[0]);
+
+ switch (pEvent->data.selection[0]) {
+ case ICONBAR_INFO_FIELD:
+ return bBarInfo(pEvent, pvReference);
+ case ICONBAR_CHOICES_FIELD:
+ vChoicesOpenAction(tChoicesWindow);
+ Window_BringToFront(tChoicesWindow);
+ break;
+ case ICONBAR_QUIT_FIELD:
+ TRACE_MSG("before exit");
+ exit(EXIT_SUCCESS);
+ break;
+ default:
+ DBG_DEC(pEvent->data.selection[0]);
+ break;
+ }
+ return TRUE;
+} /* end of bMenuSelect */
+
+/*
+ * bMenuClick - respond to an menu click
+ */
+static BOOL
+bMenuClick(event_pollblock *pEvent, void *pvReference)
+{
+ TRACE_MSG("bMenuClick");
+
+ fail(pEvent == NULL);
+ fail(pEvent->type != event_MENU);
+
+ if (menu_currentopen == tDummyDiagram.pSaveMenu) {
+ return bMenuSelect(pEvent, pvReference);
+ } else if (pvReference == NULL) {
+ return FALSE;
+ }
+ return bSaveSelect(pEvent, pvReference);
+} /* end of bMenuClick */
+
+static void
+vTemplates(void)
+{
+ TRACE_MSG("vTemplates");
+
+ Template_Initialise();
+ Template_LoadFile("Templates");
+
+ tChoicesWindow = Window_Create("Choices", template_TITLEMIN);
+ if (tChoicesWindow == 0) {
+ werr(1, "I can't find the 'Choices' template");
+ }
+
+ /* Claim events for the choices window */
+ Event_Claim(event_REDRAW, tChoicesWindow, icon_ANY,
+ bAutoRedrawWindow, NULL);
+ Event_Claim(event_CLICK, tChoicesWindow, icon_ANY,
+ bChoicesMouseClick, NULL);
+ Event_Claim(event_KEY, tChoicesWindow, icon_ANY,
+ bChoicesKeyPressed, NULL);
+} /* end of vTemplates */
+
+static void
+vInitialise(void)
+{
+ int aiMessages[] = {0};
+ icon_handle tBarIcon;
+
+
+ TRACE_MSG("vInitialise");
+
+ Resource_Initialise(szTask+1);
+ Event_Initialise3(szTask+1, 310, aiMessages);
+ EventMsg_Initialise();
+ Screen_CacheModeInfo();
+#if defined(__GNUC__)
+ flex_init(szTask+1, 0, 0);
+ flex_set_budge(1);
+#endif /* __GNUC__ */
+ vTemplates();
+
+ /* Prepare iconbar menu */
+ tDummyDiagram.tInfo.data = NULL;
+ tDummyDiagram.tInfo.length = 0;
+ tDummyDiagram.pSaveMenu = Menu_New(szTask+1, ">Info,Choices...,Quit");
+ if (tDummyDiagram.pSaveMenu == NULL) {
+ werr(1, "Sorry, no Barmenu object");
+ }
+ pInfoBox = Dialog2_CreateDialogBlock("ProgInfo", -1, -1,
+ vBarInfoSetText, NULL, NULL);
+
+ if (pInfoBox == NULL) {
+ werr(1, "Sorry, no Infobox object");
+ }
+ Menu_Warn(tDummyDiagram.pSaveMenu, ICONBAR_INFO_FIELD,
+ TRUE, bBarInfo, &tDummyDiagram);
+
+ /* Create an icon on the icon bar */
+ tBarIcon = Icon_BarIcon(szTask, iconbar_RIGHT);
+ Event_Claim(event_CLICK, window_ICONBAR, tBarIcon,
+ bMouseButtonClick, &tDummyDiagram);
+
+ /* Generic claims */
+ Event_Claim(event_OPEN, window_ANY, icon_ANY,
+ Handler_OpenWindow, NULL);
+ Event_Claim(event_CLOSE, window_ANY, icon_ANY,
+ Handler_CloseWindow, NULL);
+ Event_Claim(event_MENU, window_ANY, icon_ANY,
+ bMenuClick, NULL);
+ EventMsg_Claim(message_DATALOAD, window_ICONBAR,
+ bEventMsgHandler, NULL);
+ EventMsg_Claim(message_MODECHANGE, window_ANY,
+ Handler_ModeChange, NULL);
+} /* end of vInitialise */
+
+int
+main(int argc, char **argv)
+{
+ int iFirst, iFiletype;
+
+ TRACE_MSG("main");
+
+ vInitialise();
+ iFirst = iReadOptions(argc, argv);
+ if (iFirst != 1) {
+ return EXIT_FAILURE;
+ }
+
+ if (argc > 1) {
+ iFiletype = iGetFiletype(argv[1]);
+ if (iFiletype < 0) {
+ return EXIT_FAILURE;
+ }
+ vProcessFile(argv[1], iFiletype);
+ TRACE_MSG("main after vProcessFile");
+ }
+
+ for (;;) {
+ Event_Poll();
+ }
+} /* end of main */
diff --git a/sys/src/cmd/aux/antiword/main_u.c b/sys/src/cmd/aux/antiword/main_u.c
new file mode 100755
index 000000000..4eaaea317
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/main_u.c
@@ -0,0 +1,321 @@
+/*
+ * main_u.c
+ *
+ * Released under GPL
+ *
+ * Copyright (C) 1998-2004 A.J. van Os
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Description:
+ * The main program of 'antiword' (Unix version)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#if defined(__dos)
+#include <fcntl.h>
+#include <io.h>
+#endif /* __dos */
+#if defined(__CYGWIN__) || defined(__CYGMING__)
+# ifdef X_LOCALE
+# include <X11/Xlocale.h>
+# else
+# include <locale.h>
+# endif
+#else
+#include <locale.h>
+#endif /* __CYGWIN__ || __CYGMING__ */
+#if defined(N_PLAT_NLM)
+#if !defined(_VA_LIST)
+#include "NW-only/nw_os.h"
+#endif /* !_VA_LIST */
+#include "getopt.h"
+#endif /* N_PLAT_NLM */
+#include "version.h"
+#include "antiword.h"
+
+/* The name of this program */
+static const char *szTask = NULL;
+
+
+static void
+vUsage(void)
+{
+ fprintf(stderr, "\tName: %s\n", szTask);
+ fprintf(stderr, "\tPurpose: "PURPOSESTRING"\n");
+ fprintf(stderr, "\tAuthor: "AUTHORSTRING"\n");
+ fprintf(stderr, "\tVersion: "VERSIONSTRING);
+#if defined(__dos)
+ fprintf(stderr, VERSIONSTRING2);
+#endif /* __dos */
+ fprintf(stderr, "\n");
+ fprintf(stderr, "\tStatus: "STATUSSTRING"\n");
+ fprintf(stderr,
+ "\tUsage: %s [switches] wordfile1 [wordfile2 ...]\n", szTask);
+ fprintf(stderr,
+ "\tSwitches: [-f|-t|-a papersize|-p papersize|-x dtd]"
+ "[-m mapping][-w #][-i #][-Ls]\n");
+ fprintf(stderr, "\t\t-f formatted text output\n");
+ fprintf(stderr, "\t\t-t text output (default)\n");
+ fprintf(stderr, "\t\t-a <paper size name> Adobe PDF output\n");
+ fprintf(stderr, "\t\t-p <paper size name> PostScript output\n");
+ fprintf(stderr, "\t\t paper size like: a4, letter or legal\n");
+ fprintf(stderr, "\t\t-x <dtd> XML output\n");
+ fprintf(stderr, "\t\t like: db (DocBook)\n");
+ fprintf(stderr, "\t\t-m <mapping> character mapping file\n");
+ fprintf(stderr, "\t\t-w <width> in characters of text output\n");
+ fprintf(stderr, "\t\t-i <level> image level (PostScript only)\n");
+ fprintf(stderr, "\t\t-L use landscape mode (PostScript only)\n");
+ fprintf(stderr, "\t\t-r Show removed text\n");
+ fprintf(stderr, "\t\t-s Show hidden (by Word) text\n");
+} /* end of vUsage */
+
+/*
+ * pStdin2TmpFile - save stdin in a temporary file
+ *
+ * returns: the pointer to the temporary file or NULL
+ */
+static FILE *
+pStdin2TmpFile(long *lFilesize)
+{
+ FILE *pTmpFile;
+ size_t tSize;
+ BOOL bFailure;
+ UCHAR aucBytes[BUFSIZ];
+
+ DBG_MSG("pStdin2TmpFile");
+
+ fail(lFilesize == NULL);
+
+ /* Open the temporary file */
+ pTmpFile = tmpfile();
+ if (pTmpFile == NULL) {
+ return NULL;
+ }
+
+#if defined(__dos)
+ /* Stdin must be read as a binary stream */
+ setmode(fileno(stdin), O_BINARY);
+#endif /* __dos */
+
+ /* Copy stdin to the temporary file */
+ *lFilesize = 0;
+ bFailure = TRUE;
+ for (;;) {
+ tSize = fread(aucBytes, 1, sizeof(aucBytes), stdin);
+ if (tSize == 0) {
+ bFailure = feof(stdin) == 0;
+ break;
+ }
+ if (fwrite(aucBytes, 1, tSize, pTmpFile) != tSize) {
+ bFailure = TRUE;
+ break;
+ }
+ *lFilesize += (long)tSize;
+ }
+
+#if defined(__dos)
+ /* Switch stdin back to a text stream */
+ setmode(fileno(stdin), O_TEXT);
+#endif /* __dos */
+
+ /* Deal with the result of the copy action */
+ if (bFailure) {
+ *lFilesize = 0;
+ (void)fclose(pTmpFile);
+ return NULL;
+ }
+ rewind(pTmpFile);
+ return pTmpFile;
+} /* end of pStdin2TmpFile */
+
+/*
+ * bProcessFile - process a single file
+ *
+ * returns: TRUE when the given file is a supported Word file, otherwise FALSE
+ */
+static BOOL
+bProcessFile(const char *szFilename)
+{
+ FILE *pFile;
+ diagram_type *pDiag;
+ long lFilesize;
+ int iWordVersion;
+ BOOL bResult;
+
+ fail(szFilename == NULL || szFilename[0] == '\0');
+
+ DBG_MSG(szFilename);
+
+ if (szFilename[0] == '-' && szFilename[1] == '\0') {
+ pFile = pStdin2TmpFile(&lFilesize);
+ if (pFile == NULL) {
+ werr(0, "I can't save the standard input to a file");
+ return FALSE;
+ }
+ } else {
+ pFile = fopen(szFilename, "rb");
+ if (pFile == NULL) {
+ werr(0, "I can't open '%s' for reading", szFilename);
+ return FALSE;
+ }
+
+ lFilesize = lGetFilesize(szFilename);
+ if (lFilesize < 0) {
+ (void)fclose(pFile);
+ werr(0, "I can't get the size of '%s'", szFilename);
+ return FALSE;
+ }
+ }
+
+ iWordVersion = iGuessVersionNumber(pFile, lFilesize);
+ if (iWordVersion < 0 || iWordVersion == 3) {
+ if (bIsRtfFile(pFile)) {
+ werr(0, "%s is not a Word Document."
+ " It is probably a Rich Text Format file",
+ szFilename);
+ } if (bIsWordPerfectFile(pFile)) {
+ werr(0, "%s is not a Word Document."
+ " It is probably a Word Perfect file",
+ szFilename);
+ } else {
+#if defined(__dos)
+ werr(0, "%s is not a Word Document or the filename"
+ " is not in the 8+3 format.", szFilename);
+#else
+ werr(0, "%s is not a Word Document.", szFilename);
+#endif /* __dos */
+ }
+ (void)fclose(pFile);
+ return FALSE;
+ }
+ /* Reset any reading done during file testing */
+ rewind(pFile);
+
+ pDiag = pCreateDiagram(szTask, szFilename);
+ if (pDiag == NULL) {
+ (void)fclose(pFile);
+ return FALSE;
+ }
+
+ bResult = bWordDecryptor(pFile, lFilesize, pDiag);
+ vDestroyDiagram(pDiag);
+
+ (void)fclose(pFile);
+ return bResult;
+} /* end of bProcessFile */
+
+int
+main(int argc, char **argv)
+{
+ options_type tOptions;
+ const char *szWordfile;
+ int iFirst, iIndex, iGoodCount;
+ BOOL bUsage, bMultiple, bUseTXT, bUseXML;
+
+ if (argc <= 0) {
+ return EXIT_FAILURE;
+ }
+
+ szTask = szBasename(argv[0]);
+
+ if (argc <= 1) {
+ iFirst = 1;
+ bUsage = TRUE;
+ } else {
+ iFirst = iReadOptions(argc, argv);
+ bUsage = iFirst <= 0;
+ }
+ if (bUsage) {
+ vUsage();
+ return iFirst < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+ }
+
+#if defined(N_PLAT_NLM) && !defined(_VA_LIST)
+ nwinit();
+#endif /* N_PLAT_NLM && !_VA_LIST */
+
+ vGetOptions(&tOptions);
+
+#if !defined(__dos)
+ if (is_locale_utf8()) {
+#if defined(__STDC_ISO_10646__)
+ /*
+ * If the user wants UTF-8 and the envirionment variables
+ * support UTF-8, than set the locale accordingly
+ */
+ if (tOptions.eEncoding == encoding_utf_8) {
+ if (setlocale(LC_CTYPE, "") == NULL) {
+ werr(1, "Can't set the UTF-8 locale! "
+ "Check LANG, LC_CTYPE, LC_ALL.");
+ }
+ DBG_MSG("The UTF-8 locale has been set");
+ } else {
+ (void)setlocale(LC_CTYPE, "C");
+ }
+#endif /* __STDC_ISO_10646__ */
+ } else {
+ if (setlocale(LC_CTYPE, "") == NULL) {
+ werr(0, "Can't set the locale! Will use defaults");
+ (void)setlocale(LC_CTYPE, "C");
+ }
+ DBG_MSG("The locale has been set");
+ }
+#endif /* !__dos */
+
+ bMultiple = argc - iFirst > 1;
+ bUseTXT = tOptions.eConversionType == conversion_text ||
+ tOptions.eConversionType == conversion_fmt_text;
+ bUseXML = tOptions.eConversionType == conversion_xml;
+ iGoodCount = 0;
+
+#if defined(__dos)
+ if (tOptions.eConversionType == conversion_pdf) {
+ /* PDF must be written as a binary stream */
+ setmode(fileno(stdout), O_BINARY);
+ }
+#endif /* __dos */
+
+ if (bUseXML) {
+ fprintf(stdout,
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<!DOCTYPE %s PUBLIC \"-//OASIS//DTD DocBook XML V4.1.2//EN\"\n"
+ "\t\"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd\">\n",
+ bMultiple ? "set" : "book");
+ if (bMultiple) {
+ fprintf(stdout, "<set>\n");
+ }
+ }
+
+ for (iIndex = iFirst; iIndex < argc; iIndex++) {
+ if (bMultiple && bUseTXT) {
+ szWordfile = szBasename(argv[iIndex]);
+ fprintf(stdout, "::::::::::::::\n");
+ fprintf(stdout, "%s\n", szWordfile);
+ fprintf(stdout, "::::::::::::::\n");
+ }
+ if (bProcessFile(argv[iIndex])) {
+ iGoodCount++;
+ }
+ }
+
+ if (bMultiple && bUseXML) {
+ fprintf(stdout, "</set>\n");
+ }
+
+ DBG_DEC(iGoodCount);
+ return iGoodCount <= 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+} /* end of main */
diff --git a/sys/src/cmd/aux/antiword/misc.c b/sys/src/cmd/aux/antiword/misc.c
new file mode 100755
index 000000000..609a2f02f
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/misc.c
@@ -0,0 +1,894 @@
+/*
+ * misc.c
+ * Copyright (C) 1998-2005 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Miscellaneous functions
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#if defined(__riscos)
+#include "DeskLib:SWI.h"
+#else
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif /* __riscos */
+#if !defined(S_ISREG)
+#define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
+#endif /* !S_ISREG */
+#include "antiword.h"
+#if defined(__vms)
+#include <unixlib.h>
+#endif
+
+#if !defined(__riscos)
+/*
+ * szGetHomeDirectory - get the name of the home directory
+ */
+const char *
+szGetHomeDirectory(void)
+{
+ const char *szHome;
+
+#if defined(__vms)
+ szHome = decc$translate_vms(getenv("HOME"));
+#elif defined(__Plan9__)
+ szHome = getenv("home");
+#else
+ szHome = getenv("HOME");
+#endif /* __vms */
+
+ if (szHome == NULL || szHome[0] == '\0') {
+#if defined(N_PLAT_NLM)
+ szHome = "SYS:";
+#elif defined(__dos)
+ szHome = "C:";
+#else
+ werr(0, "I can't find the name of your HOME directory");
+ szHome = "";
+#endif /* __dos */
+ }
+ return szHome;
+} /* end of szGetHomeDirectory */
+
+/*
+ * szGetAntiwordDirectory - get the name of the Antiword directory
+ */
+const char *
+szGetAntiwordDirectory(void)
+{
+#if defined(__vms)
+ return decc$translate_vms(getenv("ANTIWORDHOME"));
+#else
+ return getenv("ANTIWORDHOME");
+#endif /* __vms */
+} /* end of szGetAntiwordDirectory */
+#endif /* !__riscos */
+
+/*
+ * Get the size of the specified file.
+ * Returns -1 if the file does not exist or is not a proper file.
+ */
+long
+lGetFilesize(const char *szFilename)
+{
+#if defined(__riscos)
+ os_error *e;
+ int iType, iSize;
+
+ e = SWI(2, 5, SWI_OS_File | XOS_Bit,
+ 17, szFilename,
+ &iType, NULL, NULL, NULL, &iSize);
+ if (e != NULL) {
+ werr(0, "Get Filesize error %d: %s",
+ e->errnum, e->errmess);
+ return -1;
+ }
+ if (iType != 1) {
+ /* It's not a proper file or the file does not exist */
+ return -1;
+ }
+ return (long)iSize;
+#else
+ struct stat tBuffer;
+
+ errno = 0;
+ if (stat(szFilename, &tBuffer) != 0) {
+ werr(0, "Get Filesize error %d", errno);
+ return -1;
+ }
+ if (!S_ISREG(tBuffer.st_mode)) {
+ /* It's not a regular file */
+ return -1;
+ }
+ return (long)tBuffer.st_size;
+#endif /* __riscos */
+} /* end of lGetFilesize */
+
+#if defined(DEBUG)
+void
+vPrintBlock(const char *szFile, int iLine,
+ const UCHAR *aucBlock, size_t tLength)
+{
+ int i, j;
+
+ fail(szFile == NULL || iLine < 0 || aucBlock == NULL);
+
+ fprintf(stderr, "%s[%3d]:\n", szFile, iLine);
+ for (i = 0; i < 32; i++) {
+ if (16 * i >= (int)tLength) {
+ return;
+ }
+ fprintf(stderr, "%03x: ", (unsigned int)(16 * i));
+ for (j = 0; j < 16; j++) {
+ if (16 * i + j < (int)tLength) {
+ fprintf(stderr, "%02x ",
+ (unsigned int)aucBlock[16 * i + j]);
+ }
+ }
+ fprintf(stderr, "\n");
+ }
+} /* end of vPrintBlock */
+
+void
+vPrintUnicode(const char *szFile, int iLine, const UCHAR *aucUni, size_t tLen)
+{
+ char *szASCII;
+
+ fail(tLen % 2 != 0);
+
+ tLen /= 2; /* Length in bytes to length in characters */
+ szASCII = xmalloc(tLen + 1);
+ (void)unincpy(szASCII, aucUni, tLen);
+ szASCII[tLen] = '\0';
+ (void)fprintf(stderr, "%s[%3d]: %.*s\n",
+ szFile, iLine, (int)tLen, szASCII);
+ szASCII = xfree(szASCII);
+} /* end of vPrintUnicode */
+
+BOOL
+bCheckDoubleLinkedList(output_type *pAnchor)
+{
+ output_type *pCurr, *pLast;
+ int iInList;
+
+ pLast = pAnchor;
+ iInList = 0;
+ for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
+ pLast = pCurr;
+ iInList++;
+ }
+ NO_DBG_DEC(iInList);
+ for (pCurr = pLast; pCurr != NULL; pCurr = pCurr->pPrev) {
+ pLast = pCurr;
+ iInList--;
+ }
+ DBG_DEC_C(iInList != 0, iInList);
+ return pAnchor == pLast && iInList == 0;
+} /* end of bCheckDoubleLinkedList */
+#endif /* DEBUG */
+
+/*
+ * bReadBytes
+ * This function reads the specified number of bytes from the specified file,
+ * starting from the specified offset.
+ * Returns TRUE when successfull, otherwise FALSE
+ */
+BOOL
+bReadBytes(UCHAR *aucBytes, size_t tMemb, ULONG ulOffset, FILE *pFile)
+{
+ fail(aucBytes == NULL || pFile == NULL || ulOffset > (ULONG)LONG_MAX);
+
+ if (ulOffset > (ULONG)LONG_MAX) {
+ return FALSE;
+ }
+ if (fseek(pFile, (long)ulOffset, SEEK_SET) != 0) {
+ return FALSE;
+ }
+ if (fread(aucBytes, sizeof(UCHAR), tMemb, pFile) != tMemb) {
+ return FALSE;
+ }
+ return TRUE;
+} /* end of bReadBytes */
+
+/*
+ * bReadBuffer
+ * This function fills the specified buffer with the specified number of bytes,
+ * starting at the specified offset within the Big/Small Block Depot.
+ *
+ * Returns TRUE when successful, otherwise FALSE
+ */
+BOOL
+bReadBuffer(FILE *pFile, ULONG ulStartBlock,
+ const ULONG *aulBlockDepot, size_t tBlockDepotLen, size_t tBlockSize,
+ UCHAR *aucBuffer, ULONG ulOffset, size_t tToRead)
+{
+ ULONG ulBegin, ulIndex;
+ size_t tLen;
+
+ fail(pFile == NULL);
+ fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
+ fail(aulBlockDepot == NULL);
+ fail(tBlockSize != BIG_BLOCK_SIZE && tBlockSize != SMALL_BLOCK_SIZE);
+ fail(aucBuffer == NULL);
+ fail(tToRead == 0);
+
+ for (ulIndex = ulStartBlock;
+ ulIndex != END_OF_CHAIN && tToRead != 0;
+ ulIndex = aulBlockDepot[ulIndex]) {
+ if (ulIndex >= (ULONG)tBlockDepotLen) {
+ DBG_DEC(ulIndex);
+ DBG_DEC(tBlockDepotLen);
+ if (tBlockSize >= BIG_BLOCK_SIZE) {
+ werr(1, "The Big Block Depot is damaged");
+ } else {
+ werr(1, "The Small Block Depot is damaged");
+ }
+ }
+ if (ulOffset >= (ULONG)tBlockSize) {
+ ulOffset -= tBlockSize;
+ continue;
+ }
+ ulBegin = ulDepotOffset(ulIndex, tBlockSize) + ulOffset;
+ tLen = min(tBlockSize - (size_t)ulOffset, tToRead);
+ ulOffset = 0;
+ if (!bReadBytes(aucBuffer, tLen, ulBegin, pFile)) {
+ werr(0, "Read big block 0x%lx not possible", ulBegin);
+ return FALSE;
+ }
+ aucBuffer += tLen;
+ tToRead -= tLen;
+ }
+ DBG_DEC_C(tToRead != 0, tToRead);
+ return tToRead == 0;
+} /* end of bReadBuffer */
+
+/*
+ * Convert a Word colornumber into a true color for use in a drawfile
+ *
+ * Returns the true color
+ */
+ULONG
+ulColor2Color(UCHAR ucFontColor)
+{
+ static const ULONG aulColorTable[] = {
+ /* 0 */ 0x00000000UL, /* Automatic */
+ /* 1 */ 0x00000000UL, /* Black */
+ /* 2 */ 0xff000000UL, /* Blue */
+ /* 3 */ 0xffff0000UL, /* Turquoise */
+ /* 4 */ 0x00ff0000UL, /* Bright Green */
+ /* 5 */ 0xff00ff00UL, /* Pink */
+ /* 6 */ 0x0000ff00UL, /* Red */
+ /* 7 */ 0x00ffff00UL, /* Yellow */
+ /* 8 */ 0xffffff00UL, /* White */
+ /* 9 */ 0x80000000UL, /* Dark Blue */
+ /* 10 */ 0x80800000UL, /* Teal */
+ /* 11 */ 0x00800000UL, /* Green */
+ /* 12 */ 0x80008000UL, /* Violet */
+ /* 13 */ 0x00008000UL, /* Dark Red */
+ /* 14 */ 0x00808000UL, /* Dark Yellow */
+ /* 15 */ 0x80808000UL, /* Gray 50% */
+ /* 16 */ 0xc0c0c000UL, /* Gray 25% */
+ };
+ if ((size_t)ucFontColor >= elementsof(aulColorTable)) {
+ return aulColorTable[0];
+ }
+ return aulColorTable[(int)ucFontColor];
+} /* end of ulColor2Color */
+
+/*
+ * iFindSplit - find a place to split the string
+ *
+ * returns the index of the split character or -1 if no split found.
+ */
+static int
+iFindSplit(const char *szString, size_t tStringLen)
+{
+ size_t tSplit;
+
+ if (tStringLen == 0) {
+ return -1;
+ }
+ tSplit = tStringLen - 1;
+ while (tSplit >= 1) {
+ if (szString[tSplit] == ' ' ||
+ (szString[tSplit] == '-' && szString[tSplit - 1] != ' ')) {
+ return (int)tSplit;
+ }
+ tSplit--;
+ }
+ return -1;
+} /* end of iFindSplit */
+
+/*
+ * pSplitList - split the specified list in a printable part and a leftover part
+ *
+ * returns the pointer to the leftover part
+ */
+output_type *
+pSplitList(output_type *pAnchor)
+{
+ output_type *pCurr, *pLeftOver;
+ int iIndex;
+
+ fail(pAnchor == NULL);
+
+ for (pCurr = pAnchor; pCurr->pNext != NULL; pCurr = pCurr->pNext)
+ ; /* EMPTY */
+ iIndex = -1;
+ for (; pCurr != NULL; pCurr = pCurr->pPrev) {
+ iIndex = iFindSplit(pCurr->szStorage, pCurr->tNextFree);
+ if (iIndex >= 0) {
+ break;
+ }
+ }
+
+ if (pCurr == NULL || iIndex < 0) {
+ /* No split, no leftover */
+ return NULL;
+ }
+ /* Split over the iIndex-th character */
+ NO_DBG_MSG("pLeftOver");
+ pLeftOver = xmalloc(sizeof(*pLeftOver));
+ fail(pCurr->tNextFree < (size_t)iIndex);
+ pLeftOver->tStorageSize = pCurr->tNextFree - (size_t)iIndex;
+ pLeftOver->szStorage = xmalloc(pLeftOver->tStorageSize);
+ pLeftOver->tNextFree = pCurr->tNextFree - (size_t)iIndex - 1;
+ (void)strncpy(pLeftOver->szStorage,
+ pCurr->szStorage + iIndex + 1, pLeftOver->tNextFree);
+ pLeftOver->szStorage[pLeftOver->tNextFree] = '\0';
+ NO_DBG_MSG(pLeftOver->szStorage);
+ pLeftOver->ucFontColor = pCurr->ucFontColor;
+ pLeftOver->usFontStyle = pCurr->usFontStyle;
+ pLeftOver->tFontRef = pCurr->tFontRef;
+ pLeftOver->usFontSize = pCurr->usFontSize;
+ pLeftOver->lStringWidth = lComputeStringWidth(
+ pLeftOver->szStorage,
+ pLeftOver->tNextFree,
+ pLeftOver->tFontRef,
+ pLeftOver->usFontSize);
+ pLeftOver->pPrev = NULL;
+ pLeftOver->pNext = pCurr->pNext;
+ if (pLeftOver->pNext != NULL) {
+ pLeftOver->pNext->pPrev = pLeftOver;
+ }
+ fail(!bCheckDoubleLinkedList(pLeftOver));
+
+ NO_DBG_MSG("pAnchor");
+ NO_DBG_HEX(pCurr->szStorage[iIndex]);
+ while (iIndex >= 0 && isspace((int)(UCHAR)pCurr->szStorage[iIndex])) {
+ iIndex--;
+ }
+ pCurr->tNextFree = (size_t)iIndex + 1;
+ pCurr->szStorage[pCurr->tNextFree] = '\0';
+ NO_DBG_MSG(pCurr->szStorage);
+ pCurr->lStringWidth = lComputeStringWidth(
+ pCurr->szStorage,
+ pCurr->tNextFree,
+ pCurr->tFontRef,
+ pCurr->usFontSize);
+ pCurr->pNext = NULL;
+ fail(!bCheckDoubleLinkedList(pAnchor));
+
+ return pLeftOver;
+} /* end of pSplitList */
+
+/*
+ * tNumber2Roman - convert a number to Roman Numerals
+ *
+ * returns the number of characters written
+ */
+size_t
+tNumber2Roman(UINT uiNumber, BOOL bUpperCase, char *szOutput)
+{
+ char *outp, *p, *q;
+ UINT uiNextVal, uiValue;
+
+ fail(szOutput == NULL);
+
+ uiNumber %= 4000; /* Very high numbers can't be represented */
+ if (uiNumber == 0) {
+ szOutput[0] = '\0';
+ return 0;
+ }
+
+ outp = szOutput;
+ p = bUpperCase ? "M\2D\5C\2L\5X\2V\5I" : "m\2d\5c\2l\5x\2v\5i";
+ uiValue = 1000;
+ for (;;) {
+ while (uiNumber >= uiValue) {
+ *outp++ = *p;
+ uiNumber -= uiValue;
+ }
+ if (uiNumber == 0) {
+ *outp = '\0';
+ fail(outp < szOutput);
+ return (size_t)(outp - szOutput);
+ }
+ q = p + 1;
+ uiNextVal = uiValue / (UINT)(UCHAR)*q;
+ if ((int)*q == 2) { /* magic */
+ uiNextVal /= (UINT)(UCHAR)*(q += 2);
+ }
+ if (uiNumber + uiNextVal >= uiValue) {
+ *outp++ = *++q;
+ uiNumber += uiNextVal;
+ } else {
+ p++;
+ uiValue /= (UINT)(UCHAR)(*p++);
+ }
+ }
+} /* end of tNumber2Roman */
+
+/*
+ * iNumber2Alpha - convert a number to alphabetic "numbers"
+ *
+ * returns the number of characters written
+ */
+size_t
+tNumber2Alpha(UINT uiNumber, BOOL bUpperCase, char *szOutput)
+{
+ char *outp;
+ UINT uiTmp;
+
+ fail(szOutput == NULL);
+
+ if (uiNumber == 0) {
+ szOutput[0] = '\0';
+ return 0;
+ }
+
+ outp = szOutput;
+ uiTmp = (UINT)(bUpperCase ? 'A': 'a');
+ if (uiNumber <= 26) {
+ uiNumber -= 1;
+ *outp++ = (char)(uiTmp + uiNumber);
+ } else if (uiNumber <= 26U + 26U*26U) {
+ uiNumber -= 26 + 1;
+ *outp++ = (char)(uiTmp + uiNumber / 26);
+ *outp++ = (char)(uiTmp + uiNumber % 26);
+ } else if (uiNumber <= 26U + 26U*26U + 26U*26U*26U) {
+ uiNumber -= 26 + 26*26 + 1;
+ *outp++ = (char)(uiTmp + uiNumber / (26*26));
+ *outp++ = (char)(uiTmp + uiNumber / 26 % 26);
+ *outp++ = (char)(uiTmp + uiNumber % 26);
+ }
+ *outp = '\0';
+ fail(outp < szOutput);
+ return (size_t)(outp - szOutput);
+} /* end of tNumber2Alpha */
+
+/*
+ * unincpy - copy a counted Unicode string to an single-byte string
+ */
+char *
+unincpy(char *s1, const UCHAR *s2, size_t n)
+{
+ char *pcDest;
+ ULONG ulChar;
+ size_t tLen;
+ USHORT usUni;
+
+ for (pcDest = s1, tLen = 0; tLen < n; pcDest++, tLen++) {
+ usUni = usGetWord(tLen * 2, s2);
+ if (usUni == 0) {
+ break;
+ }
+ ulChar = ulTranslateCharacters(usUni, 0, 8,
+ conversion_unknown, encoding_neutral, FALSE);
+ if (ulChar == IGNORE_CHARACTER) {
+ ulChar = (ULONG)'?';
+ }
+ *pcDest = (char)ulChar;
+ }
+ for (; tLen < n; tLen++) {
+ *pcDest++ = '\0';
+ }
+ return s1;
+} /* end of unincpy */
+
+/*
+ * unilen - calculate the length of a Unicode string
+ *
+ * returns the length in bytes
+ */
+size_t
+unilen(const UCHAR *s)
+{
+ size_t tLen;
+ USHORT usUni;
+
+ tLen = 0;
+ for (;;) {
+ usUni = usGetWord(tLen, s);
+ if (usUni == 0) {
+ return tLen;
+ }
+ tLen += 2;
+ }
+} /* end of unilen */
+
+/*
+ * szBaseName - get the basename of the specified filename
+ */
+const char *
+szBasename(const char *szFilename)
+{
+ const char *szTmp;
+
+ fail(szFilename == NULL);
+
+ if (szFilename == NULL || szFilename[0] == '\0') {
+ return "null";
+ }
+
+ szTmp = strrchr(szFilename, FILE_SEPARATOR[0]);
+ if (szTmp == NULL) {
+ return szFilename;
+ }
+ return ++szTmp;
+} /* end of szBasename */
+
+/*
+ * lComputeLeading - compute the leading
+ *
+ * NOTE: the fontsize is specified in half points
+ *
+ * Returns the leading in drawunits
+ */
+long
+lComputeLeading(USHORT usFontSize)
+{
+ long lLeading;
+
+ lLeading = (long)usFontSize * 500L;
+ if (usFontSize < 18) { /* Small text: 112% */
+ lLeading *= 112;
+ } else if (usFontSize < 28) { /* Normal text: 124% */
+ lLeading *= 124;
+ } else if (usFontSize < 48) { /* Small headlines: 104% */
+ lLeading *= 104;
+ } else { /* Large headlines: 100% */
+ lLeading *= 100;
+ }
+ lLeading = lMilliPoints2DrawUnits(lLeading);
+ lLeading += 50;
+ lLeading /= 100;
+ return lLeading;
+} /* end of lComputeLeading */
+
+/*
+ * Convert a UCS character to an UTF-8 string
+ *
+ * Returns the string length of the result
+ */
+size_t
+tUcs2Utf8(ULONG ulChar, char *szResult, size_t tMaxResultLen)
+{
+ if (szResult == NULL || tMaxResultLen == 0) {
+ return 0;
+ }
+
+ if (ulChar < 0x80 && tMaxResultLen >= 2) {
+ szResult[0] = (char)ulChar;
+ szResult[1] = '\0';
+ return 1;
+ }
+ if (ulChar < 0x800 && tMaxResultLen >= 3) {
+ szResult[0] = (char)(0xc0 | ulChar >> 6);
+ szResult[1] = (char)(0x80 | (ulChar & 0x3f));
+ szResult[2] = '\0';
+ return 2;
+ }
+ if (ulChar < 0x10000 && tMaxResultLen >= 4) {
+ szResult[0] = (char)(0xe0 | ulChar >> 12);
+ szResult[1] = (char)(0x80 | (ulChar >> 6 & 0x3f));
+ szResult[2] = (char)(0x80 | (ulChar & 0x3f));
+ szResult[3] = '\0';
+ return 3;
+ }
+ if (ulChar < 0x200000 && tMaxResultLen >= 5) {
+ szResult[0] = (char)(0xf0 | ulChar >> 18);
+ szResult[1] = (char)(0x80 | (ulChar >> 12 & 0x3f));
+ szResult[2] = (char)(0x80 | (ulChar >> 6 & 0x3f));
+ szResult[3] = (char)(0x80 | (ulChar & 0x3f));
+ szResult[4] = '\0';
+ return 4;
+ }
+ szResult[0] = '\0';
+ return 0;
+} /* end of tUcs2Utf8 */
+
+/*
+ * vGetBulletValue - get the bullet value for the conversing type and encoding
+ */
+void
+vGetBulletValue(conversion_type eConversionType, encoding_type eEncoding,
+ char *szResult, size_t tMaxResultLen)
+{
+ fail(szResult == NULL);
+ fail(tMaxResultLen < 2);
+
+ if (eEncoding == encoding_utf_8) {
+ (void)tUcs2Utf8(UNICODE_BULLET, szResult, tMaxResultLen);
+ } else {
+ szResult[0] = (char)ucGetBulletCharacter(eConversionType,
+ eEncoding);
+ szResult[1] = '\0';
+ }
+} /* end of vGetBulletValue */
+
+/*
+ * bAllZero - are all bytes zero?
+ */
+BOOL
+bAllZero(const UCHAR *aucBytes, size_t tLength)
+{
+ size_t tIndex;
+
+ if (aucBytes == NULL || tLength == 0) {
+ return TRUE;
+ }
+
+ for (tIndex = 0; tIndex < tLength; tIndex++) {
+ if (aucBytes[tIndex] != 0) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+} /* end of bAllZero */
+
+#if !defined(__riscos)
+/*
+ * GetCodesetFromLocale - get the codeset from the current locale
+ *
+ * Original version: Copyright (C) 1999 Bruno Haible
+ * Syntax:
+ * language[_territory][.codeset][@modifier][+special][,[sponsor][_revision]]
+ *
+ * Returns TRUE when sucessful, otherwise FALSE
+ */
+static BOOL
+bGetCodesetFromLocale(char *szCodeset, size_t tMaxCodesetLength, BOOL *pbEuro)
+{
+#if !defined(__dos)
+ const char *szLocale;
+ const char *pcTmp;
+ size_t tIndex;
+ char szModifier[6];
+#endif /* __dos */
+
+ if (pbEuro != NULL) {
+ *pbEuro = FALSE; /* Until proven otherwise */
+ }
+ if (szCodeset == NULL || tMaxCodesetLength == 0) {
+ return FALSE;
+ }
+
+#if defined(__dos)
+ if (tMaxCodesetLength < 2 + sizeof(int) * 3 + 1) {
+ DBG_DEC(tMaxCodesetLength);
+ DBG_DEC(2 + sizeof(int) * 3 + 1);
+ return FALSE;
+ }
+ /* Get the active codepage from DOS */
+ sprintf(szCodeset, "cp%d", iGetCodepage());
+ DBG_MSG(szCodeset);
+#else
+ /* Get the locale from the environment */
+ szLocale = getenv("LC_ALL");
+ if (szLocale == NULL || szLocale[0] == '\0') {
+ szLocale = getenv("LC_CTYPE");
+ if (szLocale == NULL || szLocale[0] == '\0') {
+ szLocale = getenv("LANG");
+ }
+ }
+ if (szLocale == NULL || szLocale[0] == '\0') {
+ /* No locale, so no codeset name and no modifier */
+ return FALSE;
+ }
+ DBG_MSG(szLocale);
+ pcTmp = strchr(szLocale, '.');
+ if (pcTmp == NULL) {
+ /* No codeset name */
+ szCodeset[0] = '\0';
+ } else {
+ /* Copy the codeset name */
+ pcTmp++;
+ for (tIndex = 0; tIndex < tMaxCodesetLength; tIndex++) {
+ if (*pcTmp == '@' || *pcTmp == '+' ||
+ *pcTmp == ',' || *pcTmp == '_' ||
+ *pcTmp == '\0') {
+ szCodeset[tIndex] = '\0';
+ break;
+ }
+ szCodeset[tIndex] = *pcTmp;
+ pcTmp++;
+ }
+ szCodeset[tMaxCodesetLength - 1] = '\0';
+ }
+ if (pbEuro == NULL) {
+ /* No need to get the modifier */
+ return TRUE;
+ }
+ pcTmp = strchr(szLocale, '@');
+ if (pcTmp != NULL) {
+ /* Copy the modifier */
+ pcTmp++;
+ for (tIndex = 0; tIndex < sizeof(szModifier); tIndex++) {
+ if (*pcTmp == '+' || *pcTmp == ',' ||
+ *pcTmp == '_' || *pcTmp == '\0') {
+ szModifier[tIndex] = '\0';
+ break;
+ }
+ szModifier[tIndex] = *pcTmp;
+ pcTmp++;
+ }
+ szModifier[sizeof(szModifier) - 1] = '\0';
+ *pbEuro = STRCEQ(szModifier, "Euro");
+ }
+#endif /* __dos */
+ return TRUE;
+} /* end of bGetCodesetFromLocale */
+
+/*
+ * GetNormalizedCodeset - get the normalized codeset from the current locale
+ *
+ * Returns TRUE when sucessful, otherwise FALSE
+ */
+BOOL
+bGetNormalizedCodeset(char *szCodeset, size_t tMaxCodesetLength, BOOL *pbEuro)
+{
+ BOOL bOnlyDigits;
+ const char *pcSrc;
+ char *pcDest;
+ char *szTmp, *szCodesetNorm;
+
+ if (pbEuro != NULL) {
+ *pbEuro = FALSE; /* Until proven otherwise */
+ }
+ if (szCodeset == NULL || tMaxCodesetLength < 4) {
+ return FALSE;
+ }
+
+ /* Get the codeset name */
+ szTmp = xmalloc(tMaxCodesetLength - 3);
+ if (!bGetCodesetFromLocale(szTmp, tMaxCodesetLength - 3, pbEuro)) {
+ szTmp = xfree(szTmp);
+ return FALSE;
+ }
+ /* Normalize the codeset name */
+ szCodesetNorm = xmalloc(tMaxCodesetLength - 3);
+ bOnlyDigits = TRUE;
+ pcDest = szCodesetNorm;
+ for (pcSrc = szTmp; *pcSrc != '\0'; pcSrc++) {
+ if (isalnum(*pcSrc)) {
+ *pcDest = tolower(*pcSrc);
+ if (!isdigit(*pcDest)) {
+ bOnlyDigits = FALSE;
+ }
+ pcDest++;
+ }
+ }
+ *pcDest = '\0';
+ DBG_MSG(szCodesetNorm);
+ /* Add "iso" when szCodesetNorm contains all digits */
+ if (bOnlyDigits && szCodesetNorm[0] != '\0') {
+ fail(strlen(szCodesetNorm) + 3 >= tMaxCodesetLength);
+ sprintf(szCodeset, "iso%s", szCodesetNorm);
+ } else {
+ fail(strlen(szCodesetNorm) >= tMaxCodesetLength);
+ strncpy(szCodeset, szCodesetNorm, pcDest - szCodesetNorm + 1);
+ szCodeset[tMaxCodesetLength - 1] = '\0';
+ }
+ DBG_MSG(szCodeset);
+ /* Clean up and leave */
+ szCodesetNorm = xfree(szCodesetNorm);
+ szTmp = xfree(szTmp);
+ return TRUE;
+} /* end of bGetNormalizedCodeset */
+
+/*
+ * szGetDefaultMappingFile - get the default mapping file
+ *
+ * Returns the basename of the default mapping file
+ */
+const char *
+szGetDefaultMappingFile(void)
+{
+ static const struct {
+ const char *szCodeset;
+ const char *szMappingFile;
+ } atMappingFile[] = {
+ { "iso88591", MAPPING_FILE_8859_1 },
+ { "iso88592", MAPPING_FILE_8859_2 },
+ { "iso88593", "8859-3.txt" },
+ { "iso88594", "8859-4.txt" },
+ { "iso88595", "8859-5.txt" },
+ { "iso88596", MAPPING_FILE_8859_5 },
+ { "iso88597", "8859-7.txt" },
+ { "iso88598", "8859-8.txt" },
+ { "iso88599", "8859-9.txt" },
+ { "iso885910", "8859-10.txt" },
+ { "iso885913", "8859-13.txt" },
+ { "iso885914", "8859-14.txt" },
+ { "iso885915", MAPPING_FILE_8859_15 },
+ { "iso885916", "8859-16.txt" },
+ { "koi8r", MAPPING_FILE_KOI8_R },
+ { "koi8u", MAPPING_FILE_KOI8_U },
+ { "utf8", MAPPING_FILE_UTF_8 },
+ { "cp437", MAPPING_FILE_CP437 },
+ { "cp850", "cp850.txt" },
+ { "cp852", MAPPING_FILE_CP852 },
+ { "cp862", "cp862.txt" },
+ { "cp864", "cp864.txt" },
+ { "cp866", MAPPING_FILE_CP866 },
+ { "cp1250", MAPPING_FILE_CP1250 },
+ { "cp1251", MAPPING_FILE_CP1251 },
+ { "cp1252", "cp1252.txt" },
+ };
+ size_t tIndex;
+ BOOL bEuro;
+ char szCodeset[20];
+
+ szCodeset[0] = '\0';
+ bEuro = FALSE;
+ /* Get the normalized codeset name */
+ if (!bGetNormalizedCodeset(szCodeset, sizeof(szCodeset), &bEuro)) {
+ return MAPPING_FILE_8859_1;
+ }
+ if (szCodeset[0] == '\0') {
+ if (bEuro) {
+ /* Default mapping file (with Euro sign) */
+ return MAPPING_FILE_8859_15;
+ } else {
+ /* Default mapping file (without Euro sign) */
+ return MAPPING_FILE_8859_1;
+ }
+ }
+ /* Find the name in the table */
+ for (tIndex = 0; tIndex < elementsof(atMappingFile); tIndex++) {
+ if (STREQ(atMappingFile[tIndex].szCodeset, szCodeset)) {
+ return atMappingFile[tIndex].szMappingFile;
+ }
+ }
+ /* Default default mapping file */
+#if defined(__dos)
+ return MAPPING_FILE_CP437;
+#else
+ return MAPPING_FILE_8859_1;
+#endif /* __dos */
+} /* end of szGetDefaultMappingFile */
+#endif /* !__riscos */
+
+/*
+ * tConvertDTTM - convert Windows Date and Time format
+ *
+ * returns Unix time_t or -1
+ */
+time_t
+tConvertDTTM(ULONG ulDTTM)
+{
+ struct tm tTime;
+ time_t tResult;
+
+ if (ulDTTM == 0) {
+ return (time_t)-1;
+ }
+ memset(&tTime, 0, sizeof(tTime));
+ tTime.tm_min = (int)(ulDTTM & 0x0000003f);
+ tTime.tm_hour = (int)((ulDTTM & 0x000007c0) >> 6);
+ tTime.tm_mday = (int)((ulDTTM & 0x0000f800) >> 11);
+ tTime.tm_mon = (int)((ulDTTM & 0x000f0000) >> 16);
+ tTime.tm_year = (int)((ulDTTM & 0x1ff00000) >> 20);
+ tTime.tm_isdst = -1;
+ tTime.tm_mon--; /* From 01-12 to 00-11 */
+ tResult = mktime(&tTime);
+ NO_DBG_MSG(ctime(&tResult));
+ return tResult;
+} /* end of tConvertDTTM */
diff --git a/sys/src/cmd/aux/antiword/mkfile b/sys/src/cmd/aux/antiword/mkfile
new file mode 100755
index 000000000..12d1c63b4
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/mkfile
@@ -0,0 +1,29 @@
+</$objtype/mkfile
+
+TARG=antiword
+
+CFLAGS=-Bp -I/sys/include/ape -I/$objtype/include/ape -DNDEBUG -D_POSIX_SOURCE -D__Plan9__
+
+TARG=antiword
+OFILES= main_u.$O asc85enc.$O blocklist.$O chartrans.$O datalist.$O depot.$O\
+ dib2eps.$O doclist.$O fail.$O finddata.$O findtext.$O fmt_text.$O fontlist.$O\
+ fonts.$O fonts_u.$O hdrftrlist.$O imgexam.$O imgtrans.$O jpeg2eps.$O\
+ listlist.$O misc.$O notes.$O options.$O out2window.$O output.$O pdf.$O\
+ pictlist.$O png2eps.$O postscript.$O prop0.$O prop2.$O prop6.$O prop8.$O\
+ properties.$O propmod.$O rowlist.$O sectlist.$O stylelist.$O stylesheet.$O\
+ summary.$O tabstop.$O text.$O unix.$O utf8.$O word2text.$O worddos.$O\
+ wordlib.$O wordmac.$O wordole.$O wordwin.$O xmalloc.$O xml.$O
+
+HFILES=antiword.h debug.h draw.h fail.h fontinfo.h version.h wordconst.h wordtypes.h
+
+BIN=/$objtype/bin/aux
+
+</sys/src/cmd/mkone
+
+main_u.$O: version.h
+postscript.$O: version.h
+pdf.$O: version.h
+fonts_u.$O: fontinfo.h
+
+# fontinfo.h: Unix-fontinfo.pl
+# fontinfo.pl > fontinfo.h
diff --git a/sys/src/cmd/aux/antiword/notes.c b/sys/src/cmd/aux/antiword/notes.c
new file mode 100755
index 000000000..ffc75266a
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/notes.c
@@ -0,0 +1,876 @@
+/*
+ * notes.c
+ * Copyright (C) 1998-2005 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Functions to tell the difference between footnotes and endnotes
+ */
+
+#include "antiword.h"
+
+/*
+ * Private structures to hide the way the information
+ * is stored from the rest of the program
+ */
+typedef struct footnote_local_tag {
+ footnote_block_type tInfo;
+ ULONG ulCharPosStart;
+ ULONG ulCharPosNext;
+ BOOL bUseful;
+} footnote_local_type;
+
+/* Variables needed to write the Footnote and Endnote information */
+static ULONG *aulFootnoteList = NULL;
+static size_t tFootnoteListLength = 0;
+static ULONG *aulEndnoteList = NULL;
+static size_t tEndnoteListLength = 0;
+/* Variables needed to write the Footnote Text */
+static footnote_local_type *pFootnoteText = NULL;
+static size_t tFootnoteTextLength = 0;
+
+
+/*
+ * Destroy the lists with footnote and endnote information
+ */
+void
+vDestroyNotesInfoLists(void)
+{
+ footnote_local_type *pRecord;
+ size_t tFootnote;
+
+ TRACE_MSG("vDestroyNotesInfoLists");
+
+ /* Free the lists and reset all control variables */
+ aulEndnoteList = xfree(aulEndnoteList);
+ aulFootnoteList = xfree(aulFootnoteList);
+ tEndnoteListLength = 0;
+ tFootnoteListLength = 0;
+ for (tFootnote = 0; tFootnote < tFootnoteTextLength; tFootnote++) {
+ pRecord = pFootnoteText + tFootnote;
+ pRecord->tInfo.szText = xfree(pRecord->tInfo.szText);
+ }
+ pFootnoteText = xfree(pFootnoteText);
+ tFootnoteTextLength = 0;
+} /* end of vDestroyNotesInfoLists */
+
+/*
+ * Build the list with footnote information for Word for DOS files
+ */
+static void
+vGet0FootnotesInfoAndText(FILE *pFile, const UCHAR *aucHeader)
+{
+ footnote_local_type *pCurr;
+ UCHAR *aucBuffer;
+ ULONG ulFileOffset, ulBeginOfText, ulOffset, ulBeginFootnoteInfo;
+ ULONG ulCharPos, ulBeginNextBlock;
+ size_t tFootnotes, tFootnoteInfoLen;
+ size_t tIndex;
+ UCHAR aucTmp[2];
+
+ TRACE_MSG("vGet0FootnotesInfoAndText");
+
+ fail(pFile == NULL || aucHeader == NULL);
+
+ ulBeginOfText = 128;
+ NO_DBG_HEX(ulBeginOfText);
+ ulBeginFootnoteInfo = 128 * (ULONG)usGetWord(0x14, aucHeader);
+ DBG_HEX(ulBeginFootnoteInfo);
+ ulBeginNextBlock = 128 * (ULONG)usGetWord(0x16, aucHeader);
+ DBG_HEX(ulBeginNextBlock);
+
+ if (ulBeginFootnoteInfo == ulBeginNextBlock) {
+ DBG_MSG("No Footnotes in this document");
+ return;
+ }
+
+ /* Read the the number of footnotes + 1 */
+ if (!bReadBytes(aucTmp, 2, ulBeginFootnoteInfo, pFile)) {
+ return;
+ }
+ tFootnotes = (size_t)usGetWord(0, aucTmp);
+ if (tFootnotes < 2) {
+ DBG_MSG("No Footnotes in this document (2)");
+ }
+ DBG_DEC(tFootnotes);
+ tFootnoteInfoLen = 8 * tFootnotes;
+
+ aucBuffer = xmalloc(tFootnoteInfoLen);
+ if (!bReadBytes(aucBuffer,
+ tFootnoteInfoLen, ulBeginFootnoteInfo + 4, pFile)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ DBG_PRINT_BLOCK(aucBuffer, tFootnoteInfoLen);
+
+ /* Get footnote information */
+ fail(tFootnoteListLength != 0);
+ tFootnoteListLength = tFootnotes - 1;
+ fail(tFootnoteListLength == 0);
+
+ fail(aulFootnoteList != NULL);
+ aulFootnoteList = xcalloc(tFootnoteListLength, sizeof(ULONG));
+
+ for (tIndex = 0; tIndex < tFootnoteListLength; tIndex++) {
+ ulOffset = ulGetLong(tIndex * 8, aucBuffer);
+ DBG_HEX(ulOffset);
+ ulFileOffset = ulCharPos2FileOffset(ulBeginOfText + ulOffset);
+ DBG_HEX(ulFileOffset);
+ aulFootnoteList[tIndex] = ulFileOffset;
+ }
+
+ /* Get footnote text */
+ fail(tFootnoteTextLength != 0);
+ tFootnoteTextLength = tFootnotes - 1;
+ fail(tFootnoteTextLength == 0);
+
+ fail(pFootnoteText != NULL);
+ pFootnoteText = xcalloc(tFootnoteTextLength,
+ sizeof(footnote_local_type));
+
+ for (tIndex = 0; tIndex < tFootnoteTextLength; tIndex++) {
+ pCurr = pFootnoteText + tIndex;
+ pCurr->tInfo.szText = NULL;
+ ulOffset = ulGetLong(tIndex * 8 + 4, aucBuffer);
+ DBG_HEX(ulOffset);
+ ulCharPos = ulBeginOfText + ulOffset;
+ DBG_HEX(ulCharPos);
+ DBG_HEX(ulCharPos2FileOffset(ulCharPos));
+ pCurr->ulCharPosStart = ulCharPos;
+ ulOffset = ulGetLong((tIndex + 1) * 8 + 4, aucBuffer);
+ DBG_HEX(ulOffset);
+ ulCharPos = ulBeginOfText + ulOffset;
+ DBG_HEX(ulCharPos);
+ DBG_HEX(ulCharPos2FileOffset(ulCharPos));
+ pCurr->ulCharPosNext = ulCharPos;
+ pCurr->bUseful = pCurr->ulCharPosStart != pCurr->ulCharPosNext;
+ }
+ aucBuffer = xfree(aucBuffer);
+} /* end of vGet0FootnotesInfoAndText */
+
+/*
+ * Build the lists note information for Word for DOS files
+ */
+static void
+vGet0NotesInfo(FILE *pFile, const UCHAR *aucHeader)
+{
+ TRACE_MSG("vGet0NotesInfo");
+
+ vGet0FootnotesInfoAndText(pFile, aucHeader);
+ /* There are no endnotes in a Word for DOS file */
+} /* end of vGet0NotesInfo */
+
+/*
+ * Build the list with footnote information for WinWord 1/2 files
+ */
+static void
+vGet2FootnotesInfo(FILE *pFile, const UCHAR *aucHeader)
+{
+ UCHAR *aucBuffer;
+ ULONG ulFileOffset, ulBeginOfText, ulOffset, ulBeginFootnoteInfo;
+ size_t tFootnoteInfoLen;
+ size_t tIndex;
+
+ TRACE_MSG("vGet2FootnotesInfo");
+
+ fail(pFile == NULL || aucHeader == NULL);
+
+ ulBeginOfText = ulGetLong(0x18, aucHeader); /* fcMin */
+ NO_DBG_HEX(ulBeginOfText);
+ ulBeginFootnoteInfo = ulGetLong(0x64, aucHeader); /* fcPlcffndRef */
+ NO_DBG_HEX(ulBeginFootnoteInfo);
+ tFootnoteInfoLen = (size_t)usGetWord(0x68, aucHeader); /* cbPlcffndRef */
+ NO_DBG_DEC(tFootnoteInfoLen);
+
+ if (tFootnoteInfoLen < 10) {
+ DBG_MSG("No Footnotes in this document");
+ return;
+ }
+
+ aucBuffer = xmalloc(tFootnoteInfoLen);
+ if (!bReadBytes(aucBuffer,
+ tFootnoteInfoLen, ulBeginFootnoteInfo, pFile)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tFootnoteInfoLen);
+
+ fail(tFootnoteListLength != 0);
+ tFootnoteListLength = (tFootnoteInfoLen - 4) / 6;
+ fail(tFootnoteListLength == 0);
+
+ fail(aulFootnoteList != NULL);
+ aulFootnoteList = xcalloc(tFootnoteListLength, sizeof(ULONG));
+
+ for (tIndex = 0; tIndex < tFootnoteListLength; tIndex++) {
+ ulOffset = ulGetLong(tIndex * 4, aucBuffer);
+ NO_DBG_HEX(ulOffset);
+ ulFileOffset = ulCharPos2FileOffset(ulBeginOfText + ulOffset);
+ NO_DBG_HEX(ulFileOffset);
+ aulFootnoteList[tIndex] = ulFileOffset;
+ }
+ aucBuffer = xfree(aucBuffer);
+} /* end of vGet2FootnotesInfo */
+
+/*
+ * Build the list with footnote text information for WinWord 1/2 files
+ */
+static void
+vGet2FootnotesText(FILE *pFile, const UCHAR *aucHeader)
+{
+ footnote_local_type *pCurr;
+ UCHAR *aucBuffer;
+ ULONG ulCharPos, ulBeginOfFootnotes, ulOffset, ulBeginFootnoteText;
+ size_t tFootnoteTextLen;
+ size_t tIndex;
+
+ TRACE_MSG("vGet2FootnotesText");
+
+ fail(pFile == NULL || aucHeader == NULL);
+
+ ulBeginOfFootnotes = ulGetLong(0x18, aucHeader); /* fcMin */
+ ulBeginOfFootnotes += ulGetLong(0x34, aucHeader); /* ccpText */
+ NO_DBG_HEX(ulBeginOfFootnotes);
+
+ ulBeginFootnoteText = ulGetLong(0x6a, aucHeader); /* fcPlcffndTxt */
+ NO_DBG_HEX(ulBeginFootnoteText);
+ tFootnoteTextLen =
+ (size_t)usGetWord(0x6e, aucHeader); /* cbPlcffndTxt */
+ NO_DBG_DEC(tFootnoteTextLen);
+
+ if (tFootnoteTextLen < 12) {
+ DBG_MSG("No Footnote text in this document");
+ return;
+ }
+
+ aucBuffer = xmalloc(tFootnoteTextLen);
+ if (!bReadBytes(aucBuffer,
+ tFootnoteTextLen, ulBeginFootnoteText, pFile)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tFootnoteTextLen);
+
+ fail(tFootnoteTextLength != 0);
+ tFootnoteTextLength = tFootnoteTextLen / 4 - 2;
+ fail(tFootnoteTextLength == 0);
+
+ fail(pFootnoteText != NULL);
+ pFootnoteText = xcalloc(tFootnoteTextLength,
+ sizeof(footnote_local_type));
+
+ for (tIndex = 0; tIndex < tFootnoteTextLength; tIndex++) {
+ pCurr = pFootnoteText + tIndex;
+ pCurr->tInfo.szText = NULL;
+ ulOffset = ulGetLong(tIndex * 4, aucBuffer);
+ NO_DBG_HEX(ulOffset);
+ ulCharPos = ulBeginOfFootnotes + ulOffset;
+ NO_DBG_HEX(ulCharPos);
+ NO_DBG_HEX(ulCharPos2FileOffset(ulCharPos));
+ pCurr->ulCharPosStart = ulCharPos;
+ ulOffset = ulGetLong(tIndex * 4 + 4, aucBuffer);
+ NO_DBG_HEX(ulOffset);
+ ulCharPos = ulBeginOfFootnotes + ulOffset;
+ NO_DBG_HEX(ulCharPos);
+ NO_DBG_HEX(ulCharPos2FileOffset(ulCharPos));
+ pCurr->ulCharPosNext = ulCharPos;
+ pCurr->bUseful = pCurr->ulCharPosStart != pCurr->ulCharPosNext;
+ }
+ aucBuffer = xfree(aucBuffer);
+} /* end of vGet2FootnotesText */
+
+/*
+ * Build the lists note information for WinWord 1/2 files
+ */
+static void
+vGet2NotesInfo(FILE *pFile, const UCHAR *aucHeader)
+{
+ TRACE_MSG("vGet2NotesInfo");
+
+ vGet2FootnotesInfo(pFile, aucHeader);
+ vGet2FootnotesText(pFile, aucHeader);
+ /* There are no endnotes in a WinWord 1/2 file */
+} /* end of vGet2NotesInfo */
+
+/*
+ * Build the list with footnote information for Word 6/7 files
+ */
+static void
+vGet6FootnotesInfo(FILE *pFile, ULONG ulStartBlock,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const UCHAR *aucHeader)
+{
+ UCHAR *aucBuffer;
+ ULONG ulFileOffset, ulBeginOfText, ulOffset, ulBeginFootnoteInfo;
+ size_t tFootnoteInfoLen;
+ size_t tIndex;
+
+ TRACE_MSG("vGet6FootnotesInfo");
+
+ fail(pFile == NULL || aucHeader == NULL);
+ fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
+ fail(aulBBD == NULL);
+
+ ulBeginOfText = ulGetLong(0x18, aucHeader); /* fcMin */
+ NO_DBG_HEX(ulBeginOfText);
+ ulBeginFootnoteInfo = ulGetLong(0x68, aucHeader); /* fcPlcffndRef */
+ NO_DBG_HEX(ulBeginFootnoteInfo);
+ tFootnoteInfoLen =
+ (size_t)ulGetLong(0x6c, aucHeader); /* lcbPlcffndRef */
+ NO_DBG_DEC(tFootnoteInfoLen);
+
+ if (tFootnoteInfoLen < 10) {
+ DBG_MSG("No Footnotes in this document");
+ return;
+ }
+
+ aucBuffer = xmalloc(tFootnoteInfoLen);
+ if (!bReadBuffer(pFile, ulStartBlock,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucBuffer, ulBeginFootnoteInfo, tFootnoteInfoLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tFootnoteInfoLen);
+
+ fail(tFootnoteListLength != 0);
+ tFootnoteListLength = (tFootnoteInfoLen - 4) / 6;
+ fail(tFootnoteListLength == 0);
+
+ fail(aulFootnoteList != NULL);
+ aulFootnoteList = xcalloc(tFootnoteListLength, sizeof(ULONG));
+
+ for (tIndex = 0; tIndex < tFootnoteListLength; tIndex++) {
+ ulOffset = ulGetLong(tIndex * 4, aucBuffer);
+ NO_DBG_HEX(ulOffset);
+ ulFileOffset = ulCharPos2FileOffset(ulBeginOfText + ulOffset);
+ NO_DBG_HEX(ulFileOffset);
+ aulFootnoteList[tIndex] = ulFileOffset;
+ }
+ aucBuffer = xfree(aucBuffer);
+} /* end of vGet6FootnotesInfo */
+
+/*
+ * Build the list with footnote text information for Word 6/7 files
+ */
+static void
+vGet6FootnotesText(FILE *pFile, ULONG ulStartBlock,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const UCHAR *aucHeader)
+{
+ footnote_local_type *pCurr;
+ UCHAR *aucBuffer;
+ ULONG ulCharPos, ulBeginOfFootnotes, ulOffset, ulBeginFootnoteText;
+ size_t tFootnoteTextLen;
+ size_t tIndex;
+
+ TRACE_MSG("vGet6FootnotesText");
+
+ fail(pFile == NULL || aucHeader == NULL);
+ fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
+ fail(aulBBD == NULL);
+
+ ulBeginOfFootnotes = ulGetLong(0x18, aucHeader); /* fcMin */
+ ulBeginOfFootnotes += ulGetLong(0x34, aucHeader); /* ccpText */
+ NO_DBG_HEX(ulBeginOfFootnotes);
+
+ ulBeginFootnoteText = ulGetLong(0x70, aucHeader); /* fcPlcffndTxt */
+ NO_DBG_HEX(ulBeginFootnoteText);
+ tFootnoteTextLen =
+ (size_t)ulGetLong(0x74, aucHeader); /* lcbPlcffndTxt */
+ NO_DBG_DEC(tFootnoteTextLen);
+
+ if (tFootnoteTextLen < 12) {
+ DBG_MSG("No Footnote text in this document");
+ return;
+ }
+
+ aucBuffer = xmalloc(tFootnoteTextLen);
+ if (!bReadBuffer(pFile, ulStartBlock,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucBuffer, ulBeginFootnoteText, tFootnoteTextLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tFootnoteTextLen);
+
+ fail(tFootnoteTextLength != 0);
+ tFootnoteTextLength = tFootnoteTextLen / 4 - 2;
+ fail(tFootnoteTextLength == 0);
+
+ fail(pFootnoteText != NULL);
+ pFootnoteText = xcalloc(tFootnoteTextLength,
+ sizeof(footnote_local_type));
+
+ for (tIndex = 0; tIndex < tFootnoteTextLength; tIndex++) {
+ pCurr = pFootnoteText + tIndex;
+ pCurr->tInfo.szText = NULL;
+ ulOffset = ulGetLong(tIndex * 4, aucBuffer);
+ NO_DBG_HEX(ulOffset);
+ ulCharPos = ulBeginOfFootnotes + ulOffset;
+ NO_DBG_HEX(ulCharPos);
+ NO_DBG_HEX(ulCharPos2FileOffset(ulCharPos));
+ pCurr->ulCharPosStart = ulCharPos;
+ ulOffset = ulGetLong(tIndex * 4 + 4, aucBuffer);
+ NO_DBG_HEX(ulOffset);
+ ulCharPos = ulBeginOfFootnotes + ulOffset;
+ NO_DBG_HEX(ulCharPos);
+ NO_DBG_HEX(ulCharPos2FileOffset(ulCharPos));
+ pCurr->ulCharPosNext = ulCharPos;
+ pCurr->bUseful = pCurr->ulCharPosStart != pCurr->ulCharPosNext;
+ }
+ aucBuffer = xfree(aucBuffer);
+} /* end of vGet6FootnotesText */
+
+/*
+ * Build the list with endnote information for Word 6/7 files
+ */
+static void
+vGet6EndnotesInfo(FILE *pFile, ULONG ulStartBlock,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const UCHAR *aucHeader)
+{
+ UCHAR *aucBuffer;
+ ULONG ulFileOffset, ulBeginOfText, ulOffset, ulBeginEndnoteInfo;
+ size_t tEndnoteInfoLen;
+ size_t tIndex;
+
+ TRACE_MSG("vGet6EndnotesInfo");
+
+ fail(pFile == NULL || aucHeader == NULL);
+ fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
+ fail(aulBBD == NULL);
+
+ ulBeginOfText = ulGetLong(0x18, aucHeader); /* fcMin */
+ NO_DBG_HEX(ulBeginOfText);
+ ulBeginEndnoteInfo = ulGetLong(0x1d2, aucHeader); /* fcPlcfendRef */
+ NO_DBG_HEX(ulBeginEndnoteInfo);
+ tEndnoteInfoLen =
+ (size_t)ulGetLong(0x1d6, aucHeader); /* lcbPlcfendRef */
+ NO_DBG_DEC(tEndnoteInfoLen);
+
+ if (tEndnoteInfoLen < 10) {
+ DBG_MSG("No Endnotes in this document");
+ return;
+ }
+
+ aucBuffer = xmalloc(tEndnoteInfoLen);
+ if (!bReadBuffer(pFile, ulStartBlock,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucBuffer, ulBeginEndnoteInfo, tEndnoteInfoLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tEndnoteInfoLen);
+
+ fail(tEndnoteListLength != 0);
+ tEndnoteListLength = (tEndnoteInfoLen - 4) / 6;
+ fail(tEndnoteListLength == 0);
+
+ fail(aulEndnoteList != NULL);
+ aulEndnoteList = xcalloc(tEndnoteListLength, sizeof(ULONG));
+
+ for (tIndex = 0; tIndex < tEndnoteListLength; tIndex++) {
+ ulOffset = ulGetLong(tIndex * 4, aucBuffer);
+ NO_DBG_HEX(ulOffset);
+ ulFileOffset = ulCharPos2FileOffset(ulBeginOfText + ulOffset);
+ NO_DBG_HEX(ulFileOffset);
+ aulEndnoteList[tIndex] = ulFileOffset;
+ }
+ aucBuffer = xfree(aucBuffer);
+} /* end of vGet6EndnotesInfo */
+
+/*
+ * Build the lists note information for Word 6/7 files
+ */
+static void
+vGet6NotesInfo(FILE *pFile, ULONG ulStartBlock,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const UCHAR *aucHeader)
+{
+ TRACE_MSG("vGet6NotesInfo");
+
+ vGet6FootnotesInfo(pFile, ulStartBlock,
+ aulBBD, tBBDLen, aucHeader);
+ vGet6FootnotesText(pFile, ulStartBlock,
+ aulBBD, tBBDLen, aucHeader);
+ vGet6EndnotesInfo(pFile, ulStartBlock,
+ aulBBD, tBBDLen, aucHeader);
+} /* end of vGet6NotesInfo */
+
+/*
+ * Build the list with footnote information for Word 8/9/10 files
+ */
+static void
+vGet8FootnotesInfo(FILE *pFile, const pps_info_type *pPPS,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ const UCHAR *aucHeader)
+{
+ const ULONG *aulBlockDepot;
+ UCHAR *aucBuffer;
+ ULONG ulFileOffset, ulBeginOfText, ulOffset, ulBeginFootnoteInfo;
+ size_t tFootnoteInfoLen, tBlockDepotLen, tBlockSize;
+ size_t tIndex;
+
+ TRACE_MSG("vGet8FootnotesInfo");
+
+ ulBeginOfText = ulGetLong(0x18, aucHeader); /* fcMin */
+ NO_DBG_HEX(ulBeginOfText);
+ ulBeginFootnoteInfo = ulGetLong(0xaa, aucHeader); /* fcPlcffndRef */
+ NO_DBG_HEX(ulBeginFootnoteInfo);
+ tFootnoteInfoLen =
+ (size_t)ulGetLong(0xae, aucHeader); /* lcbPlcffndRef */
+ NO_DBG_DEC(tFootnoteInfoLen);
+
+ if (tFootnoteInfoLen < 10) {
+ DBG_MSG("No Footnotes in this document");
+ return;
+ }
+
+ NO_DBG_DEC(pPPS->tTable.ulSB);
+ NO_DBG_HEX(pPPS->tTable.ulSize);
+ if (pPPS->tTable.ulSize == 0) {
+ DBG_MSG("No footnotes information");
+ return;
+ }
+
+ if (pPPS->tTable.ulSize < MIN_SIZE_FOR_BBD_USE) {
+ /* Use the Small Block Depot */
+ aulBlockDepot = aulSBD;
+ tBlockDepotLen = tSBDLen;
+ tBlockSize = SMALL_BLOCK_SIZE;
+ } else {
+ /* Use the Big Block Depot */
+ aulBlockDepot = aulBBD;
+ tBlockDepotLen = tBBDLen;
+ tBlockSize = BIG_BLOCK_SIZE;
+ }
+ aucBuffer = xmalloc(tFootnoteInfoLen);
+ if (!bReadBuffer(pFile, pPPS->tTable.ulSB,
+ aulBlockDepot, tBlockDepotLen, tBlockSize,
+ aucBuffer, ulBeginFootnoteInfo, tFootnoteInfoLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tFootnoteInfoLen);
+
+ fail(tFootnoteListLength != 0);
+ tFootnoteListLength = (tFootnoteInfoLen - 4) / 6;
+ fail(tFootnoteListLength == 0);
+
+ fail(aulFootnoteList != NULL);
+ aulFootnoteList = xcalloc(tFootnoteListLength, sizeof(ULONG));
+
+ for (tIndex = 0; tIndex < tFootnoteListLength; tIndex++) {
+ ulOffset = ulGetLong(tIndex * 4, aucBuffer);
+ NO_DBG_HEX(ulOffset);
+ ulFileOffset = ulCharPos2FileOffset(ulBeginOfText + ulOffset);
+ NO_DBG_HEX(ulFileOffset);
+ aulFootnoteList[tIndex] = ulFileOffset;
+ }
+ aucBuffer = xfree(aucBuffer);
+} /* end of vGet8FootnotesInfo */
+
+/*
+ * Build the list with footnote text information for Word 8/9/10 files
+ */
+static void
+vGet8FootnotesText(FILE *pFile, const pps_info_type *pPPS,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ const UCHAR *aucHeader)
+{
+ footnote_local_type *pCurr;
+ const ULONG *aulBlockDepot;
+ UCHAR *aucBuffer;
+ ULONG ulCharPos, ulBeginOfFootnotes, ulOffset, ulBeginFootnoteText;
+ size_t tFootnoteTextLen, tBlockDepotLen, tBlockSize;
+ size_t tIndex;
+
+ TRACE_MSG("vGet8FootnotesText");
+
+ ulBeginOfFootnotes = ulGetLong(0x18, aucHeader); /* fcMin */
+ ulBeginOfFootnotes += ulGetLong(0x4c, aucHeader); /* ccpText */
+ NO_DBG_HEX(ulBeginOfFootnotes);
+
+ ulBeginFootnoteText = ulGetLong(0xb2, aucHeader); /* fcPlcffndTxt */
+ NO_DBG_HEX(ulBeginFootnoteText);
+ tFootnoteTextLen =
+ (size_t)ulGetLong(0xb6, aucHeader); /* lcbPlcffndTxt */
+ NO_DBG_DEC(tFootnoteTextLen);
+
+ if (tFootnoteTextLen < 12) {
+ DBG_MSG("No Footnote text in this document");
+ return;
+ }
+
+ NO_DBG_DEC(pPPS->tTable.ulSB);
+ NO_DBG_HEX(pPPS->tTable.ulSize);
+ if (pPPS->tTable.ulSize == 0) {
+ DBG_MSG("No footnote text information");
+ return;
+ }
+
+ if (pPPS->tTable.ulSize < MIN_SIZE_FOR_BBD_USE) {
+ /* Use the Small Block Depot */
+ aulBlockDepot = aulSBD;
+ tBlockDepotLen = tSBDLen;
+ tBlockSize = SMALL_BLOCK_SIZE;
+ } else {
+ /* Use the Big Block Depot */
+ aulBlockDepot = aulBBD;
+ tBlockDepotLen = tBBDLen;
+ tBlockSize = BIG_BLOCK_SIZE;
+ }
+ aucBuffer = xmalloc(tFootnoteTextLen);
+ if (!bReadBuffer(pFile, pPPS->tTable.ulSB,
+ aulBlockDepot, tBlockDepotLen, tBlockSize,
+ aucBuffer, ulBeginFootnoteText, tFootnoteTextLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tFootnoteTextLen);
+
+ fail(tFootnoteTextLength != 0);
+ tFootnoteTextLength = tFootnoteTextLen / 4 - 2;
+ fail(tFootnoteTextLength == 0);
+
+ fail(pFootnoteText != NULL);
+ pFootnoteText = xcalloc(tFootnoteTextLength,
+ sizeof(footnote_local_type));
+
+ for (tIndex = 0; tIndex < tFootnoteTextLength; tIndex++) {
+ pCurr = pFootnoteText + tIndex;
+ pCurr->tInfo.szText = NULL;
+ ulOffset = ulGetLong(tIndex * 4, aucBuffer);
+ NO_DBG_HEX(ulOffset);
+ ulCharPos = ulBeginOfFootnotes + ulOffset;
+ NO_DBG_HEX(ulCharPos);
+ NO_DBG_HEX(ulCharPos2FileOffset(ulCharPos));
+ pCurr->ulCharPosStart = ulCharPos;
+ ulOffset = ulGetLong(tIndex * 4 + 4, aucBuffer);
+ NO_DBG_HEX(ulOffset);
+ ulCharPos = ulBeginOfFootnotes + ulOffset;
+ NO_DBG_HEX(ulCharPos);
+ NO_DBG_HEX(ulCharPos2FileOffset(ulCharPos));
+ pCurr->ulCharPosNext = ulCharPos;
+ pCurr->bUseful = pCurr->ulCharPosStart != pCurr->ulCharPosNext;
+ }
+ aucBuffer = xfree(aucBuffer);
+} /* end of vGet8FootnotesText */
+
+/*
+ * Build the list with endnote information for Word 8/9/10 files
+ */
+static void
+vGet8EndnotesInfo(FILE *pFile, const pps_info_type *pPPS,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ const UCHAR *aucHeader)
+{
+ const ULONG *aulBlockDepot;
+ UCHAR *aucBuffer;
+ ULONG ulFileOffset, ulBeginOfText, ulOffset, ulBeginEndnoteInfo;
+ size_t tEndnoteInfoLen, tBlockDepotLen, tBlockSize;
+ size_t tIndex;
+
+ TRACE_MSG("vGet8EndnotesInfo");
+
+ ulBeginOfText = ulGetLong(0x18, aucHeader); /* fcMin */
+ NO_DBG_HEX(ulBeginOfText);
+ ulBeginEndnoteInfo = ulGetLong(0x20a, aucHeader); /* fcPlcfendRef */
+ NO_DBG_HEX(ulBeginEndnoteInfo);
+ tEndnoteInfoLen = (size_t)ulGetLong(0x20e, aucHeader); /* lcbPlcfendRef */
+ NO_DBG_DEC(tEndnoteInfoLen);
+
+ if (tEndnoteInfoLen < 10) {
+ DBG_MSG("No endnotes in this document");
+ return;
+ }
+
+ NO_DBG_DEC(pPPS->tTable.ulSB);
+ NO_DBG_HEX(pPPS->tTable.ulSize);
+ if (pPPS->tTable.ulSize == 0) {
+ DBG_MSG("No endnotes information");
+ return;
+ }
+
+ if (pPPS->tTable.ulSize < MIN_SIZE_FOR_BBD_USE) {
+ /* Use the Small Block Depot */
+ aulBlockDepot = aulSBD;
+ tBlockDepotLen = tSBDLen;
+ tBlockSize = SMALL_BLOCK_SIZE;
+ } else {
+ /* Use the Big Block Depot */
+ aulBlockDepot = aulBBD;
+ tBlockDepotLen = tBBDLen;
+ tBlockSize = BIG_BLOCK_SIZE;
+ }
+ aucBuffer = xmalloc(tEndnoteInfoLen);
+ if (!bReadBuffer(pFile, pPPS->tTable.ulSB,
+ aulBlockDepot, tBlockDepotLen, tBlockSize,
+ aucBuffer, ulBeginEndnoteInfo, tEndnoteInfoLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tEndnoteInfoLen);
+
+ fail(tEndnoteListLength != 0);
+ tEndnoteListLength = (tEndnoteInfoLen - 4) / 6;
+ fail(tEndnoteListLength == 0);
+
+ fail(aulEndnoteList != NULL);
+ aulEndnoteList = xcalloc(tEndnoteListLength, sizeof(ULONG));
+
+ for (tIndex = 0; tIndex < tEndnoteListLength; tIndex++) {
+ ulOffset = ulGetLong(tIndex * 4, aucBuffer);
+ NO_DBG_HEX(ulOffset);
+ ulFileOffset = ulCharPos2FileOffset(ulBeginOfText + ulOffset);
+ NO_DBG_HEX(ulFileOffset);
+ aulEndnoteList[tIndex] = ulFileOffset;
+ }
+ aucBuffer = xfree(aucBuffer);
+} /* end of vGet8EndnotesInfo */
+
+/*
+ * Build the lists with footnote and endnote information for Word 8/9/10 files
+ */
+static void
+vGet8NotesInfo(FILE *pFile, const pps_info_type *pPPS,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ const UCHAR *aucHeader)
+{
+ TRACE_MSG("vGet8NotesInfo");
+
+ vGet8FootnotesInfo(pFile, pPPS,
+ aulBBD, tBBDLen, aulSBD, tSBDLen, aucHeader);
+ vGet8FootnotesText(pFile, pPPS,
+ aulBBD, tBBDLen, aulSBD, tSBDLen, aucHeader);
+ vGet8EndnotesInfo(pFile, pPPS,
+ aulBBD, tBBDLen, aulSBD, tSBDLen, aucHeader);
+} /* end of vGet8NotesInfo */
+
+/*
+ * Build the lists with footnote and endnote information
+ */
+void
+vGetNotesInfo(FILE *pFile, const pps_info_type *pPPS,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ const UCHAR *aucHeader, int iWordVersion)
+{
+ TRACE_MSG("vGetNotesInfo");
+
+ fail(pFile == NULL);
+ fail(pPPS == NULL && iWordVersion >= 6);
+ fail(aulBBD == NULL && tBBDLen != 0);
+ fail(aulSBD == NULL && tSBDLen != 0);
+ fail(aucHeader == NULL);
+
+ switch (iWordVersion) {
+ case 0:
+ vGet0NotesInfo(pFile, aucHeader);
+ break;
+ case 1:
+ case 2:
+ vGet2NotesInfo(pFile, aucHeader);
+ break;
+ case 4:
+ case 5:
+ break;
+ case 6:
+ case 7:
+ vGet6NotesInfo(pFile, pPPS->tWordDocument.ulSB,
+ aulBBD, tBBDLen, aucHeader);
+ break;
+ case 8:
+ vGet8NotesInfo(pFile, pPPS,
+ aulBBD, tBBDLen, aulSBD, tSBDLen, aucHeader);
+ break;
+ default:
+ werr(0, "Sorry, no notes information");
+ break;
+ }
+} /* end of vGetNotesInfo */
+
+/*
+ * vPrepareFootnoteText - prepare the footnote text
+ */
+void
+vPrepareFootnoteText(FILE *pFile)
+{
+ footnote_local_type *pCurr;
+ size_t tFootnote;
+
+ fail(pFile == NULL);
+ fail(pFootnoteText == NULL && tFootnoteTextLength != 0);
+
+ if (pFootnoteText == NULL || tFootnoteTextLength == 0) {
+ /* No information */
+ return;
+ }
+
+ /* Fill text and useful-ness */
+ for (tFootnote = 0; tFootnote < tFootnoteTextLength; tFootnote++) {
+ pCurr = pFootnoteText + tFootnote;
+ pCurr->bUseful = pCurr->ulCharPosStart != pCurr->ulCharPosNext;
+ if (pCurr->bUseful) {
+ pCurr->tInfo.szText = szFootnoteDecryptor(pFile,
+ pCurr->ulCharPosStart,
+ pCurr->ulCharPosNext);
+ } else {
+ pCurr->tInfo.szText = NULL;
+ }
+ }
+} /* end of vPrepareFootnoteText */
+
+/*
+ * szGetFootnootText - get the text of the spefified footnote
+ */
+const char *
+szGetFootnootText(UINT uiFootnoteIndex)
+{
+ if ((size_t)uiFootnoteIndex >= tFootnoteTextLength) {
+ return NULL;
+ }
+ return pFootnoteText[uiFootnoteIndex].tInfo.szText;
+} /* end of szGetFootnootText */
+
+/*
+ * Get the notetype of the note at the given fileoffset
+ */
+notetype_enum
+eGetNotetype(ULONG ulFileOffset)
+{
+ size_t tIndex;
+
+ TRACE_MSG("eGetNotetype");
+
+ fail(aulFootnoteList == NULL && tFootnoteListLength != 0);
+ fail(aulEndnoteList == NULL && tEndnoteListLength != 0);
+
+ /* Go for the easy answers first */
+ if (tFootnoteListLength == 0 && tEndnoteListLength == 0) {
+ return notetype_is_unknown;
+ }
+ if (tEndnoteListLength == 0) {
+ return notetype_is_footnote;
+ }
+ if (tFootnoteListLength == 0) {
+ return notetype_is_endnote;
+ }
+ /* No easy answer, so we search */
+ for (tIndex = 0; tIndex < tFootnoteListLength; tIndex++) {
+ if (aulFootnoteList[tIndex] == ulFileOffset) {
+ return notetype_is_footnote;
+ }
+ }
+ for (tIndex = 0; tIndex < tEndnoteListLength; tIndex++) {
+ if (aulEndnoteList[tIndex] == ulFileOffset) {
+ return notetype_is_endnote;
+ }
+ }
+ /* Not found */
+ return notetype_is_unknown;
+} /* end of eGetNotetype */
diff --git a/sys/src/cmd/aux/antiword/options.c b/sys/src/cmd/aux/antiword/options.c
new file mode 100755
index 000000000..8379fef92
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/options.c
@@ -0,0 +1,950 @@
+/*
+ * options.c
+ * Copyright (C) 1998-2004 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Read and write the options
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined(__riscos)
+#include "DeskLib:Error.h"
+#include "DeskLib:Wimp.h"
+#else
+#include <stdlib.h>
+#if defined(__dos) || defined(N_PLAT_NLM)
+extern int getopt(int, char **, const char *);
+#else
+#include <unistd.h>
+#endif /* __dos */
+#endif /* __riscos */
+#include "antiword.h"
+
+#if defined(__riscos)
+#define PARAGRAPH_BREAK "set paragraph_break=%d"
+#define AUTOFILETYPE "set autofiletype_allowed=%d"
+#define USE_OUTLINEFONTS "set use_outlinefonts=%d"
+#define SHOW_IMAGES "set show_images=%d"
+#define HIDE_HIDDEN_TEXT "set hide_hidden_text=%d"
+#define SCALE_FACTOR_START "set scale_factor_start=%d"
+#else
+#define LEAFNAME_SIZE (32+1)
+#endif /* __riscos */
+
+/* Current values for options */
+static options_type tOptionsCurr;
+#if defined(__riscos)
+/* Temporary values for options */
+static options_type tOptionsTemp;
+#else
+typedef struct papersize_tag {
+ char szName[16]; /* Papersize name */
+ USHORT usWidth; /* In points */
+ USHORT usHeight; /* In points */
+} papersize_type;
+
+static const papersize_type atPaperSizes[] = {
+ { "10x14", 720, 1008 },
+ { "a3", 842, 1191 },
+ { "a4", 595, 842 },
+ { "a5", 420, 595 },
+ { "b4", 729, 1032 },
+ { "b5", 516, 729 },
+ { "executive", 540, 720 },
+ { "folio", 612, 936 },
+ { "legal", 612, 1008 },
+ { "letter", 612, 792 },
+ { "note", 540, 720 },
+ { "quarto", 610, 780 },
+ { "statement", 396, 612 },
+ { "tabloid", 792, 1224 },
+ { "", 0, 0 },
+};
+#endif /* __riscos */
+/* Default values for options */
+static const options_type tOptionsDefault = {
+ DEFAULT_SCREEN_WIDTH,
+#if defined(__riscos)
+ conversion_draw,
+#else
+ conversion_text,
+#endif /* __riscos */
+ TRUE,
+ TRUE,
+ FALSE,
+ encoding_latin_1,
+ INT_MAX,
+ INT_MAX,
+ level_default,
+#if defined(__riscos)
+ TRUE,
+ DEFAULT_SCALE_FACTOR,
+#endif /* __riscos */
+};
+
+
+#if !defined(__riscos)
+/*
+ * bCorrectPapersize - see if the papersize is correct
+ *
+ * TRUE if the papersize is correct, otherwise FALSE
+ */
+static BOOL
+bCorrectPapersize(const char *szName, conversion_type eConversionType)
+{
+ const papersize_type *pPaperSize;
+
+ for (pPaperSize = atPaperSizes;
+ pPaperSize->szName[0] != '\0';
+ pPaperSize++) {
+ if (!STRCEQ(pPaperSize->szName, szName)) {
+ continue;
+ }
+ DBG_DEC(pPaperSize->usWidth);
+ DBG_DEC(pPaperSize->usHeight);
+ tOptionsCurr.eConversionType = eConversionType;
+ tOptionsCurr.iPageHeight = (int)pPaperSize->usHeight;
+ tOptionsCurr.iPageWidth = (int)pPaperSize->usWidth;
+ return TRUE;
+ }
+ return FALSE;
+} /* end of bCorrectPapersize */
+
+/*
+ * szCreateSuffix - create a suffix for the file
+ *
+ * Returns the suffix
+ */
+static const char *
+szCreateSuffix(const char *szLeafname)
+{
+ const char *pcDot;
+
+ pcDot = strrchr(szLeafname, '.');
+ if (pcDot != NULL && STRCEQ(pcDot, ".txt")) {
+ /* There is already a .txt suffix, no need for another one */
+ return "";
+ }
+ return ".txt";
+} /* end of szCreateSuffix */
+
+/*
+ * eMappingFile2Encoding - convert the mapping file to an encoding
+ */
+static encoding_type
+eMappingFile2Encoding(const char *szLeafname)
+{
+ char szMappingFile[LEAFNAME_SIZE+4];
+
+ fail(szLeafname == NULL);
+
+ if (strlen(szLeafname) + 4 >= sizeof(szMappingFile)) {
+ DBG_MSG(szLeafname);
+ return encoding_latin_1;
+ }
+
+ sprintf(szMappingFile, "%s%s", szLeafname, szCreateSuffix(szLeafname));
+
+ DBG_MSG(szMappingFile);
+
+ if (STRCEQ(szMappingFile, MAPPING_FILE_UTF_8)) {
+ return encoding_utf_8;
+ }
+ if (STRCEQ(szMappingFile, MAPPING_FILE_CP852) ||
+ STRCEQ(szMappingFile, MAPPING_FILE_CP1250) ||
+ STRCEQ(szMappingFile, MAPPING_FILE_8859_2)) {
+ return encoding_latin_2;
+ }
+ if (STRCEQ(szMappingFile, MAPPING_FILE_KOI8_R) ||
+ STRCEQ(szMappingFile, MAPPING_FILE_KOI8_U) ||
+ STRCEQ(szMappingFile, MAPPING_FILE_CP866) ||
+ STRCEQ(szMappingFile, MAPPING_FILE_CP1251) ||
+ STRCEQ(szMappingFile, MAPPING_FILE_8859_5)) {
+ return encoding_cyrillic;
+ }
+ return encoding_latin_1;
+} /* end of eMappingFile2Encoding */
+#endif /* !__riscos */
+
+/*
+ * pOpenCharacterMappingFile - open the mapping file
+ *
+ * Returns the file pointer or NULL
+ */
+static FILE *
+pOpenCharacterMappingFile(const char *szLeafname)
+{
+#if !defined(__riscos)
+ FILE *pFile;
+ const char *szHome, *szAntiword, *szSuffix;
+ size_t tFilenameLen;
+ char szMappingFile[PATH_MAX+1];
+#endif /* !__riscos */
+
+ if (szLeafname == NULL || szLeafname[0] == '\0') {
+ return NULL;
+ }
+
+ DBG_MSG(szLeafname);
+
+#if defined(__riscos)
+ return fopen(szLeafname, "r");
+#else
+ /* Set the suffix */
+ szSuffix = szCreateSuffix(szLeafname);
+
+ /* Set length */
+ tFilenameLen = strlen(szLeafname) + strlen(szSuffix);
+
+ /* Try the environment version of the mapping file */
+ szAntiword = szGetAntiwordDirectory();
+ if (szAntiword != NULL && szAntiword[0] != '\0') {
+ if (strlen(szAntiword) + tFilenameLen <
+ sizeof(szMappingFile) -
+ sizeof(FILE_SEPARATOR)) {
+ sprintf(szMappingFile,
+ "%s" FILE_SEPARATOR "%s%s",
+ szAntiword, szLeafname, szSuffix);
+ DBG_MSG(szMappingFile);
+ pFile = fopen(szMappingFile, "r");
+ if (pFile != NULL) {
+ return pFile;
+ }
+ } else {
+ werr(0, "Environment mappingfilename ignored");
+ }
+ }
+
+ /* Try the local version of the mapping file */
+ szHome = szGetHomeDirectory();
+ if (strlen(szHome) + tFilenameLen <
+ sizeof(szMappingFile) -
+ sizeof(ANTIWORD_DIR) -
+ 2 * sizeof(FILE_SEPARATOR)) {
+ sprintf(szMappingFile,
+ "%s" FILE_SEPARATOR ANTIWORD_DIR FILE_SEPARATOR "%s%s",
+ szHome, szLeafname, szSuffix);
+ DBG_MSG(szMappingFile);
+ pFile = fopen(szMappingFile, "r");
+ if (pFile != NULL) {
+ return pFile;
+ }
+ } else {
+ werr(0, "Local mappingfilename too long, ignored");
+ }
+
+ /* Try the global version of the mapping file */
+ if (tFilenameLen <
+ sizeof(szMappingFile) -
+ sizeof(GLOBAL_ANTIWORD_DIR) -
+ sizeof(FILE_SEPARATOR)) {
+ sprintf(szMappingFile,
+ GLOBAL_ANTIWORD_DIR FILE_SEPARATOR "%s%s",
+ szLeafname, szSuffix);
+ DBG_MSG(szMappingFile);
+ pFile = fopen(szMappingFile, "r");
+ if (pFile != NULL) {
+ return pFile;
+ }
+ } else {
+ werr(0, "Global mappingfilename too long, ignored");
+ }
+ werr(0, "I can't open your mapping file (%s%s)\n"
+ "It is not in '%s" FILE_SEPARATOR ANTIWORD_DIR "' nor in '"
+ GLOBAL_ANTIWORD_DIR "'.", szLeafname, szSuffix, szHome);
+ return NULL;
+#endif /* __riscos */
+} /* end of pOpenCharacterMappingFile */
+
+/*
+ * vCloseCharacterMappingFile - close the mapping file
+ */
+static void
+vCloseCharacterMappingFile(FILE *pFile)
+{
+ (void)fclose(pFile);
+} /* end of pCloseCharacterMappingFile */
+
+
+/*
+ * iReadOptions - read options
+ *
+ * returns: -1: error
+ * 0: help
+ * >0: index first file argument
+ */
+int
+iReadOptions(int argc, char **argv)
+{
+#if defined(__riscos)
+ FILE *pFile;
+ const char *szAlphabet;
+ int iAlphabet;
+ char szLine[81];
+#else
+ extern char *optarg;
+ extern int optind;
+ char *pcChar, *szTmp;
+ int iChar;
+ char szLeafname[LEAFNAME_SIZE];
+#endif /* __riscos */
+ FILE *pCharacterMappingFile;
+ int iTmp;
+ BOOL bSuccess;
+
+ DBG_MSG("iReadOptions");
+
+/* Defaults */
+ tOptionsCurr = tOptionsDefault;
+
+#if defined(__riscos)
+/* Choices file */
+ pFile = fopen("<AntiWord$ChoicesFile>", "r");
+ DBG_MSG_C(pFile == NULL, "Choices file not found");
+ DBG_HEX_C(pFile != NULL, pFile);
+ if (pFile != NULL) {
+ while (fgets(szLine, (int)sizeof(szLine), pFile) != NULL) {
+ DBG_MSG(szLine);
+ if (szLine[0] == '#' ||
+ szLine[0] == '\r' ||
+ szLine[0] == '\n') {
+ continue;
+ }
+ if (sscanf(szLine, PARAGRAPH_BREAK, &iTmp) == 1 &&
+ (iTmp == 0 ||
+ (iTmp >= MIN_SCREEN_WIDTH &&
+ iTmp <= MAX_SCREEN_WIDTH))) {
+ tOptionsCurr.iParagraphBreak = iTmp;
+ DBG_DEC(tOptionsCurr.iParagraphBreak);
+ } else if (sscanf(szLine, AUTOFILETYPE, &iTmp)
+ == 1) {
+ tOptionsCurr.bAutofiletypeAllowed =
+ iTmp != 0;
+ DBG_DEC(tOptionsCurr.bAutofiletypeAllowed);
+ } else if (sscanf(szLine, USE_OUTLINEFONTS, &iTmp)
+ == 1) {
+ tOptionsCurr.eConversionType =
+ iTmp == 0 ?
+ conversion_text : conversion_draw;
+ DBG_DEC(tOptionsCurr.eConversionType);
+ } else if (sscanf(szLine, SHOW_IMAGES, &iTmp)
+ == 1) {
+ tOptionsCurr.eImageLevel = iTmp != 0 ?
+ level_default : level_no_images;
+ } else if (sscanf(szLine, HIDE_HIDDEN_TEXT, &iTmp)
+ == 1) {
+ tOptionsCurr.bHideHiddenText = iTmp != 0;
+ DBG_DEC(tOptionsCurr.bHideHiddenText);
+ } else if (sscanf(szLine, SCALE_FACTOR_START, &iTmp)
+ == 1) {
+ if (iTmp >= MIN_SCALE_FACTOR &&
+ iTmp <= MAX_SCALE_FACTOR) {
+ tOptionsCurr.iScaleFactor = iTmp;
+ DBG_DEC(tOptionsCurr.iScaleFactor);
+ }
+ }
+ }
+ (void)fclose(pFile);
+ }
+ iAlphabet = iReadCurrentAlphabetNumber();
+ switch (iAlphabet) {
+ case 101: /* ISO-8859-1 aka Latin1 */
+ szAlphabet = "<AntiWord$Latin1>";
+ break;
+ case 112: /* ISO-8859-15 aka Latin9 */
+ szAlphabet = "<AntiWord$Latin9>";
+ break;
+ default:
+ werr(0, "Alphabet '%d' is not supported", iAlphabet);
+ return -1;
+ }
+ pCharacterMappingFile = pOpenCharacterMappingFile(szAlphabet);
+ if (pCharacterMappingFile != NULL) {
+ bSuccess = bReadCharacterMappingTable(pCharacterMappingFile);
+ vCloseCharacterMappingFile(pCharacterMappingFile);
+ } else {
+ bSuccess = FALSE;
+ }
+ return bSuccess ? 1 : -1;
+#else
+/* Environment */
+ szTmp = getenv("COLUMNS");
+ if (szTmp != NULL) {
+ DBG_MSG(szTmp);
+ iTmp = (int)strtol(szTmp, &pcChar, 10);
+ if (*pcChar == '\0') {
+ iTmp -= 4; /* This is for the edge */
+ if (iTmp < MIN_SCREEN_WIDTH) {
+ iTmp = MIN_SCREEN_WIDTH;
+ } else if (iTmp > MAX_SCREEN_WIDTH) {
+ iTmp = MAX_SCREEN_WIDTH;
+ }
+ tOptionsCurr.iParagraphBreak = iTmp;
+ DBG_DEC(tOptionsCurr.iParagraphBreak);
+ }
+ }
+ strncpy(szLeafname, szGetDefaultMappingFile(), sizeof(szLeafname) - 1);
+ szLeafname[sizeof(szLeafname) - 1] = '\0';
+/* Command line */
+ while ((iChar = getopt(argc, argv, "La:fhi:m:p:rstw:x:")) != -1) {
+ switch (iChar) {
+ case 'L':
+ tOptionsCurr.bUseLandscape = TRUE;
+ break;
+ case 'a':
+ if (!bCorrectPapersize(optarg, conversion_pdf)) {
+ werr(0, "-a without a valid papersize");
+ return -1;
+ }
+ break;
+ case 'f':
+ tOptionsCurr.eConversionType = conversion_fmt_text;
+ break;
+ case 'h':
+ return 0;
+ case 'i':
+ iTmp = (int)strtol(optarg, &pcChar, 10);
+ if (*pcChar != '\0') {
+ break;
+ }
+ switch (iTmp) {
+ case 0:
+ tOptionsCurr.eImageLevel = level_gs_special;
+ break;
+ case 1:
+ tOptionsCurr.eImageLevel = level_no_images;
+ break;
+ case 2:
+ tOptionsCurr.eImageLevel = level_ps_2;
+ break;
+ case 3:
+ tOptionsCurr.eImageLevel = level_ps_3;
+ break;
+ default:
+ tOptionsCurr.eImageLevel = level_default;
+ break;
+ }
+ DBG_DEC(tOptionsCurr.eImageLevel);
+ break;
+ case 'm':
+ if (tOptionsCurr.eConversionType == conversion_xml) {
+ werr(0, "XML doesn't need a mapping file");
+ break;
+ }
+ strncpy(szLeafname, optarg, sizeof(szLeafname) - 1);
+ szLeafname[sizeof(szLeafname) - 1] = '\0';
+ DBG_MSG(szLeafname);
+ break;
+ case 'p':
+ if (!bCorrectPapersize(optarg, conversion_ps)) {
+ werr(0, "-p without a valid papersize");
+ return -1;
+ }
+ break;
+ case 'r':
+ tOptionsCurr.bRemoveRemovedText = FALSE;
+ break;
+ case 's':
+ tOptionsCurr.bHideHiddenText = FALSE;
+ break;
+ case 't':
+ tOptionsCurr.eConversionType = conversion_text;
+ break;
+ case 'w':
+ iTmp = (int)strtol(optarg, &pcChar, 10);
+ if (*pcChar == '\0') {
+ if (iTmp != 0 && iTmp < MIN_SCREEN_WIDTH) {
+ iTmp = MIN_SCREEN_WIDTH;
+ } else if (iTmp > MAX_SCREEN_WIDTH) {
+ iTmp = MAX_SCREEN_WIDTH;
+ }
+ tOptionsCurr.iParagraphBreak = iTmp;
+ DBG_DEC(tOptionsCurr.iParagraphBreak);
+ }
+ break;
+ case 'x':
+ if (STREQ(optarg, "db")) {
+ tOptionsCurr.iParagraphBreak = 0;
+ tOptionsCurr.eConversionType = conversion_xml;
+ strcpy(szLeafname, MAPPING_FILE_UTF_8);
+ } else {
+ werr(0, "-x %s is not supported", optarg);
+ return -1;
+ }
+ break;
+ default:
+ return -1;
+ }
+ }
+
+ tOptionsCurr.eEncoding = eMappingFile2Encoding(szLeafname);
+ DBG_DEC(tOptionsCurr.eEncoding);
+
+ if (tOptionsCurr.eConversionType == conversion_ps &&
+ tOptionsCurr.eEncoding == encoding_utf_8) {
+ werr(0,
+ "The combination PostScript and UTF-8 is not supported");
+ return -1;
+ }
+
+ if (tOptionsCurr.eConversionType == conversion_pdf &&
+ tOptionsCurr.eEncoding == encoding_utf_8) {
+ werr(0,
+ "The combination PDF and UTF-8 is not supported");
+ return -1;
+ }
+
+ if (tOptionsCurr.eConversionType == conversion_pdf &&
+ tOptionsCurr.eEncoding == encoding_cyrillic) {
+ werr(0,
+ "The combination PDF and Cyrillic is not supported");
+ return -1;
+ }
+
+ if (tOptionsCurr.eConversionType == conversion_ps ||
+ tOptionsCurr.eConversionType == conversion_pdf) {
+ /* PostScript or PDF mode */
+ if (tOptionsCurr.bUseLandscape) {
+ /* Swap the page height and width */
+ iTmp = tOptionsCurr.iPageHeight;
+ tOptionsCurr.iPageHeight = tOptionsCurr.iPageWidth;
+ tOptionsCurr.iPageWidth = iTmp;
+ }
+ /* The paragraph break depends on the width of the paper */
+ tOptionsCurr.iParagraphBreak = iMilliPoints2Char(
+ (long)tOptionsCurr.iPageWidth * 1000 -
+ lDrawUnits2MilliPoints(
+ PS_LEFT_MARGIN + PS_RIGHT_MARGIN));
+ DBG_DEC(tOptionsCurr.iParagraphBreak);
+ }
+
+ pCharacterMappingFile = pOpenCharacterMappingFile(szLeafname);
+ if (pCharacterMappingFile != NULL) {
+ bSuccess = bReadCharacterMappingTable(pCharacterMappingFile);
+ vCloseCharacterMappingFile(pCharacterMappingFile);
+ } else {
+ bSuccess = FALSE;
+ }
+ return bSuccess ? optind : -1;
+#endif /* __riscos */
+} /* end of iReadOptions */
+
+/*
+ * vGetOptions - get a copy of the current option values
+ */
+void
+vGetOptions(options_type *pOptions)
+{
+ fail(pOptions == NULL);
+
+ *pOptions = tOptionsCurr;
+} /* end of vGetOptions */
+
+#if defined(__riscos)
+/*
+ * vWriteOptions - write the current options to the Options file
+ */
+static void
+vWriteOptions(void)
+{
+ FILE *pFile;
+ char *szOptionsFile;
+
+ TRACE_MSG("vWriteOptions");
+
+ szOptionsFile = getenv("AntiWord$ChoicesSave");
+ if (szOptionsFile == NULL) {
+ werr(0, "Warning: Name of the Choices file not found");
+ return;
+ }
+ if (!bMakeDirectory(szOptionsFile)) {
+ werr(0,
+ "Warning: I can't make a directory for the Choices file");
+ return;
+ }
+ pFile = fopen(szOptionsFile, "w");
+ if (pFile == NULL) {
+ werr(0, "Warning: I can't write the Choices file");
+ return;
+ }
+ (void)fprintf(pFile, PARAGRAPH_BREAK"\n",
+ tOptionsCurr.iParagraphBreak);
+ (void)fprintf(pFile, AUTOFILETYPE"\n",
+ tOptionsCurr.bAutofiletypeAllowed);
+ (void)fprintf(pFile, USE_OUTLINEFONTS"\n",
+ tOptionsCurr.eConversionType == conversion_text ? 0 : 1);
+ (void)fprintf(pFile, SHOW_IMAGES"\n",
+ tOptionsCurr.eImageLevel == level_no_images ? 0 : 1);
+ (void)fprintf(pFile, HIDE_HIDDEN_TEXT"\n",
+ tOptionsCurr.bHideHiddenText);
+ (void)fprintf(pFile, SCALE_FACTOR_START"\n",
+ tOptionsCurr.iScaleFactor);
+ (void)fclose(pFile);
+} /* end of vWriteOptions */
+
+/*
+ * vChoicesOpenAction - action to be taken when the Choices window opens
+ */
+void
+vChoicesOpenAction(window_handle tWindow)
+{
+ TRACE_MSG("vChoicesOpenAction");
+
+ tOptionsTemp = tOptionsCurr;
+ if (tOptionsTemp.iParagraphBreak == 0) {
+ vUpdateRadioButton(tWindow, CHOICES_BREAK_BUTTON, FALSE);
+ vUpdateRadioButton(tWindow, CHOICES_NO_BREAK_BUTTON, TRUE);
+ vUpdateWriteableNumber(tWindow, CHOICES_BREAK_WRITEABLE,
+ DEFAULT_SCREEN_WIDTH);
+ } else {
+ vUpdateRadioButton(tWindow, CHOICES_BREAK_BUTTON, TRUE);
+ vUpdateRadioButton(tWindow, CHOICES_NO_BREAK_BUTTON, FALSE);
+ vUpdateWriteableNumber(tWindow,
+ CHOICES_BREAK_WRITEABLE,
+ tOptionsTemp.iParagraphBreak);
+ }
+ vUpdateRadioButton(tWindow, CHOICES_AUTOFILETYPE_BUTTON,
+ tOptionsTemp.bAutofiletypeAllowed);
+ vUpdateRadioButton(tWindow, CHOICES_HIDDEN_TEXT_BUTTON,
+ tOptionsTemp.bHideHiddenText);
+ if (tOptionsTemp.eConversionType == conversion_draw) {
+ vUpdateRadioButton(tWindow,
+ CHOICES_WITH_IMAGES_BUTTON,
+ tOptionsTemp.eImageLevel != level_no_images);
+ vUpdateRadioButton(tWindow,
+ CHOICES_NO_IMAGES_BUTTON,
+ tOptionsTemp.eImageLevel == level_no_images);
+ vUpdateRadioButton(tWindow,
+ CHOICES_TEXTONLY_BUTTON, FALSE);
+ } else {
+ vUpdateRadioButton(tWindow,
+ CHOICES_WITH_IMAGES_BUTTON, FALSE);
+ vUpdateRadioButton(tWindow,
+ CHOICES_NO_IMAGES_BUTTON, FALSE);
+ vUpdateRadioButton(tWindow,
+ CHOICES_TEXTONLY_BUTTON, TRUE);
+ }
+ vUpdateWriteableNumber(tWindow,
+ CHOICES_SCALE_WRITEABLE, tOptionsTemp.iScaleFactor);
+ TRACE_MSG("end of vChoicesOpenAction");
+} /* end of vChoicesOpenAction */
+
+/*
+ * vDefaultButtonAction - action when the default button is clicked
+ */
+static void
+vDefaultButtonAction(window_handle tWindow)
+{
+ TRACE_MSG("vDefaultButtonAction");
+
+ tOptionsTemp = tOptionsDefault;
+ vUpdateRadioButton(tWindow, CHOICES_BREAK_BUTTON, TRUE);
+ vUpdateRadioButton(tWindow, CHOICES_NO_BREAK_BUTTON, FALSE);
+ vUpdateWriteableNumber(tWindow, CHOICES_BREAK_WRITEABLE,
+ tOptionsTemp.iParagraphBreak);
+ vUpdateRadioButton(tWindow, CHOICES_AUTOFILETYPE_BUTTON,
+ tOptionsTemp.bAutofiletypeAllowed);
+ vUpdateRadioButton(tWindow, CHOICES_HIDDEN_TEXT_BUTTON,
+ tOptionsTemp.bHideHiddenText);
+ vUpdateRadioButton(tWindow, CHOICES_WITH_IMAGES_BUTTON,
+ tOptionsTemp.eConversionType == conversion_draw &&
+ tOptionsTemp.eImageLevel != level_no_images);
+ vUpdateRadioButton(tWindow, CHOICES_NO_IMAGES_BUTTON,
+ tOptionsTemp.eConversionType == conversion_draw &&
+ tOptionsTemp.eImageLevel == level_no_images);
+ vUpdateRadioButton(tWindow, CHOICES_TEXTONLY_BUTTON,
+ tOptionsTemp.eConversionType == conversion_text);
+ vUpdateWriteableNumber(tWindow, CHOICES_SCALE_WRITEABLE,
+ tOptionsTemp.iScaleFactor);
+} /* end of vDefaultButtonAction */
+
+/*
+ * vApplyButtonAction - action to be taken when the OK button is clicked
+ */
+static void
+vApplyButtonAction(void)
+{
+ TRACE_MSG("vApplyButtonAction");
+
+ tOptionsCurr = tOptionsTemp;
+} /* end of vApplyButtonAction */
+
+/*
+ * vSaveButtonAction - action to be taken when the save button is clicked
+ */
+static void
+vSaveButtonAction(void)
+{
+ TRACE_MSG("vSaveButtonAction");
+
+ vApplyButtonAction();
+ vWriteOptions();
+} /* end of vSaveButtonAction */
+
+/*
+ * vSetParagraphBreak - set the paragraph break to the given number
+ */
+static void
+vSetParagraphBreak(window_handle tWindow, int iNumber)
+{
+ tOptionsTemp.iParagraphBreak = iNumber;
+ if (tOptionsTemp.iParagraphBreak == 0) {
+ return;
+ }
+ vUpdateWriteableNumber(tWindow,
+ CHOICES_BREAK_WRITEABLE,
+ tOptionsTemp.iParagraphBreak);
+} /* end of vSetParagraphBreak */
+
+/*
+ * vChangeParagraphBreak - change the paragraph break with the given number
+ */
+static void
+vChangeParagraphBreak(window_handle tWindow, int iNumber)
+{
+ int iTmp;
+
+ iTmp = tOptionsTemp.iParagraphBreak + iNumber;
+ if (iTmp < MIN_SCREEN_WIDTH || iTmp > MAX_SCREEN_WIDTH) {
+ /* Ignore */
+ return;
+ }
+ tOptionsTemp.iParagraphBreak = iTmp;
+ vUpdateWriteableNumber(tWindow,
+ CHOICES_BREAK_WRITEABLE,
+ tOptionsTemp.iParagraphBreak);
+} /* end of vChangeParagraphBreak */
+
+/*
+ * vChangeAutofiletype - invert the permission to autofiletype
+ */
+static void
+vChangeAutofiletype(window_handle tWindow)
+{
+ tOptionsTemp.bAutofiletypeAllowed =
+ !tOptionsTemp.bAutofiletypeAllowed;
+ vUpdateRadioButton(tWindow,
+ CHOICES_AUTOFILETYPE_BUTTON,
+ tOptionsTemp.bAutofiletypeAllowed);
+} /* end of vChangeAutofiletype */
+
+/*
+ * vChangeHiddenText - invert the hide/show hidden text
+ */
+static void
+vChangeHiddenText(window_handle tWindow)
+{
+ tOptionsTemp.bHideHiddenText = !tOptionsTemp.bHideHiddenText;
+ vUpdateRadioButton(tWindow,
+ CHOICES_HIDDEN_TEXT_BUTTON,
+ tOptionsTemp.bHideHiddenText);
+} /* end of vChangeHiddenText */
+
+/*
+ * vUseFontsImages - use outline fonts, show images
+ */
+static void
+vUseFontsImages(BOOL bUseOutlineFonts, BOOL bShowImages)
+{
+ tOptionsTemp.eConversionType =
+ bUseOutlineFonts ? conversion_draw : conversion_text;
+ tOptionsTemp.eImageLevel =
+ bUseOutlineFonts && bShowImages ?
+ level_default : level_no_images;
+} /* end of vUseFontsImages */
+
+/*
+ * vSetScaleFactor - set the scale factor to the given number
+ */
+static void
+vSetScaleFactor(window_handle tWindow, int iNumber)
+{
+ tOptionsTemp.iScaleFactor = iNumber;
+ vUpdateWriteableNumber(tWindow,
+ CHOICES_SCALE_WRITEABLE,
+ tOptionsTemp.iScaleFactor);
+} /* end of vSetScaleFactor */
+
+/*
+ * vChangeScaleFactor - change the scale factor with the given number
+ */
+static void
+vChangeScaleFactor(window_handle tWindow, int iNumber)
+{
+ int iTmp;
+
+ iTmp = tOptionsTemp.iScaleFactor + iNumber;
+ if (iTmp < MIN_SCALE_FACTOR || iTmp > MAX_SCALE_FACTOR) {
+ /* Ignore */
+ return;
+ }
+ tOptionsTemp.iScaleFactor = iTmp;
+ vUpdateWriteableNumber(tWindow,
+ CHOICES_SCALE_WRITEABLE,
+ tOptionsTemp.iScaleFactor);
+} /* end of vChangeScaleFactor */
+
+/*
+ * bChoicesMouseClick - handle a mouse click in the Choices window
+ */
+BOOL
+bChoicesMouseClick(event_pollblock *pEvent, void *pvReference)
+{
+ icon_handle tAction;
+ mouse_block *pMouse;
+ BOOL bCloseWindow;
+
+ TRACE_MSG("bChoicesMouseClick");
+
+ fail(pEvent == NULL);
+ fail(pEvent->type != event_CLICK);
+
+ pMouse = &pEvent->data.mouse;
+ if (!pMouse->button.data.select && !pMouse->button.data.adjust) {
+ /* Not handled here */
+ DBG_HEX(pMouse->button.value);
+ return FALSE;
+ }
+
+ /* Which action should be taken */
+ tAction = pMouse->icon;
+ if (pMouse->button.data.adjust) {
+ /* The adjust button reverses the direction */
+ switch (pMouse->icon) {
+ case CHOICES_BREAK_UP_BUTTON:
+ tAction = CHOICES_BREAK_DOWN_BUTTON;
+ break;
+ case CHOICES_BREAK_DOWN_BUTTON:
+ tAction = CHOICES_BREAK_UP_BUTTON;
+ break;
+ case CHOICES_SCALE_UP_BUTTON:
+ tAction = CHOICES_SCALE_DOWN_BUTTON;
+ break;
+ case CHOICES_SCALE_DOWN_BUTTON:
+ tAction = CHOICES_SCALE_UP_BUTTON;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Actions */
+ bCloseWindow = FALSE;
+ switch (tAction) {
+ case CHOICES_DEFAULT_BUTTON:
+ vDefaultButtonAction(pMouse->window);
+ break;
+ case CHOICES_SAVE_BUTTON:
+ vSaveButtonAction();
+ break;
+ case CHOICES_CANCEL_BUTTON:
+ bCloseWindow = TRUE;
+ break;
+ case CHOICES_APPLY_BUTTON:
+ vApplyButtonAction();
+ bCloseWindow = TRUE;
+ break;
+ case CHOICES_BREAK_BUTTON:
+ vSetParagraphBreak(pMouse->window, DEFAULT_SCREEN_WIDTH);
+ break;
+ case CHOICES_BREAK_UP_BUTTON:
+ vChangeParagraphBreak(pMouse->window, 1);
+ break;
+ case CHOICES_BREAK_DOWN_BUTTON:
+ vChangeParagraphBreak(pMouse->window, -1);
+ break;
+ case CHOICES_NO_BREAK_BUTTON:
+ vSetParagraphBreak(pMouse->window, 0);
+ break;
+ case CHOICES_AUTOFILETYPE_BUTTON:
+ vChangeAutofiletype(pMouse->window);
+ break;
+ case CHOICES_HIDDEN_TEXT_BUTTON:
+ vChangeHiddenText(pMouse->window);
+ break;
+ case CHOICES_WITH_IMAGES_BUTTON:
+ vUseFontsImages(TRUE, TRUE);
+ break;
+ case CHOICES_NO_IMAGES_BUTTON:
+ vUseFontsImages(TRUE, FALSE);
+ break;
+ case CHOICES_TEXTONLY_BUTTON:
+ vUseFontsImages(FALSE, FALSE);
+ break;
+ case CHOICES_SCALE_UP_BUTTON:
+ vChangeScaleFactor(pMouse->window, 5);
+ break;
+ case CHOICES_SCALE_DOWN_BUTTON:
+ vChangeScaleFactor(pMouse->window, -5);
+ break;
+ default:
+ DBG_DEC(pMouse->icon);
+ break;
+ }
+ if (bCloseWindow) {
+ Error_CheckFatal(Wimp_CloseWindow(pMouse->window));
+ }
+ return TRUE;
+} /* end of bChoicesMouseClick */
+
+/*
+ * bChoicesKeyPressed - handle a key in the Choices window
+ */
+BOOL
+bChoicesKeyPressed(event_pollblock *pEvent, void *pvReference)
+{
+ icon_block tIcon;
+ caret_block *pCaret;
+ char *pcChar;
+ int iNumber;
+
+ DBG_MSG("bChoicesKeyPressed");
+
+ fail(pEvent == NULL);
+ fail(pEvent->type != event_KEY);
+
+ if (pEvent->data.key.code != '\r') {
+ Error_CheckFatal(Wimp_ProcessKey(pEvent->data.key.code));
+ return TRUE;
+ }
+
+ pCaret = &pEvent->data.key.caret;
+
+ Error_CheckFatal(Wimp_GetIconState(pCaret->window, pCaret->icon, &tIcon));
+ if (!tIcon.flags.data.text || !tIcon.flags.data.indirected) {
+ werr(1, "Icon %d must be indirected text", (int)pCaret->icon);
+ }
+ iNumber = (int)strtol(tIcon.data.indirecttext.buffer, &pcChar, 10);
+
+ switch(pCaret->icon) {
+ case CHOICES_BREAK_WRITEABLE:
+ if (*pcChar != '\0' && *pcChar != '\r') {
+ DBG_DEC(*pcChar);
+ iNumber = DEFAULT_SCREEN_WIDTH;
+ } else if (iNumber < MIN_SCREEN_WIDTH) {
+ iNumber = MIN_SCREEN_WIDTH;
+ } else if (iNumber > MAX_SCREEN_WIDTH) {
+ iNumber = MAX_SCREEN_WIDTH;
+ }
+ vSetParagraphBreak(pCaret->window, iNumber);
+ break;
+ case CHOICES_SCALE_WRITEABLE:
+ if (*pcChar != '\0' && *pcChar != '\r') {
+ DBG_DEC(*pcChar);
+ iNumber = DEFAULT_SCALE_FACTOR;
+ } else if (iNumber < MIN_SCALE_FACTOR) {
+ iNumber = MIN_SCALE_FACTOR;
+ } else if (iNumber > MAX_SCALE_FACTOR) {
+ iNumber = MAX_SCALE_FACTOR;
+ }
+ vSetScaleFactor(pCaret->window, iNumber);
+ break;
+ default:
+ DBG_DEC(pCaret->icon);
+ break;
+ }
+ return TRUE;
+} /* end of bChoicesKeyPressed */
+#endif /* __riscos */
diff --git a/sys/src/cmd/aux/antiword/out2window.c b/sys/src/cmd/aux/antiword/out2window.c
new file mode 100755
index 000000000..9bdacc314
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/out2window.c
@@ -0,0 +1,768 @@
+/*
+ * out2window.c
+ * Copyright (C) 1998-2005 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Output to a text window
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "antiword.h"
+
+/* Used for numbering the chapters */
+static unsigned int auiHdrCounter[9];
+
+
+/*
+ * vString2Diagram - put a string into a diagram
+ */
+static void
+vString2Diagram(diagram_type *pDiag, output_type *pAnchor)
+{
+ output_type *pOutput;
+ long lWidth;
+ USHORT usMaxFontSize;
+
+ TRACE_MSG("vString2Diagram");
+
+ fail(pDiag == NULL);
+ fail(pAnchor == NULL);
+
+ /* Compute the maximum fontsize in this string */
+ usMaxFontSize = MIN_FONT_SIZE;
+ for (pOutput = pAnchor; pOutput != NULL; pOutput = pOutput->pNext) {
+ if (pOutput->usFontSize > usMaxFontSize) {
+ usMaxFontSize = pOutput->usFontSize;
+ }
+ }
+
+ /* Goto the next line */
+ vMove2NextLine(pDiag, pAnchor->tFontRef, usMaxFontSize);
+
+ /* Output all substrings */
+ for (pOutput = pAnchor; pOutput != NULL; pOutput = pOutput->pNext) {
+ lWidth = lMilliPoints2DrawUnits(pOutput->lStringWidth);
+ vSubstring2Diagram(pDiag, pOutput->szStorage,
+ pOutput->tNextFree, lWidth, pOutput->ucFontColor,
+ pOutput->usFontStyle, pOutput->tFontRef,
+ pOutput->usFontSize, usMaxFontSize);
+ }
+
+ /* Goto the start of the line */
+ pDiag->lXleft = 0;
+ TRACE_MSG("leaving vString2Diagram");
+} /* end of vString2Diagram */
+
+/*
+ * vSetLeftIndentation - set the left indentation of the specified diagram
+ */
+void
+vSetLeftIndentation(diagram_type *pDiag, long lLeftIndentation)
+{
+ long lX;
+
+ TRACE_MSG("vSetLeftIndentation");
+
+ fail(pDiag == NULL);
+ fail(lLeftIndentation < 0);
+
+ lX = lMilliPoints2DrawUnits(lLeftIndentation);
+ if (lX > 0) {
+ pDiag->lXleft = lX;
+ } else {
+ pDiag->lXleft = 0;
+ }
+} /* end of vSetLeftIndentation */
+
+/*
+ * lComputeNetWidth - compute the net string width
+ */
+static long
+lComputeNetWidth(output_type *pAnchor)
+{
+ output_type *pTmp;
+ long lNetWidth;
+
+ TRACE_MSG("lComputeNetWidth");
+
+ fail(pAnchor == NULL);
+
+ /* Step 1: Count all but the last sub-string */
+ lNetWidth = 0;
+ for (pTmp = pAnchor; pTmp->pNext != NULL; pTmp = pTmp->pNext) {
+ fail(pTmp->lStringWidth < 0);
+ lNetWidth += pTmp->lStringWidth;
+ }
+ fail(pTmp == NULL);
+ fail(pTmp->pNext != NULL);
+
+ /* Step 2: remove the white-space from the end of the string */
+ while (pTmp->tNextFree != 0 &&
+ isspace((int)(UCHAR)pTmp->szStorage[pTmp->tNextFree - 1])) {
+ pTmp->szStorage[pTmp->tNextFree - 1] = '\0';
+ pTmp->tNextFree--;
+ NO_DBG_DEC(pTmp->lStringWidth);
+ pTmp->lStringWidth = lComputeStringWidth(
+ pTmp->szStorage,
+ pTmp->tNextFree,
+ pTmp->tFontRef,
+ pTmp->usFontSize);
+ NO_DBG_DEC(pTmp->lStringWidth);
+ }
+
+ /* Step 3: Count the last sub-string */
+ lNetWidth += pTmp->lStringWidth;
+ return lNetWidth;
+} /* end of lComputeNetWidth */
+
+/*
+ * iComputeHoles - compute number of holes
+ * (A hole is a number of whitespace characters followed by a
+ * non-whitespace character)
+ */
+static int
+iComputeHoles(output_type *pAnchor)
+{
+ output_type *pTmp;
+ size_t tIndex;
+ int iCounter;
+ BOOL bWasSpace, bIsSpace;
+
+ TRACE_MSG("iComputeHoles");
+
+ fail(pAnchor == NULL);
+
+ iCounter = 0;
+ bIsSpace = FALSE;
+ /* Count the holes */
+ for (pTmp = pAnchor; pTmp != NULL; pTmp = pTmp->pNext) {
+ fail(pTmp->tNextFree != strlen(pTmp->szStorage));
+ for (tIndex = 0; tIndex <= pTmp->tNextFree; tIndex++) {
+ bWasSpace = bIsSpace;
+ bIsSpace = isspace((int)(UCHAR)pTmp->szStorage[tIndex]);
+ if (bWasSpace && !bIsSpace) {
+ iCounter++;
+ }
+ }
+ }
+ return iCounter;
+} /* end of iComputeHoles */
+
+/*
+ * vAlign2Window - Align a string and insert it into the text
+ */
+void
+vAlign2Window(diagram_type *pDiag, output_type *pAnchor,
+ long lScreenWidth, UCHAR ucAlignment)
+{
+ long lNetWidth, lLeftIndentation;
+
+ TRACE_MSG("vAlign2Window");
+
+ fail(pDiag == NULL || pAnchor == NULL);
+ fail(lScreenWidth < lChar2MilliPoints(MIN_SCREEN_WIDTH));
+
+ lNetWidth = lComputeNetWidth(pAnchor);
+
+ if (lScreenWidth > lChar2MilliPoints(MAX_SCREEN_WIDTH) ||
+ lNetWidth <= 0) {
+ /*
+ * Screenwidth is "infinite", so no alignment is possible
+ * Don't bother to align an empty line
+ */
+ vString2Diagram(pDiag, pAnchor);
+ TRACE_MSG("leaving vAlign2Window #1");
+ return;
+ }
+
+ switch (ucAlignment) {
+ case ALIGNMENT_CENTER:
+ lLeftIndentation = (lScreenWidth - lNetWidth) / 2;
+ DBG_DEC_C(lLeftIndentation < 0, lLeftIndentation);
+ if (lLeftIndentation > 0) {
+ vSetLeftIndentation(pDiag, lLeftIndentation);
+ }
+ break;
+ case ALIGNMENT_RIGHT:
+ lLeftIndentation = lScreenWidth - lNetWidth;
+ DBG_DEC_C(lLeftIndentation < 0, lLeftIndentation);
+ if (lLeftIndentation > 0) {
+ vSetLeftIndentation(pDiag, lLeftIndentation);
+ }
+ break;
+ case ALIGNMENT_JUSTIFY:
+ case ALIGNMENT_LEFT:
+ default:
+ break;
+ }
+ vString2Diagram(pDiag, pAnchor);
+ TRACE_MSG("leaving vAlign2Window #2");
+} /* end of vAlign2Window */
+
+/*
+ * vJustify2Window - Justify a string and insert it into the text
+ */
+void
+vJustify2Window(diagram_type *pDiag, output_type *pAnchor,
+ long lScreenWidth, long lRightIndentation, UCHAR ucAlignment)
+{
+ output_type *pTmp;
+ char *pcNew, *pcOld, *szStorage;
+ long lNetWidth, lSpaceWidth, lToAdd;
+ int iFillerLen, iHoles;
+
+ TRACE_MSG("vJustify2Window");
+
+ fail(pDiag == NULL || pAnchor == NULL);
+ fail(lScreenWidth < MIN_SCREEN_WIDTH);
+ fail(lRightIndentation > 0);
+
+ if (ucAlignment != ALIGNMENT_JUSTIFY) {
+ vAlign2Window(pDiag, pAnchor, lScreenWidth, ucAlignment);
+ return;
+ }
+
+ lNetWidth = lComputeNetWidth(pAnchor);
+
+ if (lScreenWidth > lChar2MilliPoints(MAX_SCREEN_WIDTH) ||
+ lNetWidth <= 0) {
+ /*
+ * Screenwidth is "infinite", so justify is not possible
+ * Don't bother to justify an empty line
+ */
+ vString2Diagram(pDiag, pAnchor);
+ TRACE_MSG("leaving vJustify2Window #1");
+ return;
+ }
+
+ /* Justify */
+ fail(ucAlignment != ALIGNMENT_JUSTIFY);
+ lSpaceWidth = lComputeStringWidth(" ", 1,
+ pAnchor->tFontRef, pAnchor->usFontSize);
+ lToAdd = lScreenWidth -
+ lNetWidth -
+ lDrawUnits2MilliPoints(pDiag->lXleft) +
+ lRightIndentation;
+#if defined(DEBUG)
+ if (lToAdd / lSpaceWidth < -1) {
+ DBG_DEC(lSpaceWidth);
+ DBG_DEC(lToAdd);
+ DBG_DEC(lScreenWidth);
+ DBG_DEC(lNetWidth);
+ DBG_DEC(lDrawUnits2MilliPoints(pDiag->lXleft));
+ DBG_DEC(pDiag->lXleft);
+ DBG_DEC(lRightIndentation);
+ }
+#endif /* DEBUG */
+ lToAdd /= lSpaceWidth;
+ DBG_DEC_C(lToAdd < 0, lToAdd);
+ if (lToAdd <= 0) {
+ vString2Diagram(pDiag, pAnchor);
+ TRACE_MSG("leaving vJustify2Window #2");
+ return;
+ }
+
+ /* Justify by adding spaces */
+ iHoles = iComputeHoles(pAnchor);
+ for (pTmp = pAnchor; pTmp != NULL; pTmp = pTmp->pNext) {
+ fail(pTmp->tNextFree != strlen(pTmp->szStorage));
+ fail(lToAdd < 0);
+ szStorage = xmalloc(pTmp->tNextFree + (size_t)lToAdd + 1);
+ pcNew = szStorage;
+ for (pcOld = pTmp->szStorage; *pcOld != '\0'; pcOld++) {
+ *pcNew++ = *pcOld;
+ if (*pcOld == ' ' &&
+ *(pcOld + 1) != ' ' &&
+ iHoles > 0) {
+ iFillerLen = (int)(lToAdd / iHoles);
+ lToAdd -= iFillerLen;
+ iHoles--;
+ for (; iFillerLen > 0; iFillerLen--) {
+ *pcNew++ = ' ';
+ }
+ }
+ }
+ *pcNew = '\0';
+ pTmp->szStorage = xfree(pTmp->szStorage);
+ pTmp->szStorage = szStorage;
+ pTmp->tStorageSize = pTmp->tNextFree + (size_t)lToAdd + 1;
+ pTmp->lStringWidth +=
+ (pcNew - szStorage - (long)pTmp->tNextFree) *
+ lSpaceWidth;
+ fail(pcNew < szStorage);
+ pTmp->tNextFree = (size_t)(pcNew - szStorage);
+ fail(pTmp->tNextFree != strlen(pTmp->szStorage));
+ }
+ DBG_DEC_C(lToAdd != 0, lToAdd);
+ vString2Diagram(pDiag, pAnchor);
+ TRACE_MSG("leaving vJustify2Window #3");
+} /* end of vJustify2Window */
+
+/*
+ * vResetStyles - reset the style information variables
+ */
+void
+vResetStyles(void)
+{
+ TRACE_MSG("vResetStyles");
+
+ (void)memset(auiHdrCounter, 0, sizeof(auiHdrCounter));
+} /* end of vResetStyles */
+
+/*
+ * tStyle2Window - Add the style characters to the line
+ *
+ * Returns the length of the resulting string
+ */
+size_t
+tStyle2Window(char *szLine, size_t tLineSize, const style_block_type *pStyle,
+ const section_block_type *pSection)
+{
+ char *pcTxt;
+ size_t tIndex, tStyleIndex;
+ BOOL bNeedPrevLvl;
+ level_type_enum eNumType;
+ UCHAR ucNFC;
+
+ TRACE_MSG("tStyle2Window");
+
+ fail(szLine == NULL || pStyle == NULL || pSection == NULL);
+
+ if (pStyle->usIstd == 0 || pStyle->usIstd > 9) {
+ szLine[0] = '\0';
+ return 0;
+ }
+
+ /* Set the numbers */
+ tStyleIndex = (size_t)pStyle->usIstd - 1;
+ for (tIndex = 0; tIndex < 9; tIndex++) {
+ if (tIndex == tStyleIndex) {
+ auiHdrCounter[tIndex]++;
+ } else if (tIndex > tStyleIndex) {
+ auiHdrCounter[tIndex] = 0;
+ } else if (auiHdrCounter[tIndex] == 0) {
+ auiHdrCounter[tIndex] = 1;
+ }
+ }
+
+ eNumType = eGetNumType(pStyle->ucNumLevel);
+ if (eNumType != level_type_outline) {
+ szLine[0] = '\0';
+ return 0;
+ }
+
+ /* Print the numbers */
+ pcTxt = szLine;
+ bNeedPrevLvl = (pSection->usNeedPrevLvl & BIT(tStyleIndex)) != 0;
+ for (tIndex = 0; tIndex <= tStyleIndex; tIndex++) {
+ if (tIndex == tStyleIndex ||
+ (bNeedPrevLvl && tIndex < tStyleIndex)) {
+ if (pcTxt - szLine >= tLineSize - 25) {
+ /* Prevent a possible buffer overflow */
+ DBG_DEC(pcTxt - szLine);
+ DBG_DEC(tLineSize - 25);
+ DBG_FIXME();
+ szLine[0] = '\0';
+ return 0;
+ }
+ ucNFC = pSection->aucNFC[tIndex];
+ switch(ucNFC) {
+ case LIST_ARABIC_NUM:
+ case LIST_NUMBER_TXT:
+ case LIST_ORDINAL_TXT:
+ pcTxt += sprintf(pcTxt, "%u",
+ auiHdrCounter[tIndex]);
+ break;
+ case LIST_UPPER_ROMAN:
+ case LIST_LOWER_ROMAN:
+ pcTxt += tNumber2Roman(
+ auiHdrCounter[tIndex],
+ ucNFC == LIST_UPPER_ROMAN,
+ pcTxt);
+ break;
+ case LIST_UPPER_ALPHA:
+ case LIST_LOWER_ALPHA:
+ pcTxt += tNumber2Alpha(
+ auiHdrCounter[tIndex],
+ ucNFC == LIST_UPPER_ALPHA,
+ pcTxt);
+ break;
+ case LIST_OUTLINE_NUM:
+ pcTxt += sprintf(pcTxt, "%02u",
+ auiHdrCounter[tIndex]);
+ break;
+ default:
+ DBG_DEC(ucNFC);
+ DBG_FIXME();
+ pcTxt += sprintf(pcTxt, "%u",
+ auiHdrCounter[tIndex]);
+ break;
+ }
+ if (tIndex < tStyleIndex) {
+ *pcTxt++ = '.';
+ } else if (tIndex == tStyleIndex) {
+ *pcTxt++ = ' ';
+ }
+ }
+ }
+ *pcTxt = '\0';
+ NO_DBG_MSG_C((int)pStyle->usIstd >= 1 &&
+ (int)pStyle->usIstd <= 9 &&
+ eNumType != level_type_none &&
+ eNumType != level_type_outline, szLine);
+ NO_DBG_MSG_C(szLine[0] != '\0', szLine);
+ fail(pcTxt < szLine);
+ return (size_t)(pcTxt - szLine);
+} /* end of tStyle2Window */
+
+/*
+ * vRemoveRowEnd - remove the end of table row indicator
+ *
+ * Remove the double TABLE_SEPARATOR characters from the end of the string.
+ * Special: remove the TABLE_SEPARATOR, 0x0a sequence
+ */
+static void
+vRemoveRowEnd(char *szRowTxt)
+{
+ int iLastIndex;
+
+ TRACE_MSG("vRemoveRowEnd");
+
+ fail(szRowTxt == NULL || szRowTxt[0] == '\0');
+
+ iLastIndex = (int)strlen(szRowTxt) - 1;
+
+ if (szRowTxt[iLastIndex] == TABLE_SEPARATOR ||
+ szRowTxt[iLastIndex] == (char)0x0a) {
+ szRowTxt[iLastIndex] = '\0';
+ iLastIndex--;
+ } else {
+ DBG_HEX(szRowTxt[iLastIndex]);
+ }
+
+ if (iLastIndex >= 0 && szRowTxt[iLastIndex] == (char)0x0a) {
+ szRowTxt[iLastIndex] = '\0';
+ iLastIndex--;
+ }
+
+ if (iLastIndex >= 0 && szRowTxt[iLastIndex] == TABLE_SEPARATOR) {
+ szRowTxt[iLastIndex] = '\0';
+ return;
+ }
+
+ DBG_DEC(iLastIndex);
+ DBG_HEX(szRowTxt[iLastIndex]);
+ DBG_MSG(szRowTxt);
+} /* end of vRemoveRowEnd */
+
+/*
+ * tComputeStringLengthMax - max string length in relation to max column width
+ *
+ * Return the maximum string length
+ */
+static size_t
+tComputeStringLengthMax(const char *szString, size_t tColumnWidthMax)
+{
+ const char *pcTmp;
+ size_t tLengthMax, tLenPrev, tLen, tWidth;
+
+ TRACE_MSG("tComputeStringLengthMax");
+
+ fail(szString == NULL);
+ fail(tColumnWidthMax == 0);
+
+ pcTmp = strchr(szString, '\n');
+ if (pcTmp != NULL) {
+ tLengthMax = (size_t)(pcTmp - szString + 1);
+ } else {
+ tLengthMax = strlen(szString);
+ }
+ if (tLengthMax == 0) {
+ return 0;
+ }
+
+ tLen = 0;
+ tWidth = 0;
+ for (;;) {
+ tLenPrev = tLen;
+ tLen += tGetCharacterLength(szString + tLen);
+ DBG_DEC_C(tLen > tLengthMax, tLen);
+ DBG_DEC_C(tLen > tLengthMax, tLengthMax);
+ fail(tLen > tLengthMax);
+ tWidth = tCountColumns(szString, tLen);
+ if (tWidth > tColumnWidthMax) {
+ return tLenPrev;
+ }
+ if (tLen >= tLengthMax) {
+ return tLengthMax;
+ }
+ }
+} /* end of tComputeStringLengthMax */
+
+/*
+ * tGetBreakingPoint - get the number of bytes that fit the column
+ *
+ * Returns the number of bytes that fit the column
+ */
+static size_t
+tGetBreakingPoint(const char *szString,
+ size_t tLen, size_t tWidth, size_t tColumnWidthMax)
+{
+ int iIndex;
+
+ TRACE_MSG("tGetBreakingPoint");
+
+ fail(szString == NULL);
+ fail(tLen > strlen(szString));
+ fail(tWidth > tColumnWidthMax);
+
+ if (tWidth < tColumnWidthMax ||
+ (tWidth == tColumnWidthMax &&
+ (szString[tLen] == ' ' ||
+ szString[tLen] == '\n' ||
+ szString[tLen] == '\0'))) {
+ /* The string already fits, do nothing */
+ return tLen;
+ }
+ /* Search for a breaking point */
+ for (iIndex = (int)tLen - 1; iIndex >= 0; iIndex--) {
+ if (szString[iIndex] == ' ') {
+ return (size_t)iIndex;
+ }
+ }
+ /* No breaking point found, just fill the column */
+ return tLen;
+} /* end of tGetBreakingPoint */
+
+/*
+ * tComputeColumnWidthMax - compute the maximum column width
+ */
+static size_t
+tComputeColumnWidthMax(short sWidth, long lCharWidth, double dFactor)
+{
+ size_t tColumnWidthMax;
+
+ TRACE_MSG("tComputeColumnWidthMax");
+
+ fail(sWidth < 0);
+ fail(lCharWidth <= 0);
+ fail(dFactor <= 0.0);
+
+ tColumnWidthMax = (size_t)(
+ (lTwips2MilliPoints(sWidth) * dFactor + lCharWidth / 2.0) /
+ lCharWidth);
+ if (tColumnWidthMax == 0) {
+ /* Minimum column width */
+ return 1;
+ }
+ if (tColumnWidthMax > 1) {
+ /* Make room for the TABLE_SEPARATOR_CHAR */
+ tColumnWidthMax--;
+ }
+ NO_DBG_DEC(tColumnWidthMax);
+ return tColumnWidthMax;
+} /* end of tComputeColumnWidthMax */
+
+/*
+ * vTableRow2Window - put a table row into a diagram
+ */
+void
+vTableRow2Window(diagram_type *pDiag, output_type *pOutput,
+ const row_block_type *pRowInfo,
+ conversion_type eConversionType, int iParagraphBreak)
+{
+ output_type tRow;
+ char *aszColTxt[TABLE_COLUMN_MAX];
+ char *szLine, *pcTxt;
+ double dMagnify;
+ long lCharWidthLarge, lCharWidthSmall;
+ size_t tColumnWidthTotal, atColumnWidthMax[TABLE_COLUMN_MAX];
+ size_t tSize, tColumnWidthMax, tWidth, tLen;
+ int iIndex, iNbrOfColumns, iTmp;
+ BOOL bNotReady;
+
+ TRACE_MSG("vTableRow2Window");
+
+ fail(pDiag == NULL || pOutput == NULL || pRowInfo == NULL);
+ fail(pOutput->szStorage == NULL);
+ fail(pOutput->pNext != NULL);
+ fail(iParagraphBreak < 0);
+
+ /* Character sizes */
+ lCharWidthLarge = lComputeStringWidth("W", 1,
+ pOutput->tFontRef, pOutput->usFontSize);
+ NO_DBG_DEC(lCharWidthLarge);
+ lCharWidthSmall = lComputeStringWidth("i", 1,
+ pOutput->tFontRef, pOutput->usFontSize);
+ NO_DBG_DEC(lCharWidthSmall);
+ /* For the time being: use a fixed width font */
+ fail(lCharWidthLarge != lCharWidthSmall);
+
+ vRemoveRowEnd(pOutput->szStorage);
+
+ /* Split the row text into a set of column texts */
+ aszColTxt[0] = pOutput->szStorage;
+ for (iNbrOfColumns = 1;
+ iNbrOfColumns < TABLE_COLUMN_MAX;
+ iNbrOfColumns++) {
+ aszColTxt[iNbrOfColumns] =
+ strchr(aszColTxt[iNbrOfColumns - 1],
+ TABLE_SEPARATOR);
+ if (aszColTxt[iNbrOfColumns] == NULL) {
+ break;
+ }
+ *aszColTxt[iNbrOfColumns] = '\0';
+ aszColTxt[iNbrOfColumns]++;
+ NO_DBG_DEC(iNbrOfColumns);
+ NO_DBG_MSG(aszColTxt[iNbrOfColumns]);
+ }
+
+ /* Work around a bug in Word */
+ while (iNbrOfColumns > (int)pRowInfo->ucNumberOfColumns &&
+ pRowInfo->asColumnWidth[iNbrOfColumns] == 0) {
+ iNbrOfColumns--;
+ }
+
+ DBG_DEC_C(iNbrOfColumns != (int)pRowInfo->ucNumberOfColumns,
+ iNbrOfColumns);
+ DBG_DEC_C(iNbrOfColumns != (int)pRowInfo->ucNumberOfColumns,
+ pRowInfo->ucNumberOfColumns);
+ if (iNbrOfColumns != (int)pRowInfo->ucNumberOfColumns) {
+ werr(0, "Skipping an unmatched table row");
+ return;
+ }
+
+#if defined(__FULL_TEXT_SEARCH)
+ /* No table formatting: use for full-text search (untested) */
+ for (iIndex = 0; iIndex < iNbrOfColumns; iIndex++) {
+ fprintf(pDiag->pOutFile, "%s\n" , aszColTxt[iIndex]);
+ }
+#else
+ if (bAddTableRow(pDiag, aszColTxt, iNbrOfColumns,
+ pRowInfo->asColumnWidth, pRowInfo->ucBorderInfo)) {
+ /* All work has been done */
+ return;
+ }
+
+ /* Fill the table with maximum column widths */
+ if (eConversionType == conversion_text ||
+ eConversionType == conversion_fmt_text) {
+ if (iParagraphBreak == 0 ||
+ iParagraphBreak >= MAX_SCREEN_WIDTH) {
+ dMagnify = (double)MAX_SCREEN_WIDTH;
+ } else if (iParagraphBreak <= MIN_SCREEN_WIDTH) {
+ dMagnify = (double)MIN_SCREEN_WIDTH;
+ } else {
+ dMagnify = (double)iParagraphBreak;
+ }
+ dMagnify /= (double)DEFAULT_SCREEN_WIDTH;
+ DBG_FLT_C(dMagnify < 0.99 || dMagnify > 1.01, dMagnify);
+ } else {
+ dMagnify = 1.0;
+ }
+ tColumnWidthTotal = 0;
+ for (iIndex = 0; iIndex < iNbrOfColumns; iIndex++) {
+ atColumnWidthMax[iIndex] = tComputeColumnWidthMax(
+ pRowInfo->asColumnWidth[iIndex],
+ lCharWidthLarge,
+ dMagnify);
+ tColumnWidthTotal += atColumnWidthMax[iIndex];
+ }
+
+ /*
+ * Get enough space for the row.
+ * Worst case: three bytes per UTF-8 character
+ */
+ tSize = 3 * (1 + tColumnWidthTotal + (size_t)iNbrOfColumns + 3);
+ szLine = xmalloc(tSize);
+
+ do {
+ /* Print one line of a table row */
+ bNotReady = FALSE;
+ pcTxt = szLine;
+ *pcTxt++ = TABLE_SEPARATOR_CHAR;
+ for (iIndex = 0; iIndex < iNbrOfColumns; iIndex++) {
+ tColumnWidthMax = atColumnWidthMax[iIndex];
+ if (aszColTxt[iIndex] == NULL) {
+ /* Add an empty column */
+ for (iTmp = 0;
+ iTmp < (int)tColumnWidthMax;
+ iTmp++) {
+ *pcTxt++ = (char)FILLER_CHAR;
+ }
+ *pcTxt++ = TABLE_SEPARATOR_CHAR;
+ *pcTxt = '\0';
+ continue;
+ }
+ /* Compute the length and width of the column text */
+ tLen = tComputeStringLengthMax(
+ aszColTxt[iIndex], tColumnWidthMax);
+ NO_DBG_DEC(tLen);
+ while (tLen != 0 &&
+ (aszColTxt[iIndex][tLen - 1] == '\n' ||
+ aszColTxt[iIndex][tLen - 1] == ' ')) {
+ aszColTxt[iIndex][tLen - 1] = ' ';
+ tLen--;
+ }
+ tWidth = tCountColumns(aszColTxt[iIndex], tLen);
+ fail(tWidth > tColumnWidthMax);
+ tLen = tGetBreakingPoint(aszColTxt[iIndex],
+ tLen, tWidth, tColumnWidthMax);
+ tWidth = tCountColumns(aszColTxt[iIndex], tLen);
+ if (tLen == 0 && *aszColTxt[iIndex] == '\0') {
+ /* No text at all */
+ aszColTxt[iIndex] = NULL;
+ } else {
+ /* Add the text */
+ pcTxt += sprintf(pcTxt,
+ "%.*s", (int)tLen, aszColTxt[iIndex]);
+ if (tLen == 0 && *aszColTxt[iIndex] != ' ') {
+ tLen = tGetCharacterLength(
+ aszColTxt[iIndex]);
+ DBG_CHR(*aszColTxt[iIndex]);
+ DBG_FIXME();
+ fail(tLen == 0);
+ }
+ aszColTxt[iIndex] += tLen;
+ while (*aszColTxt[iIndex] == ' ') {
+ aszColTxt[iIndex]++;
+ }
+ if (*aszColTxt[iIndex] == '\0') {
+ /* This row is now complete */
+ aszColTxt[iIndex] = NULL;
+ } else {
+ /* This row needs more lines */
+ bNotReady = TRUE;
+ }
+ }
+ /* Fill up the rest */
+ for (iTmp = 0;
+ iTmp < (int)tColumnWidthMax - (int)tWidth;
+ iTmp++) {
+ *pcTxt++ = (char)FILLER_CHAR;
+ }
+ /* End of column */
+ *pcTxt++ = TABLE_SEPARATOR_CHAR;
+ *pcTxt = '\0';
+ }
+ /* Output the table row line */
+ *pcTxt = '\0';
+ tRow = *pOutput;
+ tRow.szStorage = szLine;
+ fail(pcTxt < szLine);
+ tRow.tNextFree = (size_t)(pcTxt - szLine);
+ tRow.lStringWidth = lComputeStringWidth(
+ tRow.szStorage,
+ tRow.tNextFree,
+ tRow.tFontRef,
+ tRow.usFontSize);
+ vString2Diagram(pDiag, &tRow);
+ TRACE_MSG("after vString2Diagram in vTableRow2Window");
+ } while (bNotReady);
+ /* Clean up before you leave */
+ szLine = xfree(szLine);
+ TRACE_MSG("leaving vTableRow2Window");
+#endif /* __FULL_TEXT_SEARCH */
+} /* end of vTableRow2Window */
diff --git a/sys/src/cmd/aux/antiword/output.c b/sys/src/cmd/aux/antiword/output.c
new file mode 100755
index 000000000..b2757ab9a
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/output.c
@@ -0,0 +1,538 @@
+/*
+ * output.c
+ * Copyright (C) 2002-2004 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Generic output generating functions
+ */
+
+#include "antiword.h"
+
+static conversion_type eConversionType = conversion_unknown;
+static encoding_type eEncoding = encoding_neutral;
+
+
+/*
+ * vPrologue1 - get options and call a specific initialization
+ */
+static void
+vPrologue1(diagram_type *pDiag, const char *szTask, const char *szFilename)
+{
+ options_type tOptions;
+
+ fail(pDiag == NULL);
+ fail(szTask == NULL || szTask[0] == '\0');
+
+ vGetOptions(&tOptions);
+ eConversionType = tOptions.eConversionType;
+ eEncoding = tOptions.eEncoding;
+
+ switch (eConversionType) {
+ case conversion_text:
+ vPrologueTXT(pDiag, &tOptions);
+ break;
+ case conversion_fmt_text:
+ vPrologueFMT(pDiag, &tOptions);
+ break;
+ case conversion_ps:
+ vProloguePS(pDiag, szTask, szFilename, &tOptions);
+ break;
+ case conversion_xml:
+ vPrologueXML(pDiag, &tOptions);
+ break;
+ case conversion_pdf:
+ vProloguePDF(pDiag, szTask, &tOptions);
+ break;
+ default:
+ DBG_DEC(eConversionType);
+ break;
+ }
+} /* end of vPrologue1 */
+
+/*
+ * vEpilogue - clean up after everything is done
+ */
+static void
+vEpilogue(diagram_type *pDiag)
+{
+ switch (eConversionType) {
+ case conversion_text:
+ case conversion_fmt_text:
+ vEpilogueTXT(pDiag->pOutFile);
+ break;
+ case conversion_ps:
+ vEpiloguePS(pDiag);
+ break;
+ case conversion_xml:
+ vEpilogueXML(pDiag);
+ break;
+ case conversion_pdf:
+ vEpiloguePDF(pDiag);
+ break;
+ default:
+ DBG_DEC(eConversionType);
+ break;
+ }
+} /* end of vEpilogue */
+
+/*
+ * vImagePrologue - perform image initialization
+ */
+void
+vImagePrologue(diagram_type *pDiag, const imagedata_type *pImg)
+{
+ switch (eConversionType) {
+ case conversion_text:
+ case conversion_fmt_text:
+ break;
+ case conversion_ps:
+ vImageProloguePS(pDiag, pImg);
+ break;
+ case conversion_xml:
+ break;
+ case conversion_pdf:
+ vImageProloguePDF(pDiag, pImg);
+ break;
+ default:
+ DBG_DEC(eConversionType);
+ break;
+ }
+} /* end of vImagePrologue */
+
+/*
+ * vImageEpilogue - clean up an image
+ */
+void
+vImageEpilogue(diagram_type *pDiag)
+{
+ switch (eConversionType) {
+ case conversion_text:
+ case conversion_fmt_text:
+ break;
+ case conversion_ps:
+ vImageEpiloguePS(pDiag);
+ break;
+ case conversion_xml:
+ break;
+ case conversion_pdf:
+ vImageEpiloguePDF(pDiag);
+ break;
+ default:
+ DBG_DEC(eConversionType);
+ break;
+ }
+} /* end of vImageEpilogue */
+
+/*
+ * bAddDummyImage - add a dummy image
+ *
+ * return TRUE when successful, otherwise FALSE
+ */
+BOOL
+bAddDummyImage(diagram_type *pDiag, const imagedata_type *pImg)
+{
+ switch (eConversionType) {
+ case conversion_text:
+ case conversion_fmt_text:
+ return FALSE;
+ case conversion_ps:
+ return bAddDummyImagePS(pDiag, pImg);
+ case conversion_xml:
+ return FALSE;
+ case conversion_pdf:
+ return bAddDummyImagePDF(pDiag, pImg);
+ default:
+ DBG_DEC(eConversionType);
+ return FALSE;
+ }
+} /* end of bAddDummyImage */
+
+/*
+ * pCreateDiagram - create and initialize a diagram
+ *
+ * remark: does not return if the diagram can't be created
+ */
+diagram_type *
+pCreateDiagram(const char *szTask, const char *szFilename)
+{
+ diagram_type *pDiag;
+
+ fail(szTask == NULL || szTask[0] == '\0');
+ DBG_MSG("pCreateDiagram");
+
+ /* Get the necessary memory */
+ pDiag = xmalloc(sizeof(diagram_type));
+ /* Initialization */
+ pDiag->pOutFile = stdout;
+ vPrologue1(pDiag, szTask, szFilename);
+ /* Return success */
+ return pDiag;
+} /* end of pCreateDiagram */
+
+/*
+ * vDestroyDiagram - remove a diagram by freeing the memory it uses
+ */
+void
+vDestroyDiagram(diagram_type *pDiag)
+{
+ DBG_MSG("vDestroyDiagram");
+
+ fail(pDiag == NULL);
+
+ if (pDiag == NULL) {
+ return;
+ }
+ vEpilogue(pDiag);
+ pDiag = xfree(pDiag);
+} /* end of vDestroyDiagram */
+
+/*
+ * vPrologue2 - call a specific initialization
+ */
+void
+vPrologue2(diagram_type *pDiag, int iWordVersion)
+{
+ switch (eConversionType) {
+ case conversion_text:
+ case conversion_fmt_text:
+ break;
+ case conversion_ps:
+ vAddFontsPS(pDiag);
+ break;
+ case conversion_xml:
+ vCreateBookIntro(pDiag, iWordVersion);
+ break;
+ case conversion_pdf:
+ vCreateInfoDictionary(pDiag, iWordVersion);
+ vAddFontsPDF(pDiag);
+ break;
+ default:
+ DBG_DEC(eConversionType);
+ break;
+ }
+} /* end of vPrologue2 */
+
+/*
+ * vMove2NextLine - move to the next line
+ */
+void
+vMove2NextLine(diagram_type *pDiag, drawfile_fontref tFontRef,
+ USHORT usFontSize)
+{
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
+
+ switch (eConversionType) {
+ case conversion_text:
+ case conversion_fmt_text:
+ vMove2NextLineTXT(pDiag);
+ break;
+ case conversion_ps:
+ vMove2NextLinePS(pDiag, usFontSize);
+ break;
+ case conversion_xml:
+ vMove2NextLineXML(pDiag);
+ break;
+ case conversion_pdf:
+ vMove2NextLinePDF(pDiag, usFontSize);
+ break;
+ default:
+ DBG_DEC(eConversionType);
+ break;
+ }
+} /* end of vMove2NextLine */
+
+/*
+ * vSubstring2Diagram - put a sub string into a diagram
+ */
+void
+vSubstring2Diagram(diagram_type *pDiag,
+ char *szString, size_t tStringLength, long lStringWidth,
+ UCHAR ucFontColor, USHORT usFontstyle, drawfile_fontref tFontRef,
+ USHORT usFontSize, USHORT usMaxFontSize)
+{
+ switch (eConversionType) {
+ case conversion_text:
+ vSubstringTXT(pDiag, szString, tStringLength, lStringWidth);
+ break;
+ case conversion_fmt_text:
+ vSubstringFMT(pDiag, szString, tStringLength, lStringWidth,
+ usFontstyle);
+ break;
+ case conversion_ps:
+ vSubstringPS(pDiag, szString, tStringLength, lStringWidth,
+ ucFontColor, usFontstyle, tFontRef,
+ usFontSize, usMaxFontSize);
+ break;
+ case conversion_xml:
+ vSubstringXML(pDiag, szString, tStringLength, lStringWidth,
+ usFontstyle);
+ break;
+ case conversion_pdf:
+ vSubstringPDF(pDiag, szString, tStringLength, lStringWidth,
+ ucFontColor, usFontstyle, tFontRef,
+ usFontSize, usMaxFontSize);
+ break;
+ default:
+ DBG_DEC(eConversionType);
+ break;
+ }
+ pDiag->lXleft += lStringWidth;
+} /* end of vSubstring2Diagram */
+
+/*
+ * Create a start of paragraph (phase 1)
+ * Before indentation, list numbering, bullets etc.
+ */
+void
+vStartOfParagraph1(diagram_type *pDiag, long lBeforeIndentation)
+{
+ fail(pDiag == NULL);
+
+ switch (eConversionType) {
+ case conversion_text:
+ case conversion_fmt_text:
+ vStartOfParagraphTXT(pDiag, lBeforeIndentation);
+ break;
+ case conversion_ps:
+ vStartOfParagraphPS(pDiag, lBeforeIndentation);
+ break;
+ case conversion_xml:
+ break;
+ case conversion_pdf:
+ vStartOfParagraphPDF(pDiag, lBeforeIndentation);
+ break;
+ default:
+ DBG_DEC(eConversionType);
+ break;
+ }
+} /* end of vStartOfParagraph1 */
+
+/*
+ * Create a start of paragraph (phase 2)
+ * After indentation, list numbering, bullets etc.
+ */
+void
+vStartOfParagraph2(diagram_type *pDiag)
+{
+ fail(pDiag == NULL);
+
+ switch (eConversionType) {
+ case conversion_text:
+ case conversion_fmt_text:
+ break;
+ case conversion_ps:
+ break;
+ case conversion_xml:
+ vStartOfParagraphXML(pDiag, 1);
+ break;
+ case conversion_pdf:
+ break;
+ default:
+ DBG_DEC(eConversionType);
+ break;
+ }
+} /* end of vStartOfParagraph2 */
+
+/*
+ * Create an end of paragraph
+ */
+void
+vEndOfParagraph(diagram_type *pDiag,
+ drawfile_fontref tFontRef, USHORT usFontSize, long lAfterIndentation)
+{
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
+ fail(lAfterIndentation < 0);
+
+ switch (eConversionType) {
+ case conversion_text:
+ case conversion_fmt_text:
+ vEndOfParagraphTXT(pDiag, lAfterIndentation);
+ break;
+ case conversion_ps:
+ vEndOfParagraphPS(pDiag, usFontSize, lAfterIndentation);
+ break;
+ case conversion_xml:
+ vEndOfParagraphXML(pDiag, 1);
+ break;
+ case conversion_pdf:
+ vEndOfParagraphPDF(pDiag, usFontSize, lAfterIndentation);
+ break;
+ default:
+ DBG_DEC(eConversionType);
+ break;
+ }
+} /* end of vEndOfParagraph */
+
+/*
+ * Create an end of page
+ */
+void
+vEndOfPage(diagram_type *pDiag, long lAfterIndentation, BOOL bNewSection)
+{
+ switch (eConversionType) {
+ case conversion_text:
+ case conversion_fmt_text:
+ vEndOfPageTXT(pDiag, lAfterIndentation);
+ break;
+ case conversion_ps:
+ vEndOfPagePS(pDiag, bNewSection);
+ break;
+ case conversion_xml:
+ vEndOfPageXML(pDiag);
+ break;
+ case conversion_pdf:
+ vEndOfPagePDF(pDiag, bNewSection);
+ break;
+ default:
+ DBG_DEC(eConversionType);
+ break;
+ }
+} /* end of vEndOfPage */
+
+/*
+ * vSetHeaders - set the headers
+ */
+void
+vSetHeaders(diagram_type *pDiag, USHORT usIstd)
+{
+ switch (eConversionType) {
+ case conversion_text:
+ case conversion_fmt_text:
+ break;
+ case conversion_ps:
+ break;
+ case conversion_xml:
+ vSetHeadersXML(pDiag, usIstd);
+ break;
+ case conversion_pdf:
+ break;
+ default:
+ DBG_DEC(eConversionType);
+ break;
+ }
+} /* end of vSetHeaders */
+
+/*
+ * Create a start of list
+ */
+void
+vStartOfList(diagram_type *pDiag, UCHAR ucNFC, BOOL bIsEndOfTable)
+{
+ switch (eConversionType) {
+ case conversion_text:
+ case conversion_fmt_text:
+ break;
+ case conversion_ps:
+ break;
+ case conversion_xml:
+ vStartOfListXML(pDiag, ucNFC, bIsEndOfTable);
+ break;
+ case conversion_pdf:
+ break;
+ default:
+ DBG_DEC(eConversionType);
+ break;
+ }
+} /* end of vStartOfList */
+
+/*
+ * Create an end of list
+ */
+void
+vEndOfList(diagram_type *pDiag)
+{
+ switch (eConversionType) {
+ case conversion_text:
+ case conversion_fmt_text:
+ break;
+ case conversion_ps:
+ break;
+ case conversion_xml:
+ vEndOfListXML(pDiag);
+ break;
+ case conversion_pdf:
+ break;
+ default:
+ DBG_DEC(eConversionType);
+ break;
+ }
+} /* end of vEndOfList */
+
+/*
+ * Create a start of a list item
+ */
+void
+vStartOfListItem(diagram_type *pDiag, BOOL bNoMarks)
+{
+ switch (eConversionType) {
+ case conversion_text:
+ case conversion_fmt_text:
+ break;
+ case conversion_ps:
+ break;
+ case conversion_xml:
+ vStartOfListItemXML(pDiag, bNoMarks);
+ break;
+ case conversion_pdf:
+ break;
+ default:
+ DBG_DEC(eConversionType);
+ break;
+ }
+} /* end of vStartOfListItem */
+
+/*
+ * Create an end of a table
+ */
+void
+vEndOfTable(diagram_type *pDiag)
+{
+ switch (eConversionType) {
+ case conversion_text:
+ case conversion_fmt_text:
+ break;
+ case conversion_ps:
+ break;
+ case conversion_xml:
+ vEndOfTableXML(pDiag);
+ break;
+ case conversion_pdf:
+ break;
+ default:
+ DBG_DEC(eConversionType);
+ break;
+ }
+} /* end of vEndOfTable */
+
+/*
+ * Add a table row
+ *
+ * Returns TRUE when conversion type is XML
+ */
+BOOL
+bAddTableRow(diagram_type *pDiag, char **aszColTxt,
+ int iNbrOfColumns, const short *asColumnWidth, UCHAR ucBorderInfo)
+{
+ switch (eConversionType) {
+ case conversion_text:
+ case conversion_fmt_text:
+ break;
+ case conversion_ps:
+ break;
+ case conversion_xml:
+ vAddTableRowXML(pDiag, aszColTxt,
+ iNbrOfColumns, asColumnWidth,
+ ucBorderInfo);
+ return TRUE;
+ case conversion_pdf:
+ break;
+ default:
+ DBG_DEC(eConversionType);
+ break;
+ }
+ return FALSE;
+} /* end of bAddTableRow */
diff --git a/sys/src/cmd/aux/antiword/pdf.c b/sys/src/cmd/aux/antiword/pdf.c
new file mode 100755
index 000000000..85b710117
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/pdf.c
@@ -0,0 +1,1148 @@
+/*
+ * pdf.c
+ * Copyright (C) 2003-2005 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Functions to deal with the Adobe Portable Document Format (pdf)
+ *
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include "version.h"
+#include "antiword.h"
+
+
+/* Constants for the file positions */
+#define INITIAL_LOCATION_SIZE 20
+#define INITIAL_PAGEOBJECT_SIZE 5
+#if defined(DEBUG)
+#define EXTENSION_ARRAY_SIZE 10
+#else
+#define EXTENSION_ARRAY_SIZE 30
+#endif /* DEBUG */
+
+/* The character set */
+static encoding_type eEncoding = encoding_neutral;
+/* Current creator for a PDF header */
+static const char *szProducer = NULL;
+/* The height and width of a PDF page (in DrawUnits) */
+static long lPageHeight = LONG_MAX;
+static long lPageWidth = LONG_MAX;
+/* The height of the footer on the current page (in DrawUnits) */
+static long lFooterHeight = 0;
+/* Inside a footer (to prevent an infinite loop when the footer is too big) */
+static BOOL bInFtrSpace = FALSE;
+/* Current font information */
+static drawfile_fontref tFontRefCurr = (drawfile_fontref)-1;
+static USHORT usFontSizeCurr = 0;
+static int iFontColorCurr = -1;
+/* Current vertical position information */
+static long lYtopCurr = -1;
+/* Image counter */
+static int iImageCount = 0;
+/* Section index */
+static int iSectionIndex = 0;
+/* Are we on the first page of the section? */
+static BOOL bFirstInSection = TRUE;
+/* File positions */
+static long lFilePosition = 0;
+static long *alLocation = NULL;
+static size_t tLocations = 0;
+static int iMaxLocationNumber = 0;
+/* File position at the start of a page */
+static long lStreamStart = -1;
+/* Page objects */
+static int *aiPageObject = NULL;
+static int iPageCount = 0;
+static size_t tMaxPageObjects = 0;
+/* Current object number */
+/* 1 = root; 2 = info; 3 = pages; 4 = encoding; 5-16 = fonts; 17 = resources */
+static int iObjectNumberCurr = 17;
+
+static void vMoveTo(diagram_type *, long);
+
+static const struct {
+ const char *szPDFname;
+ const char *szPSname;
+} atFontname[] = {
+ { "Courier", FONT_MONOSPACED_PLAIN },
+ { "Courier-Bold", FONT_MONOSPACED_BOLD },
+ { "Courier-Oblique", FONT_MONOSPACED_ITALIC },
+ { "Courier-BoldOblique", FONT_MONOSPACED_BOLDITALIC },
+ { "Helvetica", FONT_SANS_SERIF_PLAIN },
+ { "Helvetica-Bold", FONT_SANS_SERIF_BOLD },
+ { "Helvetica-Oblique", FONT_SANS_SERIF_ITALIC },
+ { "Helvetica-BoldOblique", FONT_SANS_SERIF_BOLDITALIC },
+ { "Times-Roman", FONT_SERIF_PLAIN },
+ { "Times-Bold", FONT_SERIF_BOLD },
+ { "Times-Italic", FONT_SERIF_ITALIC },
+ { "Times-BoldItalic", FONT_SERIF_BOLDITALIC },
+};
+
+static const char *iso_8859_1[] = {
+"128 /Euro",
+"140 /ellipsis /trademark /perthousand /bullet",
+" /quoteleft /quoteright /guilsinglleft /guilsinglright",
+" /quotedblleft /quotedblright /quotedblbase /endash /emdash",
+" /minus /OE /oe /dagger /daggerdbl /fi /fl",
+"160 /space /exclamdown /cent /sterling /currency",
+" /yen /brokenbar /section /dieresis /copyright",
+" /ordfeminine /guillemotleft /logicalnot /hyphen /registered",
+" /macron /degree /plusminus /twosuperior /threesuperior",
+" /acute /mu /paragraph /periodcentered /cedilla",
+" /onesuperior /ordmasculine /guillemotright /onequarter",
+" /onehalf /threequarters /questiondown /Agrave /Aacute",
+" /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla",
+" /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute",
+" /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute",
+" /Ocircumflex /Otilde /Odieresis /multiply /Oslash",
+" /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn",
+" /germandbls /agrave /aacute /acircumflex /atilde",
+" /adieresis /aring /ae /ccedilla /egrave /eacute",
+" /ecircumflex /edieresis /igrave /iacute /icircumflex",
+" /idieresis /eth /ntilde /ograve /oacute /ocircumflex",
+" /otilde /odieresis /divide /oslash /ugrave /uacute",
+" /ucircumflex /udieresis /yacute /thorn /ydieresis",
+};
+
+static const char *iso_8859_2[] = {
+"160 /space /Aogonek /breve /Lslash /currency /Lcaron",
+" /Sacute /section /dieresis /Scaron /Scommaaccent",
+" /Tcaron /Zacute /hyphen /Zcaron /Zdotaccent /degree",
+" /aogonek /ogonek /lslash /acute /lcaron /sacute",
+" /caron /cedilla /scaron /scommaaccent /tcaron",
+" /zacute /hungarumlaut /zcaron /zdotaccent /Racute",
+" /Aacute /Acircumflex /Abreve /Adieresis /Lacute",
+" /Cacute /Ccedilla /Ccaron /Eacute /Eogonek",
+" /Edieresis /Ecaron /Iacute /Icircumflex /Dcaron",
+" /.notdef /Nacute /Ncaron /Oacute /Ocircumflex",
+" /Ohungarumlaut /Odieresis /multiply /Rcaron /Uring",
+" /Uacute /Uhungarumlaut /Udieresis /Yacute /Tcommaaccent",
+" /germandbls /racute /aacute /acircumflex /abreve",
+" /adieresis /lacute /cacute /ccedilla /ccaron /eacute",
+" /eogonek /edieresis /ecaron /iacute /icircumflex",
+" /dcaron /.notdef /nacute /ncaron /oacute /ocircumflex",
+" /ohungarumlaut /odieresis /divide /rcaron /uring",
+" /uacute /uhungarumlaut /udieresis /yacute /tcommaaccent",
+" /dotaccent",
+};
+
+
+/*
+ * tGetFontIndex - get the font index
+ */
+static size_t
+tGetFontIndex(drawfile_fontref tFontRef)
+{
+ const char *szFontname;
+ size_t tIndex;
+
+ /* Get the font name */
+ szFontname = szGetFontname(tFontRef);
+ fail(szFontname == NULL);
+ if (szFontname == NULL) {
+ return 0;
+ }
+
+ /* Find the name in the table */
+ for (tIndex = 0; tIndex < elementsof(atFontname); tIndex++) {
+ if (STRCEQ(atFontname[tIndex].szPSname, szFontname)) {
+ return tIndex;
+ }
+ }
+ /* Not found */
+ DBG_DEC(tFontRef);
+ DBG_MSG(szFontname);
+ return 0;
+} /* end of tGetFontIndex */
+
+/*
+ * vSetLocation - store the location of objects
+ */
+static void
+vSetLocation(int iLocationNumber)
+{
+ fail(iLocationNumber <= 0);
+
+ if ((size_t)iLocationNumber >= tLocations) {
+ /* Extend and set to zero */
+ tLocations += EXTENSION_ARRAY_SIZE;
+ alLocation = xrealloc(alLocation, tLocations * sizeof(long));
+ memset(alLocation + tLocations - EXTENSION_ARRAY_SIZE,
+ 0,
+ EXTENSION_ARRAY_SIZE * sizeof(long));
+ DBG_DEC(tLocations);
+ }
+ if (iLocationNumber > iMaxLocationNumber) {
+ iMaxLocationNumber = iLocationNumber;
+ }
+
+ DBG_DEC_C((size_t)iLocationNumber >= tLocations, iLocationNumber);
+ DBG_DEC_C((size_t)iLocationNumber >= tLocations, tLocations);
+ fail((size_t)iLocationNumber >= tLocations);
+
+ alLocation[iLocationNumber] = lFilePosition;
+} /* end of vSetLocation */
+
+/*
+ * vFillNextPageObject - fil the next page object with the current object number
+ */
+static void
+vFillNextPageObject(void)
+{
+ iPageCount++;
+ if ((size_t)iPageCount >= tMaxPageObjects) {
+ /* Extend the array */
+ tMaxPageObjects += EXTENSION_ARRAY_SIZE;
+ aiPageObject = xrealloc(aiPageObject,
+ tMaxPageObjects * sizeof(int));
+ DBG_DEC(tMaxPageObjects);
+ }
+ aiPageObject[iPageCount] = iObjectNumberCurr;
+} /* end of vFillNextPageObject */
+
+/*
+ * vFPprintf - printf and update the fileposition
+ *
+ * called with arguments like fprintf(3)
+ */
+static void
+vFPprintf(FILE *pOutFile, const char *szFormat, ...)
+{
+ va_list tArg;
+
+ va_start(tArg, szFormat);
+ lFilePosition += vfprintf(pOutFile, szFormat, tArg);
+ va_end(tArg);
+} /* end of vFPprintf */
+
+/*
+ * vCreateInfoDictionary - create the document information dictionary
+ */
+void
+vCreateInfoDictionary(diagram_type *pDiag, int iWordVersion)
+{
+ FILE *pOutFile;
+ const char *szTitle, *szAuthor, *szSubject, *szCreator;
+ const char *szCreationDate, *szModDate;
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(iWordVersion < 0);
+ fail(szProducer == NULL || szProducer[0] == '\0');
+
+ szTitle = szGetTitle();
+ szAuthor = szGetAuthor();
+ szSubject = szGetSubject();
+ szCreationDate = szGetCreationDate();
+ szModDate = szGetModDate();
+
+ switch (iWordVersion) {
+ case 0: szCreator = "Word for DOS"; break;
+ case 1: szCreator = "WinWord 1.x"; break;
+ case 2: szCreator = "WinWord 2.0"; break;
+ case 4: szCreator = "MacWord 4"; break;
+ case 5: szCreator = "MacWord 5"; break;
+ case 6: szCreator = "Word 6"; break;
+ case 7: szCreator = "Word 7/95"; break;
+ case 8: szCreator = "Word 97 or later"; break;
+ default: szCreator = NULL; break;
+ }
+
+ pOutFile = pDiag->pOutFile;
+
+ vSetLocation(2);
+ vFPprintf(pOutFile, "2 0 obj\n");
+ vFPprintf(pOutFile, "<<\n");
+ if (szTitle != NULL && szTitle[0] != '\0') {
+ vFPprintf(pOutFile, "/Title (%s)\n", szTitle);
+ }
+ if (szAuthor != NULL && szAuthor[0] != '\0') {
+ vFPprintf(pOutFile, "/Author (%s)\n", szAuthor);
+ }
+ if (szSubject != NULL && szSubject[0] != '\0') {
+ vFPprintf(pOutFile, "/Subject (%s)\n", szSubject);
+ }
+ if (szCreator != NULL && szCreator[0] != '\0') {
+ vFPprintf(pOutFile, "/Creator (%s)\n", szCreator);
+ }
+ vFPprintf(pOutFile, "/Producer (%s %s)\n", szProducer, VERSIONSTRING);
+ if (szCreationDate != NULL && szCreationDate[0] != '\0') {
+ vFPprintf(pOutFile, "/CreationDate (%s)\n", szCreationDate);
+ }
+ if (szModDate != NULL && szModDate[0] != '\0') {
+ vFPprintf(pOutFile, "/ModDate (%s)\n", szModDate);
+ }
+ vFPprintf(pOutFile, ">>\n");
+ vFPprintf(pOutFile, "endobj\n");
+} /* end of vCreateInfoDictionary */
+
+/*
+ * vAddHdrFtr - add a header or footer
+ */
+static void
+vAddHdrFtr(diagram_type *pDiag, const hdrftr_block_type *pHdrFtrInfo)
+{
+ output_type *pStart, *pPrev, *pNext;
+
+ fail(pDiag == NULL);
+ fail(pHdrFtrInfo == NULL);
+
+ vStartOfParagraphPDF(pDiag, 0);
+ pStart = pHdrFtrInfo->pText;
+ while (pStart != NULL) {
+ pNext = pStart;
+ while (pNext != NULL &&
+ (pNext->tNextFree != 1 ||
+ (pNext->szStorage[0] != PAR_END &&
+ pNext->szStorage[0] != HARD_RETURN))) {
+ pNext = pNext->pNext;
+ }
+ if (pNext == NULL) {
+ if (bOutputContainsText(pStart)) {
+ vAlign2Window(pDiag, pStart,
+ lChar2MilliPoints(DEFAULT_SCREEN_WIDTH),
+ ALIGNMENT_LEFT);
+ } else {
+ vMove2NextLinePDF(pDiag, pStart->usFontSize);
+ }
+ break;
+ }
+ fail(pNext->tNextFree != 1);
+ fail(pNext->szStorage[0] != PAR_END &&
+ pNext->szStorage[0] != HARD_RETURN);
+
+ if (pStart != pNext) {
+ /* There is something to print */
+ pPrev = pNext->pPrev;
+ fail(pPrev->pNext != pNext);
+ /* Cut the chain */
+ pPrev->pNext = NULL;
+ if (bOutputContainsText(pStart)) {
+ /* Print it */
+ vAlign2Window(pDiag, pStart,
+ lChar2MilliPoints(DEFAULT_SCREEN_WIDTH),
+ ALIGNMENT_LEFT);
+ } else {
+ /* Just an empty line */
+ vMove2NextLinePDF(pDiag, pStart->usFontSize);
+ }
+ /* Repair the chain */
+ pPrev->pNext = pNext;
+ }
+ if (pNext->szStorage[0] == PAR_END) {
+ vEndOfParagraphPDF(pDiag, pNext->usFontSize,
+ (long)pNext->usFontSize * 200);
+ }
+ pStart = pNext->pNext;
+ }
+} /* end of vAddHdrFtr */
+
+/*
+ * vAddHeader - add a page header
+ */
+static void
+vAddHeader(diagram_type *pDiag)
+{
+ const hdrftr_block_type *pHdrInfo;
+ const hdrftr_block_type *pFtrInfo;
+
+ fail(pDiag == NULL);
+
+ NO_DBG_MSG("vAddHeader");
+
+ pHdrInfo = pGetHdrFtrInfo(iSectionIndex, TRUE,
+ odd(iPageCount), bFirstInSection);
+ pFtrInfo = pGetHdrFtrInfo(iSectionIndex, FALSE,
+ odd(iPageCount), bFirstInSection);
+ /* Set the height of the footer of this page */
+ lFooterHeight = pFtrInfo == NULL ? 0 : pFtrInfo->lHeight;
+ fail(lFooterHeight < 0);
+
+ if (pHdrInfo == NULL ||
+ pHdrInfo->pText == NULL ||
+ pHdrInfo->lHeight <= 0) {
+ fail(pHdrInfo != NULL && pHdrInfo->lHeight < 0);
+ fail(pHdrInfo != NULL &&
+ pHdrInfo->pText != NULL &&
+ pHdrInfo->lHeight == 0);
+ return;
+ }
+
+ vAddHdrFtr(pDiag, pHdrInfo);
+
+ DBG_DEC_C(pHdrInfo->lHeight !=
+ lPageHeight - PS_TOP_MARGIN - pDiag->lYtop,
+ pHdrInfo->lHeight);
+ DBG_DEC_C(pHdrInfo->lHeight !=
+ lPageHeight - PS_TOP_MARGIN - pDiag->lYtop,
+ lPageHeight - PS_TOP_MARGIN - pDiag->lYtop);
+} /* end of vAddHeader */
+
+/*
+ * vAddFooter - add a page footer
+ */
+static void
+vAddFooter(diagram_type *pDiag)
+{
+ const hdrftr_block_type *pFtrInfo;
+
+ fail(pDiag == NULL);
+
+ NO_DBG_MSG("vAddFooter");
+
+ pFtrInfo = pGetHdrFtrInfo(iSectionIndex, FALSE,
+ odd(iPageCount), bFirstInSection);
+ bFirstInSection = FALSE;
+ if (pFtrInfo == NULL ||
+ pFtrInfo->pText == NULL ||
+ pFtrInfo->lHeight <= 0) {
+ fail(pFtrInfo != NULL && pFtrInfo->lHeight < 0);
+ fail(pFtrInfo != NULL &&
+ pFtrInfo->pText != NULL &&
+ pFtrInfo->lHeight == 0);
+ return;
+ }
+
+ bInFtrSpace = TRUE;
+
+ DBG_DEC_C(pFtrInfo->lHeight != lFooterHeight, pFtrInfo->lHeight);
+ DBG_DEC_C(pFtrInfo->lHeight != lFooterHeight, lFooterHeight);
+ DBG_DEC_C(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN,
+ pDiag->lYtop);
+ DBG_DEC_C(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN,
+ lFooterHeight + PS_BOTTOM_MARGIN);
+
+ if (pDiag->lYtop > lFooterHeight + PS_BOTTOM_MARGIN) {
+ /* Move down to the start of the footer */
+ pDiag->lYtop = lFooterHeight + PS_BOTTOM_MARGIN;
+ vMoveTo(pDiag, 0);
+ } else if (pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN / 2) {
+ DBG_FIXME();
+ /*
+ * Move up to the start of the footer, to prevent moving
+ * of the bottom edge of the paper
+ */
+ pDiag->lYtop = lFooterHeight + PS_BOTTOM_MARGIN;
+ vMoveTo(pDiag, 0);
+ }
+
+ DBG_FLT_C(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN,
+ dDrawUnits2Points(lFooterHeight + PS_BOTTOM_MARGIN - pDiag->lYtop));
+
+ vAddHdrFtr(pDiag, pFtrInfo);
+ bInFtrSpace = FALSE;
+} /* end of vAddFooter */
+
+/*
+ * vEndPageObject - end the current page object
+ */
+static void
+vEndPageObject(FILE *pOutFile)
+{
+ long lStreamEnd;
+
+ if (lStreamStart < 0) {
+ /* There is no current page object */
+ return;
+ }
+
+ vFPprintf(pOutFile, "ET\n");
+ lStreamEnd = lFilePosition;
+ vFPprintf(pOutFile, "endstream\n");
+ vFPprintf(pOutFile, "endobj\n");
+
+ iObjectNumberCurr++;
+ vSetLocation(iObjectNumberCurr);
+ vFPprintf(pOutFile, "%d 0 obj\n", iObjectNumberCurr);
+ vFPprintf(pOutFile, "%lu\n", lStreamEnd - lStreamStart);
+ vFPprintf(pOutFile, "endobj\n");
+} /* end of vEndPageObject */
+
+/*
+ * vMove2NextPage - move to the start of the next page
+ */
+static void
+vMove2NextPage(diagram_type *pDiag, BOOL bNewSection)
+{
+ FILE *pOutFile;
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+
+ pOutFile = pDiag->pOutFile;
+
+ vAddFooter(pDiag);
+ /* End the old page object */
+ vEndPageObject(pOutFile);
+ if (bNewSection) {
+ iSectionIndex++;
+ bFirstInSection = TRUE;
+ }
+
+ /* Start the new page object */
+ iObjectNumberCurr++;
+ vSetLocation(iObjectNumberCurr);
+ vFillNextPageObject();
+ vFPprintf(pOutFile, "%d 0 obj\n", iObjectNumberCurr);
+ vFPprintf(pOutFile, "<<\n");
+ vFPprintf(pOutFile, "/Type /Page\n");
+ vFPprintf(pOutFile, "/Parent 3 0 R\n");
+ vFPprintf(pOutFile, "/Resources 17 0 R\n");
+ vFPprintf(pOutFile, "/Contents %d 0 R\n", iObjectNumberCurr + 1);
+ vFPprintf(pOutFile, ">>\n");
+ vFPprintf(pOutFile, "endobj\n");
+
+ /* Start the new text object */
+ iObjectNumberCurr++;
+ vSetLocation(iObjectNumberCurr);
+ vFPprintf(pOutFile, "%d 0 obj\n", iObjectNumberCurr);
+ vFPprintf(pOutFile, "<<\n");
+ vFPprintf(pOutFile, "/Length %d 0 R\n", iObjectNumberCurr + 1);
+ vFPprintf(pOutFile, ">>\n");
+ vFPprintf(pOutFile, "stream\n");
+ lStreamStart = lFilePosition;
+ vFPprintf(pOutFile, "BT\n");
+
+ /* Set variables to their start of page values */
+ pDiag->lYtop = lPageHeight - PS_TOP_MARGIN;
+ tFontRefCurr = (drawfile_fontref)-1;
+ usFontSizeCurr = 0;
+ iFontColorCurr = -1;
+ lYtopCurr = -1;
+ vAddHeader(pDiag);
+} /* end of vMove2NextPage */
+
+/*
+ * vMoveTo - move to the specified X,Y coordinates
+ *
+ * Move the current position of the specified diagram to its X,Y coordinates,
+ * start on a new page if needed
+ */
+static void
+vMoveTo(diagram_type *pDiag, long lLastVerticalMovement)
+{
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+
+ if (pDiag->lYtop <= lFooterHeight + PS_BOTTOM_MARGIN && !bInFtrSpace) {
+ vMove2NextPage(pDiag, FALSE);
+ /* Repeat the last vertical movement on the new page */
+ pDiag->lYtop -= lLastVerticalMovement;
+ }
+
+ fail(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN && !bInFtrSpace);
+ DBG_DEC_C(pDiag->lYtop < PS_BOTTOM_MARGIN, pDiag->lYtop);
+ fail(pDiag->lYtop < PS_BOTTOM_MARGIN / 3);
+
+ if (pDiag->lYtop != lYtopCurr) {
+ vFPprintf(pDiag->pOutFile, "1 0 0 1 %.2f %.2f Tm\n",
+ dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
+ dDrawUnits2Points(pDiag->lYtop));
+ lYtopCurr = pDiag->lYtop;
+ }
+} /* end of vMoveTo */
+
+/*
+ * vProloguePDF - set options and perform the PDF initialization
+ */
+void
+vProloguePDF(diagram_type *pDiag,
+ const char *szTask, const options_type *pOptions)
+{
+ FILE *pOutFile;
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(pOptions == NULL);
+
+ pOutFile = pDiag->pOutFile;
+
+ eEncoding = pOptions->eEncoding;
+
+ /* Create an empty location array */
+ tLocations = INITIAL_LOCATION_SIZE;
+ alLocation = xcalloc(tLocations, sizeof(long));
+
+ /* Create an empty pageobject array */
+ tMaxPageObjects = INITIAL_PAGEOBJECT_SIZE;
+ aiPageObject = xcalloc(tMaxPageObjects, sizeof(int));
+
+ if (pOptions->iPageHeight == INT_MAX) {
+ lPageHeight = LONG_MAX;
+ } else {
+ lPageHeight = lPoints2DrawUnits(pOptions->iPageHeight);
+ }
+ DBG_DEC(lPageHeight);
+ if (pOptions->iPageWidth == INT_MAX) {
+ lPageWidth = LONG_MAX;
+ } else {
+ lPageWidth = lPoints2DrawUnits(pOptions->iPageWidth);
+ }
+ DBG_DEC(lPageWidth);
+ lFooterHeight = 0;
+ bInFtrSpace = FALSE;
+
+ tFontRefCurr = (drawfile_fontref)-1;
+ usFontSizeCurr = 0;
+ iFontColorCurr = -1;
+ lYtopCurr = -1;
+ iPageCount = 0;
+ iImageCount = 0;
+ iSectionIndex = 0;
+ bFirstInSection = TRUE;
+ lFilePosition = 0;
+ iMaxLocationNumber = 0;
+ lStreamStart = -1;
+ iObjectNumberCurr = 17;
+ pDiag->lXleft = 0;
+ pDiag->lYtop = 0;
+
+ szProducer = szTask;
+
+ vFPprintf(pOutFile, "%%PDF-1.3\n");
+ vFPprintf(pOutFile, "%%%c%c%c%c\n", 0xe2, 0xe3, 0xcf, 0xd3);
+
+ /* Root catalog */
+ vSetLocation(1);
+ vFPprintf(pOutFile, "1 0 obj\n");
+ vFPprintf(pOutFile, "<<\n");
+ vFPprintf(pOutFile, "/Type /Catalog\n");
+ vFPprintf(pOutFile, "/Pages 3 0 R\n");
+ vFPprintf(pOutFile, ">>\n");
+ vFPprintf(pOutFile, "endobj\n");
+} /* end of vProloguePDF */
+
+/*
+ * vEpiloguePDF - clean up after everything is done
+ */
+void
+vEpiloguePDF(diagram_type *pDiag)
+{
+ FILE *pOutFile;
+ long lXref;
+ int iIndex;
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+
+ pOutFile = pDiag->pOutFile;
+
+ vAddFooter(pDiag);
+ /* End the old page object */
+ vEndPageObject(pOutFile);
+
+ vSetLocation(3);
+ vFPprintf(pOutFile, "3 0 obj\n");
+ vFPprintf(pOutFile, "<<\n");
+ vFPprintf(pOutFile, "/Type /Pages\n");
+ vFPprintf(pOutFile, "/Count %d\n", iPageCount);
+ vFPprintf(pOutFile, "/MediaBox [ 0 0 %.0f %.0f ]\n",
+ dDrawUnits2Points(lPageWidth),
+ dDrawUnits2Points(lPageHeight));
+ vFPprintf(pOutFile, "/Kids [ ");
+ for (iIndex = 1; iIndex <= iPageCount; iIndex++) {
+ vFPprintf(pOutFile, "\t%d 0 R\n", aiPageObject[iIndex]);
+ }
+ vFPprintf(pOutFile, "]\n");
+ vFPprintf(pOutFile, ">>\n");
+ vFPprintf(pOutFile, "endobj\n");
+
+ lXref = lFilePosition;
+
+ vFPprintf(pOutFile, "xref\n");
+ vFPprintf(pOutFile, "0 %d\n", iMaxLocationNumber + 1);
+ vFPprintf(pOutFile, "0000000000 65535 f \n");
+ for (iIndex = 1; iIndex <= iMaxLocationNumber; iIndex++) {
+ vFPprintf(pOutFile, "%.10ld 00000 n \n", alLocation[iIndex]);
+ }
+
+ vFPprintf(pOutFile, "trailer\n");
+ vFPprintf(pOutFile, "<<\n");
+ vFPprintf(pOutFile, "/Size %d\n", iMaxLocationNumber + 1);
+ vFPprintf(pOutFile, "/Root 1 0 R\n");
+ vFPprintf(pOutFile, "/Info 2 0 R\n");
+ vFPprintf(pOutFile, ">>\n");
+
+ vFPprintf(pOutFile, "startxref\n");
+ vFPprintf(pOutFile, "%ld\n", lXref);
+ vFPprintf(pOutFile, "%%%%EOF\n");
+
+ szProducer = NULL;
+ aiPageObject = xfree(aiPageObject);
+ alLocation = xfree(alLocation);
+} /* end of vEpiloguePDF */
+
+/*
+ * vPrintPalette - print a pdf color space (palette)
+ */
+static void
+vPrintPalette(FILE *pOutFile, const imagedata_type *pImg)
+{
+ int iIndex;
+
+ fail(pOutFile == NULL);
+ fail(pImg == NULL);
+ fail(pImg->iColorsUsed < 2);
+ fail(pImg->iColorsUsed > 256);
+
+ vFPprintf(pOutFile, "\t/ColorSpace [ /Indexed\n");
+ vFPprintf(pOutFile, "\t/Device%s %d\n",
+ pImg->bColorImage ? "RGB" : "Gray", pImg->iColorsUsed - 1);
+ vFPprintf(pOutFile, "<");
+ for (iIndex = 0; iIndex < pImg->iColorsUsed; iIndex++) {
+ vFPprintf(pOutFile, "%02x",
+ (unsigned int)pImg->aucPalette[iIndex][0]);
+ if (pImg->bColorImage) {
+ vFPprintf(pOutFile, "%02x%02x",
+ (unsigned int)pImg->aucPalette[iIndex][1],
+ (unsigned int)pImg->aucPalette[iIndex][2]);
+ }
+ if (iIndex % 8 == 7) {
+ vFPprintf(pOutFile, "\n");
+ } else {
+ vFPprintf(pOutFile, " ");
+ }
+ }
+ vFPprintf(pOutFile, "> ]\n");
+} /* end of vPrintPalette */
+
+/*
+ * vImageProloguePDF - perform the image initialization
+ */
+void
+vImageProloguePDF(diagram_type *pDiag, const imagedata_type *pImg)
+{
+ FILE *pOutFile;
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(pImg == NULL);
+
+ if (pImg->iVerSizeScaled <= 0 || pImg->iHorSizeScaled <= 0) {
+ return;
+ }
+
+ iImageCount++;
+
+ DBG_DEC_C(pDiag->lXleft != 0, pDiag->lXleft);
+
+ pDiag->lYtop -= lPoints2DrawUnits(pImg->iVerSizeScaled);
+ vMoveTo(pDiag, lPoints2DrawUnits(pImg->iVerSizeScaled));
+
+ pOutFile = pDiag->pOutFile;
+
+ vFPprintf(pOutFile, "ET\n");
+ vFPprintf(pOutFile, "q %% Image %03d\n", iImageCount);
+ if (pImg->eImageType == imagetype_is_dib) {
+ /* Scanning from left to right and bottom to top */
+ vFPprintf(pOutFile, "%d 0 0 %d %.2f %.2f cm\n",
+ pImg->iHorSizeScaled, -pImg->iVerSizeScaled,
+ dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
+ dDrawUnits2Points(pDiag->lYtop) + pImg->iVerSizeScaled);
+ } else {
+ /* Scanning from left to right and top to bottom */
+ vFPprintf(pOutFile, "%d 0 0 %d %.2f %.2f cm\n",
+ pImg->iHorSizeScaled, pImg->iVerSizeScaled,
+ dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
+ dDrawUnits2Points(pDiag->lYtop));
+ }
+ vFPprintf(pOutFile, "BI\n");
+ vFPprintf(pOutFile, "\t/Width %d\n", pImg->iWidth);
+ vFPprintf(pOutFile, "\t/Height %d\n", pImg->iHeight);
+ switch (pImg->eImageType) {
+ case imagetype_is_jpeg:
+ switch (pImg->iComponents) {
+ case 1:
+ vFPprintf(pOutFile, "\t/ColorSpace /DeviceGray\n");
+ break;
+ case 3:
+ vFPprintf(pOutFile, "\t/ColorSpace /DeviceRGB\n");
+ break;
+ case 4:
+ vFPprintf(pOutFile, "\t/ColorSpace /DeviceCMYK\n");
+ if (pImg->bAdobe) {
+ /*
+ * Adobe-conforming CMYK file
+ * applying workaround for color inversion
+ */
+ vFPprintf(pOutFile,
+ "\t/Decode [1 0 1 0 1 0 1 0]\n");
+ }
+ break;
+ default:
+ DBG_DEC(pImg->iComponents);
+ break;
+ }
+ vFPprintf(pOutFile, "\t/BitsPerComponent 8\n");
+ vFPprintf(pOutFile,
+ "\t/Filter [ /ASCII85Decode /DCTDecode ]\n");
+ break;
+ case imagetype_is_png:
+ if (pImg->iComponents == 3 || pImg->iComponents == 4) {
+ vFPprintf(pOutFile, "\t/ColorSpace /DeviceRGB\n");
+ vFPprintf(pOutFile, "\t/BitsPerComponent 8\n");
+ } else if (pImg->iColorsUsed > 0) {
+ vPrintPalette(pOutFile, pImg);
+ fail(pImg->uiBitsPerComponent > 8);
+ vFPprintf(pOutFile, "\t/BitsPerComponent %u\n",
+ pImg->uiBitsPerComponent);
+ } else {
+ vFPprintf(pOutFile, "\t/ColorSpace /DeviceGray\n");
+ vFPprintf(pOutFile, "\t/BitsPerComponent 8\n");
+ }
+ vFPprintf(pOutFile,
+ "\t/Filter [ /ASCII85Decode /FlateDecode ]\n");
+ vFPprintf(pOutFile, "\t/DecodeParms [ null <<\n");
+ vFPprintf(pOutFile, "\t\t/Predictor 10\n");
+ vFPprintf(pOutFile, "\t\t/Colors %d\n", pImg->iComponents);
+ vFPprintf(pOutFile, "\t\t/BitsPerComponent %u\n",
+ pImg->uiBitsPerComponent);
+ vFPprintf(pOutFile, "\t\t/Columns %d\n", pImg->iWidth);
+ vFPprintf(pOutFile, "\t\t>> ]\n");
+ break;
+ case imagetype_is_dib:
+ if (pImg->uiBitsPerComponent <= 8) {
+ vPrintPalette(pOutFile, pImg);
+ } else {
+ vFPprintf(pOutFile, "\t/ColorSpace /DeviceRGB\n");
+ }
+ vFPprintf(pOutFile, "\t/BitsPerComponent 8\n");
+ vFPprintf(pOutFile, "\t/Filter /ASCII85Decode\n");
+ break;
+ default:
+ vFPprintf(pOutFile, "\t/ColorSpace /Device%s\n",
+ pImg->bColorImage ? "RGB" : "Gray");
+ vFPprintf(pOutFile, "\t/BitsPerComponent 8\n");
+ vFPprintf(pOutFile, "\t/Filter /ASCIIHexDecode\n");
+ break;
+ }
+ vFPprintf(pOutFile, "ID\n");
+} /* end of vImageProloguePDF */
+
+/*
+ * vImageEpiloguePDF - clean up after the image
+ */
+void
+vImageEpiloguePDF(diagram_type *pDiag)
+{
+ FILE *pOutFile;
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+
+ pOutFile = pDiag->pOutFile;
+
+ /* Correction for the image bytes */
+ lFilePosition = ftell(pOutFile);
+
+ vFPprintf(pOutFile, "EI\n");
+ vFPprintf(pOutFile, "Q\n");
+ vFPprintf(pOutFile, "BT\n");
+
+ pDiag->lXleft = 0;
+} /* end of vImageEpiloguePDF */
+
+/*
+ * bAddDummyImagePDF - add a dummy image
+ *
+ * return TRUE when successful, otherwise FALSE
+ */
+BOOL
+bAddDummyImagePDF(diagram_type *pDiag, const imagedata_type *pImg)
+{
+ FILE *pOutFile;
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(pImg == NULL);
+
+ if (pImg->iVerSizeScaled <= 0 || pImg->iHorSizeScaled <= 0) {
+ return FALSE;
+ }
+
+ iImageCount++;
+
+ DBG_DEC_C(pDiag->lXleft != 0, pDiag->lXleft);
+
+ pDiag->lYtop -= lPoints2DrawUnits(pImg->iVerSizeScaled);
+ vMoveTo(pDiag, lPoints2DrawUnits(pImg->iVerSizeScaled));
+
+ pOutFile = pDiag->pOutFile;
+
+ vFPprintf(pOutFile, "ET\n");
+ vFPprintf(pOutFile, "q %% Image %03d\n", iImageCount);
+ vFPprintf(pOutFile, "\t1.0 w\n");
+ vFPprintf(pOutFile, "\t0.3 G\n");
+ vFPprintf(pOutFile, "\t%.2f %.2f %d %d re\n",
+ dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
+ dDrawUnits2Points(pDiag->lYtop),
+ pImg->iHorSizeScaled,
+ pImg->iVerSizeScaled);
+ vFPprintf(pOutFile, "\tS\n");
+ vFPprintf(pOutFile, "Q\n");
+ vFPprintf(pOutFile, "BT\n");
+
+ pDiag->lXleft = 0;
+
+ return TRUE;
+} /* end of bAddDummyImagePDF */
+
+/*
+ * vAddFontsPDF - add the font information
+ */
+void
+vAddFontsPDF(diagram_type *pDiag)
+{
+ FILE *pOutFile;
+ size_t tIndex;
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+
+ pOutFile = pDiag->pOutFile;
+
+ /* The font encoding */
+ vSetLocation(4);
+ vFPprintf(pOutFile, "4 0 obj\n");
+ vFPprintf(pOutFile, "<<\n");
+ vFPprintf(pOutFile, "/Type /Encoding\n");
+ vFPprintf(pOutFile, "/BaseEncoding /StandardEncoding\n");
+ vFPprintf(pOutFile, "/Differences [\n");
+ switch (eEncoding) {
+ case encoding_latin_1:
+ for (tIndex = 0;
+ tIndex < elementsof(iso_8859_1);
+ tIndex++) {
+ vFPprintf(pOutFile, "%s\n", iso_8859_1[tIndex]);
+ }
+ break;
+ case encoding_latin_2:
+ for (tIndex = 0;
+ tIndex < elementsof(iso_8859_2);
+ tIndex++) {
+ vFPprintf(pOutFile, "%s\n", iso_8859_2[tIndex]);
+ }
+ break;
+ case encoding_cyrillic:
+ werr(1,
+ "The combination PDF and Cyrillic is not supported");
+ break;
+ case encoding_utf_8:
+ werr(1,
+ "The combination PDF and UTF-8 is not supported");
+ break;
+ default:
+ DBG_DEC(eEncoding);
+ break;
+ }
+ vFPprintf(pOutFile, "]\n");
+ vFPprintf(pOutFile, ">>\n");
+ vFPprintf(pOutFile, "endobj\n");
+
+ /* Twelve of the standard type 1 fonts */
+ for (tIndex = 0; tIndex < 12; tIndex++) {
+ vSetLocation(5 + tIndex);
+ vFPprintf(pOutFile, "%u 0 obj\n", 5 + tIndex);
+ vFPprintf(pOutFile, "<<\n");
+ vFPprintf(pOutFile, "/Type /Font\n");
+ vFPprintf(pOutFile, "/Subtype /Type1\n");
+ vFPprintf(pOutFile, "/Name /F%u\n", 1 + tIndex);
+ vFPprintf(pOutFile, "/BaseFont /%s\n",
+ atFontname[tIndex].szPDFname);
+ vFPprintf(pOutFile, "/Encoding 4 0 R\n");
+ vFPprintf(pOutFile, ">>\n");
+ vFPprintf(pOutFile, "endobj\n");
+ }
+
+ /* The Resources */
+ vSetLocation(17);
+ vFPprintf(pOutFile, "17 0 obj\n");
+ vFPprintf(pOutFile, "<<\n");
+ vFPprintf(pOutFile, "/ProcSet [ /PDF /Text ]\n");
+ vFPprintf(pOutFile, "/Font <<\n");
+ for (tIndex = 0; tIndex < 12; tIndex++) {
+ vFPprintf(pOutFile, "\t/F%u %u 0 R\n", 1 + tIndex, 5 + tIndex);
+ }
+ vFPprintf(pOutFile, "\t>>\n");
+ vFPprintf(pOutFile, ">>\n");
+ vFPprintf(pOutFile, "endobj\n");
+ vAddHeader(pDiag);
+} /* end of vAddFontsPDF */
+
+/*
+ * vPrintPDF - print a PDF string
+ */
+static void
+vPrintPDF(FILE *pFile, const char *szString, size_t tStringLength,
+ USHORT usFontstyle)
+{
+ const UCHAR *aucBytes;
+ double dMove;
+ size_t tCount;
+
+ fail(szString == NULL);
+
+ if (szString == NULL || szString[0] == '\0' || tStringLength == 0) {
+ return;
+ }
+ DBG_DEC_C(usFontSizeCurr < MIN_FONT_SIZE, usFontSizeCurr);
+
+ dMove = 0.0;
+
+ /* Up for superscript */
+ if (bIsSuperscript(usFontstyle) && usFontSizeCurr != 0) {
+ dMove = (double)((usFontSizeCurr + 1) / 2) * 0.375;
+ vFPprintf(pFile, "%.2f Ts\n", dMove);
+ }
+
+ /* Down for subscript */
+ if (bIsSubscript(usFontstyle) && usFontSizeCurr != 0) {
+ dMove = (double)usFontSizeCurr * 0.125;
+ vFPprintf(pFile, "%.2f Ts\n", -dMove);
+ }
+
+ /* Generate and print the PDF output */
+ aucBytes = (UCHAR *)szString;
+ vFPprintf(pFile, "(");
+ for (tCount = 0; tCount < tStringLength ; tCount++) {
+ switch (aucBytes[tCount]) {
+ case '(':
+ case ')':
+ case '\\':
+ vFPprintf(pFile, "\\%c", szString[tCount]);
+ break;
+ default:
+ if (aucBytes[tCount] < 0x20 ||
+ aucBytes[tCount] == 0x7f ||
+ (aucBytes[tCount] >= 0x81 &&
+ aucBytes[tCount] < 0x8c)) {
+ DBG_HEX(aucBytes[tCount]);
+ vFPprintf(pFile, " ");
+ } else if (aucBytes[tCount] >= 0x80) {
+ vFPprintf(pFile, "\\%03o",
+ (UINT)aucBytes[tCount]);
+ } else {
+ vFPprintf(pFile, "%c", szString[tCount]);
+ }
+ break;
+ }
+ }
+ vFPprintf(pFile, ") Tj\n");
+
+ /* Undo the superscript/subscript move */
+ if (dMove != 0.0) {
+ vFPprintf(pFile, "0 Ts\n");
+ }
+} /* end of vPrintPDF */
+
+/*
+ * vSetColor - move to the specified color
+ */
+static void
+vSetColor(FILE *pFile, UCHAR ucFontColor)
+{
+ ULONG ulTmp, ulRed, ulGreen, ulBlue;
+
+ ulTmp = ulColor2Color(ucFontColor);
+ ulRed = (ulTmp & 0x0000ff00) >> 8;
+ ulGreen = (ulTmp & 0x00ff0000) >> 16;
+ ulBlue = (ulTmp & 0xff000000) >> 24;
+ vFPprintf(pFile, "%.3f %.3f %.3f rg\n",
+ ulRed / 255.0, ulGreen / 255.0, ulBlue / 255.0);
+} /* end of vSetColor */
+
+/*
+ * vMove2NextLinePDF - move to the next line
+ */
+void
+vMove2NextLinePDF(diagram_type *pDiag, USHORT usFontSize)
+{
+ fail(pDiag == NULL);
+ fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
+
+ pDiag->lYtop -= lComputeLeading(usFontSize);
+} /* end of vMove2NextLinePDF */
+
+/*
+ * vSubstringPDF - print a sub string
+ */
+void
+vSubstringPDF(diagram_type *pDiag,
+ char *szString, size_t tStringLength, long lStringWidth,
+ UCHAR ucFontColor, USHORT usFontstyle, drawfile_fontref tFontRef,
+ USHORT usFontSize, USHORT usMaxFontSize)
+{
+ size_t tFontIndex;
+
+ fail(pDiag == NULL || szString == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(pDiag->lXleft < 0);
+ fail(tStringLength != strlen(szString));
+ fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
+ fail(usMaxFontSize < MIN_FONT_SIZE || usMaxFontSize > MAX_FONT_SIZE);
+ fail(usFontSize > usMaxFontSize);
+
+ if (szString[0] == '\0' || tStringLength == 0) {
+ return;
+ }
+
+ vMoveTo(pDiag, lComputeLeading(usMaxFontSize));
+ if (tFontRef != tFontRefCurr || usFontSize != usFontSizeCurr) {
+ tFontIndex = tGetFontIndex(tFontRef);
+ vFPprintf(pDiag->pOutFile, "/F%u %.1f Tf\n",
+ 1 + tFontIndex, (double)usFontSize / 2.0);
+ tFontRefCurr = tFontRef;
+ usFontSizeCurr = usFontSize;
+ }
+ if ((int)ucFontColor != iFontColorCurr) {
+ vSetColor(pDiag->pOutFile, ucFontColor);
+ iFontColorCurr = (int)ucFontColor;
+ }
+ vPrintPDF(pDiag->pOutFile, szString, tStringLength, usFontstyle);
+ pDiag->lXleft += lStringWidth;
+} /* end of vSubstringPDF */
+
+/*
+ * Create an start of paragraph by moving the y-top mark
+ */
+void
+vStartOfParagraphPDF(diagram_type *pDiag, long lBeforeIndentation)
+{
+ fail(pDiag == NULL);
+ fail(lBeforeIndentation < 0);
+
+ pDiag->lXleft = 0;
+ pDiag->lYtop -= lMilliPoints2DrawUnits(lBeforeIndentation);
+} /* end of vStartOfParagraphPDF */
+
+/*
+ * Create an end of paragraph by moving the y-top mark
+ */
+void
+vEndOfParagraphPDF(diagram_type *pDiag,
+ USHORT usFontSize, long lAfterIndentation)
+{
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
+ fail(lAfterIndentation < 0);
+
+ if (pDiag->lXleft > 0) {
+ /* To the start of the line */
+ vMove2NextLinePDF(pDiag, usFontSize);
+ }
+
+ pDiag->lXleft = 0;
+ pDiag->lYtop -= lMilliPoints2DrawUnits(lAfterIndentation);
+} /* end of vEndOfParagraphPDF */
+
+/*
+ * Create an end of page
+ */
+void
+vEndOfPagePDF(diagram_type *pDiag, BOOL bNewSection)
+{
+ vMove2NextPage(pDiag, bNewSection);
+} /* end of vEndOfPagePDF */
diff --git a/sys/src/cmd/aux/antiword/pictlist.c b/sys/src/cmd/aux/antiword/pictlist.c
new file mode 100755
index 000000000..dd9e4bfc0
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/pictlist.c
@@ -0,0 +1,109 @@
+/*
+ * pictlist.c
+ * Copyright (C) 2000-2004 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Build, read and destroy a list of Word picture information
+ */
+
+#include <stdlib.h>
+#include "antiword.h"
+
+
+/*
+ * Private structure to hide the way the information
+ * is stored from the rest of the program
+ */
+typedef struct picture_mem_tag {
+ picture_block_type tInfo;
+ struct picture_mem_tag *pNext;
+} picture_mem_type;
+
+/* Variables needed to write the Picture Information List */
+static picture_mem_type *pAnchor = NULL;
+static picture_mem_type *pPictureLast = NULL;
+
+
+/*
+ * vDestroyPictInfoList - destroy the Picture Information List
+ */
+void
+vDestroyPictInfoList(void)
+{
+ picture_mem_type *pCurr, *pNext;
+
+ DBG_MSG("vDestroyPictInfoList");
+
+ /* Free the Picture Information List */
+ pCurr = pAnchor;
+ while (pCurr != NULL) {
+ pNext = pCurr->pNext;
+ pCurr = xfree(pCurr);
+ pCurr = pNext;
+ }
+ pAnchor = NULL;
+ /* Reset all control variables */
+ pPictureLast = NULL;
+} /* end of vDestroyPictInfoList */
+
+/*
+ * vAdd2PictInfoList - Add an element to the Picture Information List
+ */
+void
+vAdd2PictInfoList(const picture_block_type *pPictureBlock)
+{
+ picture_mem_type *pListMember;
+
+ fail(pPictureBlock == NULL);
+
+ NO_DBG_MSG("bAdd2PictInfoList");
+
+ if (pPictureBlock->ulFileOffset == FC_INVALID) {
+ /*
+ * This offset is really past the end of the file,
+ * so don't waste any memory by storing it.
+ */
+ return;
+ }
+ if (pPictureBlock->ulFileOffsetPicture == FC_INVALID) {
+ /*
+ * The place where this picture is supposed to be stored
+ * doesn't exist.
+ */
+ return;
+ }
+
+ NO_DBG_HEX(pPictureBlock->ulFileOffset);
+ NO_DBG_HEX(pPictureBlock->ulFileOffsetPicture);
+ NO_DBG_HEX(pPictureBlock->ulPictureOffset);
+
+ /* Create list member */
+ pListMember = xmalloc(sizeof(picture_mem_type));
+ /* Fill the list member */
+ pListMember->tInfo = *pPictureBlock;
+ pListMember->pNext = NULL;
+ /* Add the new member to the list */
+ if (pAnchor == NULL) {
+ pAnchor = pListMember;
+ } else {
+ fail(pPictureLast == NULL);
+ pPictureLast->pNext = pListMember;
+ }
+ pPictureLast = pListMember;
+} /* end of vAdd2PictInfoList */
+
+/*
+ * Get the info with the given file offset from the Picture Information List
+ */
+ULONG
+ulGetPictInfoListItem(ULONG ulFileOffset)
+{
+ picture_mem_type *pCurr;
+
+ for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
+ if (pCurr->tInfo.ulFileOffset == ulFileOffset) {
+ return pCurr->tInfo.ulFileOffsetPicture;
+ }
+ }
+ return FC_INVALID;
+} /* end of ulGetPictInfoListItem */
diff --git a/sys/src/cmd/aux/antiword/png2eps.c b/sys/src/cmd/aux/antiword/png2eps.c
new file mode 100755
index 000000000..25d1755a7
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/png2eps.c
@@ -0,0 +1,191 @@
+/*
+ * png2eps.c
+ * Copyright (C) 2000-2002 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Functions to translate png images into eps
+ *
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "antiword.h"
+
+#if defined(DEBUG)
+static int iPicCounter = 0;
+#endif /* DEBUG */
+
+
+/*
+ * tSkipToData - skip until a IDAT chunk is found
+ *
+ * returns the length of the pixeldata or -1 in case of error
+ */
+static size_t
+tSkipToData(FILE *pFile, size_t tMaxBytes, size_t *ptSkipped)
+{
+ ULONG ulName, ulTmp;
+ size_t tDataLength, tToSkip;
+ int iCounter;
+
+ fail(pFile == NULL);
+ fail(ptSkipped == NULL);
+
+ /* Examine chunks */
+ while (*ptSkipped + 8 < tMaxBytes) {
+ tDataLength = (size_t)ulNextLongBE(pFile);
+ DBG_DEC(tDataLength);
+ *ptSkipped += 4;
+
+ ulName = 0x00;
+ for (iCounter = 0; iCounter < 4; iCounter++) {
+ ulTmp = (ULONG)iNextByte(pFile);
+ if (!isalpha((int)ulTmp)) {
+ DBG_HEX(ulTmp);
+ return (size_t)-1;
+ }
+ ulName <<= 8;
+ ulName |= ulTmp;
+ }
+ DBG_HEX(ulName);
+ *ptSkipped += 4;
+
+ if (ulName == PNG_CN_IEND) {
+ break;
+ }
+ if (ulName == PNG_CN_IDAT) {
+ return tDataLength;
+ }
+
+ tToSkip = tDataLength + 4;
+ if (tToSkip >= tMaxBytes - *ptSkipped) {
+ DBG_DEC(tToSkip);
+ DBG_DEC(tMaxBytes - *ptSkipped);
+ return (size_t)-1;
+ }
+ (void)tSkipBytes(pFile, tToSkip);
+ *ptSkipped += tToSkip;
+ }
+
+ return (size_t)-1;
+} /* end of iSkipToData */
+
+/*
+ * iFindFirstPixelData - find the first pixeldata if a PNG image
+ *
+ * returns the length of the pixeldata or -1 in case of error
+ */
+static size_t
+tFindFirstPixelData(FILE *pFile, size_t tMaxBytes, size_t *ptSkipped)
+{
+ fail(pFile == NULL);
+ fail(tMaxBytes == 0);
+ fail(ptSkipped == NULL);
+
+ if (tMaxBytes < 8) {
+ DBG_DEC(tMaxBytes);
+ return (size_t)-1;
+ }
+
+ /* Skip over the PNG signature */
+ (void)tSkipBytes(pFile, 8);
+ *ptSkipped = 8;
+
+ return tSkipToData(pFile, tMaxBytes, ptSkipped);
+} /* end of iFindFirstPixelData */
+
+/*
+ * tFindNextPixelData - find the next pixeldata if a PNG image
+ *
+ * returns the length of the pixeldata or -1 in case of error
+ */
+static size_t
+tFindNextPixelData(FILE *pFile, size_t tMaxBytes, size_t *ptSkipped)
+{
+ fail(pFile == NULL);
+ fail(tMaxBytes == 0);
+ fail(ptSkipped == NULL);
+
+ if (tMaxBytes < 4) {
+ DBG_DEC(tMaxBytes);
+ return (size_t)-1;
+ }
+
+ /* Skip over the crc */
+ (void)tSkipBytes(pFile, 4);
+ *ptSkipped = 4;
+
+ return tSkipToData(pFile, tMaxBytes, ptSkipped);
+} /* end of tFindNextPixelData */
+
+#if defined(DEBUG)
+/*
+ * vCopy2File
+ */
+static void
+vCopy2File(FILE *pFile, ULONG ulFileOffset, size_t tPictureLen)
+{
+ FILE *pOutFile;
+ size_t tIndex;
+ int iTmp;
+ char szFilename[30];
+
+ if (!bSetDataOffset(pFile, ulFileOffset)) {
+ return;
+ }
+
+ sprintf(szFilename, "/tmp/pic/pic%04d.png", ++iPicCounter);
+ pOutFile = fopen(szFilename, "wb");
+ if (pOutFile == NULL) {
+ return;
+ }
+ for (tIndex = 0; tIndex < tPictureLen; tIndex++) {
+ iTmp = iNextByte(pFile);
+ if (putc(iTmp, pOutFile) == EOF) {
+ break;
+ }
+ }
+ (void)fclose(pOutFile);
+} /* end of vCopy2File */
+#endif /* DEBUG */
+
+/*
+ * bTranslatePNG - translate a PNG image
+ *
+ * This function translates an image from png to eps
+ *
+ * return TRUE when sucessful, otherwise FALSE
+ */
+BOOL
+bTranslatePNG(diagram_type *pDiag, FILE *pFile,
+ ULONG ulFileOffset, size_t tPictureLen, const imagedata_type *pImg)
+{
+ size_t tMaxBytes, tDataLength, tSkipped;
+
+#if defined(DEBUG)
+ vCopy2File(pFile, ulFileOffset, tPictureLen);
+#endif /* DEBUG */
+
+ /* Seek to start position of PNG data */
+ if (!bSetDataOffset(pFile, ulFileOffset)) {
+ return FALSE;
+ }
+
+ tMaxBytes = tPictureLen;
+ tDataLength = tFindFirstPixelData(pFile, tMaxBytes, &tSkipped);
+ if (tDataLength == (size_t)-1) {
+ return FALSE;
+ }
+
+ vImagePrologue(pDiag, pImg);
+ do {
+ tMaxBytes -= tSkipped;
+ vASCII85EncodeArray(pFile, pDiag->pOutFile, tDataLength);
+ tMaxBytes -= tDataLength;
+ tDataLength = tFindNextPixelData(pFile, tMaxBytes, &tSkipped);
+ } while (tDataLength != (size_t)-1);
+ vASCII85EncodeByte(pDiag->pOutFile, EOF);
+ vImageEpilogue(pDiag);
+
+ return TRUE;
+} /* end of bTranslatePNG */
diff --git a/sys/src/cmd/aux/antiword/png2sprt.c b/sys/src/cmd/aux/antiword/png2sprt.c
new file mode 100755
index 000000000..d40ceb64c
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/png2sprt.c
@@ -0,0 +1,26 @@
+/*
+ * png2sprt.c
+ * Copyright (C) 2000 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Functions to translate png pictures into sprites
+ */
+
+#include <stdio.h>
+#include "antiword.h"
+
+
+/*
+ * bTranslatePNG - translate a PNG picture
+ *
+ * This function translates a picture from png to sprite
+ *
+ * return TRUE when sucessful, otherwise FALSE
+ */
+BOOL
+bTranslatePNG(diagram_type *pDiag, FILE *pFile,
+ ULONG ulFileOffset, size_t tPictureLen, const imagedata_type *pImg)
+{
+ /* PNG is not supported yet */
+ return bAddDummyImage(pDiag, pImg);
+} /* end of bTranslatePNG */
diff --git a/sys/src/cmd/aux/antiword/postscript.c b/sys/src/cmd/aux/antiword/postscript.c
new file mode 100755
index 000000000..fd20e530e
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/postscript.c
@@ -0,0 +1,1171 @@
+/*
+ * postscript.c
+ * Copyright (C) 1999-2005 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Functions to deal with the PostScript format
+ *
+ *================================================================
+ * The function vImagePrologue is based on:
+ * jpeg2ps - convert JPEG compressed images to PostScript Level 2
+ * Copyright (C) 1994-99 Thomas Merz (tm@muc.de)
+ *================================================================
+ * The credit should go to him, but all the bugs are mine.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <time.h>
+#include <string.h>
+#include "version.h"
+#include "antiword.h"
+
+/* The character set */
+static encoding_type eEncoding = encoding_neutral;
+/* The image level */
+static image_level_enum eImageLevel = level_default;
+/* The output must use landscape orientation */
+static BOOL bUseLandscape = FALSE;
+/* The height and width of a PostScript page (in DrawUnits) */
+static long lPageHeight = LONG_MAX;
+static long lPageWidth = LONG_MAX;
+/* The height of the footer on the current page (in DrawUnits) */
+static long lFooterHeight = 0;
+/* Inside a footer (to prevent an infinite loop when the footer is too big) */
+static BOOL bInFtrSpace = FALSE;
+/* Current time for a PS header */
+static const char *szCreationDate = NULL;
+/* Current creator for a PS header */
+static const char *szCreator = NULL;
+/* Current font information */
+static drawfile_fontref tFontRefCurr = (drawfile_fontref)-1;
+static USHORT usFontSizeCurr = 0;
+static int iFontColorCurr = -1;
+/* Current vertical position information */
+static long lYtopCurr = -1;
+/* PostScript page counter */
+static int iPageCount = 0;
+/* Image counter */
+static int iImageCount = 0;
+/* Section index */
+static int iSectionIndex = 0;
+/* Are we on the first page of the section? */
+static BOOL bFirstInSection = TRUE;
+
+static void vMoveTo(diagram_type *, long);
+
+static const char *iso_8859_1_data[] = {
+"/newcodes % ISO-8859-1 character encodings",
+"[",
+"140/ellipsis 141/trademark 142/perthousand 143/bullet",
+"144/quoteleft 145/quoteright 146/guilsinglleft 147/guilsinglright",
+"148/quotedblleft 149/quotedblright 150/quotedblbase 151/endash 152/emdash",
+"153/minus 154/OE 155/oe 156/dagger 157/daggerdbl 158/fi 159/fl",
+"160/space 161/exclamdown 162/cent 163/sterling 164/currency",
+"165/yen 166/brokenbar 167/section 168/dieresis 169/copyright",
+"170/ordfeminine 171/guillemotleft 172/logicalnot 173/hyphen 174/registered",
+"175/macron 176/degree 177/plusminus 178/twosuperior 179/threesuperior",
+"180/acute 181/mu 182/paragraph 183/periodcentered 184/cedilla",
+"185/onesuperior 186/ordmasculine 187/guillemotright 188/onequarter",
+"189/onehalf 190/threequarters 191/questiondown 192/Agrave 193/Aacute",
+"194/Acircumflex 195/Atilde 196/Adieresis 197/Aring 198/AE 199/Ccedilla",
+"200/Egrave 201/Eacute 202/Ecircumflex 203/Edieresis 204/Igrave 205/Iacute",
+"206/Icircumflex 207/Idieresis 208/Eth 209/Ntilde 210/Ograve 211/Oacute",
+"212/Ocircumflex 213/Otilde 214/Odieresis 215/multiply 216/Oslash",
+"217/Ugrave 218/Uacute 219/Ucircumflex 220/Udieresis 221/Yacute 222/Thorn",
+"223/germandbls 224/agrave 225/aacute 226/acircumflex 227/atilde",
+"228/adieresis 229/aring 230/ae 231/ccedilla 232/egrave 233/eacute",
+"234/ecircumflex 235/edieresis 236/igrave 237/iacute 238/icircumflex",
+"239/idieresis 240/eth 241/ntilde 242/ograve 243/oacute 244/ocircumflex",
+"245/otilde 246/odieresis 247/divide 248/oslash 249/ugrave 250/uacute",
+"251/ucircumflex 252/udieresis 253/yacute 254/thorn 255/ydieresis",
+"] bind def",
+"",
+"/reencdict 12 dict def",
+"",
+};
+
+static const char *iso_8859_2_data[] = {
+"/newcodes % ISO-8859-2 character encodings",
+"[",
+"160/space 161/Aogonek 162/breve 163/Lslash 164/currency 165/Lcaron",
+"166/Sacute 167/section 168/dieresis 169/Scaron 170/Scommaaccent",
+"171/Tcaron 172/Zacute 173/hyphen 174/Zcaron 175/Zdotaccent 176/degree",
+"177/aogonek 178/ogonek 179/lslash 180/acute 181/lcaron 182/sacute",
+"183/caron 184/cedilla 185/scaron 186/scommaaccent 187/tcaron",
+"188/zacute 189/hungarumlaut 190/zcaron 191/zdotaccent 192/Racute",
+"193/Aacute 194/Acircumflex 195/Abreve 196/Adieresis 197/Lacute",
+"198/Cacute 199/Ccedilla 200/Ccaron 201/Eacute 202/Eogonek",
+"203/Edieresis 204/Ecaron 205/Iacute 206/Icircumflex 207/Dcaron",
+"208/Dcroat 209/Nacute 210/Ncaron 211/Oacute 212/Ocircumflex",
+"213/Ohungarumlaut 214/Odieresis 215/multiply 216/Rcaron 217/Uring",
+"218/Uacute 219/Uhungarumlaut 220/Udieresis 221/Yacute 222/Tcommaaccent",
+"223/germandbls 224/racute 225/aacute 226/acircumflex 227/abreve",
+"228/adieresis 229/lacute 230/cacute 231/ccedilla 232/ccaron 233/eacute",
+"234/eogonek 235/edieresis 236/ecaron 237/iacute 238/icircumflex",
+"239/dcaron 240/dcroat 241/nacute 242/ncaron 243/oacute 244/ocircumflex",
+"245/ohungarumlaut 246/odieresis 247/divide 248/rcaron 249/uring",
+"250/uacute 251/uhungarumlaut 252/udieresis 253/yacute 254/tcommaaccent",
+"255/dotaccent",
+"] bind def",
+"",
+"/reencdict 12 dict def",
+"",
+};
+
+static const char *iso_8859_5_data[] = {
+"/newcodes % ISO-8859-5 character encodings",
+"[",
+"160/space 161/afii10023 162/afii10051 163/afii10052 164/afii10053",
+"165/afii10054 166/afii10055 167/afii10056 168/afii10057 169/afii10058",
+"170/afii10059 171/afii10060 172/afii10061 173/hyphen 174/afii10062",
+"175/afii10145 176/afii10017 177/afii10018 178/afii10019 179/afii10020",
+"180/afii10021 181/afii10022 182/afii10024 183/afii10025 184/afii10026",
+"185/afii10027 186/afii10028 187/afii10029 188/afii10030 189/afii10031",
+"190/afii10032 191/afii10033 192/afii10034 193/afii10035 194/afii10036",
+"195/afii10037 196/afii10038 197/afii10039 198/afii10040 199/afii10041",
+"200/afii10042 201/afii10043 202/afii10044 203/afii10045 204/afii10046",
+"205/afii10047 206/afii10048 207/afii10049 208/afii10065 209/afii10066",
+"210/afii10067 211/afii10068 212/afii10069 213/afii10070 214/afii10072",
+"215/afii10073 216/afii10074 217/afii10075 218/afii10076 219/afii10077",
+"220/afii10078 221/afii10079 222/afii10080 223/afii10081 224/afii10082",
+"225/afii10083 226/afii10084 227/afii10085 228/afii10086 229/afii10087",
+"230/afii10088 231/afii10089 232/afii10090 233/afii10091 234/afii10092",
+"235/afii10093 236/afii10094 237/afii10095 238/afii10096 239/afii10097",
+"240/afii61352 241/afii10071 242/afii10099 243/afii10100 244/afii10101",
+"245/afii10102 246/afii10103 247/afii10104 248/afii10105 249/afii10106",
+"250/afii10107 251/afii10108 252/afii10109 253/section 254/afii10110",
+"255/afii10193",
+"] bind def",
+"",
+"/reencdict 12 dict def",
+"",
+};
+
+static const char *iso_8859_x_func[] = {
+"% change fonts using ISO-8859-x characters",
+"/ChgFnt % size psname natname => font",
+"{",
+" dup FontDirectory exch known % is re-encoded name known?",
+" { exch pop } % yes, get rid of long name",
+" { dup 3 1 roll ReEncode } ifelse % no, re-encode it",
+" findfont exch scalefont setfont",
+"} bind def",
+"",
+"/ReEncode",
+"{",
+"reencdict begin",
+" /newname exch def",
+" /basename exch def",
+" /basedict basename findfont def",
+" /newfont basedict maxlength dict def",
+" basedict",
+" { exch dup /FID ne",
+" { dup /Encoding eq",
+" { exch dup length array copy newfont 3 1 roll put }",
+" { exch newfont 3 1 roll put } ifelse",
+" }",
+" { pop pop } ifelse",
+" } forall",
+" newfont /FontName newname put",
+" newcodes aload pop newcodes length 2 idiv",
+" { newfont /Encoding get 3 1 roll put } repeat",
+" newname newfont definefont pop",
+"end",
+"} bind def",
+"",
+};
+
+static const char *misc_func[] = {
+"% draw a line and show the string",
+"/LineShow % string linewidth movement",
+"{",
+" gsave",
+" 0 exch rmoveto",
+" setlinewidth",
+" dup",
+" stringwidth pop",
+" 0 rlineto stroke",
+" grestore",
+" show",
+"} bind def",
+"",
+"% begin an EPS file (level 2 and up)",
+"/BeginEPSF",
+"{",
+" /b4_Inc_state save def",
+" /dict_count countdictstack def",
+" /op_count count 1 sub def",
+" userdict begin",
+" /showpage { } def",
+" 0 setgray 0 setlinecap",
+" 1 setlinewidth 0 setlinejoin",
+" 10 setmiterlimit [ ] 0 setdash newpath",
+" false setstrokeadjust false setoverprint",
+"} bind def",
+"",
+"% end an EPS file",
+"/EndEPSF {",
+" count op_count sub { pop } repeat",
+" countdictstack dict_count sub { end } repeat",
+" b4_Inc_state restore",
+"} bind def",
+"",
+};
+
+
+/*
+ * vAddPageSetup - add the page setup
+ */
+static void
+vAddPageSetup(FILE *pOutFile)
+{
+ if (bUseLandscape) {
+ fprintf(pOutFile, "%%%%BeginPageSetup\n");
+ fprintf(pOutFile, "90 rotate\n");
+ fprintf(pOutFile, "0.00 %.2f translate\n",
+ -dDrawUnits2Points(lPageHeight));
+ fprintf(pOutFile, "%%%%EndPageSetup\n");
+ }
+} /* end of vAddPageSetup */
+
+/*
+ * vAddHdrFtr - add a header or footer
+ */
+static void
+vAddHdrFtr(diagram_type *pDiag, const hdrftr_block_type *pHdrFtrInfo)
+{
+ output_type *pStart, *pPrev, *pNext;
+
+ fail(pDiag == NULL);
+ fail(pHdrFtrInfo == NULL);
+
+ vStartOfParagraphPS(pDiag, 0);
+ pStart = pHdrFtrInfo->pText;
+ while (pStart != NULL) {
+ pNext = pStart;
+ while (pNext != NULL &&
+ (pNext->tNextFree != 1 ||
+ (pNext->szStorage[0] != PAR_END &&
+ pNext->szStorage[0] != HARD_RETURN))) {
+ pNext = pNext->pNext;
+ }
+ if (pNext == NULL) {
+ if (bOutputContainsText(pStart)) {
+ vAlign2Window(pDiag, pStart,
+ lChar2MilliPoints(DEFAULT_SCREEN_WIDTH),
+ ALIGNMENT_LEFT);
+ } else {
+ vMove2NextLinePS(pDiag, pStart->usFontSize);
+ }
+ break;
+ }
+ fail(pNext->tNextFree != 1);
+ fail(pNext->szStorage[0] != PAR_END &&
+ pNext->szStorage[0] != HARD_RETURN);
+
+ if (pStart != pNext) {
+ /* There is something to print */
+ pPrev = pNext->pPrev;
+ fail(pPrev->pNext != pNext);
+ /* Cut the chain */
+ pPrev->pNext = NULL;
+ if (bOutputContainsText(pStart)) {
+ /* Print it */
+ vAlign2Window(pDiag, pStart,
+ lChar2MilliPoints(DEFAULT_SCREEN_WIDTH),
+ ALIGNMENT_LEFT);
+ } else {
+ /* Just an empty line */
+ vMove2NextLinePS(pDiag, pStart->usFontSize);
+ }
+ /* Repair the chain */
+ pPrev->pNext = pNext;
+ }
+ if (pNext->szStorage[0] == PAR_END) {
+ vEndOfParagraphPS(pDiag, pNext->usFontSize,
+ (long)pNext->usFontSize * 200);
+ }
+ pStart = pNext->pNext;
+ }
+} /* end of vAddHdrFtr */
+
+/*
+ * vAddHeader - add a page header
+ */
+static void
+vAddHeader(diagram_type *pDiag)
+{
+ const hdrftr_block_type *pHdrInfo;
+ const hdrftr_block_type *pFtrInfo;
+
+ fail(pDiag == NULL);
+
+ NO_DBG_MSG("vAddHeader");
+
+ pHdrInfo = pGetHdrFtrInfo(iSectionIndex, TRUE,
+ odd(iPageCount), bFirstInSection);
+ pFtrInfo = pGetHdrFtrInfo(iSectionIndex, FALSE,
+ odd(iPageCount), bFirstInSection);
+ /* Set the height of the footer of this page */
+ lFooterHeight = pFtrInfo == NULL ? 0 : pFtrInfo->lHeight;
+ fail(lFooterHeight < 0);
+
+ if (pHdrInfo == NULL ||
+ pHdrInfo->pText == NULL ||
+ pHdrInfo->lHeight <= 0) {
+ fail(pHdrInfo != NULL && pHdrInfo->lHeight < 0);
+ fail(pHdrInfo != NULL &&
+ pHdrInfo->pText != NULL &&
+ pHdrInfo->lHeight == 0);
+ return;
+ }
+
+ vAddHdrFtr(pDiag, pHdrInfo);
+
+ DBG_DEC_C(pHdrInfo->lHeight !=
+ lPageHeight - PS_TOP_MARGIN - pDiag->lYtop,
+ pHdrInfo->lHeight);
+ DBG_DEC_C(pHdrInfo->lHeight !=
+ lPageHeight - PS_TOP_MARGIN - pDiag->lYtop,
+ lPageHeight - PS_TOP_MARGIN - pDiag->lYtop);
+
+#if 0 /* defined(DEBUG) */
+ fprintf(pDiag->pOutFile,
+ "(HEADER: FileOffset 0x%04lx-0x%04lx; Height %ld-%ld) show\n",
+ ulCharPos2FileOffset(pHdrInfo->ulCharPosStart),
+ ulCharPos2FileOffset(pHdrInfo->ulCharPosNext),
+ pHdrInfo->lHeight,
+ lPageHeight - PS_TOP_MARGIN - pDiag->lYtop);
+#endif
+} /* end of vAddHeader */
+
+/*
+ * vAddFooter - add a page footer
+ */
+static void
+vAddFooter(diagram_type *pDiag)
+{
+ const hdrftr_block_type *pFtrInfo;
+
+ fail(pDiag == NULL);
+
+ NO_DBG_MSG("vAddFooter");
+ pFtrInfo = pGetHdrFtrInfo(iSectionIndex, FALSE,
+ odd(iPageCount), bFirstInSection);
+ bFirstInSection = FALSE;
+ if (pFtrInfo == NULL ||
+ pFtrInfo->pText == NULL ||
+ pFtrInfo->lHeight <= 0) {
+ fail(pFtrInfo != NULL && pFtrInfo->lHeight < 0);
+ fail(pFtrInfo != NULL &&
+ pFtrInfo->pText != NULL &&
+ pFtrInfo->lHeight == 0);
+ return;
+ }
+
+ bInFtrSpace = TRUE;
+
+ DBG_DEC_C(pFtrInfo->lHeight != lFooterHeight, pFtrInfo->lHeight);
+ DBG_DEC_C(pFtrInfo->lHeight != lFooterHeight, lFooterHeight);
+ DBG_DEC_C(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN,
+ pDiag->lYtop);
+ DBG_DEC_C(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN,
+ lFooterHeight + PS_BOTTOM_MARGIN);
+
+ if (pDiag->lYtop > lFooterHeight + PS_BOTTOM_MARGIN) {
+ /* Move down to the start of the footer */
+ pDiag->lYtop = lFooterHeight + PS_BOTTOM_MARGIN;
+ vMoveTo(pDiag, 0);
+ } else if (pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN / 2) {
+ DBG_FIXME();
+ /*
+ * Move up to the start of the footer, to prevent moving
+ * of the bottom edge of the paper
+ */
+ pDiag->lYtop = lFooterHeight + PS_BOTTOM_MARGIN;
+ vMoveTo(pDiag, 0);
+ }
+
+ DBG_FLT_C(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN,
+ dDrawUnits2Points(lFooterHeight + PS_BOTTOM_MARGIN - pDiag->lYtop));
+
+#if 0 /* defined(DEBUG) */
+ fprintf(pDiag->pOutFile,
+ "(FOOTER: FileOffset 0x%04lx-0x%04lx; Bottom %ld-%ld) show\n",
+ ulCharPos2FileOffset(pFtrInfo->ulCharPosStart),
+ ulCharPos2FileOffset(pFtrInfo->ulCharPosNext),
+ pDiag->lYtop,
+ pFtrInfo->lHeight + PS_BOTTOM_MARGIN);
+#endif
+ vAddHdrFtr(pDiag, pFtrInfo);
+ bInFtrSpace = FALSE;
+} /* end of vAddFooter */
+
+/*
+ * vMove2NextPage - move to the start of the next page
+ */
+static void
+vMove2NextPage(diagram_type *pDiag, BOOL bNewSection)
+{
+ fail(pDiag == NULL);
+
+ vAddFooter(pDiag);
+ fprintf(pDiag->pOutFile, "showpage\n");
+ iPageCount++;
+ fprintf(pDiag->pOutFile, "%%%%Page: %d %d\n", iPageCount, iPageCount);
+ if (bNewSection) {
+ iSectionIndex++;
+ bFirstInSection = TRUE;
+ }
+ vAddPageSetup(pDiag->pOutFile);
+ pDiag->lYtop = lPageHeight - PS_TOP_MARGIN;
+ lYtopCurr = -1;
+ vAddHeader(pDiag);
+} /* end of vMove2NextPage */
+
+/*
+ * vMoveTo - move to the specified X,Y coordinates
+ *
+ * Move the current position of the specified diagram to its X,Y coordinates,
+ * start on a new page if needed
+ */
+static void
+vMoveTo(diagram_type *pDiag, long lLastVerticalMovement)
+{
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+
+ if (pDiag->lYtop <= lFooterHeight + PS_BOTTOM_MARGIN && !bInFtrSpace) {
+ vMove2NextPage(pDiag, FALSE);
+ /* Repeat the last vertical movement on the new page */
+ pDiag->lYtop -= lLastVerticalMovement;
+ }
+
+ fail(pDiag->lYtop < lFooterHeight + PS_BOTTOM_MARGIN && !bInFtrSpace);
+ DBG_DEC_C(pDiag->lYtop < PS_BOTTOM_MARGIN, pDiag->lYtop);
+ fail(pDiag->lYtop < PS_BOTTOM_MARGIN / 3);
+
+ if (pDiag->lYtop != lYtopCurr) {
+ fprintf(pDiag->pOutFile, "%.2f %.2f moveto\n",
+ dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
+ dDrawUnits2Points(pDiag->lYtop));
+ lYtopCurr = pDiag->lYtop;
+ }
+} /* end of vMoveTo */
+
+/*
+ * vProloguePS - set options and perform the PostScript initialization
+ */
+void
+vProloguePS(diagram_type *pDiag,
+ const char *szTask, const char *szFilename,
+ const options_type *pOptions)
+{
+ FILE *pOutFile;
+ const char *szTmp;
+ time_t tTime;
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(szTask == NULL || szTask[0] == '\0');
+ fail(pOptions == NULL);
+
+ pOutFile = pDiag->pOutFile;
+
+ bUseLandscape = pOptions->bUseLandscape;
+ eEncoding = pOptions->eEncoding;
+ eImageLevel = pOptions->eImageLevel;
+
+ if (pOptions->iPageHeight == INT_MAX) {
+ lPageHeight = LONG_MAX;
+ } else {
+ lPageHeight = lPoints2DrawUnits(pOptions->iPageHeight);
+ }
+ DBG_DEC(lPageHeight);
+ if (pOptions->iPageWidth == INT_MAX) {
+ lPageWidth = LONG_MAX;
+ } else {
+ lPageWidth = lPoints2DrawUnits(pOptions->iPageWidth);
+ }
+ DBG_DEC(lPageWidth);
+ lFooterHeight = 0;
+ bInFtrSpace = FALSE;
+
+ tFontRefCurr = (drawfile_fontref)-1;
+ usFontSizeCurr = 0;
+ iFontColorCurr = -1;
+ lYtopCurr = -1;
+ iPageCount = 0;
+ iImageCount = 0;
+ iSectionIndex = 0;
+ bFirstInSection = TRUE;
+ pDiag->lXleft = 0;
+ pDiag->lYtop = lPageHeight - PS_TOP_MARGIN;
+
+ szCreator = szTask;
+
+ fprintf(pOutFile, "%%!PS-Adobe-2.0\n");
+ fprintf(pOutFile, "%%%%Title: %s\n", szBasename(szFilename));
+ fprintf(pOutFile, "%%%%Creator: %s %s\n", szCreator, VERSIONSTRING);
+ szTmp = getenv("LOGNAME");
+ if (szTmp == NULL || szTmp[0] == '\0') {
+ szTmp = getenv("USER");
+ if (szTmp == NULL || szTmp[0] == '\0') {
+ szTmp = "unknown";
+ }
+ }
+ fprintf(pOutFile, "%%%%For: %.50s\n", szTmp);
+ errno = 0;
+ tTime = time(NULL);
+ if (tTime == (time_t)-1 && errno != 0) {
+ szCreationDate = NULL;
+ } else {
+ szCreationDate = ctime(&tTime);
+ }
+ if (szCreationDate == NULL || szCreationDate[0] == '\0') {
+ szCreationDate = "unknown\n";
+ }
+ fprintf(pOutFile, "%%%%CreationDate: %s", szCreationDate);
+ if (bUseLandscape) {
+ fprintf(pOutFile, "%%%%Orientation: Landscape\n");
+ fprintf(pOutFile, "%%%%BoundingBox: 0 0 %.0f %.0f\n",
+ dDrawUnits2Points(lPageHeight),
+ dDrawUnits2Points(lPageWidth));
+ } else {
+ fprintf(pOutFile, "%%%%Orientation: Portrait\n");
+ fprintf(pOutFile, "%%%%BoundingBox: 0 0 %.0f %.0f\n",
+ dDrawUnits2Points(lPageWidth),
+ dDrawUnits2Points(lPageHeight));
+ }
+} /* end of vProloguePS */
+
+/*
+ * vEpiloguePS - clean up after everything is done
+ */
+void
+vEpiloguePS(diagram_type *pDiag)
+{
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+
+ if (pDiag->lYtop < lPageHeight - PS_TOP_MARGIN) {
+ vAddFooter(pDiag);
+ fprintf(pDiag->pOutFile, "showpage\n");
+ }
+ fprintf(pDiag->pOutFile, "%%%%Trailer\n");
+ fprintf(pDiag->pOutFile, "%%%%Pages: %d\n", iPageCount);
+ fprintf(pDiag->pOutFile, "%%%%EOF\n");
+ szCreationDate = NULL;
+ szCreator = NULL;
+} /* end of vEpiloguePS */
+
+/*
+ * vPrintPalette - print a postscript palette
+ */
+static void
+vPrintPalette(FILE *pOutFile, const imagedata_type *pImg)
+{
+ int iIndex;
+
+ fail(pOutFile == NULL);
+ fail(pImg == NULL);
+ fail(pImg->iColorsUsed < 2);
+ fail(pImg->iColorsUsed > 256);
+
+ fprintf(pOutFile, "[ /Indexed\n");
+ fprintf(pOutFile, "\t/Device%s %d\n",
+ pImg->bColorImage ? "RGB" : "Gray", pImg->iColorsUsed - 1);
+ fprintf(pOutFile, "<");
+ for (iIndex = 0; iIndex < pImg->iColorsUsed; iIndex++) {
+ fprintf(pOutFile, "%02x",
+ (unsigned int)pImg->aucPalette[iIndex][0]);
+ if (pImg->bColorImage) {
+ fprintf(pOutFile, "%02x%02x",
+ (unsigned int)pImg->aucPalette[iIndex][1],
+ (unsigned int)pImg->aucPalette[iIndex][2]);
+ }
+ if (iIndex % 8 == 7) {
+ fprintf(pOutFile, "\n");
+ } else {
+ fprintf(pOutFile, " ");
+ }
+ }
+ fprintf(pOutFile, ">\n");
+ fprintf(pOutFile, "] setcolorspace\n");
+} /* end of vPrintPalette */
+
+/*
+ * vImageProloguePS - perform the Encapsulated PostScript initialization
+ */
+void
+vImageProloguePS(diagram_type *pDiag, const imagedata_type *pImg)
+{
+ FILE *pOutFile;
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(pImg == NULL);
+
+ if (pImg->iVerSizeScaled <= 0 || pImg->iHorSizeScaled <= 0) {
+ return;
+ }
+
+ fail(szCreationDate == NULL);
+ fail(szCreator == NULL);
+ fail(eImageLevel == level_no_images);
+
+ iImageCount++;
+
+ DBG_DEC_C(pDiag->lXleft != 0, pDiag->lXleft);
+
+ pDiag->lYtop -= lPoints2DrawUnits(pImg->iVerSizeScaled);
+ vMoveTo(pDiag, lPoints2DrawUnits(pImg->iVerSizeScaled));
+
+ pOutFile = pDiag->pOutFile;
+
+ fprintf(pOutFile, "BeginEPSF\n");
+ fprintf(pOutFile, "%%%%BeginDocument: image%03d.eps\n", iImageCount);
+ fprintf(pOutFile, "%%!PS-Adobe-2.0 EPSF-2.0\n");
+ fprintf(pOutFile, "%%%%Creator: %s %s\n", szCreator, VERSIONSTRING);
+ fprintf(pOutFile, "%%%%Title: Image %03d\n", iImageCount);
+ fprintf(pOutFile, "%%%%CreationDate: %s", szCreationDate);
+ fprintf(pOutFile, "%%%%BoundingBox: 0 0 %d %d\n",
+ pImg->iHorSizeScaled, pImg->iVerSizeScaled);
+ fprintf(pOutFile, "%%%%DocumentData: Clean7Bit\n");
+ fprintf(pOutFile, "%%%%LanguageLevel: 2\n");
+ fprintf(pOutFile, "%%%%EndComments\n");
+ fprintf(pOutFile, "%%%%BeginProlog\n");
+ fprintf(pOutFile, "%%%%EndProlog\n");
+ fprintf(pOutFile, "%%%%Page: 1 1\n");
+
+ fprintf(pOutFile, "save\n");
+
+ switch (pImg->eImageType) {
+ case imagetype_is_jpeg:
+ fprintf(pOutFile, "/Data1 currentfile ");
+ fprintf(pOutFile, "/ASCII85Decode filter def\n");
+ fprintf(pOutFile, "/Data Data1 << ");
+ fprintf(pOutFile, ">> /DCTDecode filter def\n");
+ switch (pImg->iComponents) {
+ case 1:
+ fprintf(pOutFile, "/DeviceGray setcolorspace\n");
+ break;
+ case 3:
+ fprintf(pOutFile, "/DeviceRGB setcolorspace\n");
+ break;
+ case 4:
+ fprintf(pOutFile, "/DeviceCMYK setcolorspace\n");
+ break;
+ default:
+ DBG_DEC(pImg->iComponents);
+ break;
+ }
+ break;
+ case imagetype_is_png:
+ if (eImageLevel == level_gs_special) {
+ fprintf(pOutFile,
+ "/Data2 currentfile /ASCII85Decode filter def\n");
+ fprintf(pOutFile,
+ "/Data1 Data2 << >> /FlateDecode filter def\n");
+ fprintf(pOutFile, "/Data Data1 <<\n");
+ fprintf(pOutFile, "\t/Colors %d\n", pImg->iComponents);
+ fprintf(pOutFile, "\t/BitsPerComponent %u\n",
+ pImg->uiBitsPerComponent);
+ fprintf(pOutFile, "\t/Columns %d\n", pImg->iWidth);
+ fprintf(pOutFile,
+ ">> /PNGPredictorDecode filter def\n");
+ } else {
+ fprintf(pOutFile,
+ "/Data1 currentfile /ASCII85Decode filter def\n");
+ fprintf(pOutFile,
+ "/Data Data1 << >> /FlateDecode filter def\n");
+ }
+ if (pImg->iComponents == 3 || pImg->iComponents == 4) {
+ fprintf(pOutFile, "/DeviceRGB setcolorspace\n");
+ } else if (pImg->iColorsUsed > 0) {
+ vPrintPalette(pOutFile, pImg);
+ } else {
+ fprintf(pOutFile, "/DeviceGray setcolorspace\n");
+ }
+ break;
+ case imagetype_is_dib:
+ fprintf(pOutFile, "/Data currentfile ");
+ fprintf(pOutFile, "/ASCII85Decode filter def\n");
+ if (pImg->uiBitsPerComponent <= 8) {
+ vPrintPalette(pOutFile, pImg);
+ } else {
+ fprintf(pOutFile, "/DeviceRGB setcolorspace\n");
+ }
+ break;
+ default:
+ fprintf(pOutFile, "/Data currentfile ");
+ fprintf(pOutFile, "/ASCIIHexDecode filter def\n");
+ fprintf(pOutFile, "/Device%s setcolorspace\n",
+ pImg->bColorImage ? "RGB" : "Gray");
+ break;
+ }
+
+ /* Translate to lower left corner of image */
+ fprintf(pOutFile, "%.2f %.2f translate\n",
+ dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
+ dDrawUnits2Points(pDiag->lYtop));
+
+ fprintf(pOutFile, "%d %d scale\n",
+ pImg->iHorSizeScaled, pImg->iVerSizeScaled);
+
+ fprintf(pOutFile, "{ <<\n");
+ fprintf(pOutFile, "\t/ImageType 1\n");
+ fprintf(pOutFile, "\t/Width %d\n", pImg->iWidth);
+ fprintf(pOutFile, "\t/Height %d\n", pImg->iHeight);
+ if (pImg->eImageType == imagetype_is_dib) {
+ /* Scanning from left to right and bottom to top */
+ fprintf(pOutFile, "\t/ImageMatrix [ %d 0 0 %d 0 0 ]\n",
+ pImg->iWidth, pImg->iHeight);
+ } else {
+ /* Scanning from left to right and top to bottom */
+ fprintf(pOutFile, "\t/ImageMatrix [ %d 0 0 %d 0 %d ]\n",
+ pImg->iWidth, -pImg->iHeight, pImg->iHeight);
+ }
+ fprintf(pOutFile, "\t/DataSource Data\n");
+
+ switch (pImg->eImageType) {
+ case imagetype_is_jpeg:
+ fprintf(pOutFile, "\t/BitsPerComponent 8\n");
+ switch (pImg->iComponents) {
+ case 1:
+ fprintf(pOutFile, "\t/Decode [0 1]\n");
+ break;
+ case 3:
+ fprintf(pOutFile, "\t/Decode [0 1 0 1 0 1]\n");
+ break;
+ case 4:
+ if (pImg->bAdobe) {
+ /*
+ * Adobe-conforming CMYK file
+ * applying workaround for color inversion
+ */
+ fprintf(pOutFile,
+ "\t/Decode [1 0 1 0 1 0 1 0]\n");
+ } else {
+ fprintf(pOutFile,
+ "\t/Decode [0 1 0 1 0 1 0 1]\n");
+ }
+ break;
+ default:
+ DBG_DEC(pImg->iComponents);
+ break;
+ }
+ break;
+ case imagetype_is_png:
+ if (pImg->iComponents == 3) {
+ fprintf(pOutFile, "\t/BitsPerComponent 8\n");
+ fprintf(pOutFile, "\t/Decode [0 1 0 1 0 1]\n");
+ } else if (pImg->iColorsUsed > 0) {
+ fail(pImg->uiBitsPerComponent > 8);
+ fprintf(pOutFile, "\t/BitsPerComponent %u\n",
+ pImg->uiBitsPerComponent);
+ fprintf(pOutFile, "\t/Decode [0 %d]\n",
+ (1 << pImg->uiBitsPerComponent) - 1);
+ } else {
+ fprintf(pOutFile, "\t/BitsPerComponent 8\n");
+ fprintf(pOutFile, "\t/Decode [0 1]\n");
+ }
+ break;
+ case imagetype_is_dib:
+ fprintf(pOutFile, "\t/BitsPerComponent 8\n");
+ if (pImg->uiBitsPerComponent <= 8) {
+ fprintf(pOutFile, "\t/Decode [0 255]\n");
+ } else {
+ fprintf(pOutFile, "\t/Decode [0 1 0 1 0 1]\n");
+ }
+ break;
+ default:
+ fprintf(pOutFile, "\t/BitsPerComponent 8\n");
+ if (pImg->bColorImage) {
+ fprintf(pOutFile, "\t/Decode [0 1 0 1 0 1]\n");
+ } else {
+ fprintf(pOutFile, "\t/Decode [0 1]\n");
+ }
+ break;
+ }
+
+ fprintf(pOutFile, " >> image\n");
+ fprintf(pOutFile, " Data closefile\n");
+ fprintf(pOutFile, " showpage\n");
+ fprintf(pOutFile, " restore\n");
+ fprintf(pOutFile, "} exec\n");
+} /* end of vImageProloguePS */
+
+/*
+ * vImageEpiloguePS - clean up after Encapsulated PostScript
+ */
+void
+vImageEpiloguePS(diagram_type *pDiag)
+{
+ FILE *pOutFile;
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+
+ pOutFile = pDiag->pOutFile;
+
+ fprintf(pOutFile, "%%%%EOF\n");
+ fprintf(pOutFile, "%%%%EndDocument\n");
+ fprintf(pOutFile, "EndEPSF\n");
+
+ pDiag->lXleft = 0;
+} /* end of vImageEpiloguePS */
+
+/*
+ * bAddDummyImagePS - add a dummy image
+ *
+ * return TRUE when successful, otherwise FALSE
+ */
+BOOL
+bAddDummyImagePS(diagram_type *pDiag, const imagedata_type *pImg)
+{
+ FILE *pOutFile;
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(pImg == NULL);
+
+ if (pImg->iVerSizeScaled <= 0 || pImg->iHorSizeScaled <= 0) {
+ return FALSE;
+ }
+
+ iImageCount++;
+
+ DBG_DEC_C(pDiag->lXleft != 0, pDiag->lXleft);
+
+ pDiag->lYtop -= lPoints2DrawUnits(pImg->iVerSizeScaled);
+ vMoveTo(pDiag, lPoints2DrawUnits(pImg->iVerSizeScaled));
+
+ pOutFile = pDiag->pOutFile;
+
+ fprintf(pOutFile, "gsave %% Image %03d\n", iImageCount);
+ fprintf(pOutFile, "\tnewpath\n");
+ fprintf(pOutFile, "\t%.2f %.2f moveto\n",
+ dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
+ dDrawUnits2Points(pDiag->lYtop));
+ fprintf(pOutFile, "\t1.0 setlinewidth\n");
+ fprintf(pOutFile, "\t0.3 setgray\n");
+ fprintf(pOutFile, "\t0 %d rlineto\n", pImg->iVerSizeScaled);
+ fprintf(pOutFile, "\t%d 0 rlineto\n", pImg->iHorSizeScaled);
+ fprintf(pOutFile, "\t0 %d rlineto\n", -pImg->iVerSizeScaled);
+ fprintf(pOutFile, "\tclosepath\n");
+ fprintf(pOutFile, "\tstroke\n");
+ fprintf(pOutFile, "grestore\n");
+
+ pDiag->lXleft = 0;
+
+ return TRUE;
+} /* end of bAddDummyImagePS */
+
+/*
+ * vAddFontsPS - add the list of fonts and complete the prologue
+ */
+void
+vAddFontsPS(diagram_type *pDiag)
+{
+ FILE *pOutFile;
+ const font_table_type *pTmp, *pTmp2;
+ size_t tIndex;
+ int iLineLen, iOurFontnameLen;
+ BOOL bFound;
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+
+ pOutFile = pDiag->pOutFile;
+ iLineLen = fprintf(pOutFile, "%%%%DocumentFonts:");
+
+ if (tGetFontTableLength() == 0) {
+ iLineLen += fprintf(pOutFile, " Courier");
+ } else {
+ pTmp = NULL;
+ while ((pTmp = pGetNextFontTableRecord(pTmp)) != NULL) {
+ /* Print the document fonts */
+ bFound = FALSE;
+ pTmp2 = NULL;
+ while ((pTmp2 = pGetNextFontTableRecord(pTmp2))
+ != NULL && pTmp2 < pTmp) {
+ bFound = STREQ(pTmp2->szOurFontname,
+ pTmp->szOurFontname);
+ if (bFound) {
+ break;
+ }
+ }
+ iOurFontnameLen = (int)strlen(pTmp->szOurFontname);
+ if (bFound || iOurFontnameLen <= 0) {
+ continue;
+ }
+ if (iLineLen + iOurFontnameLen > 76) {
+ fprintf(pOutFile, "\n%%%%+");
+ iLineLen = 3;
+ }
+ iLineLen += fprintf(pOutFile,
+ " %s", pTmp->szOurFontname);
+ }
+ }
+ fprintf(pOutFile, "\n");
+ fprintf(pOutFile, "%%%%Pages: (atend)\n");
+ fprintf(pOutFile, "%%%%EndComments\n");
+ fprintf(pOutFile, "%%%%BeginProlog\n");
+
+ switch (eEncoding) {
+ case encoding_latin_1:
+ for (tIndex = 0;
+ tIndex < elementsof(iso_8859_1_data);
+ tIndex++) {
+ fprintf(pOutFile, "%s\n", iso_8859_1_data[tIndex]);
+ }
+ fprintf(pOutFile, "\n");
+ for (tIndex = 0;
+ tIndex < elementsof(iso_8859_x_func);
+ tIndex++) {
+ fprintf(pOutFile, "%s\n", iso_8859_x_func[tIndex]);
+ }
+ break;
+ case encoding_latin_2:
+ for (tIndex = 0;
+ tIndex < elementsof(iso_8859_2_data);
+ tIndex++) {
+ fprintf(pOutFile, "%s\n", iso_8859_2_data[tIndex]);
+ }
+ fprintf(pOutFile, "\n");
+ for (tIndex = 0;
+ tIndex < elementsof(iso_8859_x_func);
+ tIndex++) {
+ fprintf(pOutFile, "%s\n", iso_8859_x_func[tIndex]);
+ }
+ break;
+ case encoding_cyrillic:
+ for (tIndex = 0;
+ tIndex < elementsof(iso_8859_5_data);
+ tIndex++) {
+ fprintf(pOutFile, "%s\n", iso_8859_5_data[tIndex]);
+ }
+ fprintf(pOutFile, "\n");
+ for (tIndex = 0;
+ tIndex < elementsof(iso_8859_x_func);
+ tIndex++) {
+ fprintf(pOutFile, "%s\n", iso_8859_x_func[tIndex]);
+ }
+ break;
+ case encoding_utf_8:
+ werr(1,
+ "The combination PostScript and UTF-8 is not supported");
+ break;
+ default:
+ DBG_DEC(eEncoding);
+ break;
+ }
+
+ /* The rest of the functions */
+ for (tIndex = 0; tIndex < elementsof(misc_func); tIndex++) {
+ fprintf(pOutFile, "%s\n", misc_func[tIndex]);
+ }
+ fprintf(pOutFile, "%%%%EndProlog\n");
+ iPageCount = 1;
+ fprintf(pDiag->pOutFile, "%%%%Page: %d %d\n", iPageCount, iPageCount);
+ vAddPageSetup(pDiag->pOutFile);
+ vAddHeader(pDiag);
+} /* end of vAddFontsPS */
+
+/*
+ * vPrintPS - print a PostScript string
+ */
+static void
+vPrintPS(FILE *pFile, const char *szString, size_t tStringLength,
+ USHORT usFontstyle)
+{
+ double dSuperscriptMove, dSubscriptMove;
+ const UCHAR *ucBytes;
+ size_t tCount;
+
+ fail(szString == NULL);
+
+ if (szString == NULL || szString[0] == '\0' || tStringLength == 0) {
+ return;
+ }
+ DBG_DEC_C(usFontSizeCurr < MIN_FONT_SIZE, usFontSizeCurr);
+
+ dSuperscriptMove = 0.0;
+ dSubscriptMove = 0.0;
+
+ /* Up for superscript */
+ if (bIsSuperscript(usFontstyle) && usFontSizeCurr != 0) {
+ dSuperscriptMove = (double)((usFontSizeCurr + 1) / 2) * 0.375;
+ fprintf(pFile, "0 %.2f rmoveto\n", dSuperscriptMove);
+ }
+
+ /* Down for subscript */
+ if (bIsSubscript(usFontstyle) && usFontSizeCurr != 0) {
+ dSubscriptMove = (double)usFontSizeCurr * 0.125;
+ fprintf(pFile, "0 %.2f rmoveto\n", -dSubscriptMove);
+ }
+
+ /* Generate and print the PostScript output */
+ ucBytes = (UCHAR *)szString;
+ (void)putc('(', pFile);
+ for (tCount = 0; tCount < tStringLength ; tCount++) {
+ switch (ucBytes[tCount]) {
+ case '(':
+ case ')':
+ case '\\':
+ (void)putc('\\', pFile);
+ (void)putc(szString[tCount], pFile);
+ break;
+ default:
+ if (ucBytes[tCount] < 0x20 ||
+ (ucBytes[tCount] >= 0x7f &&
+ ucBytes[tCount] < 0x8c)) {
+ DBG_HEX(ucBytes[tCount]);
+ (void)putc(' ', pFile);
+ } else if (ucBytes[tCount] >= 0x80) {
+ fprintf(pFile, "\\%03o", (UINT)ucBytes[tCount]);
+ } else {
+ (void)putc(szString[tCount], pFile);
+ }
+ break;
+ }
+ }
+ fprintf(pFile, ") ");
+ if ((bIsStrike(usFontstyle) || bIsMarkDel(usFontstyle)) &&
+ usFontSizeCurr != 0) {
+ fprintf(pFile, "%.2f %.2f LineShow\n",
+ (double)usFontSizeCurr * 0.02,
+ (double)usFontSizeCurr * 0.12);
+ } else if (bIsUnderline(usFontstyle) && usFontSizeCurr != 0) {
+ fprintf(pFile, "%.2f %.2f LineShow\n",
+ (double)usFontSizeCurr * 0.02,
+ (double)usFontSizeCurr * -0.06);
+ } else {
+ fprintf(pFile, "show\n");
+ }
+
+ /* Undo the superscript move */
+ if (bIsSuperscript(usFontstyle) && usFontSizeCurr != 0) {
+ fprintf(pFile, "0 %.2f rmoveto\n", -dSuperscriptMove);
+ }
+
+ /* Undo the subscript move */
+ if (bIsSubscript(usFontstyle) && usFontSizeCurr != 0) {
+ fprintf(pFile, "0 %.2f rmoveto\n", dSubscriptMove);
+ }
+} /* end of vPrintPS */
+
+/*
+ * vSetColor - move to the specified color
+ */
+static void
+vSetColor(FILE *pFile, UCHAR ucFontColor)
+{
+ ULONG ulTmp, ulRed, ulGreen, ulBlue;
+
+ ulTmp = ulColor2Color(ucFontColor);
+ ulRed = (ulTmp & 0x0000ff00) >> 8;
+ ulGreen = (ulTmp & 0x00ff0000) >> 16;
+ ulBlue = (ulTmp & 0xff000000) >> 24;
+ fprintf(pFile, "%.3f %.3f %.3f setrgbcolor\n",
+ ulRed / 255.0, ulGreen / 255.0, ulBlue / 255.0);
+} /* end of vSetColor */
+
+/*
+ * vMove2NextLinePS - move to the next line
+ */
+void
+vMove2NextLinePS(diagram_type *pDiag, USHORT usFontSize)
+{
+ fail(pDiag == NULL);
+ fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
+
+ pDiag->lYtop -= lComputeLeading(usFontSize);
+} /* end of vMove2NextLinePS */
+
+/*
+ * vSubstringPS - print a sub string
+ */
+void
+vSubstringPS(diagram_type *pDiag,
+ char *szString, size_t tStringLength, long lStringWidth,
+ UCHAR ucFontColor, USHORT usFontstyle, drawfile_fontref tFontRef,
+ USHORT usFontSize, USHORT usMaxFontSize)
+{
+ const char *szOurFontname;
+
+ fail(pDiag == NULL || szString == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(pDiag->lXleft < 0);
+ fail(tStringLength != strlen(szString));
+ fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
+ fail(usMaxFontSize < MIN_FONT_SIZE || usMaxFontSize > MAX_FONT_SIZE);
+ fail(usFontSize > usMaxFontSize);
+
+ if (szString[0] == '\0' || tStringLength == 0) {
+ return;
+ }
+
+ if (tFontRef != tFontRefCurr || usFontSize != usFontSizeCurr) {
+ szOurFontname = szGetFontname(tFontRef);
+ fail(szOurFontname == NULL);
+ fprintf(pDiag->pOutFile,
+ "%.1f /%s /%s-ISO-8859-x ChgFnt\n",
+ (double)usFontSize / 2.0,
+ szOurFontname, szOurFontname);
+ tFontRefCurr = tFontRef;
+ usFontSizeCurr = usFontSize;
+ }
+ if ((int)ucFontColor != iFontColorCurr) {
+ vSetColor(pDiag->pOutFile, ucFontColor);
+ iFontColorCurr = (int)ucFontColor;
+ }
+ vMoveTo(pDiag, lComputeLeading(usMaxFontSize));
+ vPrintPS(pDiag->pOutFile, szString, tStringLength, usFontstyle);
+ pDiag->lXleft += lStringWidth;
+} /* end of vSubstringPS */
+
+/*
+ * Create an start of paragraph by moving the y-top mark
+ */
+void
+vStartOfParagraphPS(diagram_type *pDiag, long lBeforeIndentation)
+{
+ fail(pDiag == NULL);
+ fail(lBeforeIndentation < 0);
+
+ pDiag->lXleft = 0;
+ pDiag->lYtop -= lMilliPoints2DrawUnits(lBeforeIndentation);
+} /* end of vStartOfParagraphPS */
+
+/*
+ * Create an end of paragraph by moving the y-top mark
+ */
+void
+vEndOfParagraphPS(diagram_type *pDiag,
+ USHORT usFontSize, long lAfterIndentation)
+{
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
+ fail(lAfterIndentation < 0);
+
+ if (pDiag->lXleft > 0) {
+ /* To the start of the line */
+ vMove2NextLinePS(pDiag, usFontSize);
+ }
+
+ pDiag->lXleft = 0;
+ pDiag->lYtop -= lMilliPoints2DrawUnits(lAfterIndentation);
+} /* end of vEndOfParagraphPS */
+
+/*
+ * Create an end of page
+ */
+void
+vEndOfPagePS(diagram_type *pDiag, BOOL bNewSection)
+{
+ vMove2NextPage(pDiag, bNewSection);
+} /* end of vEndOfPagePS */
diff --git a/sys/src/cmd/aux/antiword/prop0.c b/sys/src/cmd/aux/antiword/prop0.c
new file mode 100755
index 000000000..bac2fbdb2
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/prop0.c
@@ -0,0 +1,489 @@
+/*
+ * prop0.c
+ * Copyright (C) 2002-2004 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Read the property information from a Word for DOS file
+ */
+
+#include <string.h>
+#include <time.h>
+#include "antiword.h"
+
+
+/*
+ * tConvertDosDate - convert DOS date format
+ *
+ * returns Unix time_t or -1
+ */
+static time_t
+tConvertDosDate(const char *szDosDate)
+{
+ struct tm tTime;
+ const char *pcTmp;
+ time_t tResult;
+
+ memset(&tTime, 0, sizeof(tTime));
+ pcTmp = szDosDate;
+ /* Get the month */
+ if (!isdigit(*pcTmp)) {
+ return (time_t)-1;
+ }
+ tTime.tm_mon = (int)(*pcTmp - '0');
+ pcTmp++;
+ if (isdigit(*pcTmp)) {
+ tTime.tm_mon *= 10;
+ tTime.tm_mon += (int)(*pcTmp - '0');
+ pcTmp++;
+ }
+ /* Get the first separater */
+ if (isalnum(*pcTmp)) {
+ return (time_t)-1;
+ }
+ pcTmp++;
+ /* Get the day */
+ if (!isdigit(*pcTmp)) {
+ return (time_t)-1;
+ }
+ tTime.tm_mday = (int)(*pcTmp - '0');
+ pcTmp++;
+ if (isdigit(*pcTmp)) {
+ tTime.tm_mday *= 10;
+ tTime.tm_mday += (int)(*pcTmp - '0');
+ pcTmp++;
+ }
+ /* Get the second separater */
+ if (isalnum(*pcTmp)) {
+ return (time_t)-1;
+ }
+ pcTmp++;
+ /* Get the year */
+ if (!isdigit(*pcTmp)) {
+ return (time_t)-1;
+ }
+ tTime.tm_year = (int)(*pcTmp - '0');
+ pcTmp++;
+ if (isdigit(*pcTmp)) {
+ tTime.tm_year *= 10;
+ tTime.tm_year += (int)(*pcTmp - '0');
+ pcTmp++;
+ }
+ /* Check the values */
+ if (tTime.tm_mon == 0 || tTime.tm_mday == 0 || tTime.tm_mday > 31) {
+ return (time_t)-1;
+ }
+ /* Correct the values */
+ tTime.tm_mon--; /* From 01-12 to 00-11 */
+ if (tTime.tm_year < 80) {
+ tTime.tm_year += 100; /* 00 means 2000 is 100 */
+ }
+ tTime.tm_isdst = -1;
+ tResult = mktime(&tTime);
+ NO_DBG_MSG(ctime(&tResult));
+ return tResult;
+} /* end of tConvertDosDate */
+
+/*
+ * Build the lists with Document Property Information for Word for DOS files
+ */
+void
+vGet0DopInfo(FILE *pFile, const UCHAR *aucHeader)
+{
+ document_block_type tDocument;
+ UCHAR *aucBuffer;
+ ULONG ulBeginSumdInfo, ulBeginNextBlock;
+ size_t tLen;
+ USHORT usOffset;
+
+ tDocument.ucHdrFtrSpecification = 0;
+ tDocument.usDefaultTabWidth = usGetWord(0x70, aucHeader); /* dxaTab */
+ tDocument.tCreateDate = (time_t)-1;
+ tDocument.tRevisedDate = (time_t)-1;
+
+ ulBeginSumdInfo = 128 * (ULONG)usGetWord(0x1c, aucHeader);
+ DBG_HEX(ulBeginSumdInfo);
+ ulBeginNextBlock = 128 * (ULONG)usGetWord(0x6a, aucHeader);
+ DBG_HEX(ulBeginNextBlock);
+
+ if (ulBeginSumdInfo < ulBeginNextBlock && ulBeginNextBlock != 0) {
+ /* There is a summary information block */
+ tLen = (size_t)(ulBeginNextBlock - ulBeginSumdInfo);
+ aucBuffer = xmalloc(tLen);
+ /* Read the summary information block */
+ if (bReadBytes(aucBuffer, tLen, ulBeginSumdInfo, pFile)) {
+ usOffset = usGetWord(12, aucBuffer);
+ if (aucBuffer[usOffset] != 0) {
+ NO_DBG_STRN(aucBuffer + usOffset, 8);
+ tDocument.tRevisedDate =
+ tConvertDosDate((char *)aucBuffer + usOffset);
+ }
+ usOffset = usGetWord(14, aucBuffer);
+ if (aucBuffer[usOffset] != 0) {
+ NO_DBG_STRN(aucBuffer + usOffset, 8);
+ tDocument.tCreateDate =
+ tConvertDosDate((char *)aucBuffer + usOffset);
+ }
+ }
+ aucBuffer = xfree(aucBuffer);
+ }
+ vCreateDocumentInfoList(&tDocument);
+} /* end of vGet0DopInfo */
+
+/*
+ * Fill the section information block with information
+ * from a Word for DOS file.
+ */
+static void
+vGet0SectionInfo(const UCHAR *aucGrpprl, size_t tBytes,
+ section_block_type *pSection)
+{
+ USHORT usCcol;
+ UCHAR ucTmp;
+
+ fail(aucGrpprl == NULL || pSection == NULL);
+
+ if (tBytes < 2) {
+ return;
+ }
+ /* bkc */
+ ucTmp = ucGetByte(1, aucGrpprl);
+ DBG_HEX(ucTmp);
+ ucTmp &= 0x07;
+ DBG_HEX(ucTmp);
+ pSection->bNewPage = ucTmp != 0 && ucTmp != 1;
+ if (tBytes < 18) {
+ return;
+ }
+ /* ccolM1 */
+ usCcol = (USHORT)ucGetByte(17, aucGrpprl);
+ DBG_DEC(usCcol);
+} /* end of vGet0SectionInfo */
+
+/*
+ * Build the lists with Section Property Information for Word for DOS files
+ */
+void
+vGet0SepInfo(FILE *pFile, const UCHAR *aucHeader)
+{
+ section_block_type tSection;
+ UCHAR *aucBuffer;
+ ULONG ulBeginOfText, ulTextOffset, ulBeginSectInfo;
+ ULONG ulCharPos, ulSectPage, ulBeginNextBlock;
+ size_t tSectInfoLen, tIndex, tSections, tBytes;
+ UCHAR aucTmp[2], aucFpage[35];
+
+ fail(pFile == NULL || aucHeader == NULL);
+
+ ulBeginOfText = 128;
+ NO_DBG_HEX(ulBeginOfText);
+ ulBeginSectInfo = 128 * (ULONG)usGetWord(0x18, aucHeader);
+ DBG_HEX(ulBeginSectInfo);
+ ulBeginNextBlock = 128 * (ULONG)usGetWord(0x1a, aucHeader);
+ DBG_HEX(ulBeginNextBlock);
+ if (ulBeginSectInfo == ulBeginNextBlock) {
+ /* There is no section information block */
+ return;
+ }
+
+ /* Get the the number of sections */
+ if (!bReadBytes(aucTmp, 2, ulBeginSectInfo, pFile)) {
+ return;
+ }
+ tSections = (size_t)usGetWord(0, aucTmp);
+ NO_DBG_DEC(tSections);
+
+ /* Read the Section Descriptors */
+ tSectInfoLen = 10 * tSections;
+ NO_DBG_DEC(tSectInfoLen);
+ aucBuffer = xmalloc(tSectInfoLen);
+ if (!bReadBytes(aucBuffer, tSectInfoLen, ulBeginSectInfo + 4, pFile)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tSectInfoLen);
+
+ /* Read the Section Properties */
+ for (tIndex = 0; tIndex < tSections; tIndex++) {
+ ulTextOffset = ulGetLong(10 * tIndex, aucBuffer);
+ NO_DBG_HEX(ulTextOffset);
+ ulCharPos = ulBeginOfText + ulTextOffset;
+ NO_DBG_HEX(ulTextOffset);
+ ulSectPage = ulGetLong(10 * tIndex + 6, aucBuffer);
+ NO_DBG_HEX(ulSectPage);
+ if (ulSectPage == FC_INVALID || /* Must use defaults */
+ ulSectPage < 128 || /* Should not happen */
+ ulSectPage >= ulBeginSectInfo) { /* Should not happen */
+ DBG_HEX_C(ulSectPage != FC_INVALID, ulSectPage);
+ vDefault2SectionInfoList(ulCharPos);
+ continue;
+ }
+ /* Get the number of bytes to read */
+ if (!bReadBytes(aucTmp, 1, ulSectPage, pFile)) {
+ continue;
+ }
+ tBytes = 1 + (size_t)ucGetByte(0, aucTmp);
+ NO_DBG_DEC(tBytes);
+ if (tBytes > sizeof(aucFpage)) {
+ DBG_DEC(tBytes);
+ tBytes = sizeof(aucFpage);
+ }
+ /* Read the bytes */
+ if (!bReadBytes(aucFpage, tBytes, ulSectPage, pFile)) {
+ continue;
+ }
+ NO_DBG_PRINT_BLOCK(aucFpage, tBytes);
+ /* Process the bytes */
+ vGetDefaultSection(&tSection);
+ vGet0SectionInfo(aucFpage + 1, tBytes - 1, &tSection);
+ vAdd2SectionInfoList(&tSection, ulCharPos);
+ }
+ /* Clean up before you leave */
+ aucBuffer = xfree(aucBuffer);
+} /* end of vGet0SepInfo */
+
+/*
+ * Fill the style information block with information
+ * from a Word for DOS file.
+ */
+static void
+vGet0StyleInfo(int iFodo, const UCHAR *aucGrpprl, style_block_type *pStyle)
+{
+ int iBytes;
+ UCHAR ucTmp;
+
+ fail(iFodo <= 0 || aucGrpprl == NULL || pStyle == NULL);
+
+ pStyle->usIstdNext = ISTD_NORMAL;
+
+ iBytes = (int)ucGetByte(iFodo, aucGrpprl);
+ if (iBytes < 1) {
+ return;
+ }
+ /* stc if styled */
+ ucTmp = ucGetByte(iFodo + 1, aucGrpprl);
+ if ((ucTmp & BIT(0)) != 0) {
+ ucTmp >>= 1;
+ if (ucTmp >= 88 && ucTmp <= 94) {
+ /* Header levels 1 through 7 */
+ pStyle->usIstd = ucTmp - 87;
+ pStyle->ucNumLevel = 1;
+ }
+ }
+ if (iBytes < 2) {
+ return;
+ }
+ /* jc */
+ ucTmp = ucGetByte(iFodo + 2, aucGrpprl);
+ pStyle->ucAlignment = ucTmp & 0x02;
+ if (iBytes < 3) {
+ return;
+ }
+ /* stc */
+ ucTmp = ucGetByte(iFodo + 3, aucGrpprl);
+ ucTmp &= 0x7f;
+ if (ucTmp >= 88 && ucTmp <= 94) {
+ /* Header levels 1 through 7 */
+ pStyle->usIstd = ucTmp - 87;
+ pStyle->ucNumLevel = 1;
+ }
+ if (iBytes < 6) {
+ return;
+ }
+ /* dxaRight */
+ pStyle->sRightIndent = (short)usGetWord(iFodo + 5, aucGrpprl);
+ NO_DBG_DEC(pStyle->sRightIndent);
+ if (iBytes < 8) {
+ return;
+ }
+ /* dxaLeft */
+ pStyle->sLeftIndent = (short)usGetWord(iFodo + 7, aucGrpprl);
+ NO_DBG_DEC(pStyle->sLeftIndent);
+ if (iBytes < 10) {
+ return;
+ }
+ /* dxaLeft1 */
+ pStyle->sLeftIndent1 = (short)usGetWord(iFodo + 9, aucGrpprl);
+ NO_DBG_DEC(pStyle->sLeftIndent1);
+ if (iBytes < 14) {
+ return;
+ }
+ /* dyaBefore */
+ pStyle->usBeforeIndent = usGetWord(iFodo + 13, aucGrpprl);
+ NO_DBG_DEC(pStyle->usBeforeIndent);
+ if (iBytes < 16) {
+ return;
+ }
+ /* dyaAfter */
+ pStyle->usAfterIndent = usGetWord(iFodo + 15, aucGrpprl);
+ NO_DBG_DEC(pStyle->usAfterIndent);
+} /* end of vGet0StyleInfo */
+
+/*
+ * Build the lists with Paragraph Information for Word for DOS files
+ */
+void
+vGet0PapInfo(FILE *pFile, const UCHAR *aucHeader)
+{
+ style_block_type tStyle;
+ ULONG ulBeginParfInfo, ulCharPos, ulCharPosNext;
+ int iIndex, iRun, iFodo;
+ UCHAR aucFpage[128];
+
+ fail(pFile == NULL || aucHeader == NULL);
+
+ ulBeginParfInfo = 128 * (ULONG)usGetWord(0x12, aucHeader);
+ NO_DBG_HEX(ulBeginParfInfo);
+
+ do {
+ if (!bReadBytes(aucFpage, 128, ulBeginParfInfo, pFile)) {
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucFpage, 128);
+ ulCharPosNext = ulGetLong(0, aucFpage);
+ iRun = (int)ucGetByte(0x7f, aucFpage);
+ NO_DBG_DEC(iRun);
+ for (iIndex = 0; iIndex < iRun; iIndex++) {
+ iFodo = (int)usGetWord(6 * iIndex + 8, aucFpage);
+ if (iFodo <= 0 || iFodo > 0x79) {
+ DBG_DEC_C(iFodo != (int)0xffff, iFodo);
+ continue;
+ }
+ vFillStyleFromStylesheet(0, &tStyle);
+ vGet0StyleInfo(iFodo, aucFpage + 4, &tStyle);
+ ulCharPos = ulCharPosNext;
+ ulCharPosNext = ulGetLong(6 * iIndex + 4, aucFpage);
+ tStyle.ulFileOffset = ulCharPos;
+ vAdd2StyleInfoList(&tStyle);
+ }
+ ulBeginParfInfo += 128;
+ } while (ulCharPosNext == ulBeginParfInfo);
+} /* end of vGet0PapInfo */
+
+/*
+ * Fill the font information block with information
+ * from a Word for DOS file.
+ */
+static void
+vGet0FontInfo(int iFodo, const UCHAR *aucGrpprl, font_block_type *pFont)
+{
+ int iBytes;
+ UCHAR ucTmp;
+
+ fail(iFodo <= 0 || aucGrpprl == NULL || pFont == NULL);
+
+ iBytes = (int)ucGetByte(iFodo, aucGrpprl);
+ if (iBytes < 2) {
+ return;
+ }
+ /* fBold, fItalic, cFtc */
+ ucTmp = ucGetByte(iFodo + 2, aucGrpprl);
+ if ((ucTmp & BIT(0)) != 0) {
+ pFont->usFontStyle |= FONT_BOLD;
+ }
+ if ((ucTmp & BIT(1)) != 0) {
+ pFont->usFontStyle |= FONT_ITALIC;
+ }
+ pFont->ucFontNumber = ucTmp >> 2;
+ NO_DBG_DEC(pFont->ucFontNumber);
+ if (iBytes < 3) {
+ return;
+ }
+ /* cHps */
+ pFont->usFontSize = (USHORT)ucGetByte(iFodo + 3, aucGrpprl);
+ NO_DBG_DEC(pFont->usFontSize);
+ if (iBytes < 4) {
+ return;
+ }
+ /* cKul, fStrike, fCaps, fSmallCaps, fVanish */
+ ucTmp = ucGetByte(iFodo + 4, aucGrpprl);
+ if ((ucTmp & BIT(0)) != 0 || (ucTmp & BIT(2)) != 0) {
+ pFont->usFontStyle |= FONT_UNDERLINE;
+ }
+ if ((ucTmp & BIT(1)) != 0) {
+ pFont->usFontStyle |= FONT_STRIKE;
+ }
+ if ((ucTmp & BIT(4)) != 0) {
+ pFont->usFontStyle |= FONT_CAPITALS;
+ }
+ if ((ucTmp & BIT(5)) != 0) {
+ pFont->usFontStyle |= FONT_SMALL_CAPITALS;
+ }
+ if ((ucTmp & BIT(7)) != 0) {
+ pFont->usFontStyle |= FONT_HIDDEN;
+ }
+ DBG_HEX(pFont->usFontStyle);
+ if (iBytes < 6) {
+ return;
+ }
+ /* cIss */
+ ucTmp = ucGetByte(iFodo + 6, aucGrpprl);
+ if (ucTmp != 0) {
+ if (ucTmp < 128) {
+ pFont->usFontStyle |= FONT_SUPERSCRIPT;
+ DBG_MSG("Superscript");
+ } else {
+ pFont->usFontStyle |= FONT_SUBSCRIPT;
+ DBG_MSG("Subscript");
+ }
+ }
+ if (iBytes < 7) {
+ return;
+ }
+ /* cIco */
+ ucTmp = ucGetByte(iFodo + 7, aucGrpprl);
+ switch (ucTmp & 0x07) {
+ case 0: pFont->ucFontColor = FONT_COLOR_BLACK; break;
+ case 1: pFont->ucFontColor = FONT_COLOR_RED; break;
+ case 2: pFont->ucFontColor = FONT_COLOR_GREEN; break;
+ case 3: pFont->ucFontColor = FONT_COLOR_BLUE; break;
+ case 4: pFont->ucFontColor = FONT_COLOR_CYAN; break;
+ case 5: pFont->ucFontColor = FONT_COLOR_MAGENTA; break;
+ case 6: pFont->ucFontColor = FONT_COLOR_YELLOW; break;
+ case 7: pFont->ucFontColor = FONT_COLOR_WHITE; break;
+ default:pFont->ucFontColor = FONT_COLOR_BLACK; break;
+ }
+ NO_DBG_DEC(pFont->ucFontColor);
+} /* end of vGet0FontInfo */
+
+/*
+ * Build the lists with Character Information for Word for DOS files
+ */
+void
+vGet0ChrInfo(FILE *pFile, const UCHAR *aucHeader)
+{
+ font_block_type tFont;
+ ULONG ulBeginCharInfo, ulCharPos, ulCharPosNext;
+ int iIndex, iRun, iFodo;
+ UCHAR aucFpage[128];
+
+ fail(pFile == NULL || aucHeader == NULL);
+
+ ulBeginCharInfo = ulGetLong(0x0e, aucHeader);
+ NO_DBG_HEX(ulBeginCharInfo);
+ ulBeginCharInfo = ROUND128(ulBeginCharInfo);
+ NO_DBG_HEX(ulBeginCharInfo);
+
+ do {
+ if (!bReadBytes(aucFpage, 128, ulBeginCharInfo, pFile)) {
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucFpage, 128);
+ ulCharPosNext = ulGetLong(0, aucFpage);
+ iRun = (int)ucGetByte(0x7f, aucFpage);
+ NO_DBG_DEC(iRun);
+ for (iIndex = 0; iIndex < iRun; iIndex++) {
+ iFodo = (int)usGetWord(6 * iIndex + 8, aucFpage);
+ if (iFodo <= 0 || iFodo > 0x79) {
+ DBG_DEC_C(iFodo != (int)0xffff, iFodo);
+ continue;
+ }
+ vFillFontFromStylesheet(0, &tFont);
+ vGet0FontInfo(iFodo, aucFpage + 4, &tFont);
+ ulCharPos = ulCharPosNext;
+ ulCharPosNext = ulGetLong(6 * iIndex + 4, aucFpage);
+ tFont.ulFileOffset = ulCharPos;
+ vAdd2FontInfoList(&tFont);
+ }
+ ulBeginCharInfo += 128;
+ } while (ulCharPosNext == ulBeginCharInfo);
+} /* end of vGet0ChrInfo */
diff --git a/sys/src/cmd/aux/antiword/prop2.c b/sys/src/cmd/aux/antiword/prop2.c
new file mode 100755
index 000000000..eda108a6a
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/prop2.c
@@ -0,0 +1,1067 @@
+/*
+ * prop2.c
+ * Copyright (C) 2002-2005 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Read the property information from a WinWord 1 or 2 file
+ */
+
+#include <string.h>
+#include "antiword.h"
+
+
+#define MAX_FILESIZE 0x2000000UL /* 32 Mb */
+
+/*
+ * iGet2InfoLength - the length of the information for WinWord 1/2 files
+ */
+static int
+iGet2InfoLength(int iByteNbr, const UCHAR *aucGrpprl)
+{
+ int iTmp, iDel, iAdd;
+
+ switch (ucGetByte(iByteNbr, aucGrpprl)) {
+ case 3: case 15: case 78: case 152: case 154: case 155:
+ return 2 + (int)ucGetByte(iByteNbr + 1, aucGrpprl);
+ case 16: case 17: case 18: case 19: case 21: case 22: case 26:
+ case 27: case 28: case 30: case 31: case 32: case 33: case 34:
+ case 35: case 36: case 38: case 39: case 40: case 41: case 42:
+ case 43: case 45: case 46: case 47: case 48: case 49: case 68:
+ case 71: case 72: case 82: case 83: case 96: case 97: case 98:
+ case 99: case 115: case 116: case 119: case 120: case 123: case 124:
+ case 129: case 130: case 131: case 132: case 135: case 136: case 139:
+ case 140: case 141: case 142: case 143: case 144: case 145: case 146:
+ case 147: case 148: case 153: case 159: case 161: case 162:
+ return 1 + 2;
+ case 23:
+ iTmp = (int)ucGetByte(iByteNbr + 1, aucGrpprl);
+ if (iTmp == 255) {
+ iDel = (int)ucGetByte(iByteNbr + 2, aucGrpprl);
+ iAdd = (int)ucGetByte(
+ iByteNbr + 3 + iDel * 4, aucGrpprl);
+ iTmp = 2 + iDel * 4 + iAdd * 3;
+ }
+ return 2 + iTmp;
+ case 70:
+ return 1 + 3;
+ case 95:
+ return 1 + 13;
+ case 157: case 163:
+ return 1 + 5;
+ case 158: case 160: case 164:
+ return 1 + 4;
+ default:
+ return 1 + 1;
+ }
+} /* end of iGet2InfoLength */
+
+/*
+ * Build the lists with Document Property Information for WinWord 1/2 files
+ */
+void
+vGet2DopInfo(FILE *pFile, const UCHAR *aucHeader)
+{
+ document_block_type tDocument;
+ UCHAR *aucBuffer;
+ ULONG ulBeginDocpInfo, ulTmp;
+ size_t tDocpInfoLen;
+ USHORT usTmp;
+
+ ulBeginDocpInfo = ulGetLong(0x112, aucHeader); /* fcDop */
+ DBG_HEX(ulBeginDocpInfo);
+ tDocpInfoLen = (size_t)usGetWord(0x116, aucHeader); /* cbDop */
+ DBG_DEC(tDocpInfoLen);
+ if (tDocpInfoLen < 28) {
+ DBG_MSG("No Document information");
+ return;
+ }
+
+ aucBuffer = xmalloc(tDocpInfoLen);
+ if (!bReadBytes(aucBuffer, tDocpInfoLen, ulBeginDocpInfo, pFile)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+
+ usTmp = usGetWord(0x00, aucBuffer);
+ tDocument.ucHdrFtrSpecification = (UCHAR)(usTmp >> 8); /* grpfIhdt */
+ tDocument.usDefaultTabWidth = usGetWord(0x0a, aucBuffer); /* dxaTab */
+ ulTmp = ulGetLong(0x14, aucBuffer); /* dttmCreated */
+ tDocument.tCreateDate = tConvertDTTM(ulTmp);
+ ulTmp = ulGetLong(0x18, aucBuffer); /* dttmRevised */
+ tDocument.tRevisedDate = tConvertDTTM(ulTmp);
+ vCreateDocumentInfoList(&tDocument);
+
+ aucBuffer = xfree(aucBuffer);
+} /* end of vGet2DopInfo */
+
+/*
+ * Fill the section information block with information
+ * from a WinWord 1/2 file.
+ */
+static void
+vGet2SectionInfo(const UCHAR *aucGrpprl, size_t tBytes,
+ section_block_type *pSection)
+{
+ int iFodoOff, iInfoLen;
+ USHORT usCcol;
+ UCHAR ucTmp;
+
+ fail(aucGrpprl == NULL || pSection == NULL);
+
+ iFodoOff = 0;
+ while (tBytes >= (size_t)iFodoOff + 1) {
+ switch (ucGetByte(iFodoOff, aucGrpprl)) {
+ case 117: /* bkc */
+ ucTmp = ucGetByte(iFodoOff + 1, aucGrpprl);
+ DBG_DEC(ucTmp);
+ pSection->bNewPage = ucTmp != 0 && ucTmp != 1;
+ break;
+ case 119: /* ccolM1 */
+ usCcol = 1 + usGetWord(iFodoOff + 1, aucGrpprl);
+ DBG_DEC(usCcol);
+ break;
+ case 128: /* grpfIhdt */
+ pSection->ucHdrFtrSpecification =
+ ucGetByte(iFodoOff + 1, aucGrpprl);
+ break;
+ default:
+ break;
+ }
+ iInfoLen = iGet2InfoLength(iFodoOff, aucGrpprl);
+ fail(iInfoLen <= 0);
+ iFodoOff += iInfoLen;
+ }
+} /* end of vGet2SectionInfo */
+
+/*
+ * Build the lists with Section Property Information for WinWord 1/2 files
+ */
+void
+vGet2SepInfo(FILE *pFile, const UCHAR *aucHeader)
+{
+ section_block_type tSection;
+ ULONG *aulSectPage, *aulCharPos;
+ UCHAR *aucBuffer, *aucFpage;
+ ULONG ulBeginOfText, ulTextOffset, ulBeginSectInfo;
+ size_t tSectInfoLen, tIndex, tOffset, tLen, tBytes;
+ UCHAR aucTmp[1];
+
+ fail(pFile == NULL || aucHeader == NULL);
+
+ ulBeginOfText = ulGetLong(0x18, aucHeader); /* fcMin */
+ NO_DBG_HEX(ulBeginOfText);
+ ulBeginSectInfo = ulGetLong(0x7c, aucHeader); /* fcPlcfsed */
+ DBG_HEX(ulBeginSectInfo);
+ tSectInfoLen = (size_t)usGetWord(0x80, aucHeader); /* cbPlcfsed */
+ DBG_DEC(tSectInfoLen);
+ if (tSectInfoLen < 4) {
+ DBG_DEC(tSectInfoLen);
+ return;
+ }
+
+ aucBuffer = xmalloc(tSectInfoLen);
+ if (!bReadBytes(aucBuffer, tSectInfoLen, ulBeginSectInfo, pFile)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tSectInfoLen);
+
+ /* Read the Section Descriptors */
+ tLen = (tSectInfoLen - 4) / 10;
+ /* Save the section offsets */
+ aulCharPos = xcalloc(tLen, sizeof(ULONG));
+ for (tIndex = 0, tOffset = 0;
+ tIndex < tLen;
+ tIndex++, tOffset += 4) {
+ ulTextOffset = ulGetLong(tOffset, aucBuffer);
+ NO_DBG_HEX(ulTextOffset);
+ aulCharPos[tIndex] = ulBeginOfText + ulTextOffset;
+ NO_DBG_HEX(aulCharPos[tIndex]);
+ }
+ /* Save the Sepx offsets */
+ aulSectPage = xcalloc(tLen, sizeof(ULONG));
+ for (tIndex = 0, tOffset = (tLen + 1) * 4;
+ tIndex < tLen;
+ tIndex++, tOffset += 6) {
+ aulSectPage[tIndex] = ulGetLong(tOffset + 2, aucBuffer);
+ NO_DBG_HEX(aulSectPage[tIndex]); /* fcSepx */
+ }
+ aucBuffer = xfree(aucBuffer);
+
+ /* Read the Section Properties */
+ for (tIndex = 0; tIndex < tLen; tIndex++) {
+ if (aulSectPage[tIndex] == FC_INVALID) {
+ vDefault2SectionInfoList(aulCharPos[tIndex]);
+ continue;
+ }
+ /* Get the number of bytes to read */
+ if (!bReadBytes(aucTmp, 1, aulSectPage[tIndex], pFile)) {
+ continue;
+ }
+ tBytes = 1 + (size_t)ucGetByte(0, aucTmp);
+ NO_DBG_DEC(tBytes);
+ /* Read the bytes */
+ aucFpage = xmalloc(tBytes);
+ if (!bReadBytes(aucFpage, tBytes, aulSectPage[tIndex], pFile)) {
+ aucFpage = xfree(aucFpage);
+ continue;
+ }
+ NO_DBG_PRINT_BLOCK(aucFpage, tBytes);
+ /* Process the bytes */
+ vGetDefaultSection(&tSection);
+ vGet2SectionInfo(aucFpage + 1, tBytes - 1, &tSection);
+ vAdd2SectionInfoList(&tSection, aulCharPos[tIndex]);
+ aucFpage = xfree(aucFpage);
+ }
+ aulCharPos = xfree(aulCharPos);
+ aulSectPage = xfree(aulSectPage);
+} /* end of vGet2SepInfo */
+
+/*
+ * Build the list with Header/Footer Information for WinWord 1/2 files
+ */
+void
+vGet2HdrFtrInfo(FILE *pFile, const UCHAR *aucHeader)
+{
+ ULONG *aulCharPos;
+ UCHAR *aucBuffer;
+ ULONG ulHdrFtrOffset, ulBeginHdrFtrInfo;
+ size_t tHdrFtrInfoLen, tIndex, tOffset, tLen;
+
+ fail(pFile == NULL || aucHeader == NULL);
+
+ ulBeginHdrFtrInfo = ulGetLong(0x9a, aucHeader); /* fcPlcfhdd */
+ NO_DBG_HEX(ulBeginHdrFtrInfo);
+ tHdrFtrInfoLen = (size_t)usGetWord(0x9e, aucHeader); /* cbPlcfhdd */
+ NO_DBG_DEC(tHdrFtrInfoLen);
+ if (tHdrFtrInfoLen < 8) {
+ DBG_DEC_C(tHdrFtrInfoLen != 0, tHdrFtrInfoLen);
+ return;
+ }
+
+ aucBuffer = xmalloc(tHdrFtrInfoLen);
+ if (!bReadBytes(aucBuffer, tHdrFtrInfoLen, ulBeginHdrFtrInfo, pFile)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tHdrFtrInfoLen);
+
+ tLen = tHdrFtrInfoLen / 4 - 1;
+ /* Save the header/footer offsets */
+ aulCharPos = xcalloc(tLen, sizeof(ULONG));
+ for (tIndex = 0, tOffset = 0;
+ tIndex < tLen;
+ tIndex++, tOffset += 4) {
+ ulHdrFtrOffset = ulGetLong(tOffset, aucBuffer);
+ NO_DBG_HEX(ulHdrFtrOffset);
+ aulCharPos[tIndex] = ulHdrFtrOffset2CharPos(ulHdrFtrOffset);
+ NO_DBG_HEX(aulCharPos[tIndex]);
+ }
+ vCreat2HdrFtrInfoList(aulCharPos, tLen);
+ aulCharPos = xfree(aulCharPos);
+ aucBuffer = xfree(aucBuffer);
+} /* end of vGet2HdrFtrInfo */
+
+/*
+ * Translate the rowinfo to a member of the row_info enumeration
+ */
+row_info_enum
+eGet2RowInfo(int iFodo,
+ const UCHAR *aucGrpprl, int iBytes, row_block_type *pRow)
+{
+ int iFodoOff, iInfoLen;
+ int iIndex, iSize, iCol;
+ int iPosCurr, iPosPrev;
+ USHORT usTmp;
+ BOOL bFound24_0, bFound24_1, bFound25_0, bFound25_1, bFound154;
+
+ fail(iFodo < 0 || aucGrpprl == NULL || pRow == NULL);
+
+ iFodoOff = 0;
+ bFound24_0 = FALSE;
+ bFound24_1 = FALSE;
+ bFound25_0 = FALSE;
+ bFound25_1 = FALSE;
+ bFound154 = FALSE;
+ while (iBytes >= iFodoOff + 1) {
+ iInfoLen = 0;
+ switch (ucGetByte(iFodo + iFodoOff, aucGrpprl)) {
+ case 24: /* fIntable */
+ if (odd(ucGetByte(iFodo + iFodoOff + 1, aucGrpprl))) {
+ bFound24_1 = TRUE;
+ } else {
+ bFound24_0 = TRUE;
+ }
+ break;
+ case 25: /* fTtp */
+ if (odd(ucGetByte(iFodo + iFodoOff + 1, aucGrpprl))) {
+ bFound25_1 = TRUE;
+ } else {
+ bFound25_0 = TRUE;
+ }
+ break;
+ case 30: /* brcTop10 */
+ usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
+ usTmp &= 0x01ff;
+ NO_DBG_DEC(usTmp >> 6);
+ if (usTmp == 0) {
+ pRow->ucBorderInfo &= ~TABLE_BORDER_TOP;
+ } else {
+ pRow->ucBorderInfo |= TABLE_BORDER_TOP;
+ }
+ break;
+ case 31: /* brcLeft10 */
+ usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
+ usTmp &= 0x01ff;
+ NO_DBG_DEC(usTmp >> 6);
+ if (usTmp == 0) {
+ pRow->ucBorderInfo &= ~TABLE_BORDER_LEFT;
+ } else {
+ pRow->ucBorderInfo |= TABLE_BORDER_LEFT;
+ }
+ break;
+ case 32: /* brcBottom10 */
+ usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
+ usTmp &= 0x01ff;
+ NO_DBG_DEC(usTmp >> 6);
+ if (usTmp == 0) {
+ pRow->ucBorderInfo &= ~TABLE_BORDER_BOTTOM;
+ } else {
+ pRow->ucBorderInfo |= TABLE_BORDER_BOTTOM;
+ }
+ break;
+ case 33: /* brcRight10 */
+ usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
+ usTmp &= 0x01ff;
+ NO_DBG_DEC(usTmp >> 6);
+ if (usTmp == 0) {
+ pRow->ucBorderInfo &= ~TABLE_BORDER_RIGHT;
+ } else {
+ pRow->ucBorderInfo |= TABLE_BORDER_RIGHT;
+ }
+ break;
+ case 38: /* brcTop */
+ usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
+ usTmp &= 0x0018;
+ NO_DBG_DEC(usTmp >> 3);
+ if (usTmp == 0) {
+ pRow->ucBorderInfo &= ~TABLE_BORDER_TOP;
+ } else {
+ pRow->ucBorderInfo |= TABLE_BORDER_TOP;
+ }
+ break;
+ case 39: /* brcLeft */
+ usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
+ usTmp &= 0x0018;
+ NO_DBG_DEC(usTmp >> 3);
+ if (usTmp == 0) {
+ pRow->ucBorderInfo &= ~TABLE_BORDER_LEFT;
+ } else {
+ pRow->ucBorderInfo |= TABLE_BORDER_LEFT;
+ }
+ break;
+ case 40: /* brcBottom */
+ usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
+ usTmp &= 0x0018;
+ NO_DBG_DEC(usTmp >> 3);
+ if (usTmp == 0) {
+ pRow->ucBorderInfo &= ~TABLE_BORDER_BOTTOM;
+ } else {
+ pRow->ucBorderInfo |= TABLE_BORDER_BOTTOM;
+ }
+ break;
+ case 41: /* brcRight */
+ usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
+ usTmp &= 0x0018;
+ NO_DBG_DEC(usTmp >> 3);
+ if (usTmp == 0) {
+ pRow->ucBorderInfo &= ~TABLE_BORDER_RIGHT;
+ } else {
+ pRow->ucBorderInfo |= TABLE_BORDER_RIGHT;
+ }
+ break;
+ case 152: /* cDefTable10 */
+ case 154: /* cDefTable */
+ iSize = (int)usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
+ if (iSize < 6 || iBytes < iFodoOff + 7) {
+ DBG_DEC(iSize);
+ DBG_DEC(iBytes);
+ DBG_DEC(iFodoOff);
+ iInfoLen = 1;
+ break;
+ }
+ iCol = (int)ucGetByte(iFodo + iFodoOff + 3, aucGrpprl);
+ if (iCol < 1 ||
+ iBytes < iFodoOff + 3 + (iCol + 1) * 2) {
+ DBG_DEC(iCol);
+ DBG_DEC(iBytes);
+ DBG_DEC(iFodoOff);
+ DBG_DEC(ucGetByte(iFodo + iFodoOff, aucGrpprl));
+ iInfoLen = 1;
+ break;
+ }
+ if (iCol >= (int)elementsof(pRow->asColumnWidth)) {
+ DBG_DEC(iCol);
+ werr(1, "The number of columns is corrupt");
+ }
+ pRow->ucNumberOfColumns = (UCHAR)iCol;
+ iPosPrev = (int)(short)usGetWord(
+ iFodo + iFodoOff + 4,
+ aucGrpprl);
+ for (iIndex = 0; iIndex < iCol; iIndex++) {
+ iPosCurr = (int)(short)usGetWord(
+ iFodo + iFodoOff + 6 + iIndex * 2,
+ aucGrpprl);
+ pRow->asColumnWidth[iIndex] =
+ (short)(iPosCurr - iPosPrev);
+ iPosPrev = iPosCurr;
+ }
+ bFound154 = TRUE;
+ break;
+ default:
+ break;
+ }
+ if (iInfoLen <= 0) {
+ iInfoLen =
+ iGet2InfoLength(iFodo + iFodoOff, aucGrpprl);
+ fail(iInfoLen <= 0);
+ }
+ iFodoOff += iInfoLen;
+ }
+ if (bFound24_1 && bFound25_1 && bFound154) {
+ return found_end_of_row;
+ }
+ if (bFound24_0 && bFound25_0 && !bFound154) {
+ return found_not_end_of_row;
+ }
+ if (bFound24_1) {
+ return found_a_cell;
+ }
+ if (bFound24_0) {
+ return found_not_a_cell;
+ }
+ return found_nothing;
+} /* end of eGet2RowInfo */
+
+/*
+ * Fill the style information block with information
+ * from a WinWord 1/2 file.
+ */
+void
+vGet2StyleInfo(int iFodo,
+ const UCHAR *aucGrpprl, int iBytes, style_block_type *pStyle)
+{
+ int iFodoOff, iInfoLen;
+ int iTmp, iDel, iAdd;
+ short sTmp;
+ UCHAR ucTmp;
+
+ fail(iFodo < 0 || aucGrpprl == NULL || pStyle == NULL);
+
+ NO_DBG_DEC(pStyle->usIstd);
+
+ iFodoOff = 0;
+ while (iBytes >= iFodoOff + 1) {
+ iInfoLen = 0;
+ switch (ucGetByte(iFodo + iFodoOff, aucGrpprl)) {
+ case 2: /* istd */
+ sTmp = (short)ucGetByte(
+ iFodo + iFodoOff + 1, aucGrpprl);
+ NO_DBG_DEC(sTmp);
+ break;
+ case 5: /* jc */
+ pStyle->ucAlignment = ucGetByte(
+ iFodo + iFodoOff + 1, aucGrpprl);
+ break;
+ case 12: /* nfcSeqNumb */
+ pStyle->ucNFC = ucGetByte(
+ iFodo + iFodoOff + 1, aucGrpprl);
+ break;
+ case 13: /* nLvlAnm */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 1, aucGrpprl);
+ pStyle->ucNumLevel = ucTmp;
+ pStyle->bNumPause =
+ eGetNumType(ucTmp) == level_type_pause;
+ break;
+ case 15: /* ChgTabsPapx */
+ case 23: /* ChgTabs */
+ iTmp = (int)ucGetByte(iFodo + iFodoOff + 1, aucGrpprl);
+ if (iTmp < 2) {
+ iInfoLen = 1;
+ break;
+ }
+ NO_DBG_DEC(iTmp);
+ iDel = (int)ucGetByte(iFodo + iFodoOff + 2, aucGrpprl);
+ if (iTmp < 2 + 2 * iDel) {
+ iInfoLen = 1;
+ break;
+ }
+ NO_DBG_DEC(iDel);
+ iAdd = (int)ucGetByte(
+ iFodo + iFodoOff + 3 + 2 * iDel, aucGrpprl);
+ if (iTmp < 2 + 2 * iDel + 2 * iAdd) {
+ iInfoLen = 1;
+ break;
+ }
+ NO_DBG_DEC(iAdd);
+ break;
+ case 16: /* dxaRight */
+ pStyle->sRightIndent = (short)usGetWord(
+ iFodo + iFodoOff + 1, aucGrpprl);
+ NO_DBG_DEC(pStyle->sRightIndent);
+ break;
+ case 17: /* dxaLeft */
+ pStyle->sLeftIndent = (short)usGetWord(
+ iFodo + iFodoOff + 1, aucGrpprl);
+ NO_DBG_DEC(pStyle->sLeftIndent);
+ break;
+ case 18: /* Nest dxaLeft */
+ sTmp = (short)usGetWord(
+ iFodo + iFodoOff + 1, aucGrpprl);
+ pStyle->sLeftIndent += sTmp;
+ if (pStyle->sLeftIndent < 0) {
+ pStyle->sLeftIndent = 0;
+ }
+ NO_DBG_DEC(sTmp);
+ NO_DBG_DEC(pStyle->sLeftIndent);
+ break;
+ case 19: /* dxaLeft1 */
+ pStyle->sLeftIndent1 = (short)usGetWord(
+ iFodo + iFodoOff + 1, aucGrpprl);
+ NO_DBG_DEC(pStyle->sLeftIndent1);
+ break;
+ case 21: /* dyaBefore */
+ pStyle->usBeforeIndent = usGetWord(
+ iFodo + iFodoOff + 1, aucGrpprl);
+ NO_DBG_DEC(pStyle->usBeforeIndent);
+ break;
+ case 22: /* dyaAfter */
+ pStyle->usAfterIndent = usGetWord(
+ iFodo + iFodoOff + 1, aucGrpprl);
+ NO_DBG_DEC(pStyle->usAfterIndent);
+ break;
+ default:
+ break;
+ }
+ if (iInfoLen <= 0) {
+ iInfoLen =
+ iGet2InfoLength(iFodo + iFodoOff, aucGrpprl);
+ fail(iInfoLen <= 0);
+ }
+ iFodoOff += iInfoLen;
+ }
+} /* end of vGet2StyleInfo */
+
+/*
+ * Build the lists with Paragraph Information for WinWord 1/2 files
+ */
+void
+vGet2PapInfo(FILE *pFile, const UCHAR *aucHeader)
+{
+ row_block_type tRow;
+ style_block_type tStyle;
+ USHORT *ausParfPage;
+ UCHAR *aucBuffer;
+ ULONG ulCharPos, ulCharPosFirst, ulCharPosLast;
+ ULONG ulBeginParfInfo;
+ size_t tParfInfoLen, tParfPageNum, tOffset, tSize, tLenOld, tLen;
+ int iIndex, iIndex2, iRun, iFodo, iLen;
+ row_info_enum eRowInfo;
+ USHORT usParfFirstPage, usCount, usIstd;
+ UCHAR ucStc;
+ UCHAR aucFpage[BIG_BLOCK_SIZE];
+
+ fail(pFile == NULL || aucHeader == NULL);
+
+ ulBeginParfInfo = ulGetLong(0xa6, aucHeader); /* fcPlcfbtePapx */
+ NO_DBG_HEX(ulBeginParfInfo);
+ tParfInfoLen = (size_t)usGetWord(0xaa, aucHeader); /* cbPlcfbtePapx */
+ NO_DBG_DEC(tParfInfoLen);
+ if (tParfInfoLen < 4) {
+ DBG_DEC(tParfInfoLen);
+ return;
+ }
+
+ aucBuffer = xmalloc(tParfInfoLen);
+ if (!bReadBytes(aucBuffer, tParfInfoLen, ulBeginParfInfo, pFile)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tParfInfoLen);
+
+ tLen = (tParfInfoLen - 4) / 6;
+ ausParfPage = xcalloc(tLen, sizeof(USHORT));
+ for (iIndex = 0, tOffset = (tLen + 1) * 4;
+ iIndex < (int)tLen;
+ iIndex++, tOffset += 2) {
+ ausParfPage[iIndex] = usGetWord(tOffset, aucBuffer);
+ NO_DBG_DEC(ausParfPage[iIndex]);
+ }
+ DBG_HEX(ulGetLong(0, aucBuffer));
+ aucBuffer = xfree(aucBuffer);
+ tParfPageNum = (size_t)usGetWord(0x144, aucHeader); /* cpnBtePap */
+ DBG_DEC(tParfPageNum);
+ if (tLen < tParfPageNum) {
+ /* Replace ParfPage by a longer version */
+ tLenOld = tLen;
+ usParfFirstPage = usGetWord(0x140, aucHeader); /* pnPapFirst */
+ DBG_DEC(usParfFirstPage);
+ tLen += tParfPageNum - 1;
+ tSize = tLen * sizeof(USHORT);
+ ausParfPage = xrealloc(ausParfPage, tSize);
+ /* Add new values */
+ usCount = usParfFirstPage + 1;
+ for (iIndex = (int)tLenOld; iIndex < (int)tLen; iIndex++) {
+ ausParfPage[iIndex] = usCount;
+ NO_DBG_DEC(ausParfPage[iIndex]);
+ usCount++;
+ }
+ }
+
+ (void)memset(&tRow, 0, sizeof(tRow));
+ ulCharPosFirst = CP_INVALID;
+ for (iIndex = 0; iIndex < (int)tLen; iIndex++) {
+ if (!bReadBytes(aucFpage, BIG_BLOCK_SIZE,
+ (ULONG)ausParfPage[iIndex] * BIG_BLOCK_SIZE,
+ pFile)) {
+ break;
+ }
+ NO_DBG_PRINT_BLOCK(aucFpage, BIG_BLOCK_SIZE);
+ iRun = (int)ucGetByte(0x1ff, aucFpage);
+ NO_DBG_DEC(iRun);
+ for (iIndex2 = 0; iIndex2 < iRun; iIndex2++) {
+ if ((iRun + 1) * 4 + iIndex2 * 1 >= BIG_BLOCK_SIZE) {
+ break;
+ }
+ NO_DBG_HEX(ulGetLong(iIndex2 * 4, aucFpage));
+ iFodo = 2 * (int)ucGetByte(
+ (iRun + 1) * 4 + iIndex2 * 1, aucFpage);
+ if (iFodo <= 0) {
+ continue;
+ }
+
+ iLen = 2 * (int)ucGetByte(iFodo, aucFpage);
+
+ ucStc = ucGetByte(iFodo + 1, aucFpage);
+ usIstd = usStc2istd(ucStc);
+
+ vFillStyleFromStylesheet(usIstd, &tStyle);
+ vGet2StyleInfo(iFodo, aucFpage + 8, iLen - 8, &tStyle);
+ ulCharPos = ulGetLong(iIndex2 * 4, aucFpage);
+ NO_DBG_HEX(ulCharPos);
+ tStyle.ulFileOffset = ulCharPos;
+ vAdd2StyleInfoList(&tStyle);
+
+ eRowInfo = eGet2RowInfo(iFodo,
+ aucFpage + 8, iLen - 8, &tRow);
+
+ switch(eRowInfo) {
+ case found_a_cell:
+ if (ulCharPosFirst != CP_INVALID) {
+ break;
+ }
+ ulCharPosFirst = ulGetLong(
+ iIndex2 * 4, aucFpage);
+ NO_DBG_HEX(ulCharPosFirst);
+ tRow.ulCharPosStart = ulCharPosFirst;
+ tRow.ulFileOffsetStart = ulCharPosFirst;
+ break;
+ case found_end_of_row:
+ ulCharPosLast = ulGetLong(
+ iIndex2 * 4, aucFpage);
+ NO_DBG_HEX(ulCharPosLast);
+ tRow.ulCharPosEnd = ulCharPosLast;
+ /* Add 1 for compatiblity with Word 6 and up */
+ tRow.ulFileOffsetEnd = ulCharPosLast + 1;
+ vAdd2RowInfoList(&tRow);
+ (void)memset(&tRow, 0, sizeof(tRow));
+ ulCharPosFirst = CP_INVALID;
+ break;
+ case found_nothing:
+ break;
+ default:
+ DBG_DEC(eRowInfo);
+ break;
+ }
+ }
+ }
+ ausParfPage = xfree(ausParfPage);
+} /* end of vGet2PapInfo */
+
+/*
+ * Fill the font information block with information
+ * from a WinWord 1 file.
+ */
+void
+vGet1FontInfo(int iFodo,
+ const UCHAR *aucGrpprl, size_t tBytes, font_block_type *pFont)
+{
+ BOOL bIcoChange, bFtcChange, bHpsChange, bKulChange;
+ USHORT usTmp;
+ UCHAR ucTmp;
+ UCHAR aucChpx[12];
+
+ fail(iFodo < 0 || aucGrpprl == NULL || pFont == NULL);
+
+ if (tBytes > sizeof(aucChpx)) {
+ NO_DBG_PRINT_BLOCK(aucGrpprl + iFodo, tBytes);
+ return;
+ }
+
+ /* Build the CHPX structure */
+ (void)memset(aucChpx, 0, sizeof(aucChpx));
+ (void)memcpy(aucChpx, aucGrpprl + iFodo, min(tBytes, sizeof(aucChpx)));
+
+ usTmp = usGetWord(0, aucChpx);
+ if ((usTmp & BIT(0)) != 0) {
+ pFont->usFontStyle ^= FONT_BOLD;
+ }
+ if ((usTmp & BIT(1)) != 0) {
+ pFont->usFontStyle ^= FONT_ITALIC;
+ }
+ if ((usTmp & BIT(2)) != 0) {
+ pFont->usFontStyle ^= FONT_STRIKE;
+ }
+ if ((usTmp & BIT(5)) != 0) {
+ pFont->usFontStyle ^= FONT_SMALL_CAPITALS;
+ }
+ if ((usTmp & BIT(6)) != 0) {
+ pFont->usFontStyle ^= FONT_CAPITALS;
+ }
+ if ((usTmp & BIT(7)) != 0) {
+ pFont->usFontStyle ^= FONT_HIDDEN;
+ }
+
+ ucTmp = ucGetByte(5, aucChpx);
+ if (ucTmp != 0) {
+ if (ucTmp < 128) {
+ pFont->usFontStyle |= FONT_SUPERSCRIPT;
+ DBG_MSG("Superscript");
+ } else {
+ pFont->usFontStyle |= FONT_SUBSCRIPT;
+ DBG_MSG("Subscript");
+ }
+ }
+
+ bIcoChange = (usTmp & BIT(10)) != 0;
+ bFtcChange = (usTmp & BIT(11)) != 0;
+ bHpsChange = (usTmp & BIT(12)) != 0;
+ bKulChange = (usTmp & BIT(13)) != 0;
+
+ if (bFtcChange) {
+ usTmp = usGetWord(2, aucChpx);
+ if (usTmp <= (USHORT)UCHAR_MAX) {
+ pFont->ucFontNumber = (UCHAR)usTmp;
+ } else {
+ pFont->ucFontNumber = 0;
+ }
+ }
+
+ if (bHpsChange) {
+ pFont->usFontSize = (USHORT)ucGetByte(4, aucChpx);
+ }
+
+ if (bIcoChange || bKulChange) {
+ usTmp = usGetWord(6, aucChpx);
+ if (bIcoChange) {
+ pFont->ucFontColor = (UCHAR)((usTmp & 0x0f00) >> 8);
+ if (pFont->ucFontColor <= 7) {
+ /* Add 1 for compatibility with Word 2 and up */
+ pFont->ucFontColor++;
+ } else {
+ DBG_DEC(pFont->ucFontColor);
+ pFont->ucFontColor = 0;
+ }
+ }
+ if (bKulChange) {
+ usTmp = (usTmp & 0x7000) >> 12;
+ DBG_DEC_C(usTmp > 4, usTmp);
+ if (usTmp == 0) {
+ pFont->usFontStyle &= ~FONT_UNDERLINE;
+ } else {
+ pFont->usFontStyle |= FONT_UNDERLINE;
+ }
+ }
+ }
+} /* end of vGet1FontInfo */
+
+/*
+ * Fill the font information block with information
+ * from a WinWord 1/2 file.
+ */
+void
+vGet2FontInfo(int iFodo,
+ const UCHAR *aucGrpprl, size_t tBytes, font_block_type *pFont)
+{
+ BOOL bIcoChange, bFtcChange, bHpsChange, bKulChange;
+ USHORT usTmp;
+ UCHAR ucTmp;
+ UCHAR aucChpx[18];
+
+ fail(iFodo < 0 || aucGrpprl == NULL || pFont == NULL);
+
+ if (tBytes > sizeof(aucChpx)) {
+ NO_DBG_PRINT_BLOCK(aucGrpprl + iFodo, tBytes);
+ return;
+ }
+
+ /* Build the CHPX structure */
+ (void)memset(aucChpx, 0, sizeof(aucChpx));
+ (void)memcpy(aucChpx, aucGrpprl + iFodo, min(tBytes, sizeof(aucChpx)));
+
+ usTmp = usGetWord(0, aucChpx);
+ if ((usTmp & BIT(0)) != 0) {
+ pFont->usFontStyle ^= FONT_BOLD;
+ }
+ if ((usTmp & BIT(1)) != 0) {
+ pFont->usFontStyle ^= FONT_ITALIC;
+ }
+ if (usTmp & BIT(3)) {
+ pFont->usFontStyle ^= FONT_MARKDEL;
+ }
+ if ((usTmp & BIT(5)) != 0) {
+ pFont->usFontStyle ^= FONT_SMALL_CAPITALS;
+ }
+ if ((usTmp & BIT(6)) != 0) {
+ pFont->usFontStyle ^= FONT_CAPITALS;
+ }
+ if ((usTmp & BIT(7)) != 0) {
+ pFont->usFontStyle ^= FONT_HIDDEN;
+ }
+ if (usTmp & BIT(10)) {
+ pFont->usFontStyle ^= FONT_STRIKE;
+ }
+
+ ucTmp = ucGetByte(10, aucChpx);
+ DBG_MSG_C(ucTmp != 0 && ucTmp < 128, "Superscript");
+ DBG_MSG_C(ucTmp >= 128, "Subscript");
+
+ usTmp = usGetWord(2, aucChpx);
+ if (usTmp == 0) {
+ /* No changes, nothing to do */
+ return;
+ }
+
+ bIcoChange = (usTmp & BIT(0)) != 0;
+ bFtcChange = (usTmp & BIT(1)) != 0;
+ bHpsChange = (usTmp & BIT(2)) != 0;
+ bKulChange = (usTmp & BIT(3)) != 0;
+
+ if (bFtcChange) {
+ usTmp = usGetWord(4, aucChpx);
+ if (usTmp <= (USHORT)UCHAR_MAX) {
+ pFont->ucFontNumber = (UCHAR)usTmp;
+ } else {
+ pFont->ucFontNumber = 0;
+ }
+ }
+
+ if (bHpsChange) {
+ pFont->usFontSize = usGetWord(6, aucChpx);
+ }
+
+ if (bIcoChange || bKulChange) {
+ ucTmp = ucGetByte(9, aucChpx);
+ if (bIcoChange) {
+ pFont->ucFontColor = ucTmp & 0x1f;
+ if (pFont->ucFontColor > 16) {
+ DBG_DEC(pFont->ucFontColor);
+ pFont->ucFontColor = 0;
+ }
+ }
+ if (bKulChange) {
+ ucTmp = (ucTmp & 0xe0) >> 5;
+ DBG_DEC_C(ucTmp > 4, ucTmp);
+ if (ucTmp == 0) {
+ pFont->usFontStyle &= ~FONT_UNDERLINE;
+ } else {
+ pFont->usFontStyle |= FONT_UNDERLINE;
+ }
+ }
+ }
+} /* end of vGet2FontInfo */
+
+/*
+ * Fill the picture information block with information from a WinWord 1 file.
+ * Returns TRUE when successful, otherwise FALSE
+ */
+static BOOL
+bGet1PicInfo(int iFodo,
+ const UCHAR *aucGrpprl, size_t tBytes, picture_block_type *pPicture)
+{
+ ULONG ulTmp;
+ UCHAR aucChpx[12];
+
+ fail(iFodo < 0 || aucGrpprl == NULL || pPicture == NULL);
+
+ if (tBytes > sizeof(aucChpx)) {
+ NO_DBG_PRINT_BLOCK(aucGrpprl + iFodo, tBytes);
+ tBytes = sizeof(aucChpx);
+ }
+
+ /* Build the CHPX structure */
+ (void)memset(aucChpx, 0, sizeof(aucChpx));
+ (void)memcpy(aucChpx, aucGrpprl + iFodo, min(tBytes, sizeof(aucChpx)));
+
+ ulTmp = ulGetLong(8, aucChpx);
+ if (ulTmp != 0 && ulTmp < MAX_FILESIZE) {
+ pPicture->ulPictureOffset = ulTmp;
+ DBG_HEX(pPicture->ulPictureOffset);
+ return TRUE;
+ }
+ return FALSE;
+} /* end of bGet1PicInfo */
+
+/*
+ * Fill the picture information block with information from a WinWord 2 file.
+ * Returns TRUE when successful, otherwise FALSE
+ */
+static BOOL
+bGet2PicInfo(int iFodo,
+ const UCHAR *aucGrpprl, size_t tBytes, picture_block_type *pPicture)
+{
+ ULONG ulTmp;
+ UCHAR aucChpx[18];
+
+ fail(iFodo < 0 || aucGrpprl == NULL || pPicture == NULL);
+
+ if (tBytes > sizeof(aucChpx)) {
+ NO_DBG_PRINT_BLOCK(aucGrpprl + iFodo, tBytes);
+ tBytes = sizeof(aucChpx);
+ }
+
+ /* Build the CHPX structure */
+ (void)memset(aucChpx, 0, sizeof(aucChpx));
+ (void)memcpy(aucChpx, aucGrpprl + iFodo, min(tBytes, sizeof(aucChpx)));
+
+ ulTmp = ulGetLong(14, aucChpx);
+ if (ulTmp != 0 && ulTmp < MAX_FILESIZE) {
+ pPicture->ulPictureOffset = ulTmp;
+ DBG_HEX(pPicture->ulPictureOffset);
+ DBG_DEC(tBytes);
+ return TRUE;
+ }
+ return FALSE;
+} /* end of bGet2PicInfo */
+
+/*
+ * Build the lists with Character Information for WinWord 1/2 files
+ */
+void
+vGet2ChrInfo(FILE *pFile, int iWordVersion, const UCHAR *aucHeader)
+{
+ font_block_type tFont;
+ picture_block_type tPicture;
+ USHORT *ausCharPage;
+ UCHAR *aucBuffer;
+ ULONG ulFileOffset, ulCharPos, ulBeginCharInfo;
+ size_t tCharInfoLen, tOffset, tSize, tChrLen, tCharPageNum;
+ size_t tLenOld, tLen;
+ int iIndex, iIndex2, iRun, iFodo;
+ BOOL bSuccess1, bSuccess2;
+ USHORT usCharFirstPage, usCount, usIstd;
+ UCHAR aucFpage[BIG_BLOCK_SIZE];
+
+ fail(pFile == NULL || aucHeader == NULL);
+ fail(iWordVersion != 1 && iWordVersion != 2);
+
+ ulBeginCharInfo = ulGetLong(0xa0, aucHeader); /* fcPlcfbteChpx */
+ DBG_HEX(ulBeginCharInfo);
+ tCharInfoLen = (size_t)usGetWord(0xa4, aucHeader); /* cbPlcfbteChpx */
+ DBG_DEC(tCharInfoLen);
+ if (tCharInfoLen < 4) {
+ DBG_DEC(tCharInfoLen);
+ return;
+ }
+
+ aucBuffer = xmalloc(tCharInfoLen);
+ if (!bReadBytes(aucBuffer, tCharInfoLen, ulBeginCharInfo, pFile)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tCharInfoLen);
+
+ tLen = (tCharInfoLen - 4) / 6;
+ ausCharPage = xcalloc(tLen, sizeof(USHORT));
+ for (iIndex = 0, tOffset = (tLen + 1) * 4;
+ iIndex < (int)tLen;
+ iIndex++, tOffset += 2) {
+ ausCharPage[iIndex] = usGetWord(tOffset, aucBuffer);
+ NO_DBG_DEC(ausCharPage[iIndex]);
+ }
+ DBG_HEX(ulGetLong(0, aucBuffer));
+ aucBuffer = xfree(aucBuffer);
+ tCharPageNum = (size_t)usGetWord(0x142, aucHeader); /* cpnBteChp */
+ DBG_DEC(tCharPageNum);
+ if (tLen < tCharPageNum) {
+ /* Replace CharPage by a longer version */
+ tLenOld = tLen;
+ usCharFirstPage = usGetWord(0x13e, aucHeader); /* pnChrFirst */
+ NO_DBG_DEC(usCharFirstPage);
+ tLen += tCharPageNum - 1;
+ tSize = tLen * sizeof(USHORT);
+ ausCharPage = xrealloc(ausCharPage, tSize);
+ /* Add new values */
+ usCount = usCharFirstPage + 1;
+ for (iIndex = (int)tLenOld; iIndex < (int)tLen; iIndex++) {
+ ausCharPage[iIndex] = usCount;
+ NO_DBG_DEC(ausCharPage[iIndex]);
+ usCount++;
+ }
+ }
+
+ for (iIndex = 0; iIndex < (int)tLen; iIndex++) {
+ if (!bReadBytes(aucFpage, BIG_BLOCK_SIZE,
+ (ULONG)ausCharPage[iIndex] * BIG_BLOCK_SIZE,
+ pFile)) {
+ break;
+ }
+ NO_DBG_PRINT_BLOCK(aucFpage, BIG_BLOCK_SIZE);
+ iRun = (int)ucGetByte(0x1ff, aucFpage);
+ NO_DBG_DEC(iRun);
+ for (iIndex2 = 0; iIndex2 < iRun; iIndex2++) {
+ if ((iRun + 1) * 4 + iIndex2 >= BIG_BLOCK_SIZE) {
+ break;
+ }
+ ulCharPos = ulGetLong(iIndex2 * 4, aucFpage);
+ ulFileOffset = ulCharPos;
+ iFodo = 2 * (int)ucGetByte(
+ (iRun + 1) * 4 + iIndex2, aucFpage);
+
+ tChrLen = (size_t)ucGetByte(iFodo, aucFpage);
+
+ usIstd = usGetIstd(ulFileOffset);
+ vFillFontFromStylesheet(usIstd, &tFont);
+ if (iFodo != 0) {
+ if (iWordVersion == 1) {
+ vGet1FontInfo(iFodo,
+ aucFpage + 1, tChrLen, &tFont);
+ } else if (iWordVersion == 2) {
+ vGet2FontInfo(iFodo,
+ aucFpage + 1, tChrLen, &tFont);
+ }
+ }
+ tFont.ulFileOffset = ulFileOffset;
+ vAdd2FontInfoList(&tFont);
+
+ if (iFodo <= 0) {
+ continue;
+ }
+
+ (void)memset(&tPicture, 0, sizeof(tPicture));
+ bSuccess1 = iWordVersion == 1 &&
+ bGet1PicInfo(iFodo, aucFpage + 1,
+ tChrLen, &tPicture);
+ bSuccess2 = iWordVersion == 2 &&
+ bGet2PicInfo(iFodo, aucFpage + 1,
+ tChrLen, &tPicture);
+ if (bSuccess1 || bSuccess2) {
+ tPicture.ulFileOffset = ulFileOffset;
+ tPicture.ulFileOffsetPicture =
+ tPicture.ulPictureOffset;
+ vAdd2PictInfoList(&tPicture);
+ }
+ }
+ }
+ ausCharPage = xfree(ausCharPage);
+} /* end of vGet2ChrInfo */
diff --git a/sys/src/cmd/aux/antiword/prop6.c b/sys/src/cmd/aux/antiword/prop6.c
new file mode 100755
index 000000000..e4c468da4
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/prop6.c
@@ -0,0 +1,1141 @@
+/*
+ * prop6.c
+ * Copyright (C) 1998-2005 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Read the property information from a MS Word 6 or 7 file
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "antiword.h"
+
+
+/*
+ * iGet6InfoLength - the length of the information for Word 6/7 files
+ */
+static int
+iGet6InfoLength(int iByteNbr, const UCHAR *aucGrpprl)
+{
+ int iTmp, iDel, iAdd;
+
+ switch (ucGetByte(iByteNbr, aucGrpprl)) {
+ case 2: case 16: case 17: case 18: case 19: case 21: case 22:
+ case 26: case 27: case 28: case 30: case 31: case 32: case 33:
+ case 34: case 35: case 36: case 38: case 39: case 40: case 41:
+ case 42: case 43: case 45: case 46: case 47: case 48: case 49:
+ case 69: case 72: case 80: case 93: case 96: case 97: case 99:
+ case 101: case 105: case 106: case 107: case 109: case 110: case 121:
+ case 122: case 123: case 124: case 140: case 141: case 144: case 145:
+ case 148: case 149: case 154: case 155: case 156: case 157: case 160:
+ case 161: case 164: case 165: case 166: case 167: case 168: case 169:
+ case 170: case 171: case 182: case 183: case 184: case 189: case 195:
+ case 197: case 198:
+ return 1 + 2;
+ case 3: case 12: case 15: case 81: case 103: case 108: case 188:
+ case 190: case 191:
+ return 2 + (int)ucGetByte(iByteNbr + 1, aucGrpprl);
+ case 20: case 70: case 74: case 192: case 194: case 196: case 200:
+ return 1 + 4;
+ case 23:
+ iTmp = (int)ucGetByte(iByteNbr + 1, aucGrpprl);
+ if (iTmp == 255) {
+ iDel = (int)ucGetByte(iByteNbr + 2, aucGrpprl);
+ iAdd = (int)ucGetByte(
+ iByteNbr + 3 + iDel * 4, aucGrpprl);
+ iTmp = 2 + iDel * 4 + iAdd * 3;
+ }
+ return 2 + iTmp;
+ case 68: case 193: case 199:
+ return 1 + 5;
+ case 73: case 95: case 136: case 137:
+ return 1 + 3;
+ case 120: case 187:
+ return 1 + 12;
+ default:
+ return 1 + 1;
+ }
+} /* end of iGet6InfoLength */
+
+/*
+ * Build the lists with Document Property Information for Word 6/7 files
+ */
+void
+vGet6DopInfo(FILE *pFile, ULONG ulStartBlock,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const UCHAR *aucHeader)
+{
+ document_block_type tDocument;
+ UCHAR *aucBuffer;
+ ULONG ulBeginDocpInfo, ulTmp;
+ size_t tDocpInfoLen;
+ USHORT usTmp;
+
+ ulBeginDocpInfo = ulGetLong(0x150, aucHeader); /* fcDop */
+ DBG_HEX(ulBeginDocpInfo);
+ tDocpInfoLen = (size_t)ulGetLong(0x154, aucHeader); /* lcbDop */
+ DBG_DEC(tDocpInfoLen);
+ if (tDocpInfoLen < 28) {
+ DBG_MSG("No Document information");
+ return;
+ }
+
+ aucBuffer = xmalloc(tDocpInfoLen);
+ if (!bReadBuffer(pFile, ulStartBlock,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucBuffer, ulBeginDocpInfo, tDocpInfoLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+
+ usTmp = usGetWord(0x00, aucBuffer);
+ tDocument.ucHdrFtrSpecification = (UCHAR)(usTmp >> 8); /* grpfIhdt */
+ tDocument.usDefaultTabWidth = usGetWord(0x0a, aucBuffer); /* dxaTab */
+ ulTmp = ulGetLong(0x14, aucBuffer); /* dttmCreated */
+ tDocument.tCreateDate = tConvertDTTM(ulTmp);
+ ulTmp = ulGetLong(0x18, aucBuffer); /* dttmRevised */
+ tDocument.tRevisedDate = tConvertDTTM(ulTmp);
+ vCreateDocumentInfoList(&tDocument);
+
+ aucBuffer = xfree(aucBuffer);
+} /* end of vGet6DopInfo */
+
+/*
+ * Fill the section information block with information
+ * from a Word 6/7 file.
+ */
+static void
+vGet6SectionInfo(const UCHAR *aucGrpprl, size_t tBytes,
+ section_block_type *pSection)
+{
+ UINT uiIndex;
+ int iFodoOff, iInfoLen, iSize, iTmp;
+ USHORT usCcol;
+ UCHAR ucTmp;
+
+ fail(aucGrpprl == NULL || pSection == NULL);
+
+ iFodoOff = 0;
+ while (tBytes >= (size_t)iFodoOff + 1) {
+ iInfoLen = 0;
+ switch (ucGetByte(iFodoOff, aucGrpprl)) {
+ case 133: /* olstAnm */
+ iSize = (int)ucGetByte(iFodoOff + 1, aucGrpprl);
+ DBG_DEC_C(iSize != 212, iSize);
+ for (uiIndex = 0, iTmp = iFodoOff + 2;
+ uiIndex < 9 && iTmp < iFodoOff + 2 + iSize - 15;
+ uiIndex++, iTmp += 16) {
+ pSection->aucNFC[uiIndex] =
+ ucGetByte(iTmp, aucGrpprl);
+ NO_DBG_DEC(pSection->aucNFC[uiIndex]);
+ ucTmp = ucGetByte(iTmp + 3, aucGrpprl);
+ NO_DBG_HEX(ucTmp);
+ if ((ucTmp & BIT(2)) != 0) {
+ pSection->usNeedPrevLvl |=
+ (USHORT)BIT(uiIndex);
+ }
+ if ((ucTmp & BIT(3)) != 0) {
+ pSection->usHangingIndent |=
+ (USHORT)BIT(uiIndex);
+ }
+ }
+ DBG_HEX(pSection->usNeedPrevLvl);
+ DBG_HEX(pSection->usHangingIndent);
+ break;
+ case 142: /* bkc */
+ ucTmp = ucGetByte(iFodoOff + 1, aucGrpprl);
+ DBG_DEC(ucTmp);
+ pSection->bNewPage = ucTmp != 0 && ucTmp != 1;
+ break;
+ case 144: /* ccolM1 */
+ usCcol = 1 + usGetWord(iFodoOff + 1, aucGrpprl);
+ DBG_DEC(usCcol);
+ break;
+ case 153: /* grpfIhdt */
+ pSection->ucHdrFtrSpecification =
+ ucGetByte(iFodoOff + 1, aucGrpprl);
+ break;
+ default:
+ break;
+ }
+ if (iInfoLen <= 0) {
+ iInfoLen = iGet6InfoLength(iFodoOff, aucGrpprl);
+ fail(iInfoLen <= 0);
+ }
+ iFodoOff += iInfoLen;
+ }
+} /* end of vGet6SectionInfo */
+
+/*
+ * Build the lists with Section Property Information for Word 6/7 files
+ */
+void
+vGet6SepInfo(FILE *pFile, ULONG ulStartBlock,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const UCHAR *aucHeader)
+{
+ section_block_type tSection;
+ ULONG *aulSectPage, *aulCharPos;
+ UCHAR *aucBuffer, *aucFpage;
+ ULONG ulBeginOfText, ulTextOffset, ulBeginSectInfo;
+ size_t tSectInfoLen, tIndex, tOffset, tLen, tBytes;
+ UCHAR aucTmp[2];
+
+ fail(pFile == NULL || aucHeader == NULL);
+ fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
+ fail(aulBBD == NULL);
+
+ ulBeginOfText = ulGetLong(0x18, aucHeader); /* fcMin */
+ NO_DBG_HEX(ulBeginOfText);
+ ulBeginSectInfo = ulGetLong(0x88, aucHeader); /* fcPlcfsed */
+ DBG_HEX(ulBeginSectInfo);
+ tSectInfoLen = (size_t)ulGetLong(0x8c, aucHeader); /* lcbPlcfsed */
+ DBG_DEC(tSectInfoLen);
+ if (tSectInfoLen < 4) {
+ DBG_DEC(tSectInfoLen);
+ return;
+ }
+
+ aucBuffer = xmalloc(tSectInfoLen);
+ if (!bReadBuffer(pFile, ulStartBlock,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucBuffer, ulBeginSectInfo, tSectInfoLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tSectInfoLen);
+
+ /* Read the Section Descriptors */
+ tLen = (tSectInfoLen - 4) / 16;
+ /* Save the section offsets */
+ aulCharPos = xcalloc(tLen, sizeof(ULONG));
+ for (tIndex = 0, tOffset = 0; tIndex < tLen; tIndex++, tOffset += 4) {
+ ulTextOffset = ulGetLong(tOffset, aucBuffer);
+ NO_DBG_HEX(ulTextOffset);
+ aulCharPos[tIndex] = ulBeginOfText + ulTextOffset;
+ NO_DBG_HEX(aulCharPos[tIndex]);
+ }
+ /* Save the Sepx offsets */
+ aulSectPage = xcalloc(tLen, sizeof(ULONG));
+ for (tIndex = 0, tOffset = (tLen + 1) * 4;
+ tIndex < tLen;
+ tIndex++, tOffset += 12) {
+ aulSectPage[tIndex] = ulGetLong(tOffset + 2, aucBuffer);
+ NO_DBG_HEX(aulSectPage[tIndex]); /* fcSepx */
+ }
+ aucBuffer = xfree(aucBuffer);
+
+ /* Read the Section Properties */
+ for (tIndex = 0; tIndex < tLen; tIndex++) {
+ if (aulSectPage[tIndex] == FC_INVALID) {
+ vDefault2SectionInfoList(aulCharPos[tIndex]);
+ continue;
+ }
+ /* Get the number of bytes to read */
+ if (!bReadBuffer(pFile, ulStartBlock,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucTmp, aulSectPage[tIndex], 2)) {
+ continue;
+ }
+ tBytes = 2 + (size_t)usGetWord(0, aucTmp);
+ NO_DBG_DEC(tBytes);
+ /* Read the bytes */
+ aucFpage = xmalloc(tBytes);
+ if (!bReadBuffer(pFile, ulStartBlock,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucFpage, aulSectPage[tIndex], tBytes)) {
+ aucFpage = xfree(aucFpage);
+ continue;
+ }
+ NO_DBG_PRINT_BLOCK(aucFpage, tBytes);
+ /* Process the bytes */
+ vGetDefaultSection(&tSection);
+ vGet6SectionInfo(aucFpage + 2, tBytes - 2, &tSection);
+ vAdd2SectionInfoList(&tSection, aulCharPos[tIndex]);
+ aucFpage = xfree(aucFpage);
+ }
+ aulCharPos = xfree(aulCharPos);
+ aulSectPage = xfree(aulSectPage);
+} /* end of vGet6SepInfo */
+
+/*
+ * Build the list with Header/Footer Information for Word 6/7 files
+ */
+void
+vGet6HdrFtrInfo(FILE *pFile, ULONG ulStartBlock,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const UCHAR *aucHeader)
+{
+ ULONG *aulCharPos;
+ UCHAR *aucBuffer;
+ ULONG ulHdrFtrOffset, ulBeginHdrFtrInfo;
+ size_t tHdrFtrInfoLen, tIndex, tOffset, tLen;
+
+ fail(pFile == NULL || aucHeader == NULL);
+ fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
+ fail(aulBBD == NULL);
+
+ ulBeginHdrFtrInfo = ulGetLong(0xb0, aucHeader); /* fcPlcfhdd */
+ NO_DBG_HEX(ulBeginHdrFtrInfo);
+ tHdrFtrInfoLen = (size_t)ulGetLong(0xb4, aucHeader); /* lcbPlcfhdd */
+ NO_DBG_DEC(tHdrFtrInfoLen);
+ if (tHdrFtrInfoLen < 8) {
+ DBG_DEC_C(tHdrFtrInfoLen != 0, tHdrFtrInfoLen);
+ return;
+ }
+
+ aucBuffer = xmalloc(tHdrFtrInfoLen);
+ if (!bReadBuffer(pFile, ulStartBlock,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucBuffer, ulBeginHdrFtrInfo, tHdrFtrInfoLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tHdrFtrInfoLen);
+
+ tLen = tHdrFtrInfoLen / 4 - 1;
+ /* Save the header/footer offsets */
+ aulCharPos = xcalloc(tLen, sizeof(ULONG));
+ for (tIndex = 0, tOffset = 0;
+ tIndex < tLen;
+ tIndex++, tOffset += 4) {
+ ulHdrFtrOffset = ulGetLong(tOffset, aucBuffer);
+ NO_DBG_HEX(ulHdrFtrOffset);
+ aulCharPos[tIndex] = ulHdrFtrOffset2CharPos(ulHdrFtrOffset);
+ NO_DBG_HEX(aulCharPos[tIndex]);
+ }
+ vCreat6HdrFtrInfoList(aulCharPos, tLen);
+ aulCharPos = xfree(aulCharPos);
+ aucBuffer = xfree(aucBuffer);
+} /* end of vGet6HdrFtrInfo */
+
+/*
+ * Translate the rowinfo to a member of the row_info enumeration
+ */
+row_info_enum
+eGet6RowInfo(int iFodo,
+ const UCHAR *aucGrpprl, int iBytes, row_block_type *pRow)
+{
+ int iFodoOff, iInfoLen;
+ int iIndex, iSize, iCol;
+ int iPosCurr, iPosPrev;
+ USHORT usTmp;
+ BOOL bFound24_0, bFound24_1, bFound25_0, bFound25_1, bFound190;
+
+ fail(iFodo < 0 || aucGrpprl == NULL || pRow == NULL);
+
+ iFodoOff = 0;
+ bFound24_0 = FALSE;
+ bFound24_1 = FALSE;
+ bFound25_0 = FALSE;
+ bFound25_1 = FALSE;
+ bFound190 = FALSE;
+ while (iBytes >= iFodoOff + 1) {
+ iInfoLen = 0;
+ switch (ucGetByte(iFodo + iFodoOff, aucGrpprl)) {
+ case 24: /* fInTable */
+ if (odd(ucGetByte(iFodo + iFodoOff + 1, aucGrpprl))) {
+ bFound24_1 = TRUE;
+ } else {
+ bFound24_0 = TRUE;
+ }
+ break;
+ case 25: /* fTtp */
+ if (odd(ucGetByte(iFodo + iFodoOff + 1, aucGrpprl))) {
+ bFound25_1 = TRUE;
+ } else {
+ bFound25_0 = TRUE;
+ }
+ break;
+ case 38: /* brcTop */
+ usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
+ usTmp &= 0x0018;
+ NO_DBG_DEC(usTmp >> 3);
+ if (usTmp == 0) {
+ pRow->ucBorderInfo &= ~TABLE_BORDER_TOP;
+ } else {
+ pRow->ucBorderInfo |= TABLE_BORDER_TOP;
+ }
+ break;
+ case 39: /* brcLeft */
+ usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
+ usTmp &= 0x0018;
+ NO_DBG_DEC(usTmp >> 3);
+ if (usTmp == 0) {
+ pRow->ucBorderInfo &= ~TABLE_BORDER_LEFT;
+ } else {
+ pRow->ucBorderInfo |= TABLE_BORDER_LEFT;
+ }
+ break;
+ case 40: /* brcBottom */
+ usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
+ usTmp &= 0x0018;
+ NO_DBG_DEC(usTmp >> 3);
+ if (usTmp == 0) {
+ pRow->ucBorderInfo &= ~TABLE_BORDER_BOTTOM;
+ } else {
+ pRow->ucBorderInfo |= TABLE_BORDER_BOTTOM;
+ }
+ break;
+ case 41: /* brcRight */
+ usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
+ usTmp &= 0x0018;
+ NO_DBG_DEC(usTmp >> 3);
+ if (usTmp == 0) {
+ pRow->ucBorderInfo &= ~TABLE_BORDER_RIGHT;
+ } else {
+ pRow->ucBorderInfo |= TABLE_BORDER_RIGHT;
+ }
+ break;
+ case 188: /* cDefTable10 */
+ DBG_MSG("188: sprmTDefTable10");
+ iSize = (int)usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
+ DBG_DEC(iSize);
+ break;
+ case 190: /* cDefTable */
+ iSize = (int)usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
+ if (iSize < 6 || iBytes < iFodoOff + 7) {
+ DBG_DEC(iSize);
+ DBG_DEC(iFodoOff);
+ iInfoLen = 1;
+ break;
+ }
+ iCol = (int)ucGetByte(iFodo + iFodoOff + 3, aucGrpprl);
+ if (iCol < 1 ||
+ iBytes < iFodoOff + 3 + (iCol + 1) * 2) {
+ DBG_DEC(iCol);
+ DBG_DEC(iFodoOff);
+ iInfoLen = 1;
+ break;
+ }
+ if (iCol >= (int)elementsof(pRow->asColumnWidth)) {
+ DBG_DEC(iCol);
+ werr(1, "The number of columns is corrupt");
+ }
+ pRow->ucNumberOfColumns = (UCHAR)iCol;
+ iPosPrev = (int)(short)usGetWord(
+ iFodo + iFodoOff + 4,
+ aucGrpprl);
+ for (iIndex = 0; iIndex < iCol; iIndex++) {
+ iPosCurr = (int)(short)usGetWord(
+ iFodo + iFodoOff + 6 + iIndex * 2,
+ aucGrpprl);
+ pRow->asColumnWidth[iIndex] =
+ (short)(iPosCurr - iPosPrev);
+ iPosPrev = iPosCurr;
+ }
+ bFound190 = TRUE;
+ break;
+ default:
+ break;
+ }
+ if (iInfoLen <= 0) {
+ iInfoLen =
+ iGet6InfoLength(iFodo + iFodoOff, aucGrpprl);
+ fail(iInfoLen <= 0);
+ }
+ iFodoOff += iInfoLen;
+ }
+
+ if (bFound25_1 && bFound190) {
+ return found_end_of_row;
+ }
+ if (bFound25_0 && !bFound190) {
+ return found_not_end_of_row;
+ }
+ if (bFound24_1) {
+ return found_a_cell;
+ }
+ if (bFound24_0) {
+ return found_not_a_cell;
+ }
+ return found_nothing;
+} /* end of eGet6RowInfo */
+
+/*
+ * Fill the style information block with information
+ * from a Word 6/7 file.
+ */
+void
+vGet6StyleInfo(int iFodo,
+ const UCHAR *aucGrpprl, int iBytes, style_block_type *pStyle)
+{
+ int iFodoOff, iInfoLen;
+ int iTmp, iDel, iAdd, iBefore;
+ short sTmp;
+ UCHAR ucTmp;
+
+ fail(iFodo < 0 || aucGrpprl == NULL || pStyle == NULL);
+
+ NO_DBG_DEC(pStyle->usIstd);
+
+ iFodoOff = 0;
+ while (iBytes >= iFodoOff + 1) {
+ iInfoLen = 0;
+ switch (ucGetByte(iFodo + iFodoOff, aucGrpprl)) {
+ case 2: /* istd */
+ sTmp = (short)ucGetByte(
+ iFodo + iFodoOff + 1, aucGrpprl);
+ NO_DBG_DEC(sTmp);
+ break;
+ case 5: /* jc */
+ pStyle->ucAlignment = ucGetByte(
+ iFodo + iFodoOff + 1, aucGrpprl);
+ break;
+ case 12: /* anld */
+ iTmp = (int)ucGetByte(
+ iFodo + iFodoOff + 1, aucGrpprl);
+ DBG_DEC_C(iTmp < 52, iTmp);
+ if (iTmp >= 1) {
+ pStyle->ucNFC = ucGetByte(
+ iFodo + iFodoOff + 2, aucGrpprl);
+ }
+ if (pStyle->ucNFC != LIST_BULLETS && iTmp >= 2) {
+ iBefore = (int)ucGetByte(
+ iFodo + iFodoOff + 3, aucGrpprl);
+ } else {
+ iBefore = 0;
+ }
+ if (iTmp >= 12) {
+ pStyle->usStartAt = usGetWord(
+ iFodo + iFodoOff + 12, aucGrpprl);
+ }
+ if (iTmp >= iBefore + 21) {
+ pStyle->usListChar = (USHORT)ucGetByte(
+ iFodo + iFodoOff + iBefore + 22,
+ aucGrpprl);
+ NO_DBG_HEX(pStyle->usListChar);
+ }
+ break;
+ case 13: /* nLvlAnm */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 1, aucGrpprl);
+ pStyle->ucNumLevel = ucTmp;
+ pStyle->bNumPause =
+ eGetNumType(ucTmp) == level_type_pause;
+ break;
+ case 15: /* ChgTabsPapx */
+ case 23: /* ChgTabs */
+ iTmp = (int)ucGetByte(iFodo + iFodoOff + 1, aucGrpprl);
+ if (iTmp < 2) {
+ iInfoLen = 1;
+ break;
+ }
+ NO_DBG_DEC(iTmp);
+ iDel = (int)ucGetByte(iFodo + iFodoOff + 2, aucGrpprl);
+ if (iTmp < 2 + 2 * iDel) {
+ iInfoLen = 1;
+ break;
+ }
+ NO_DBG_DEC(iDel);
+ iAdd = (int)ucGetByte(
+ iFodo + iFodoOff + 3 + 2 * iDel, aucGrpprl);
+ if (iTmp < 2 + 2 * iDel + 2 * iAdd) {
+ iInfoLen = 1;
+ break;
+ }
+ NO_DBG_DEC(iAdd);
+ break;
+ case 16: /* dxaRight */
+ pStyle->sRightIndent = (short)usGetWord(
+ iFodo + iFodoOff + 1, aucGrpprl);
+ NO_DBG_DEC(pStyle->sRightIndent);
+ break;
+ case 17: /* dxaLeft */
+ pStyle->sLeftIndent = (short)usGetWord(
+ iFodo + iFodoOff + 1, aucGrpprl);
+ NO_DBG_DEC(pStyle->sLeftIndent);
+ break;
+ case 18: /* Nest dxaLeft */
+ sTmp = (short)usGetWord(
+ iFodo + iFodoOff + 1, aucGrpprl);
+ pStyle->sLeftIndent += sTmp;
+ if (pStyle->sLeftIndent < 0) {
+ pStyle->sLeftIndent = 0;
+ }
+ NO_DBG_DEC(sTmp);
+ NO_DBG_DEC(pStyle->sLeftIndent);
+ break;
+ case 19: /* dxaLeft1 */
+ pStyle->sLeftIndent1 = (short)usGetWord(
+ iFodo + iFodoOff + 1, aucGrpprl);
+ NO_DBG_DEC(pStyle->sLeftIndent1);
+ break;
+ case 21: /* dyaBefore */
+ pStyle->usBeforeIndent = usGetWord(
+ iFodo + iFodoOff + 1, aucGrpprl);
+ NO_DBG_DEC(pStyle->usBeforeIndent);
+ break;
+ case 22: /* dyaAfter */
+ pStyle->usAfterIndent = usGetWord(
+ iFodo + iFodoOff + 1, aucGrpprl);
+ NO_DBG_DEC(pStyle->usAfterIndent);
+ break;
+ default:
+ break;
+ }
+ if (iInfoLen <= 0) {
+ iInfoLen =
+ iGet6InfoLength(iFodo + iFodoOff, aucGrpprl);
+ fail(iInfoLen <= 0);
+ }
+ iFodoOff += iInfoLen;
+ }
+} /* end of vGet6StyleInfo */
+
+/*
+ * Build the lists with Paragraph Information for Word 6/7 files
+ */
+void
+vGet6PapInfo(FILE *pFile, ULONG ulStartBlock,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const UCHAR *aucHeader)
+{
+ row_block_type tRow;
+ style_block_type tStyle;
+ USHORT *ausParfPage;
+ UCHAR *aucBuffer;
+ ULONG ulCharPos, ulCharPosFirst, ulCharPosLast;
+ ULONG ulBeginParfInfo;
+ size_t tParfInfoLen, tParfPageNum, tOffset, tSize, tLenOld, tLen;
+ size_t tIndex, tIndex2, tRun;
+ int iFodo, iLen;
+ row_info_enum eRowInfo;
+ USHORT usParfFirstPage, usCount, usIstd;
+ UCHAR aucFpage[BIG_BLOCK_SIZE];
+
+ fail(pFile == NULL || aucHeader == NULL);
+ fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
+ fail(aulBBD == NULL);
+
+ ulBeginParfInfo = ulGetLong(0xc0, aucHeader); /* fcPlcfbtePapx */
+ NO_DBG_HEX(ulBeginParfInfo);
+ tParfInfoLen = (size_t)ulGetLong(0xc4, aucHeader); /* lcbPlcfbtePapx */
+ NO_DBG_DEC(tParfInfoLen);
+ if (tParfInfoLen < 4) {
+ DBG_DEC(tParfInfoLen);
+ return;
+ }
+
+ aucBuffer = xmalloc(tParfInfoLen);
+ if (!bReadBuffer(pFile, ulStartBlock,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucBuffer, ulBeginParfInfo, tParfInfoLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tParfInfoLen);
+
+ tLen = (tParfInfoLen - 4) / 6;
+ ausParfPage = xcalloc(tLen, sizeof(USHORT));
+ for (tIndex = 0, tOffset = (tLen + 1) * 4;
+ tIndex < tLen;
+ tIndex++, tOffset += 2) {
+ ausParfPage[tIndex] = usGetWord(tOffset, aucBuffer);
+ NO_DBG_DEC(ausParfPage[tIndex]);
+ }
+ DBG_HEX(ulGetLong(0, aucBuffer));
+ aucBuffer = xfree(aucBuffer);
+ tParfPageNum = (size_t)usGetWord(0x190, aucHeader); /* cpnBtePap */
+ DBG_DEC(tParfPageNum);
+ if (tLen < tParfPageNum) {
+ /* Replace ParfPage by a longer version */
+ tLenOld = tLen;
+ usParfFirstPage = usGetWord(0x18c, aucHeader); /* pnPapFirst */
+ DBG_DEC(usParfFirstPage);
+ tLen += tParfPageNum - 1;
+ tSize = tLen * sizeof(USHORT);
+ ausParfPage = xrealloc(ausParfPage, tSize);
+ /* Add new values */
+ usCount = usParfFirstPage + 1;
+ for (tIndex = tLenOld; tIndex < tLen; tIndex++) {
+ ausParfPage[tIndex] = usCount;
+ NO_DBG_DEC(ausParfPage[tIndex]);
+ usCount++;
+ }
+ }
+
+ (void)memset(&tRow, 0, sizeof(tRow));
+ ulCharPosFirst = CP_INVALID;
+ for (tIndex = 0; tIndex < tLen; tIndex++) {
+ if (!bReadBuffer(pFile, ulStartBlock,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucFpage,
+ (ULONG)ausParfPage[tIndex] * BIG_BLOCK_SIZE,
+ BIG_BLOCK_SIZE)) {
+ break;
+ }
+ tRun = (size_t)ucGetByte(0x1ff, aucFpage);
+ NO_DBG_DEC(tRun);
+ for (tIndex2 = 0; tIndex2 < tRun; tIndex2++) {
+ NO_DBG_HEX(ulGetLong(tIndex2 * 4, aucFpage));
+ iFodo = 2 * (int)ucGetByte(
+ (tRun + 1) * 4 + tIndex2 * 7, aucFpage);
+ if (iFodo <= 0) {
+ continue;
+ }
+
+ iLen = 2 * (int)ucGetByte(iFodo, aucFpage);
+
+ usIstd = (USHORT)ucGetByte(iFodo + 1, aucFpage);
+ vFillStyleFromStylesheet(usIstd, &tStyle);
+ vGet6StyleInfo(iFodo, aucFpage + 3, iLen - 3, &tStyle);
+ ulCharPos = ulGetLong(tIndex2 * 4, aucFpage);
+ NO_DBG_HEX(ulCharPos);
+ tStyle.ulFileOffset = ulCharPos2FileOffsetX(
+ ulCharPos, &tStyle.eListID);
+ vAdd2StyleInfoList(&tStyle);
+
+ eRowInfo = eGet6RowInfo(iFodo,
+ aucFpage + 3, iLen - 3, &tRow);
+ switch(eRowInfo) {
+ case found_a_cell:
+ if (ulCharPosFirst != CP_INVALID) {
+ break;
+ }
+ ulCharPosFirst = ulGetLong(
+ tIndex2 * 4, aucFpage);
+ NO_DBG_HEX(ulCharPosFirst);
+ tRow.ulCharPosStart = ulCharPosFirst;
+ tRow.ulFileOffsetStart =
+ ulCharPos2FileOffset(ulCharPosFirst);
+ DBG_HEX_C(tRow.ulFileOffsetStart == FC_INVALID,
+ ulCharPosFirst);
+ break;
+ case found_end_of_row:
+ ulCharPosLast = ulGetLong(
+ tIndex2 * 4, aucFpage);
+ NO_DBG_HEX(ulCharPosLast);
+ tRow.ulCharPosEnd = ulCharPosLast;
+ tRow.ulFileOffsetEnd =
+ ulCharPos2FileOffset(ulCharPosLast);
+ DBG_HEX_C(tRow.ulFileOffsetEnd == FC_INVALID,
+ ulCharPosLast);
+ vAdd2RowInfoList(&tRow);
+ (void)memset(&tRow, 0, sizeof(tRow));
+ ulCharPosFirst = CP_INVALID;
+ break;
+ case found_nothing:
+ break;
+ default:
+ DBG_DEC(eRowInfo);
+ break;
+ }
+ }
+ }
+ ausParfPage = xfree(ausParfPage);
+} /* end of vGet6PapInfo */
+
+/*
+ * Fill the font information block with information
+ * from a Word 6/7 file.
+ * Returns TRUE when successful, otherwise FALSE
+ */
+void
+vGet6FontInfo(int iFodo, USHORT usIstd,
+ const UCHAR *aucGrpprl, int iBytes, font_block_type *pFont)
+{
+ long lTmp;
+ int iFodoOff, iInfoLen;
+ USHORT usTmp;
+ UCHAR ucTmp;
+
+ TRACE_MSG("vGet6FontInfo");
+
+ fail(iFodo < 0 || aucGrpprl == NULL || pFont == NULL);
+
+ iFodoOff = 0;
+ while (iBytes >= iFodoOff + 1) {
+ switch (ucGetByte(iFodo + iFodoOff, aucGrpprl)) {
+ case 65: /* fRMarkDel */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 1, aucGrpprl);
+ if (ucTmp == 0) {
+ pFont->usFontStyle &= ~FONT_MARKDEL;
+ } else {
+ pFont->usFontStyle |= FONT_MARKDEL;
+ }
+ break;
+ case 80: /* cIstd */
+ usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
+ NO_DBG_DEC(usTmp);
+ break;
+ case 82: /* cDefault */
+ pFont->usFontStyle &= FONT_HIDDEN;
+ pFont->ucFontColor = FONT_COLOR_DEFAULT;
+ break;
+ case 83: /* cPlain */
+ DBG_MSG("83: cPlain");
+ vFillFontFromStylesheet(usIstd, pFont);
+ break;
+ case 85: /* fBold */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 1, aucGrpprl);
+ switch (ucTmp) {
+ case 0: /* Unset */
+ pFont->usFontStyle &= ~FONT_BOLD;
+ break;
+ case 1: /* Set */
+ pFont->usFontStyle |= FONT_BOLD;
+ break;
+ case 128: /* Unchanged */
+ break;
+ case 129: /* Negation */
+ pFont->usFontStyle ^= FONT_BOLD;
+ break;
+ default:
+ DBG_DEC(ucTmp);
+ DBG_FIXME();
+ break;
+ }
+ break;
+ case 86: /* fItalic */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 1, aucGrpprl);
+ switch (ucTmp) {
+ case 0: /* Unset */
+ pFont->usFontStyle &= ~FONT_ITALIC;
+ break;
+ case 1: /* Set */
+ pFont->usFontStyle |= FONT_ITALIC;
+ break;
+ case 128: /* Unchanged */
+ break;
+ case 129: /* Negation */
+ pFont->usFontStyle ^= FONT_ITALIC;
+ break;
+ default:
+ DBG_DEC(ucTmp);
+ DBG_FIXME();
+ break;
+ }
+ break;
+ case 87: /* fStrike */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 1, aucGrpprl);
+ switch (ucTmp) {
+ case 0: /* Unset */
+ pFont->usFontStyle &= ~FONT_STRIKE;
+ break;
+ case 1: /* Set */
+ pFont->usFontStyle |= FONT_STRIKE;
+ break;
+ case 128: /* Unchanged */
+ break;
+ case 129: /* Negation */
+ pFont->usFontStyle ^= FONT_STRIKE;
+ break;
+ default:
+ DBG_DEC(ucTmp);
+ DBG_FIXME();
+ break;
+ }
+ break;
+ case 90: /* fSmallCaps */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 1, aucGrpprl);
+ switch (ucTmp) {
+ case 0: /* Unset */
+ pFont->usFontStyle &= ~FONT_SMALL_CAPITALS;
+ break;
+ case 1: /* Set */
+ pFont->usFontStyle |= FONT_SMALL_CAPITALS;
+ break;
+ case 128: /* Unchanged */
+ break;
+ case 129: /* Negation */
+ pFont->usFontStyle ^= FONT_SMALL_CAPITALS;
+ break;
+ default:
+ DBG_DEC(ucTmp);
+ DBG_FIXME();
+ break;
+ }
+ break;
+ case 91: /* fCaps */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 1, aucGrpprl);
+ switch (ucTmp) {
+ case 0: /* Unset */
+ pFont->usFontStyle &= ~FONT_CAPITALS;
+ break;
+ case 1: /* Set */
+ pFont->usFontStyle |= FONT_CAPITALS;
+ break;
+ case 128: /* Unchanged */
+ break;
+ case 129: /* Negation */
+ pFont->usFontStyle ^= FONT_CAPITALS;
+ break;
+ default:
+ DBG_DEC(ucTmp);
+ DBG_FIXME();
+ break;
+ }
+ break;
+ case 92: /* fVanish */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 1, aucGrpprl);
+ switch (ucTmp) {
+ case 0: /* Unset */
+ pFont->usFontStyle &= ~FONT_HIDDEN;
+ break;
+ case 1: /* Set */
+ pFont->usFontStyle |= FONT_HIDDEN;
+ break;
+ case 128: /* Unchanged */
+ break;
+ case 129: /* Negation */
+ pFont->usFontStyle ^= FONT_HIDDEN;
+ break;
+ default:
+ DBG_DEC(ucTmp);
+ DBG_FIXME();
+ break;
+ }
+ break;
+ case 93: /* cFtc */
+ usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
+ if (usTmp <= (USHORT)UCHAR_MAX) {
+ pFont->ucFontNumber = (UCHAR)usTmp;
+ } else {
+ DBG_DEC(usTmp);
+ DBG_FIXME();
+ pFont->ucFontNumber = 0;
+ }
+ break;
+ case 94: /* cKul */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 1, aucGrpprl);
+ if (ucTmp == 0 || ucTmp == 5) {
+ pFont->usFontStyle &= ~FONT_UNDERLINE;
+ } else {
+ NO_DBG_MSG("Underline text");
+ pFont->usFontStyle |= FONT_UNDERLINE;
+ if (ucTmp == 6) {
+ DBG_MSG("Bold text");
+ pFont->usFontStyle |= FONT_BOLD;
+ }
+ }
+ break;
+ case 95: /* cHps, cHpsPos */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 1, aucGrpprl);
+ DBG_DEC(ucTmp);
+ if (ucTmp != 0) {
+ pFont->usFontSize = (USHORT)ucTmp;
+ }
+ ucTmp = ucGetByte(iFodo + iFodoOff + 2, aucGrpprl);
+ DBG_DEC(ucTmp);
+ break;
+ case 98: /* cIco */
+ pFont->ucFontColor =
+ ucGetByte(iFodo + iFodoOff + 1, aucGrpprl);
+ break;
+ case 99: /* cHps */
+ pFont->usFontSize =
+ usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
+ break;
+ case 100: /* cHpsInc */
+ DBG_MSG("100: sprmCHpsInc");
+ ucTmp = ucGetByte(iFodo + iFodoOff + 1, aucGrpprl);
+ DBG_DEC(ucTmp);
+ break;
+ case 103: /* cMajority */
+ DBG_MSG("103: sprmCMajority");
+ break;
+ case 104: /* cIss */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 1, aucGrpprl);
+ ucTmp &= 0x07;
+ if (ucTmp == 1) {
+ pFont->usFontStyle |= FONT_SUPERSCRIPT;
+ NO_DBG_MSG("Superscript");
+ } else if (ucTmp == 2) {
+ pFont->usFontStyle |= FONT_SUBSCRIPT;
+ NO_DBG_MSG("Subscript");
+ }
+ break;
+ case 106: /* cHpsInc1 */
+ usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
+ lTmp = (long)pFont->usFontSize + (long)usTmp;
+ if (lTmp < 8) {
+ pFont->usFontSize = 8;
+ } else if (lTmp > 32766) {
+ pFont->usFontSize = 32766;
+ } else {
+ pFont->usFontSize = (USHORT)lTmp;
+ }
+ break;
+ case 108: /* cMajority50 */
+ DBG_MSG("108: sprmCMajority50");
+ break;
+ case 109: /* cHpsMul */
+ DBG_MSG("109: sprmCHpsMul");
+ usTmp = usGetWord(iFodo + iFodoOff + 1, aucGrpprl);
+ DBG_DEC(usTmp);
+ break;
+ default:
+ break;
+ }
+ iInfoLen = iGet6InfoLength(iFodo + iFodoOff, aucGrpprl);
+ fail(iInfoLen <= 0);
+ iFodoOff += iInfoLen;
+ }
+} /* end of vGet6FontInfo */
+
+/*
+ * Fill the picture information block with information
+ * from a Word 6/7 file.
+ * Returns TRUE when successful, otherwise FALSE
+ */
+static BOOL
+bGet6PicInfo(int iFodo,
+ const UCHAR *aucGrpprl, int iBytes, picture_block_type *pPicture)
+{
+ int iFodoOff, iInfoLen;
+ BOOL bFound;
+ UCHAR ucTmp;
+
+ TRACE_MSG("vGet6PicInfo");
+
+ fail(iFodo < 0 || aucGrpprl == NULL || pPicture == NULL);
+
+ iFodoOff = 0;
+ bFound = FALSE;
+ while (iBytes >= iFodoOff + 1) {
+ switch (ucGetByte(iFodo + iFodoOff, aucGrpprl)) {
+ case 68: /* fcPic */
+ pPicture->ulPictureOffset = ulGetLong(
+ iFodo + iFodoOff + 2, aucGrpprl);
+ bFound = TRUE;
+ break;
+#if 0
+ case 71: /* fData */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 1, aucGrpprl);
+ if (ucTmp == 0x01) {
+ /* Not a picture, but a form field */
+ return FALSE;
+ }
+ DBG_DEC_C(ucTmp != 0, ucTmp);
+ break;
+#endif
+ case 75: /* fOle2 */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 1, aucGrpprl);
+ if (ucTmp == 0x01) {
+ /* Not a picture, but an OLE object */
+ return FALSE;
+ }
+ DBG_DEC_C(ucTmp != 0, ucTmp);
+ break;
+ default:
+ break;
+ }
+ iInfoLen = iGet6InfoLength(iFodo + iFodoOff, aucGrpprl);
+ fail(iInfoLen <= 0);
+ iFodoOff += iInfoLen;
+ }
+ return bFound;
+} /* end of bGet6PicInfo */
+
+/*
+ * Build the lists with Character Information for Word 6/7 files
+ */
+void
+vGet6ChrInfo(FILE *pFile, ULONG ulStartBlock,
+ const ULONG *aulBBD, size_t tBBDLen, const UCHAR *aucHeader)
+{
+ font_block_type tFont;
+ picture_block_type tPicture;
+ USHORT *ausCharPage;
+ UCHAR *aucBuffer;
+ ULONG ulFileOffset, ulCharPos, ulBeginCharInfo;
+ size_t tCharInfoLen, tOffset, tSize, tLenOld, tLen, tCharPageNum;
+ size_t tIndex, tIndex2, tRun;
+ int iFodo, iLen;
+ USHORT usCharFirstPage, usCount, usIstd;
+ UCHAR aucFpage[BIG_BLOCK_SIZE];
+
+ fail(pFile == NULL || aucHeader == NULL);
+ fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
+ fail(aulBBD == NULL);
+
+ ulBeginCharInfo = ulGetLong(0xb8, aucHeader); /* fcPlcfbteChpx */
+ NO_DBG_HEX(lBeginCharInfo);
+ tCharInfoLen = (size_t)ulGetLong(0xbc, aucHeader); /* lcbPlcfbteChpx */
+ NO_DBG_DEC(tCharInfoLen);
+ if (tCharInfoLen < 4) {
+ DBG_DEC(tCharInfoLen);
+ return;
+ }
+
+ aucBuffer = xmalloc(tCharInfoLen);
+ if (!bReadBuffer(pFile, ulStartBlock,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucBuffer, ulBeginCharInfo, tCharInfoLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+
+ tLen = (tCharInfoLen - 4) / 6;
+ ausCharPage = xcalloc(tLen, sizeof(USHORT));
+ for (tIndex = 0, tOffset = (tLen + 1) * 4;
+ tIndex < tLen;
+ tIndex++, tOffset += 2) {
+ ausCharPage[tIndex] = usGetWord(tOffset, aucBuffer);
+ NO_DBG_DEC(ausCharPage[tIndex]);
+ }
+ DBG_HEX(ulGetLong(0, aucBuffer));
+ aucBuffer = xfree(aucBuffer);
+ tCharPageNum = (size_t)usGetWord(0x18e, aucHeader); /* cpnBteChp */
+ DBG_DEC(tCharPageNum);
+ if (tLen < tCharPageNum) {
+ /* Replace CharPage by a longer version */
+ tLenOld = tLen;
+ usCharFirstPage = usGetWord(0x18a, aucHeader); /* pnChrFirst */
+ DBG_DEC(usCharFirstPage);
+ tLen += tCharPageNum - 1;
+ tSize = tLen * sizeof(USHORT);
+ ausCharPage = xrealloc(ausCharPage, tSize);
+ /* Add new values */
+ usCount = usCharFirstPage + 1;
+ for (tIndex = tLenOld; tIndex < tLen; tIndex++) {
+ ausCharPage[tIndex] = usCount;
+ NO_DBG_DEC(ausCharPage[tIndex]);
+ usCount++;
+ }
+ }
+
+ for (tIndex = 0; tIndex < tLen; tIndex++) {
+ if (!bReadBuffer(pFile, ulStartBlock,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucFpage,
+ (ULONG)ausCharPage[tIndex] * BIG_BLOCK_SIZE,
+ BIG_BLOCK_SIZE)) {
+ break;
+ }
+ tRun = (size_t)ucGetByte(0x1ff, aucFpage);
+ NO_DBG_DEC(tRun);
+ for (tIndex2 = 0; tIndex2 < tRun; tIndex2++) {
+ ulCharPos = ulGetLong(tIndex2 * 4, aucFpage);
+ ulFileOffset = ulCharPos2FileOffset(ulCharPos);
+ iFodo = 2 * (int)ucGetByte(
+ (tRun + 1) * 4 + tIndex2, aucFpage);
+
+ iLen = (int)ucGetByte(iFodo, aucFpage);
+
+ usIstd = usGetIstd(ulFileOffset);
+ vFillFontFromStylesheet(usIstd, &tFont);
+ if (iFodo != 0) {
+ vGet6FontInfo(iFodo, usIstd,
+ aucFpage + 1, iLen - 1, &tFont);
+ }
+ tFont.ulFileOffset = ulFileOffset;
+ vAdd2FontInfoList(&tFont);
+
+ if (iFodo <= 0) {
+ continue;
+ }
+
+ (void)memset(&tPicture, 0, sizeof(tPicture));
+ if (bGet6PicInfo(iFodo, aucFpage + 1,
+ iLen - 1, &tPicture)) {
+ tPicture.ulFileOffset = ulFileOffset;
+ tPicture.ulFileOffsetPicture =
+ ulDataPos2FileOffset(
+ tPicture.ulPictureOffset);
+ vAdd2PictInfoList(&tPicture);
+ }
+ }
+ }
+ ausCharPage = xfree(ausCharPage);
+} /* end of vGet6ChrInfo */
diff --git a/sys/src/cmd/aux/antiword/prop8.c b/sys/src/cmd/aux/antiword/prop8.c
new file mode 100755
index 000000000..c31204e08
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/prop8.c
@@ -0,0 +1,1496 @@
+/*
+ * prop8.c
+ * Copyright (C) 1998-2005 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Read the property information from a MS Word 8, 9,10 or 11 file
+ *
+ * Word 8 is better known as Word 97 or as Word 98 for Mac
+ * Word 9 is better known as Word 2000 or as Word 2001 for Mac
+ * Word 10 is better known as Word 2002 or as Word XP
+ * Word 11 is better known as Word 2003
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "antiword.h"
+
+#define DEFAULT_LISTCHAR 0x002e /* A full stop */
+
+
+/*
+ * iGet8InfoLength - the length of the information for Word 8/9/10/11 files
+ */
+static int
+iGet8InfoLength(int iByteNbr, const UCHAR *aucGrpprl)
+{
+ int iTmp, iDel, iAdd;
+ USHORT usOpCode;
+
+ usOpCode = usGetWord(iByteNbr, aucGrpprl);
+
+ switch (usOpCode & 0xe000) {
+ case 0x0000: case 0x2000:
+ return 3;
+ case 0x4000: case 0x8000: case 0xa000:
+ return 4;
+ case 0xe000:
+ return 5;
+ case 0x6000:
+ return 6;
+ case 0xc000:
+ iTmp = (int)ucGetByte(iByteNbr + 2, aucGrpprl);
+ if (usOpCode == 0xc615 && iTmp == 255) {
+ iDel = (int)ucGetByte(iByteNbr + 3, aucGrpprl);
+ iAdd = (int)ucGetByte(
+ iByteNbr + 4 + iDel * 4, aucGrpprl);
+ iTmp = 2 + iDel * 4 + iAdd * 3;
+ }
+ return 3 + iTmp;
+ default:
+ DBG_HEX(usOpCode);
+ DBG_FIXME();
+ return 1;
+ }
+} /* end of iGet8InfoLength */
+
+/*
+ * aucFillInfoBuffer - fill the information buffer
+ *
+ * Returns the information buffer when successful, otherwise NULL
+ */
+static UCHAR *
+aucFillInfoBuffer(FILE *pFile, const pps_type *pTable,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ ULONG ulBeginInfo, size_t tInfoLen)
+{
+ const ULONG *aulBlockDepot;
+ UCHAR *aucBuffer;
+ size_t tBlockDepotLen, tBlockSize;
+
+ fail(pFile == NULL || pTable == NULL);
+ fail(aulBBD == NULL || aulSBD == NULL);
+ fail(tInfoLen == 0);
+
+ NO_DBG_DEC(pTable->ulSB);
+ NO_DBG_HEX(pTable->ulSize);
+ if (pTable->ulSize == 0) {
+ DBG_MSG("No information");
+ return NULL;
+ }
+
+ if (pTable->ulSize < MIN_SIZE_FOR_BBD_USE) {
+ /* Use the Small Block Depot */
+ aulBlockDepot = aulSBD;
+ tBlockDepotLen = tSBDLen;
+ tBlockSize = SMALL_BLOCK_SIZE;
+ } else {
+ /* Use the Big Block Depot */
+ aulBlockDepot = aulBBD;
+ tBlockDepotLen = tBBDLen;
+ tBlockSize = BIG_BLOCK_SIZE;
+ }
+ aucBuffer = xmalloc(tInfoLen);
+ if (!bReadBuffer(pFile, pTable->ulSB,
+ aulBlockDepot, tBlockDepotLen, tBlockSize,
+ aucBuffer, ulBeginInfo, tInfoLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return NULL;
+ }
+ return aucBuffer;
+} /* end of aucFillInfoBuffer */
+
+/*
+ * Build the lists with Document Property Information for Word 8/9/10/11 files
+ */
+void
+vGet8DopInfo(FILE *pFile, const pps_type *pTable,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ const UCHAR *aucHeader)
+{
+ document_block_type tDocument;
+ UCHAR *aucBuffer;
+ ULONG ulBeginDocpInfo, ulTmp;
+ size_t tDocpInfoLen;
+ USHORT usTmp;
+
+ fail(pFile == NULL || pTable == NULL || aucHeader == NULL);
+ fail(aulBBD == NULL || aulSBD == NULL);
+
+ ulBeginDocpInfo = ulGetLong(0x192, aucHeader); /* fcDop */
+ NO_DBG_HEX(ulBeginSectInfo);
+ tDocpInfoLen = (size_t)ulGetLong(0x196, aucHeader); /* lcbDop */
+ NO_DBG_DEC(tSectInfoLen);
+ if (tDocpInfoLen < 28) {
+ DBG_MSG("No Document information");
+ return;
+ }
+
+ aucBuffer = aucFillInfoBuffer(pFile, pTable,
+ aulBBD, tBBDLen, aulSBD, tSBDLen,
+ ulBeginDocpInfo, tDocpInfoLen);
+ if (aucBuffer == NULL) {
+ return;
+ }
+
+ usTmp = usGetWord(0x00, aucBuffer);
+ tDocument.ucHdrFtrSpecification = (UCHAR)(usTmp >> 8); /* grpfIhdt */
+ tDocument.usDefaultTabWidth = usGetWord(0x0a, aucBuffer); /* dxaTab */
+ ulTmp = ulGetLong(0x14, aucBuffer); /* dttmCreated */
+ tDocument.tCreateDate = tConvertDTTM(ulTmp);
+ ulTmp = ulGetLong(0x18, aucBuffer); /* dttmRevised */
+ tDocument.tRevisedDate = tConvertDTTM(ulTmp);
+ vCreateDocumentInfoList(&tDocument);
+
+ aucBuffer = xfree(aucBuffer);
+} /* end of vGet8DopInfo */
+
+/*
+ * Fill the section information block with information
+ * from a Word 8/9/10/11 file.
+ */
+static void
+vGet8SectionInfo(const UCHAR *aucGrpprl, size_t tBytes,
+ section_block_type *pSection)
+{
+ UINT uiIndex;
+ int iFodoOff, iInfoLen, iSize, iTmp;
+ USHORT usCcol;
+ UCHAR ucTmp;
+
+ fail(aucGrpprl == NULL || pSection == NULL);
+
+ iFodoOff = 0;
+ while (tBytes >= (size_t)iFodoOff + 2) {
+ iInfoLen = 0;
+ switch (usGetWord(iFodoOff, aucGrpprl)) {
+ case 0x3009: /* bkc */
+ ucTmp = ucGetByte(iFodoOff + 2, aucGrpprl);
+ DBG_DEC(ucTmp);
+ pSection->bNewPage = ucTmp != 0 && ucTmp != 1;
+ break;
+ case 0x3014: /* grpfIhdt */
+ pSection->ucHdrFtrSpecification =
+ ucGetByte(iFodoOff + 2, aucGrpprl);
+ break;
+ case 0x500b: /* ccolM1 */
+ usCcol = 1 + usGetWord(iFodoOff + 2, aucGrpprl);
+ DBG_DEC(usCcol);
+ break;
+ case 0xd202: /* olstAnm */
+ iSize = (int)ucGetByte(iFodoOff + 2, aucGrpprl);
+ DBG_DEC_C(iSize != 212, iSize);
+ for (uiIndex = 0, iTmp = iFodoOff + 3;
+ uiIndex < 9 && iTmp < iFodoOff + 3 + iSize - 15;
+ uiIndex++, iTmp += 16) {
+ pSection->aucNFC[uiIndex] =
+ ucGetByte(iTmp, aucGrpprl);
+ DBG_DEC(pSection->aucNFC[uiIndex]);
+ ucTmp = ucGetByte(iTmp + 3, aucGrpprl);
+ DBG_HEX(ucTmp);
+ if ((ucTmp & BIT(2)) != 0) {
+ pSection->usNeedPrevLvl |=
+ (USHORT)BIT(uiIndex);
+ }
+ if ((ucTmp & BIT(3)) != 0) {
+ pSection->usHangingIndent |=
+ (USHORT)BIT(uiIndex);
+ }
+ }
+ DBG_HEX(pSection->usNeedPrevLvl);
+ DBG_HEX(pSection->usHangingIndent);
+ break;
+ default:
+ break;
+ }
+ if (iInfoLen <= 0) {
+ iInfoLen = iGet8InfoLength(iFodoOff, aucGrpprl);
+ fail(iInfoLen <= 0);
+ }
+ iFodoOff += iInfoLen;
+ }
+} /* end of vGet8SectionInfo */
+
+/*
+ * Build the lists with Section Property Information for Word 8/9/10/11 files
+ */
+void
+vGet8SepInfo(FILE *pFile, const pps_info_type *pPPS,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ const UCHAR *aucHeader)
+{
+ section_block_type tSection;
+ ULONG *aulSectPage, *aulCharPos;
+ UCHAR *aucBuffer, *aucFpage;
+ ULONG ulBeginOfText, ulTextOffset, ulBeginSectInfo;
+ size_t tSectInfoLen, tIndex, tOffset, tLen, tBytes;
+ UCHAR aucTmp[2];
+
+ fail(pFile == NULL || pPPS == NULL || aucHeader == NULL);
+ fail(aulBBD == NULL || aulSBD == NULL);
+
+ ulBeginOfText = ulGetLong(0x18, aucHeader); /* fcMin */
+ NO_DBG_HEX(ulBeginOfText);
+ ulBeginSectInfo = ulGetLong(0xca, aucHeader); /* fcPlcfsed */
+ NO_DBG_HEX(ulBeginSectInfo);
+ tSectInfoLen = (size_t)ulGetLong(0xce, aucHeader); /* lcbPlcfsed */
+ NO_DBG_DEC(tSectInfoLen);
+ if (tSectInfoLen < 4) {
+ DBG_DEC(tSectInfoLen);
+ return;
+ }
+
+ aucBuffer = aucFillInfoBuffer(pFile, &pPPS->tTable,
+ aulBBD, tBBDLen, aulSBD, tSBDLen,
+ ulBeginSectInfo, tSectInfoLen);
+ if (aucBuffer == NULL) {
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tSectInfoLen);
+
+ /* Read the Section Descriptors */
+ tLen = (tSectInfoLen - 4) / 16;
+ /* Save the section offsets */
+ aulCharPos = xcalloc(tLen, sizeof(ULONG));
+ for (tIndex = 0, tOffset = 0;
+ tIndex < tLen;
+ tIndex++, tOffset += 4) {
+ ulTextOffset = ulGetLong(tOffset, aucBuffer);
+ NO_DBG_HEX(ulTextOffset);
+ aulCharPos[tIndex] = ulBeginOfText + ulTextOffset;
+ NO_DBG_HEX(aulCharPos[tIndex]);
+ }
+ /* Save the Sepx offsets */
+ aulSectPage = xcalloc(tLen, sizeof(ULONG));
+ for (tIndex = 0, tOffset = (tLen + 1) * 4;
+ tIndex < tLen;
+ tIndex++, tOffset += 12) {
+ aulSectPage[tIndex] = ulGetLong(tOffset + 2, aucBuffer);
+ NO_DBG_HEX(aulSectPage[tIndex]); /* fcSepx */
+ }
+ aucBuffer = xfree(aucBuffer);
+
+ /* Read the Section Properties */
+ for (tIndex = 0; tIndex < tLen; tIndex++) {
+ if (aulSectPage[tIndex] == FC_INVALID) {
+ vDefault2SectionInfoList(aulCharPos[tIndex]);
+ continue;
+ }
+ /* Get the number of bytes to read */
+ if (!bReadBuffer(pFile, pPPS->tWordDocument.ulSB,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucTmp, aulSectPage[tIndex], 2)) {
+ continue;
+ }
+ tBytes = 2 + (size_t)usGetWord(0, aucTmp);
+ NO_DBG_DEC(tBytes);
+ /* Read the bytes */
+ aucFpage = xmalloc(tBytes);
+ if (!bReadBuffer(pFile, pPPS->tWordDocument.ulSB,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucFpage, aulSectPage[tIndex], tBytes)) {
+ aucFpage = xfree(aucFpage);
+ continue;
+ }
+ NO_DBG_PRINT_BLOCK(aucFpage, tBytes);
+ /* Process the bytes */
+ vGetDefaultSection(&tSection);
+ vGet8SectionInfo(aucFpage + 2, tBytes - 2, &tSection);
+ vAdd2SectionInfoList(&tSection, aulCharPos[tIndex]);
+ aucFpage = xfree(aucFpage);
+ }
+ aulCharPos = xfree(aulCharPos);
+ aulSectPage = xfree(aulSectPage);
+} /* end of vGet8SepInfo */
+
+/*
+ * Build the list with Header/Footer Information for Word 8/9/10/11 files
+ */
+void
+vGet8HdrFtrInfo(FILE *pFile, const pps_type *pTable,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ const UCHAR *aucHeader)
+{
+ ULONG *aulCharPos;
+ UCHAR *aucBuffer;
+ ULONG ulHdrFtrOffset, ulBeginHdrFtrInfo;
+ size_t tHdrFtrInfoLen, tIndex, tOffset, tLen;
+
+ fail(pFile == NULL || pTable == NULL || aucHeader == NULL);
+ fail(aulBBD == NULL || aulSBD == NULL);
+
+ ulBeginHdrFtrInfo = ulGetLong(0xf2, aucHeader); /* fcPlcfhdd */
+ NO_DBG_HEX(ulBeginHdrFtrInfo);
+ tHdrFtrInfoLen = (size_t)ulGetLong(0xf6, aucHeader); /* lcbPlcfhdd */
+ NO_DBG_DEC(tHdrFtrInfoLen);
+ if (tHdrFtrInfoLen < 8) {
+ DBG_DEC_C(tHdrFtrInfoLen != 0, tHdrFtrInfoLen);
+ return;
+ }
+
+ aucBuffer = aucFillInfoBuffer(pFile, pTable,
+ aulBBD, tBBDLen, aulSBD, tSBDLen,
+ ulBeginHdrFtrInfo, tHdrFtrInfoLen);
+ if (aucBuffer == NULL) {
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tHdrFtrInfoLen);
+
+ tLen = tHdrFtrInfoLen / 4 - 1;
+ DBG_DEC_C(tLen % 12 != 1 && tLen % 12 != 7, tLen);
+ /* Save the header/footer offsets */
+ aulCharPos = xcalloc(tLen, sizeof(ULONG));
+ for (tIndex = 0, tOffset = 0;
+ tIndex < tLen;
+ tIndex++, tOffset += 4) {
+ ulHdrFtrOffset = ulGetLong(tOffset, aucBuffer);
+ NO_DBG_HEX(ulHdrFtrOffset);
+ aulCharPos[tIndex] = ulHdrFtrOffset2CharPos(ulHdrFtrOffset);
+ NO_DBG_HEX(aulCharPos[tIndex]);
+ }
+ vCreat8HdrFtrInfoList(aulCharPos, tLen);
+ /* Clean up and leave */
+ aulCharPos = xfree(aulCharPos);
+ aucBuffer = xfree(aucBuffer);
+} /* end of vGet8HdrFtrInfo */
+
+/*
+ * Translate the rowinfo to a member of the row_info enumeration
+ */
+row_info_enum
+eGet8RowInfo(int iFodo,
+ const UCHAR *aucGrpprl, int iBytes, row_block_type *pRow)
+{
+ int iFodoOff, iInfoLen;
+ int iIndex, iSize, iCol;
+ int iPosCurr, iPosPrev;
+ USHORT usTmp;
+ BOOL bFound2416_0, bFound2416_1, bFound2417_0, bFound2417_1;
+ BOOL bFound244b_0, bFound244b_1, bFound244c_0, bFound244c_1;
+ BOOL bFoundd608;
+
+ fail(iFodo < 0 || aucGrpprl == NULL || pRow == NULL);
+
+ iFodoOff = 0;
+ bFound2416_0 = FALSE;
+ bFound2416_1 = FALSE;
+ bFound2417_0 = FALSE;
+ bFound2417_1 = FALSE;
+ bFound244b_0 = FALSE;
+ bFound244b_1 = FALSE;
+ bFound244c_0 = FALSE;
+ bFound244c_1 = FALSE;
+ bFoundd608 = FALSE;
+ while (iBytes >= iFodoOff + 2) {
+ iInfoLen = 0;
+ switch (usGetWord(iFodo + iFodoOff, aucGrpprl)) {
+ case 0x2416: /* fInTable */
+ if (odd(ucGetByte(iFodo + iFodoOff + 2, aucGrpprl))) {
+ bFound2416_1 = TRUE;
+ } else {
+ bFound2416_0 = TRUE;
+ }
+ break;
+ case 0x2417: /* fTtp */
+ if (odd(ucGetByte(iFodo + iFodoOff + 2, aucGrpprl))) {
+ bFound2417_1 = TRUE;
+ } else {
+ bFound2417_0 = TRUE;
+ }
+ break;
+ case 0x244b: /* sub-table fInTable */
+ if (odd(ucGetByte(iFodo + iFodoOff + 2, aucGrpprl))) {
+ bFound244b_1 = TRUE;
+ } else {
+ bFound244b_0 = TRUE;
+ }
+ break;
+ case 0x244c: /* sub-table fTtp */
+ if (odd(ucGetByte(iFodo + iFodoOff + 2, aucGrpprl))) {
+ bFound244c_1 = TRUE;
+ } else {
+ bFound244c_0 = TRUE;
+ }
+ break;
+ case 0x6424: /* brcTop */
+ usTmp = usGetWord(iFodo + iFodoOff + 2, aucGrpprl);
+ usTmp &= 0xff00;
+ NO_DBG_DEC(usTmp >> 8);
+ if (usTmp == 0) {
+ pRow->ucBorderInfo &= ~TABLE_BORDER_TOP;
+ } else {
+ pRow->ucBorderInfo |= TABLE_BORDER_TOP;
+ }
+ break;
+ case 0x6425: /* brcLeft */
+ usTmp = usGetWord(iFodo + iFodoOff + 2, aucGrpprl);
+ usTmp &= 0xff00;
+ NO_DBG_DEC(usTmp >> 8);
+ if (usTmp == 0) {
+ pRow->ucBorderInfo &= ~TABLE_BORDER_LEFT;
+ } else {
+ pRow->ucBorderInfo |= TABLE_BORDER_LEFT;
+ }
+ break;
+ case 0x6426: /* brcBottom */
+ usTmp = usGetWord(iFodo + iFodoOff + 2, aucGrpprl);
+ usTmp &= 0xff00;
+ NO_DBG_DEC(usTmp >> 8);
+ if (usTmp == 0) {
+ pRow->ucBorderInfo &= ~TABLE_BORDER_BOTTOM;
+ } else {
+ pRow->ucBorderInfo |= TABLE_BORDER_BOTTOM;
+ }
+ break;
+ case 0x6427: /* brcRight */
+ usTmp = usGetWord(iFodo + iFodoOff + 2, aucGrpprl);
+ usTmp &= 0xff00;
+ NO_DBG_DEC(usTmp >> 8);
+ if (usTmp == 0) {
+ pRow->ucBorderInfo &= ~TABLE_BORDER_RIGHT;
+ } else {
+ pRow->ucBorderInfo |= TABLE_BORDER_RIGHT;
+ }
+ break;
+ case 0xd606: /* cDefTable10 */
+ DBG_MSG("0xd606: sprmTDefTable10");
+ iSize = (int)usGetWord(iFodo + iFodoOff + 2, aucGrpprl);
+ DBG_DEC(iSize);
+ break;
+ case 0xd608: /* cDefTable */
+ iSize = (int)usGetWord(iFodo + iFodoOff + 2, aucGrpprl);
+ if (iSize < 6 || iBytes < iFodoOff + 8) {
+ DBG_DEC(iSize);
+ DBG_DEC(iFodoOff);
+ iInfoLen = 2;
+ break;
+ }
+ iCol = (int)ucGetByte(iFodo + iFodoOff + 4, aucGrpprl);
+ if (iCol < 1 ||
+ iBytes < iFodoOff + 4 + (iCol + 1) * 2) {
+ DBG_DEC(iCol);
+ DBG_DEC(iFodoOff);
+ iInfoLen = 2;
+ break;
+ }
+ if (iCol >= (int)elementsof(pRow->asColumnWidth)) {
+ DBG_DEC(iCol);
+ werr(1, "The number of columns is corrupt");
+ }
+ pRow->ucNumberOfColumns = (UCHAR)iCol;
+ iPosPrev = (int)(short)usGetWord(
+ iFodo + iFodoOff + 5,
+ aucGrpprl);
+ for (iIndex = 0; iIndex < iCol; iIndex++) {
+ iPosCurr = (int)(short)usGetWord(
+ iFodo + iFodoOff + 7 + iIndex * 2,
+ aucGrpprl);
+ pRow->asColumnWidth[iIndex] =
+ (short)(iPosCurr - iPosPrev);
+ iPosPrev = iPosCurr;
+ }
+ bFoundd608 = TRUE;
+ break;
+ default:
+ break;
+ }
+ if (iInfoLen <= 0) {
+ iInfoLen =
+ iGet8InfoLength(iFodo + iFodoOff, aucGrpprl);
+ fail(iInfoLen <= 0);
+ }
+ iFodoOff += iInfoLen;
+ }
+
+ if (bFound2417_1 && bFoundd608) {
+ return found_end_of_row;
+ }
+ if (bFound2417_0 && !bFoundd608) {
+ return found_not_end_of_row;
+ }
+ if (bFound2416_1 || bFound244b_1) {
+ return found_a_cell;
+ }
+ if (bFound2416_0 || bFound244b_0) {
+ return found_not_a_cell;
+ }
+ return found_nothing;
+} /* end of eGet8RowInfo */
+
+/*
+ * Fill the style information block with information
+ * from a Word 8/9/10/11 file.
+ */
+void
+vGet8StyleInfo(int iFodo,
+ const UCHAR *aucGrpprl, int iBytes, style_block_type *pStyle)
+{
+ list_block_type tList6;
+ const list_block_type *pList;
+ int iFodoOff, iInfoLen;
+ int iTmp, iDel, iAdd, iBefore;
+ USHORT usOpCode, usTmp;
+ short sTmp;
+
+ fail(iFodo < 0 || aucGrpprl == NULL || pStyle == NULL);
+
+ NO_DBG_DEC_C(pStyle->usListIndex != 0, pStyle->usIstd);
+ NO_DBG_DEC_C(pStyle->usListIndex != 0, pStyle->usListIndex);
+
+ (void)memset(&tList6, 0, sizeof(tList6));
+
+ iFodoOff = 0;
+ while (iBytes >= iFodoOff + 2) {
+ iInfoLen = 0;
+ usOpCode = usGetWord(iFodo + iFodoOff, aucGrpprl);
+ switch (usOpCode) {
+ case 0x2403: /* jc */
+ pStyle->ucAlignment = ucGetByte(
+ iFodo + iFodoOff + 2, aucGrpprl);
+ break;
+ case 0x260a: /* ilvl */
+ pStyle->ucListLevel =
+ ucGetByte(iFodo + iFodoOff + 2, aucGrpprl);
+ NO_DBG_DEC(pStyle->ucListLevel);
+ pStyle->ucNumLevel = pStyle->ucListLevel;
+ break;
+ case 0x4600: /* istd */
+ usTmp = usGetWord(iFodo + iFodoOff + 2, aucGrpprl);
+ NO_DBG_DEC(usTmp);
+ break;
+ case 0x460b: /* ilfo */
+ pStyle->usListIndex =
+ usGetWord(iFodo + iFodoOff + 2, aucGrpprl);
+ NO_DBG_DEC(pStyle->usListIndex);
+ break;
+ case 0x4610: /* Nest dxaLeft */
+ sTmp = (short)usGetWord(
+ iFodo + iFodoOff + 2, aucGrpprl);
+ pStyle->sLeftIndent += sTmp;
+ if (pStyle->sLeftIndent < 0) {
+ pStyle->sLeftIndent = 0;
+ }
+ DBG_DEC(sTmp);
+ DBG_DEC(pStyle->sLeftIndent);
+ break;
+ case 0xc60d: /* ChgTabsPapx */
+ case 0xc615: /* ChgTabs */
+ iTmp = (int)ucGetByte(iFodo + iFodoOff + 2, aucGrpprl);
+ if (iTmp < 2) {
+ iInfoLen = 1;
+ break;
+ }
+ NO_DBG_DEC(iTmp);
+ iDel = (int)ucGetByte(iFodo + iFodoOff + 3, aucGrpprl);
+ if (iTmp < 2 + 2 * iDel) {
+ iInfoLen = 1;
+ break;
+ }
+ NO_DBG_DEC(iDel);
+ iAdd = (int)ucGetByte(
+ iFodo + iFodoOff + 4 + 2 * iDel, aucGrpprl);
+ if (iTmp < 2 + 2 * iDel + 2 * iAdd) {
+ iInfoLen = 1;
+ break;
+ }
+ NO_DBG_DEC(iAdd);
+ break;
+ case 0x840e: /* dxaRight */
+ pStyle->sRightIndent = (short)usGetWord(
+ iFodo + iFodoOff + 2, aucGrpprl);
+ NO_DBG_DEC(pStyle->sRightIndent);
+ break;
+ case 0x840f: /* dxaLeft */
+ pStyle->sLeftIndent = (short)usGetWord(
+ iFodo + iFodoOff + 2, aucGrpprl);
+ NO_DBG_DEC(pStyle->sLeftIndent);
+ break;
+ case 0x8411: /* dxaLeft1 */
+ pStyle->sLeftIndent1 = (short)usGetWord(
+ iFodo + iFodoOff + 2, aucGrpprl);
+ NO_DBG_DEC(pStyle->sLeftIndent1);
+ break;
+ case 0xa413: /* dyaBefore */
+ pStyle->usBeforeIndent = usGetWord(
+ iFodo + iFodoOff + 2, aucGrpprl);
+ NO_DBG_DEC(pStyle->usBeforeIndent);
+ break;
+ case 0xa414: /* dyaAfter */
+ pStyle->usAfterIndent = usGetWord(
+ iFodo + iFodoOff + 2, aucGrpprl);
+ NO_DBG_DEC(pStyle->usAfterIndent);
+ break;
+ case 0xc63e: /* anld */
+ iTmp = (int)ucGetByte(
+ iFodo + iFodoOff + 2, aucGrpprl);
+ DBG_DEC_C(iTmp < 84, iTmp);
+ if (iTmp >= 1) {
+ tList6.ucNFC = ucGetByte(
+ iFodo + iFodoOff + 3, aucGrpprl);
+ }
+ if (tList6.ucNFC != LIST_BULLETS && iTmp >= 2) {
+ iBefore = (int)ucGetByte(
+ iFodo + iFodoOff + 4, aucGrpprl);
+ } else {
+ iBefore = 0;
+ }
+ if (iTmp >= 12) {
+ tList6.ulStartAt = (ULONG)usGetWord(
+ iFodo + iFodoOff + 13, aucGrpprl);
+ }
+ if (iTmp >= iBefore + 22) {
+ tList6.usListChar = usGetWord(
+ iFodo + iFodoOff + iBefore + 23,
+ aucGrpprl);
+ DBG_HEX(tList6.usListChar);
+ }
+ break;
+ default:
+ NO_DBG_HEX(usOpCode);
+ break;
+ }
+ if (iInfoLen <= 0) {
+ iInfoLen =
+ iGet8InfoLength(iFodo + iFodoOff, aucGrpprl);
+ fail(iInfoLen <= 0);
+ }
+ iFodoOff += iInfoLen;
+ }
+
+ if (pStyle->usListIndex == 2047) {
+ /* Old style list */
+ pStyle->usStartAt = (USHORT)tList6.ulStartAt;
+ pStyle->usListChar = tList6.usListChar;
+ pStyle->ucNFC = tList6.ucNFC;
+ } else {
+ /* New style list */
+ pList = pGetListInfo(pStyle->usListIndex, pStyle->ucListLevel);
+ if (pList != NULL) {
+ pStyle->bNoRestart = pList->bNoRestart;
+ fail(pList->ulStartAt > (ULONG)USHRT_MAX);
+ pStyle->usStartAt = (USHORT)pList->ulStartAt;
+ pStyle->usListChar = pList->usListChar;
+ pStyle->ucNFC = pList->ucNFC;
+ if (pStyle->sLeftIndent <= 0) {
+ pStyle->sLeftIndent = pList->sLeftIndent;
+ }
+ }
+ }
+} /* end of vGet8StyleInfo */
+
+/*
+ * Get the left indentation value from the style information block
+ *
+ * Returns the value when found, otherwise 0
+ */
+static short
+sGetLeftIndent(const UCHAR *aucGrpprl, size_t tBytes)
+{
+ int iOffset, iInfoLen;
+ USHORT usOpCode, usTmp;
+
+ fail(aucGrpprl == NULL);
+
+ iOffset = 0;
+ while (tBytes >= (size_t)iOffset + 4) {
+ usOpCode = usGetWord(iOffset, aucGrpprl);
+ if (usOpCode == 0x840f) { /* dxaLeft */
+ usTmp = usGetWord(iOffset + 2, aucGrpprl);
+ if (usTmp <= 0x7fff) {
+ NO_DBG_DEC(usTmp);
+ return (short)usTmp;
+ }
+ }
+ iInfoLen = iGet8InfoLength(iOffset, aucGrpprl);
+ fail(iInfoLen <= 0);
+ iOffset += iInfoLen;
+ }
+ return 0;
+} /* end of sGetLeftIndent */
+
+/*
+ * Build the list with List Information for Word 8/9/10/11 files
+ */
+void
+vGet8LstInfo(FILE *pFile, const pps_info_type *pPPS,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ const UCHAR *aucHeader)
+{
+ list_block_type tList;
+ const ULONG *aulBlockDepot;
+ UCHAR *aucLfoInfo, *aucLstfInfo, *aucPapx, *aucXString;
+ ULONG ulBeginLfoInfo, ulBeginLstfInfo, ulBeginLvlfInfo;
+ ULONG ulListID, ulStart;
+ size_t tBlockDepotLen, tBlockSize;
+ size_t tLfoInfoLen, tLstfInfoLen, tPapxLen, tXstLen, tOff;
+ size_t tLstfRecords, tStart, tIndex;
+ int iNums;
+ USHORT usIstd;
+ UCHAR ucTmp, ucListLevel, ucMaxLevel, ucChpxLen;
+ UCHAR aucLvlfInfo[28], aucXst[2];
+
+ fail(pFile == NULL || pPPS == NULL || aucHeader == NULL);
+ fail(aulBBD == NULL || aulSBD == NULL);
+
+ NO_DBG_DEC(pPPS->tTable.ulSB);
+ NO_DBG_HEX(pPPS->tTable.ulSize);
+ if (pPPS->tTable.ulSize == 0) {
+ DBG_MSG("No list information");
+ return;
+ }
+
+ if (pPPS->tTable.ulSize < MIN_SIZE_FOR_BBD_USE) {
+ /* Use the Small Block Depot */
+ aulBlockDepot = aulSBD;
+ tBlockDepotLen = tSBDLen;
+ tBlockSize = SMALL_BLOCK_SIZE;
+ } else {
+ /* Use the Big Block Depot */
+ aulBlockDepot = aulBBD;
+ tBlockDepotLen = tBBDLen;
+ tBlockSize = BIG_BLOCK_SIZE;
+ }
+
+ /* LFO (List Format Override) */
+ ulBeginLfoInfo = ulGetLong(0x2ea, aucHeader); /* fcPlfLfo */
+ DBG_HEX(ulBeginLfoInfo);
+ tLfoInfoLen = (size_t)ulGetLong(0x2ee, aucHeader); /* lcbPlfLfo */
+ DBG_DEC(tLfoInfoLen);
+ if (tLfoInfoLen == 0) {
+ DBG_MSG("No lists in this document");
+ return;
+ }
+
+ aucLfoInfo = xmalloc(tLfoInfoLen);
+ if (!bReadBuffer(pFile, pPPS->tTable.ulSB,
+ aulBlockDepot, tBlockDepotLen, tBlockSize,
+ aucLfoInfo, ulBeginLfoInfo, tLfoInfoLen)) {
+ aucLfoInfo = xfree(aucLfoInfo);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucLfoInfo, tLfoInfoLen);
+ vBuildLfoList(aucLfoInfo, tLfoInfoLen);
+ aucLfoInfo = xfree(aucLfoInfo);
+
+ /* LSTF (LiST data on File) */
+ ulBeginLstfInfo = ulGetLong(0x2e2, aucHeader); /* fcPlcfLst */
+ DBG_HEX(ulBeginLstfInfo);
+ tLstfInfoLen = (size_t)ulGetLong(0x2e6, aucHeader); /* lcbPlcfLst */
+ DBG_DEC(tLstfInfoLen);
+ if (tLstfInfoLen == 0) {
+ DBG_MSG("No list data on file");
+ return;
+ }
+
+ aucLstfInfo = xmalloc(tLstfInfoLen);
+ if (!bReadBuffer(pFile, pPPS->tTable.ulSB,
+ aulBlockDepot, tBlockDepotLen, tBlockSize,
+ aucLstfInfo, ulBeginLstfInfo, tLstfInfoLen)) {
+ aucLstfInfo = xfree(aucLstfInfo);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucLstfInfo, tLstfInfoLen);
+
+ tLstfRecords = (size_t)usGetWord(0, aucLstfInfo);
+ if (2 + tLstfRecords * 28 < tLstfInfoLen) {
+ DBG_DEC(2 + tLstfRecords * 28);
+ DBG_DEC(tLstfInfoLen);
+ aucLstfInfo = xfree(aucLstfInfo);
+ return;
+ }
+
+ /* LVLF (List leVeL on File) */
+ ulBeginLvlfInfo = ulBeginLstfInfo + tLstfInfoLen;
+ DBG_HEX(ulBeginLvlfInfo);
+
+ aucXString = NULL;
+ ulStart = ulBeginLvlfInfo;
+
+ for (tIndex = 0, tStart = 2;
+ tIndex < tLstfRecords;
+ tIndex++, tStart += 28) {
+ ulListID = ulGetLong(tStart, aucLstfInfo);
+ NO_DBG_HEX(ulListID);
+ ucTmp = ucGetByte(tStart + 26, aucLstfInfo);
+ ucMaxLevel = odd(ucTmp) ? 1 : 9;
+ for (ucListLevel = 0; ucListLevel < ucMaxLevel; ucListLevel++) {
+ fail(aucXString != NULL);
+ usIstd = usGetWord(
+ tStart + 8 + 2 * (size_t)ucListLevel,
+ aucLstfInfo);
+ DBG_DEC_C(usIstd != STI_NIL, usIstd);
+ NO_DBG_HEX(ulStart);
+ (void)memset(&tList, 0, sizeof(tList));
+ /* Read the lvlf (List leVeL on File) */
+ if (!bReadBuffer(pFile, pPPS->tTable.ulSB,
+ aulBlockDepot, tBlockDepotLen,
+ tBlockSize, aucLvlfInfo,
+ ulStart, sizeof(aucLvlfInfo))) {
+ aucLstfInfo = xfree(aucLstfInfo);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucLvlfInfo, sizeof(aucLvlfInfo));
+ if (bAllZero(aucLvlfInfo, sizeof(aucLvlfInfo))) {
+ tList.ulStartAt = 1;
+ tList.ucNFC = 0x00;
+ tList.bNoRestart = FALSE;
+ } else {
+ tList.ulStartAt = ulGetLong(0, aucLvlfInfo);
+ tList.ucNFC = ucGetByte(4, aucLvlfInfo);
+ ucTmp = ucGetByte(5, aucLvlfInfo);
+ tList.bNoRestart = (ucTmp & BIT(3)) != 0;
+ DBG_MSG_C((ucTmp & BIT(4)) != 0 &&
+ (ucTmp & BIT(6)) != 0, "Found one");
+ }
+ ulStart += sizeof(aucLvlfInfo);
+ tPapxLen = (size_t)ucGetByte(25, aucLvlfInfo);
+ if (tPapxLen != 0) {
+ aucPapx = xmalloc(tPapxLen);
+ /* Read the Papx */
+ if (!bReadBuffer(pFile, pPPS->tTable.ulSB,
+ aulBlockDepot, tBlockDepotLen,
+ tBlockSize, aucPapx,
+ ulStart, tPapxLen)) {
+ aucPapx = xfree(aucPapx);
+ aucLstfInfo = xfree(aucLstfInfo);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucPapx, tPapxLen);
+ tList.sLeftIndent =
+ sGetLeftIndent(aucPapx, tPapxLen);
+ aucPapx = xfree(aucPapx);
+ }
+ ulStart += tPapxLen;
+ ucChpxLen = ucGetByte(24, aucLvlfInfo);
+ ulStart += (ULONG)ucChpxLen;
+ /* Read the length of the XString */
+ if (!bReadBuffer(pFile, pPPS->tTable.ulSB,
+ aulBlockDepot, tBlockDepotLen,
+ tBlockSize, aucXst,
+ ulStart, sizeof(aucXst))) {
+ aucLstfInfo = xfree(aucLstfInfo);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucXst, sizeof(aucXst));
+ tXstLen = (size_t)usGetWord(0, aucXst);
+ ulStart += sizeof(aucXst);
+ if (tXstLen == 0) {
+ tList.usListChar = DEFAULT_LISTCHAR;
+ vAdd2ListInfoList(ulListID,
+ usIstd,
+ ucListLevel,
+ &tList);
+ continue;
+ }
+ tXstLen *= 2; /* Length in chars to length in bytes */
+ aucXString = xmalloc(tXstLen);
+ /* Read the XString */
+ if (!bReadBuffer(pFile, pPPS->tTable.ulSB,
+ aulBlockDepot, tBlockDepotLen,
+ tBlockSize, aucXString,
+ ulStart, tXstLen)) {
+ aucXString = xfree(aucXString);
+ aucLstfInfo = xfree(aucLstfInfo);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucXString, tXstLen);
+ tOff = 0;
+ for (iNums = 6; iNums < 15; iNums++) {
+ ucTmp = ucGetByte(iNums, aucLvlfInfo);
+ if (ucTmp == 0) {
+ break;
+ }
+ tOff = (size_t)ucTmp;
+ }
+ tOff *= 2; /* Offset in chars to offset in bytes */
+ NO_DBG_DEC(tOff);
+ if (tList.ucNFC == LIST_SPECIAL ||
+ tList.ucNFC == LIST_SPECIAL2 ||
+ tList.ucNFC == LIST_BULLETS) {
+ tList.usListChar = usGetWord(0, aucXString);
+ } else if (tOff != 0 && tOff < tXstLen) {
+ tList.usListChar = usGetWord(tOff, aucXString);
+ } else {
+ tList.usListChar = DEFAULT_LISTCHAR;
+ }
+ vAdd2ListInfoList(ulListID,
+ usIstd,
+ ucListLevel,
+ &tList);
+ ulStart += tXstLen;
+ aucXString = xfree(aucXString);
+ }
+ }
+ aucLstfInfo = xfree(aucLstfInfo);
+} /* end of vGet8LstInfo */
+
+/*
+ * Build the lists with Paragraph Information for Word 8/9/10/11 files
+ */
+void
+vGet8PapInfo(FILE *pFile, const pps_info_type *pPPS,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ const UCHAR *aucHeader)
+{
+ row_block_type tRow;
+ style_block_type tStyle;
+ ULONG *aulParfPage;
+ UCHAR *aucBuffer;
+ ULONG ulCharPos, ulCharPosFirst, ulCharPosLast;
+ ULONG ulBeginParfInfo;
+ size_t tParfInfoLen, tOffset, tLen;
+ int iIndex, iIndex2, iRun, iFodo, iLen;
+ row_info_enum eRowInfo;
+ USHORT usIstd;
+ UCHAR aucFpage[BIG_BLOCK_SIZE];
+
+ fail(pFile == NULL || pPPS == NULL || aucHeader == NULL);
+ fail(aulBBD == NULL || aulSBD == NULL);
+
+ ulBeginParfInfo = ulGetLong(0x102, aucHeader); /* fcPlcfbtePapx */
+ NO_DBG_HEX(ulBeginParfInfo);
+ tParfInfoLen = (size_t)ulGetLong(0x106, aucHeader); /* lcbPlcfbtePapx */
+ NO_DBG_DEC(tParfInfoLen);
+ if (tParfInfoLen < 4) {
+ DBG_DEC(tParfInfoLen);
+ return;
+ }
+
+ aucBuffer = aucFillInfoBuffer(pFile, &pPPS->tTable,
+ aulBBD, tBBDLen, aulSBD, tSBDLen,
+ ulBeginParfInfo, tParfInfoLen);
+ if (aucBuffer == NULL) {
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tParfInfoLen);
+
+ tLen = (tParfInfoLen / 4 - 1) / 2;
+ aulParfPage = xcalloc(tLen, sizeof(ULONG));
+ for (iIndex = 0, tOffset = (tLen + 1) * 4;
+ iIndex < (int)tLen;
+ iIndex++, tOffset += 4) {
+ aulParfPage[iIndex] = ulGetLong(tOffset, aucBuffer);
+ NO_DBG_DEC(aulParfPage[iIndex]);
+ }
+ DBG_HEX(ulGetLong(0, aucBuffer));
+ aucBuffer = xfree(aucBuffer);
+ NO_DBG_PRINT_BLOCK(aucHeader, HEADER_SIZE);
+
+ (void)memset(&tRow, 0, sizeof(tRow));
+ ulCharPosFirst = CP_INVALID;
+ for (iIndex = 0; iIndex < (int)tLen; iIndex++) {
+ fail(aulParfPage[iIndex] > ULONG_MAX / BIG_BLOCK_SIZE);
+ if (!bReadBuffer(pFile, pPPS->tWordDocument.ulSB,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucFpage,
+ aulParfPage[iIndex] * BIG_BLOCK_SIZE,
+ BIG_BLOCK_SIZE)) {
+ break;
+ }
+ NO_DBG_PRINT_BLOCK(aucFpage, BIG_BLOCK_SIZE);
+ iRun = (int)ucGetByte(0x1ff, aucFpage);
+ NO_DBG_DEC(iRun);
+ for (iIndex2 = 0; iIndex2 < iRun; iIndex2++) {
+ NO_DBG_HEX(ulGetLong(iIndex2 * 4, aucFpage));
+ iFodo = 2 * (int)ucGetByte(
+ (iRun + 1) * 4 + iIndex2 * 13, aucFpage);
+ if (iFodo <= 0) {
+ continue;
+ }
+
+ iLen = 2 * (int)ucGetByte(iFodo, aucFpage);
+ if (iLen == 0) {
+ iFodo++;
+ iLen = 2 * (int)ucGetByte(iFodo, aucFpage);
+ }
+
+ usIstd = usGetWord(iFodo + 1, aucFpage);
+ vFillStyleFromStylesheet(usIstd, &tStyle);
+ vGet8StyleInfo(iFodo, aucFpage + 3, iLen - 3, &tStyle);
+ ulCharPos = ulGetLong(iIndex2 * 4, aucFpage);
+ NO_DBG_HEX(ulCharPos);
+ tStyle.ulFileOffset = ulCharPos2FileOffsetX(
+ ulCharPos, &tStyle.eListID);
+ vAdd2StyleInfoList(&tStyle);
+
+ eRowInfo = eGet8RowInfo(iFodo,
+ aucFpage + 3, iLen - 3, &tRow);
+ switch (eRowInfo) {
+ case found_a_cell:
+ if (ulCharPosFirst != CP_INVALID) {
+ break;
+ }
+ ulCharPosFirst = ulGetLong(
+ iIndex2 * 4, aucFpage);
+ NO_DBG_HEX(ulCharPosFirst);
+ tRow.ulCharPosStart = ulCharPosFirst;
+ tRow.ulFileOffsetStart =
+ ulCharPos2FileOffset(ulCharPosFirst);
+ NO_DBG_HEX_C(
+ tRow.ulFileOffsetStart == FC_INVALID,
+ ulCharPosFirst);
+ break;
+ case found_end_of_row:
+ ulCharPosLast = ulGetLong(
+ iIndex2 * 4, aucFpage);
+ NO_DBG_HEX(ulCharPosLast);
+ tRow.ulCharPosEnd = ulCharPosLast;
+ tRow.ulFileOffsetEnd =
+ ulCharPos2FileOffset(ulCharPosLast);
+ NO_DBG_HEX_C(tRow.ulFileOffsetEnd == FC_INVALID,
+ ulCharPosLast);
+ vAdd2RowInfoList(&tRow);
+ (void)memset(&tRow, 0, sizeof(tRow));
+ ulCharPosFirst = CP_INVALID;
+ break;
+ case found_nothing:
+ break;
+ default:
+ DBG_DEC(eRowInfo);
+ break;
+ }
+ }
+ }
+ aulParfPage = xfree(aulParfPage);
+} /* end of vGet8PapInfo */
+
+/*
+ * Fill the font information block with information
+ * from a Word 8/9/10/11 file.
+ */
+void
+vGet8FontInfo(int iFodo, USHORT usIstd,
+ const UCHAR *aucGrpprl, int iBytes, font_block_type *pFont)
+{
+ long lTmp;
+ int iFodoOff, iInfoLen;
+ USHORT usFtc0, usFtc1, usFtc2, usTmp;
+ UCHAR ucTmp;
+
+ fail(iFodo < 0 || aucGrpprl == NULL || pFont == NULL);
+
+ usFtc0 = USHRT_MAX;
+ usFtc1 = USHRT_MAX;
+ usFtc2 = USHRT_MAX;
+
+ iFodoOff = 0;
+ while (iBytes >= iFodoOff + 2) {
+ switch (usGetWord(iFodo + iFodoOff, aucGrpprl)) {
+ case 0x0800: /* fRMarkDel */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 2, aucGrpprl);
+ if (ucTmp == 0) {
+ pFont->usFontStyle &= ~FONT_MARKDEL;
+ } else {
+ pFont->usFontStyle |= FONT_MARKDEL;
+ }
+ break;
+ case 0x0835: /* fBold */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 2, aucGrpprl);
+ switch (ucTmp) {
+ case 0: /* Unset */
+ pFont->usFontStyle &= ~FONT_BOLD;
+ break;
+ case 1: /* Set */
+ pFont->usFontStyle |= FONT_BOLD;
+ break;
+ case 128: /* Unchanged */
+ break;
+ case 129: /* Negation */
+ pFont->usFontStyle ^= FONT_BOLD;
+ break;
+ default:
+ DBG_DEC(ucTmp);
+ DBG_FIXME();
+ break;
+ }
+ break;
+ case 0x0836: /* fItalic */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 2, aucGrpprl);
+ switch (ucTmp) {
+ case 0: /* Unset */
+ pFont->usFontStyle &= ~FONT_ITALIC;
+ break;
+ case 1: /* Set */
+ pFont->usFontStyle |= FONT_ITALIC;
+ break;
+ case 128: /* Unchanged */
+ break;
+ case 129: /* Negation */
+ pFont->usFontStyle ^= FONT_ITALIC;
+ break;
+ default:
+ DBG_DEC(ucTmp);
+ DBG_FIXME();
+ break;
+ }
+ break;
+ case 0x0837: /* fStrike */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 2, aucGrpprl);
+ switch (ucTmp) {
+ case 0: /* Unset */
+ pFont->usFontStyle &= ~FONT_STRIKE;
+ break;
+ case 1: /* Set */
+ pFont->usFontStyle |= FONT_STRIKE;
+ break;
+ case 128: /* Unchanged */
+ break;
+ case 129: /* Negation */
+ pFont->usFontStyle ^= FONT_STRIKE;
+ break;
+ default:
+ DBG_DEC(ucTmp);
+ DBG_FIXME();
+ break;
+ }
+ break;
+ case 0x083a: /* fSmallCaps */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 2, aucGrpprl);
+ switch (ucTmp) {
+ case 0: /* Unset */
+ pFont->usFontStyle &= ~FONT_SMALL_CAPITALS;
+ break;
+ case 1: /* Set */
+ pFont->usFontStyle |= FONT_SMALL_CAPITALS;
+ break;
+ case 128: /* Unchanged */
+ break;
+ case 129: /* Negation */
+ pFont->usFontStyle ^= FONT_SMALL_CAPITALS;
+ break;
+ default:
+ DBG_DEC(ucTmp);
+ DBG_FIXME();
+ break;
+ }
+ break;
+ case 0x083b: /* fCaps */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 2, aucGrpprl);
+ switch (ucTmp) {
+ case 0: /* Unset */
+ pFont->usFontStyle &= ~FONT_CAPITALS;
+ break;
+ case 1: /* Set */
+ pFont->usFontStyle |= FONT_CAPITALS;
+ break;
+ case 128: /* Unchanged */
+ break;
+ case 129: /* Negation */
+ pFont->usFontStyle ^= FONT_CAPITALS;
+ break;
+ default:
+ DBG_DEC(ucTmp);
+ DBG_FIXME();
+ break;
+ }
+ break;
+ case 0x083c: /* fVanish */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 2, aucGrpprl);
+ switch (ucTmp) {
+ case 0: /* Unset */
+ pFont->usFontStyle &= ~FONT_HIDDEN;
+ break;
+ case 1: /* Set */
+ pFont->usFontStyle |= FONT_HIDDEN;
+ break;
+ case 128: /* Unchanged */
+ break;
+ case 129: /* Negation */
+ pFont->usFontStyle ^= FONT_HIDDEN;
+ break;
+ default:
+ DBG_DEC(ucTmp);
+ DBG_FIXME();
+ break;
+ }
+ break;
+ case 0x2a32: /* cDefault */
+ pFont->usFontStyle &= FONT_HIDDEN;
+ pFont->ucFontColor = FONT_COLOR_DEFAULT;
+ break;
+ case 0x2a33: /* cPlain */
+ DBG_MSG("2a33: cPlain");
+ vFillFontFromStylesheet(usIstd, pFont);
+ break;
+ case 0x2a3e: /* cKul */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 2, aucGrpprl);
+ if (ucTmp == 0 || ucTmp == 5) {
+ pFont->usFontStyle &= ~FONT_UNDERLINE;
+ } else {
+ NO_DBG_MSG("Underline text");
+ pFont->usFontStyle |= FONT_UNDERLINE;
+ if (ucTmp == 6) {
+ DBG_MSG("Bold text");
+ pFont->usFontStyle |= FONT_BOLD;
+ }
+ }
+ break;
+ case 0x2a42: /* cIco */
+ pFont->ucFontColor =
+ ucGetByte(iFodo + iFodoOff + 2, aucGrpprl);
+ NO_DBG_DEC(pFont->ucFontColor);
+ break;
+ case 0x2a44: /* cHpsInc */
+ DBG_MSG("0x2a44: sprmCHpsInc");
+ ucTmp = ucGetByte(iFodo + iFodoOff + 2, aucGrpprl);
+ DBG_DEC(ucTmp);
+ break;
+ case 0x2a48: /* cIss */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 2, aucGrpprl);
+ ucTmp &= 0x07;
+ if (ucTmp == 1) {
+ pFont->usFontStyle |= FONT_SUPERSCRIPT;
+ NO_DBG_MSG("Superscript");
+ } else if (ucTmp == 2) {
+ pFont->usFontStyle |= FONT_SUBSCRIPT;
+ NO_DBG_MSG("Subscript");
+ }
+ break;
+ case 0x4a30: /* cIstd */
+ usTmp = usGetWord(iFodo + iFodoOff + 2, aucGrpprl);
+ NO_DBG_DEC(usTmp);
+ break;
+ case 0x4a43: /* cHps */
+ pFont->usFontSize =
+ usGetWord(iFodo + iFodoOff + 2, aucGrpprl);
+ NO_DBG_DEC(pFont->usFontSize);
+ break;
+ case 0x4a4d: /* cHpsMul */
+ DBG_MSG("0x4a4d: sprmCHpsMul");
+ usTmp = usGetWord(iFodo + iFodoOff + 2, aucGrpprl);
+ DBG_DEC(usTmp);
+ break;
+ case 0x4a4f: /* cFtc0 */
+ usFtc0 = usGetWord(iFodo + iFodoOff + 2, aucGrpprl);
+ break;
+ case 0x4a50: /* cFtc1 */
+ usFtc1 = usGetWord(iFodo + iFodoOff + 2, aucGrpprl);
+ break;
+ case 0x4a51: /* cFtc2 */
+ usFtc2 = usGetWord(iFodo + iFodoOff + 2, aucGrpprl);
+ break;
+ case 0xca47: /* cMajority */
+ DBG_MSG("0xca47: sprmCMajority");
+ break;
+ case 0xca4a: /* cHpsInc1 */
+ usTmp = usGetWord(iFodo + iFodoOff + 2, aucGrpprl);
+ lTmp = (long)pFont->usFontSize + (long)usTmp;
+ if (lTmp < 8) {
+ pFont->usFontSize = 8;
+ } else if (lTmp > 32766) {
+ pFont->usFontSize = 32766;
+ } else {
+ pFont->usFontSize = (USHORT)lTmp;
+ }
+ break;
+ case 0xca4c: /* cMajority50 */
+ DBG_MSG("0xca4c: sprmCMajority50");
+ break;
+ case 0xea3f: /* cHps, cHpsPos */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 2, aucGrpprl);
+ DBG_DEC(ucTmp);
+ if (ucTmp != 0) {
+ pFont->usFontSize = (USHORT)ucTmp;
+ }
+ ucTmp = ucGetByte(iFodo + iFodoOff + 3, aucGrpprl);
+ DBG_DEC(ucTmp);
+ break;
+ default:
+ break;
+ }
+ iInfoLen = iGet8InfoLength(iFodo + iFodoOff, aucGrpprl);
+ fail(iInfoLen <= 0);
+ iFodoOff += iInfoLen;
+ }
+
+ /* Combine the Ftc's to a FontNumber */
+ NO_DBG_DEC_C(usFtc0 != USHRT_MAX, usFtc0);
+ NO_DBG_DEC_C(usFtc2 != USHRT_MAX, usFtc2);
+ NO_DBG_DEC_C(usFtc1 != USHRT_MAX, usFtc1);
+ if (usFtc0 <= 0x7fff) {
+ if (usFtc0 <= (USHORT)UCHAR_MAX) {
+ pFont->ucFontNumber = (UCHAR)usFtc0;
+ } else {
+ DBG_DEC(usFtc0);
+ DBG_FIXME();
+ pFont->ucFontNumber = 0;
+ }
+ } else if (usFtc2 <= 0x7fff) {
+ if (usFtc2 <= (USHORT)UCHAR_MAX) {
+ pFont->ucFontNumber = (UCHAR)usFtc2;
+ } else {
+ DBG_DEC(usFtc2);
+ DBG_FIXME();
+ pFont->ucFontNumber = 0;
+ }
+ } else if (usFtc1 <= 0x7fff) {
+ if (usFtc1 <= (USHORT)UCHAR_MAX) {
+ pFont->ucFontNumber = (UCHAR)usFtc1;
+ } else {
+ DBG_DEC(usFtc1);
+ DBG_FIXME();
+ pFont->ucFontNumber = 0;
+ }
+ }
+} /* end of vGet8FontInfo */
+
+/*
+ * Fill the picture information block with information
+ * from a Word 8/9/10/11 file.
+ * Returns TRUE when successful, otherwise FALSE
+ */
+static BOOL
+bGet8PicInfo(int iFodo,
+ const UCHAR *aucGrpprl, int iBytes, picture_block_type *pPicture)
+{
+ ULONG ulTmp;
+ int iFodoOff, iInfoLen;
+ BOOL bFound;
+ UCHAR ucTmp;
+
+ fail(iFodo <= 0 || aucGrpprl == NULL || pPicture == NULL);
+
+ iFodoOff = 0;
+ bFound = FALSE;
+ while (iBytes >= iFodoOff + 2) {
+ switch (usGetWord(iFodo + iFodoOff, aucGrpprl)) {
+#if 0
+ case 0x0806: /* fData */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 2, aucGrpprl);
+ if (ucTmp == 0x01) {
+ /* Not a picture, but a form field */
+ return FALSE;
+ }
+ DBG_DEC_C(ucTmp != 0, ucTmp);
+ break;
+#endif
+ case 0x080a: /* fOle2 */
+ ucTmp = ucGetByte(iFodo + iFodoOff + 2, aucGrpprl);
+ if (ucTmp == 0x01) {
+ /* Not a picture, but an OLE object */
+ return FALSE;
+ }
+ DBG_DEC_C(ucTmp != 0, ucTmp);
+ break;
+ case 0x680e: /* fcObj */
+ ulTmp = ulGetLong(iFodo + iFodoOff + 2, aucGrpprl);
+ DBG_HEX(ulTmp);
+ break;
+ case 0x6a03: /* fcPic */
+ pPicture->ulPictureOffset = ulGetLong(
+ iFodo + iFodoOff + 2, aucGrpprl);
+ bFound = TRUE;
+ break;
+ default:
+ break;
+ }
+ iInfoLen = iGet8InfoLength(iFodo + iFodoOff, aucGrpprl);
+ fail(iInfoLen <= 0);
+ iFodoOff += iInfoLen;
+ }
+ return bFound;
+} /* end of bGet8PicInfo */
+
+/*
+ * Build the lists with Character Information for Word 8/9/10/11 files
+ */
+void
+vGet8ChrInfo(FILE *pFile, const pps_info_type *pPPS,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ const UCHAR *aucHeader)
+{
+ font_block_type tFont;
+ picture_block_type tPicture;
+ ULONG *aulCharPage;
+ UCHAR *aucBuffer;
+ ULONG ulFileOffset, ulCharPos, ulBeginCharInfo;
+ size_t tCharInfoLen, tOffset, tLen;
+ int iIndex, iIndex2, iRun, iFodo, iLen;
+ USHORT usIstd;
+ UCHAR aucFpage[BIG_BLOCK_SIZE];
+
+ fail(pFile == NULL || pPPS == NULL || aucHeader == NULL);
+ fail(aulBBD == NULL || aulSBD == NULL);
+
+ ulBeginCharInfo = ulGetLong(0xfa, aucHeader); /* fcPlcfbteChpx */
+ NO_DBG_HEX(ulBeginCharInfo);
+ tCharInfoLen = (size_t)ulGetLong(0xfe, aucHeader); /* lcbPlcfbteChpx */
+ NO_DBG_DEC(tCharInfoLen);
+ if (tCharInfoLen < 4) {
+ DBG_DEC(tCharInfoLen);
+ return;
+ }
+
+ aucBuffer = aucFillInfoBuffer(pFile, &pPPS->tTable,
+ aulBBD, tBBDLen, aulSBD, tSBDLen,
+ ulBeginCharInfo, tCharInfoLen);
+ if (aucBuffer == NULL) {
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tCharInfoLen);
+
+ tLen = (tCharInfoLen / 4 - 1) / 2;
+ aulCharPage = xcalloc(tLen, sizeof(ULONG));
+ for (iIndex = 0, tOffset = (tLen + 1) * 4;
+ iIndex < (int)tLen;
+ iIndex++, tOffset += 4) {
+ aulCharPage[iIndex] = ulGetLong(tOffset, aucBuffer);
+ NO_DBG_DEC(aulCharPage[iIndex]);
+ }
+ DBG_HEX(ulGetLong(0, aucBuffer));
+ aucBuffer = xfree(aucBuffer);
+ NO_DBG_PRINT_BLOCK(aucHeader, HEADER_SIZE);
+
+ for (iIndex = 0; iIndex < (int)tLen; iIndex++) {
+ fail(aulCharPage[iIndex] > ULONG_MAX / BIG_BLOCK_SIZE);
+ if (!bReadBuffer(pFile, pPPS->tWordDocument.ulSB,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucFpage,
+ aulCharPage[iIndex] * BIG_BLOCK_SIZE,
+ BIG_BLOCK_SIZE)) {
+ break;
+ }
+ NO_DBG_PRINT_BLOCK(aucFpage, BIG_BLOCK_SIZE);
+ iRun = (int)ucGetByte(0x1ff, aucFpage);
+ NO_DBG_DEC(iRun);
+ for (iIndex2 = 0; iIndex2 < iRun; iIndex2++) {
+ ulCharPos = ulGetLong(iIndex2 * 4, aucFpage);
+ ulFileOffset = ulCharPos2FileOffset(ulCharPos);
+ iFodo = 2 * (int)ucGetByte(
+ (iRun + 1) * 4 + iIndex2, aucFpage);
+
+ iLen = (int)ucGetByte(iFodo, aucFpage);
+
+ usIstd = usGetIstd(ulFileOffset);
+ vFillFontFromStylesheet(usIstd, &tFont);
+ if (iFodo != 0) {
+ vGet8FontInfo(iFodo, usIstd,
+ aucFpage + 1, iLen - 1, &tFont);
+ }
+ tFont.ulFileOffset = ulFileOffset;
+ vAdd2FontInfoList(&tFont);
+
+ if (iFodo <= 0) {
+ continue;
+ }
+
+ (void)memset(&tPicture, 0, sizeof(tPicture));
+ if (bGet8PicInfo(iFodo, aucFpage + 1,
+ iLen - 1, &tPicture)) {
+ tPicture.ulFileOffset = ulFileOffset;
+ tPicture.ulFileOffsetPicture =
+ ulDataPos2FileOffset(
+ tPicture.ulPictureOffset);
+ vAdd2PictInfoList(&tPicture);
+ }
+ }
+ }
+ aulCharPage = xfree(aulCharPage);
+} /* end of vGet8ChrInfo */
diff --git a/sys/src/cmd/aux/antiword/properties.c b/sys/src/cmd/aux/antiword/properties.c
new file mode 100755
index 000000000..28087a490
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/properties.c
@@ -0,0 +1,198 @@
+/*
+ * properties.c
+ * Copyright (C) 1998-2005 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Read the properties information from a MS Word file
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "antiword.h"
+
+
+/*
+ * Build the lists with Property Information
+ */
+void
+vGetPropertyInfo(FILE *pFile, const pps_info_type *pPPS,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ const UCHAR *aucHeader, int iWordVersion)
+{
+ options_type tOptions;
+
+ TRACE_MSG("vGetPropertyInfo");
+
+ fail(pFile == NULL);
+ fail(pPPS == NULL && iWordVersion >= 6);
+ fail(aulBBD == NULL && tBBDLen != 0);
+ fail(aulSBD == NULL && tSBDLen != 0);
+ fail(aucHeader == NULL);
+
+ /* Get the options */
+ vGetOptions(&tOptions);
+
+ /* Get the property information per Word version */
+ switch (iWordVersion) {
+ case 0:
+ vGet0DopInfo(pFile, aucHeader);
+ vGet0SepInfo(pFile, aucHeader);
+ vGet0PapInfo(pFile, aucHeader);
+ if (tOptions.eConversionType == conversion_draw ||
+ tOptions.eConversionType == conversion_ps ||
+ tOptions.eConversionType == conversion_xml ||
+ tOptions.eConversionType == conversion_fmt_text ||
+ tOptions.eConversionType == conversion_pdf) {
+ vGet0ChrInfo(pFile, aucHeader);
+ }
+ if (tOptions.eConversionType == conversion_draw ||
+ tOptions.eConversionType == conversion_ps ||
+ tOptions.eConversionType == conversion_pdf) {
+ vCreate0FontTable();
+ }
+ vSet0SummaryInfo(pFile, aucHeader);
+ break;
+ case 1:
+ case 2:
+ vGet2Stylesheet(pFile, iWordVersion, aucHeader);
+ vGet2DopInfo(pFile, aucHeader);
+ vGet2SepInfo(pFile, aucHeader);
+ vGet2PapInfo(pFile, aucHeader);
+ if (tOptions.eConversionType == conversion_ps ||
+ tOptions.eConversionType == conversion_pdf) {
+ vGet2HdrFtrInfo(pFile, aucHeader);
+ }
+ if (tOptions.eConversionType == conversion_draw ||
+ tOptions.eConversionType == conversion_ps ||
+ tOptions.eConversionType == conversion_xml ||
+ tOptions.eConversionType == conversion_fmt_text ||
+ tOptions.eConversionType == conversion_pdf) {
+ vGet2ChrInfo(pFile, iWordVersion, aucHeader);
+ }
+ if (tOptions.eConversionType == conversion_draw ||
+ tOptions.eConversionType == conversion_ps ||
+ tOptions.eConversionType == conversion_pdf) {
+ vCreate2FontTable(pFile, iWordVersion, aucHeader);
+ }
+ vSet2SummaryInfo(pFile, iWordVersion, aucHeader);
+ break;
+ case 4:
+ case 5:
+ break;
+ case 6:
+ case 7:
+ vGet6Stylesheet(pFile, pPPS->tWordDocument.ulSB,
+ aulBBD, tBBDLen, aucHeader);
+ vGet6DopInfo(pFile, pPPS->tWordDocument.ulSB,
+ aulBBD, tBBDLen, aucHeader);
+ vGet6SepInfo(pFile, pPPS->tWordDocument.ulSB,
+ aulBBD, tBBDLen, aucHeader);
+ vGet6PapInfo(pFile, pPPS->tWordDocument.ulSB,
+ aulBBD, tBBDLen, aucHeader);
+ if (tOptions.eConversionType == conversion_ps ||
+ tOptions.eConversionType == conversion_pdf) {
+ vGet6HdrFtrInfo(pFile, pPPS->tWordDocument.ulSB,
+ aulBBD, tBBDLen, aucHeader);
+ }
+ if (tOptions.eConversionType == conversion_draw ||
+ tOptions.eConversionType == conversion_ps ||
+ tOptions.eConversionType == conversion_xml ||
+ tOptions.eConversionType == conversion_fmt_text ||
+ tOptions.eConversionType == conversion_pdf) {
+ vGet6ChrInfo(pFile, pPPS->tWordDocument.ulSB,
+ aulBBD, tBBDLen, aucHeader);
+ }
+ if (tOptions.eConversionType == conversion_draw ||
+ tOptions.eConversionType == conversion_ps ||
+ tOptions.eConversionType == conversion_pdf) {
+ vCreate6FontTable(pFile, pPPS->tWordDocument.ulSB,
+ aulBBD, tBBDLen, aucHeader);
+ }
+ vSet6SummaryInfo(pFile, pPPS,
+ aulBBD, tBBDLen, aulSBD, tSBDLen, aucHeader);
+ break;
+ case 8:
+ vGet8LstInfo(pFile, pPPS,
+ aulBBD, tBBDLen, aulSBD, tSBDLen, aucHeader);
+ vGet8Stylesheet(pFile, pPPS,
+ aulBBD, tBBDLen, aulSBD, tSBDLen, aucHeader);
+ vGet8DopInfo(pFile, &pPPS->tTable,
+ aulBBD, tBBDLen, aulSBD, tSBDLen, aucHeader);
+ vGet8SepInfo(pFile, pPPS,
+ aulBBD, tBBDLen, aulSBD, tSBDLen, aucHeader);
+ vGet8PapInfo(pFile, pPPS,
+ aulBBD, tBBDLen, aulSBD, tSBDLen, aucHeader);
+ if (tOptions.eConversionType == conversion_ps ||
+ tOptions.eConversionType == conversion_pdf) {
+ vGet8HdrFtrInfo(pFile, &pPPS->tTable,
+ aulBBD, tBBDLen, aulSBD, tSBDLen, aucHeader);
+ }
+ if (tOptions.eConversionType == conversion_draw ||
+ tOptions.eConversionType == conversion_ps ||
+ tOptions.eConversionType == conversion_xml ||
+ tOptions.eConversionType == conversion_fmt_text ||
+ tOptions.eConversionType == conversion_pdf) {
+ vGet8ChrInfo(pFile, pPPS,
+ aulBBD, tBBDLen, aulSBD, tSBDLen, aucHeader);
+ }
+ if (tOptions.eConversionType == conversion_draw ||
+ tOptions.eConversionType == conversion_ps ||
+ tOptions.eConversionType == conversion_pdf) {
+ vCreate8FontTable(pFile, pPPS,
+ aulBBD, tBBDLen, aulSBD, tSBDLen, aucHeader);
+ }
+ vSet8SummaryInfo(pFile, pPPS,
+ aulBBD, tBBDLen, aulSBD, tSBDLen, aucHeader);
+ break;
+ default:
+ DBG_DEC(iWordVersion);
+ DBG_FIXME();
+ werr(0, "Sorry, no property information");
+ break;
+ }
+
+ /* Temporarily: Correct the font table */
+ vCorrectFontTable(tOptions.eConversionType, tOptions.eEncoding);
+} /* end of vGetPropertyInfo */
+
+/*
+ * ePropMod2RowInfo - Turn the Property Modifier into row information
+ *
+ * Returns: the row information
+ */
+row_info_enum
+ePropMod2RowInfo(USHORT usPropMod, int iWordVersion)
+{
+ row_block_type tRow;
+ const UCHAR *aucPropMod;
+ int iLen;
+
+ TRACE_MSG("ePropMod2RowInfo");
+
+ aucPropMod = aucReadPropModListItem(usPropMod);
+ if (aucPropMod == NULL) {
+ return found_nothing;
+ }
+ iLen = (int)usGetWord(0, aucPropMod);
+
+ switch (iWordVersion) {
+ case 0:
+ return found_nothing;
+ case 1:
+ case 2:
+ return eGet2RowInfo(0, aucPropMod + 2, iLen, &tRow);
+ case 4:
+ case 5:
+ return found_nothing;
+ case 6:
+ case 7:
+ return eGet6RowInfo(0, aucPropMod + 2, iLen, &tRow);
+ case 8:
+ return eGet8RowInfo(0, aucPropMod + 2, iLen, &tRow);
+ default:
+ DBG_DEC(iWordVersion);
+ DBG_FIXME();
+ return found_nothing;
+ }
+} /* end of ePropMod2RowInfo */
diff --git a/sys/src/cmd/aux/antiword/propmod.c b/sys/src/cmd/aux/antiword/propmod.c
new file mode 100755
index 000000000..7a3cdbb11
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/propmod.c
@@ -0,0 +1,110 @@
+/*
+ * propmod.c
+ * Copyright (C) 2001-2003 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Build, read and destroy a list (array) of Word property modifiers
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "antiword.h"
+
+#if defined(DEBUG)
+#define ELEMENTS_TO_ADD 3
+#else
+#define ELEMENTS_TO_ADD 30
+#endif /* DEBUG */
+
+/* Variables needed to write the property modifier list */
+static UCHAR **ppAnchor = NULL;
+static size_t tNextFree = 0;
+static size_t tMaxElements = 0;
+
+
+/*
+ * vDestroyPropModList - destroy the property modifier list
+ */
+void
+vDestroyPropModList(void)
+{
+ size_t tIndex;
+
+ DBG_MSG("vDestroyPropModList");
+
+ /* Free all the elements of the list */
+ for (tIndex = 0; tIndex < tNextFree; tIndex++) {
+ ppAnchor[tIndex] = xfree(ppAnchor[tIndex]);
+ }
+ /* Free the list itself */
+ ppAnchor = xfree(ppAnchor);
+ /* Reset all control variables */
+ tNextFree = 0;
+ tMaxElements = 0;
+} /* end of vDestroyPropModList */
+
+/*
+ * vAdd2PropModList - add an element to the property modifier list
+ */
+void
+vAdd2PropModList(const UCHAR *aucPropMod)
+{
+ size_t tSize, tLen;
+
+ fail(aucPropMod == NULL);
+
+ NO_DBG_MSG("vAdd2PropModList");
+
+ if (tNextFree >= tMaxElements) {
+ tMaxElements += ELEMENTS_TO_ADD;
+ tSize = tMaxElements * sizeof(UCHAR **);
+ ppAnchor = xrealloc(ppAnchor, tSize);
+ }
+ NO_DBG_DEC(tNextFree);
+
+ tLen = 2 + (size_t)usGetWord(0, aucPropMod);
+ NO_DBG_HEX(tLen);
+ NO_DBG_PRINT_BLOCK(pucPropMod, tLen);
+ ppAnchor[tNextFree] = xmalloc(tLen);
+ memcpy(ppAnchor[tNextFree], aucPropMod, tLen);
+ tNextFree++;
+} /* end of vAdd2PropModList */
+
+/*
+ * aucReadPropModListItem - get an item of the property modifier list
+ */
+const UCHAR *
+aucReadPropModListItem(USHORT usPropMod)
+{
+ static UCHAR aucBuffer[4];
+ size_t tIndex;
+
+ if (usPropMod == IGNORE_PROPMOD) {
+ /* This Properties Modifier must be ignored */
+ return NULL;
+ }
+
+ if (!odd(usPropMod)) {
+ /* Variant 1: The information is in the input ifself */
+ aucBuffer[0] = 2;
+ aucBuffer[1] = 0;
+ aucBuffer[2] = (UCHAR)((usPropMod & 0x00fe) >> 1);
+ aucBuffer[3] = (UCHAR)((usPropMod & 0xff00) >> 8);
+ return aucBuffer;
+ }
+
+ if (ppAnchor == NULL) {
+ /* No information available */
+ return NULL;
+ }
+
+ /* Variant 2: The input contains an index */
+ tIndex = (size_t)(usPropMod >> 1);
+ if (tIndex >= tNextFree) {
+ DBG_HEX(usPropMod);
+ DBG_DEC(tIndex);
+ DBG_DEC(tNextFree);
+ return NULL;
+ }
+ return ppAnchor[tIndex];
+} /* end of aucGetPropModListItem */
diff --git a/sys/src/cmd/aux/antiword/riscos.c b/sys/src/cmd/aux/antiword/riscos.c
new file mode 100755
index 000000000..78bd0fdc0
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/riscos.c
@@ -0,0 +1,251 @@
+/*
+ * riscos.c
+ * Copyright (C) 2001,2002 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * RISC OS only functions
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include "DeskLib:Error.h"
+#include "DeskLib:SWI.h"
+#include "antiword.h"
+
+#if !defined(DrawFile_Render)
+#define DrawFile_Render 0x045540
+#endif /* !DrawFile_Render */
+#if !defined(JPEG_Info)
+#define JPEG_Info 0x049980
+#endif /* !JPEG_Info */
+
+/*
+ * werr - write an error message and exit if needed
+ */
+void
+werr(int iFatal, const char *szFormat, ...)
+{
+ va_list tArg;
+
+ va_start(tArg, szFormat);
+ Error_Report(iFatal, (char *)szFormat, tArg);
+ va_end(tArg);
+ switch (iFatal) {
+ case 0: /* The message is just a warning, so no exit */
+ return;
+ case 1: /* Fatal error with a standard exit */
+ exit(EXIT_FAILURE);
+ default: /* Fatal error with a non-standard exit */
+ exit(iFatal);
+ }
+} /* end of werr */
+
+/*
+ * iGetFiletype
+ * This function will get the filetype of the given file.
+ * returns the filetype.
+ */
+int
+iGetFiletype(const char *szFilename)
+{
+ os_error *e;
+ int iType;
+
+ fail(szFilename == NULL || szFilename[0] == '\0');
+
+ e = SWI(2, 7, SWI_OS_File | XOS_Bit,
+ 23, szFilename,
+ NULL, NULL, NULL, NULL, NULL, NULL, &iType);
+ if (e == NULL) {
+ return iType;
+ }
+ werr(0, "Get Filetype error %d: %s", e->errnum, e->errmess);
+ return -1;
+} /* end of iGetFiletype */
+
+/*
+ * vSetFiletype
+ * This procedure will set the filetype of the given file to the given
+ * type.
+ */
+void
+vSetFiletype(const char *szFilename, int iFiletype)
+{
+ os_error *e;
+
+ fail(szFilename == NULL || szFilename[0] == '\0');
+
+ if (iFiletype < 0x000 || iFiletype > 0xfff) {
+ return;
+ }
+ e = SWI(3, 0, SWI_OS_File | XOS_Bit,
+ 18, szFilename, iFiletype);
+ if (e != NULL) {
+ switch (e->errnum) {
+ case 0x000113: /* ROM */
+ case 0x0104e1: /* Read-only floppy DOSFS */
+ case 0x0108c9: /* Read-only floppy ADFS */
+ case 0x013803: /* Read-only ArcFS */
+ case 0x80344a: /* CD-ROM */
+ break;
+ default:
+ werr(0, "Set Filetype error %d: %s",
+ e->errnum, e->errmess);
+ break;
+ }
+ }
+} /* end of vSetFileType */
+
+/*
+ * Check if the directory part of the given file exists, make the directory
+ * if it does not exist yet.
+ * Returns TRUE in case of success, otherwise FALSE.
+ */
+BOOL
+bMakeDirectory(const char *szFilename)
+{
+ os_error *e;
+ char *pcLastDot;
+ int iObjectType;
+ char szDirectory[PATH_MAX+1];
+
+ DBG_MSG("bMakeDirectory");
+ fail(szFilename == NULL || szFilename[0] == '\0');
+ DBG_MSG(szFilename);
+
+ if (strlen(szFilename) >= sizeof(szDirectory)) {
+ DBG_DEC(strlen(szFilename));
+ return FALSE;
+ }
+ strcpy(szDirectory, szFilename);
+ pcLastDot = strrchr(szDirectory, '.');
+ if (pcLastDot == NULL) {
+ /* No directory equals current directory */
+ DBG_MSG("No directory part given");
+ return TRUE;
+ }
+ *pcLastDot = '\0';
+ DBG_MSG(szDirectory);
+ /* Check if the name exists */
+ e = SWI(2, 1, SWI_OS_File | XOS_Bit,
+ 17, szDirectory,
+ &iObjectType);
+ if (e != NULL) {
+ werr(0, "Directory check %d: %s", e->errnum, e->errmess);
+ return FALSE;
+ }
+ if (iObjectType == 2) {
+ /* The name exists and it is a directory */
+ DBG_MSG("The directory already exists");
+ return TRUE;
+ }
+ if (iObjectType != 0) {
+ /* The name exists and it is not a directory */
+ DBG_DEC(iObjectType);
+ return FALSE;
+ }
+ /* The name does not exist, make the directory */
+ e = SWI(5, 0, SWI_OS_File | XOS_Bit,
+ 8, szDirectory, 0, 0, 0);
+ if (e != NULL) {
+ werr(0, "I can't make a directory %d: %s",
+ e->errnum, e->errmess);
+ return FALSE;
+ }
+ return TRUE;
+} /* end of bMakeDirectory */
+
+/*
+ * iReadCurrentAlphabetNumber
+ * This function reads the current Alphabet number.
+ * Returns the current Alphabet number when successful, otherwise -1
+ */
+int
+iReadCurrentAlphabetNumber(void)
+{
+ os_error *e;
+ int iAlphabetNumber;
+
+ e = SWI(2, 2, SWI_OS_Byte | XOS_Bit,
+ 71, 127,
+ NULL, &iAlphabetNumber);
+ if (e == NULL) {
+ return iAlphabetNumber;
+ }
+ werr(0, "Read alphabet error %d: %s", e->errnum, e->errmess);
+ return -1;
+} /* end of iReadCurrentAlphabetNumber */
+
+/*
+ * iGetRiscOsVersion - get the RISC OS version number
+ *
+ * returns the RISC OS version * 100
+ */
+int
+iGetRiscOsVersion(void)
+{
+ os_error *e;
+ int iVersion;
+
+ e = SWI(3, 2, SWI_OS_Byte | XOS_Bit,
+ 129, 0, 0xff,
+ NULL, &iVersion);
+ if (e != NULL) {
+ werr(0, "Read RISC OS version error %d: %s",
+ e->errnum, e->errmess);
+ return 0;
+ }
+ switch (iVersion) {
+ case 0xa0: /* Arthur 1.20 */
+ return 120;
+ case 0xa1: /* RISC OS 2.00 */
+ return 200;
+ case 0xa2: /* RISC OS 2.01 */
+ return 201;
+ case 0xa3: /* RISC OS 3.00 */
+ return 300;
+ case 0xa4: /* RISC OS 3.1x */
+ return 310;
+ case 0xa5: /* RISC OS 3.50 */
+ return 350;
+ case 0xa6: /* RISC OS 3.60 */
+ return 360;
+ case 0xa7: /* RISC OS 3.7x */
+ return 370;
+ case 0xa8: /* RISC OS 4.0x */
+ return 400;
+ default:
+ if (iVersion >= 0xa9 && iVersion <= 0xaf) {
+ /* RISC OS 4.10 and up */
+ return 410;
+ }
+ /* Unknown version */
+ return 0;
+ }
+} /* end of iGetRiscOsVersion */
+
+#if defined(DEBUG)
+BOOL
+bGetJpegInfo(UCHAR *pucJpeg, size_t tJpegSize)
+{
+ os_error *e;
+ int iReg0, iReg4, iReg5;
+
+ e = SWI(3, 6, JPEG_Info | XOS_Bit,
+ 0x00, pucJpeg, tJpegSize,
+ &iReg0, NULL, NULL, NULL, &iReg4, &iReg5);
+ if (e == NULL) {
+ if (iReg0 & BIT(2)) {
+ DBG_MSG("Pixel density is a simple ratio");
+ } else {
+ DBG_MSG("Pixel density is in dpi");
+ }
+ DBG_DEC(iReg4);
+ DBG_DEC(iReg5);
+ return TRUE;
+ }
+ werr(0, "JPEG Info error %d: %s", e->errnum, e->errmess);
+ return FALSE;
+} /* end of bGetJpegInfo */
+#endif /* DEBUG */
diff --git a/sys/src/cmd/aux/antiword/rowlist.c b/sys/src/cmd/aux/antiword/rowlist.c
new file mode 100755
index 000000000..a3dd2fbcc
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/rowlist.c
@@ -0,0 +1,117 @@
+/*
+ * rowlist.c
+ * Copyright (C) 1998-2004 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Build, read and destroy a list of Word table-row information
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "antiword.h"
+
+/*
+ * Private structure to hide the way the information
+ * is stored from the rest of the program
+ */
+typedef struct row_desc_tag {
+ row_block_type tInfo;
+ struct row_desc_tag *pNext;
+} row_desc_type;
+
+/* Variables needed to write the Row Information List */
+static row_desc_type *pAnchor = NULL;
+static row_desc_type *pRowLast = NULL;
+/* Variable needed to read the Row Information List */
+static row_desc_type *pRowCurrent = NULL;
+
+
+/*
+ * vDestroyRowInfoList - destroy the Row Information List
+ */
+void
+vDestroyRowInfoList(void)
+{
+ row_desc_type *pCurr, *pNext;
+
+ DBG_MSG("vDestroyRowInfoList");
+
+ /* Free the Row Information List */
+ pCurr = pAnchor;
+ while (pCurr != NULL) {
+ pNext = pCurr->pNext;
+ pCurr = xfree(pCurr);
+ pCurr = pNext;
+ }
+ pAnchor = NULL;
+ /* Reset all control variables */
+ pRowLast = NULL;
+ pRowCurrent = NULL;
+} /* end of vDestroyRowInfoList */
+
+/*
+ * vAdd2RowInfoList - Add an element to the Row Information List
+ */
+void
+vAdd2RowInfoList(const row_block_type *pRowBlock)
+{
+ row_desc_type *pListMember;
+ short *psTmp;
+ int iIndex;
+
+ fail(pRowBlock == NULL);
+
+ if (pRowBlock->ulFileOffsetStart == FC_INVALID ||
+ pRowBlock->ulFileOffsetEnd == FC_INVALID ||
+ pRowBlock->ulFileOffsetStart == pRowBlock->ulFileOffsetEnd) {
+ DBG_HEX_C(pRowBlock->ulFileOffsetStart != FC_INVALID,
+ pRowBlock->ulFileOffsetStart);
+ DBG_HEX_C(pRowBlock->ulFileOffsetEnd != FC_INVALID,
+ pRowBlock->ulFileOffsetEnd);
+ return;
+ }
+
+ NO_DBG_HEX(pRowBlock->ulFileOffsetStart);
+ NO_DBG_HEX(pRowBlock->ulFileOffsetEnd);
+ NO_DBG_DEC(pRowBlock->ucNumberOfColumns);
+
+ /* Create the new list member */
+ pListMember = xmalloc(sizeof(row_desc_type));
+ /* Fill the new list member */
+ pListMember->tInfo = *pRowBlock;
+ pListMember->pNext = NULL;
+ /* Correct the values where needed */
+ for (iIndex = 0, psTmp = pListMember->tInfo.asColumnWidth;
+ iIndex < (int)pListMember->tInfo.ucNumberOfColumns;
+ iIndex++, psTmp++) {
+ if (*psTmp < 0) {
+ *psTmp = 0;
+ DBG_MSG("The column width was negative");
+ }
+ }
+ /* Add the new member to the list */
+ if (pAnchor == NULL) {
+ pAnchor = pListMember;
+ pRowCurrent = pListMember;
+ } else {
+ fail(pRowLast == NULL);
+ pRowLast->pNext = pListMember;
+ }
+ pRowLast = pListMember;
+} /* end of vAdd2RowInfoList */
+
+/*
+ * Get the next item in the Row Information List
+ */
+const row_block_type *
+pGetNextRowInfoListItem(void)
+{
+ const row_block_type *pItem;
+
+ if (pRowCurrent == NULL) {
+ return NULL;
+ }
+ pItem = &pRowCurrent->tInfo;
+ pRowCurrent = pRowCurrent->pNext;
+ return pItem;
+} /* end of pGetNextRowInfoListItem */
diff --git a/sys/src/cmd/aux/antiword/saveas.c b/sys/src/cmd/aux/antiword/saveas.c
new file mode 100755
index 000000000..678ff045d
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/saveas.c
@@ -0,0 +1,387 @@
+/*
+ * saveas.c
+ * Copyright (C) 1998-2001 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Functions to save the results as a textfile or a drawfile
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "DeskLib:Menu.h"
+#include "DeskLib:Save.h"
+#include "DeskLib:Template.h"
+#include "DeskLib:Window.h"
+#include "drawfile.h"
+#include "antiword.h"
+
+/* The window handle of the save window */
+static window_handle tSaveWindow = 0;
+
+/* Xfer_send box fields */
+#define DRAG_SPRITE 3
+#define OK_BUTTON 0
+#define CANCEL_BUTTON (-1)
+#define FILENAME_ICON 2
+
+
+/*
+ * saveas - a wrapper around Save_InitSaveWindowhandler
+ */
+static void
+saveas(int iFileType, char *szOutfile, size_t tEstSize,
+ save_filesaver save_function, void *pvReference)
+{
+ TRACE_MSG("saveas");
+
+ if (tSaveWindow == 0) {
+ tSaveWindow = Window_Create("xfer_send", template_TITLEMIN);
+ }
+ Icon_SetText(tSaveWindow, FILENAME_ICON, szOutfile);
+ Window_Show(tSaveWindow, open_UNDERPOINTER);
+ (void)Save_InitSaveWindowHandler(tSaveWindow, FALSE, TRUE, TRUE,
+ DRAG_SPRITE, OK_BUTTON, CANCEL_BUTTON, FILENAME_ICON,
+ save_function, NULL, NULL, tEstSize, iFileType, pvReference);
+} /* end of saveas */
+
+static BOOL
+bWrite2File(void *pvBytes, size_t tSize, FILE *pFile, const char *szFilename)
+{
+ if (fwrite(pvBytes, sizeof(char), tSize, pFile) != tSize) {
+ werr(0, "I can't write to '%s'", szFilename);
+ return FALSE;
+ }
+ return TRUE;
+} /* end of bWrite2File */
+
+/*
+ * bText2File - Save the generated draw file to a Text file
+ */
+static BOOL
+bText2File(char *szFilename, void *pvHandle)
+{
+ FILE *pFile;
+ diagram_type *pDiag;
+ drawfile_object *pObj;
+ drawfile_text *pText;
+ const char *pcTmp;
+ int iToGo, iX, iYtopPrev, iHeight, iLines;
+ BOOL bFirst, bIndent, bSuccess;
+
+ TRACE_MSG("bText2File");
+
+ fail(szFilename == NULL || szFilename[0] == '\0');
+ fail(pvHandle == NULL);
+
+ DBG_MSG(szFilename);
+
+ pDiag = (diagram_type *)pvHandle;
+ pFile = fopen(szFilename, "w");
+ if (pFile == NULL) {
+ werr(0, "I can't open '%s' for writing", szFilename);
+ return FALSE;
+ }
+ bFirst = TRUE;
+ iYtopPrev = 0;
+ iHeight = (int)lWord2DrawUnits20(DEFAULT_FONT_SIZE);
+ bSuccess = TRUE;
+ fail(pDiag->tInfo.length < offsetof(drawfile_diagram, objects));
+ iToGo = pDiag->tInfo.length - offsetof(drawfile_diagram, objects);
+ DBG_DEC(iToGo);
+ pcTmp = (const char *)pDiag->tInfo.data +
+ offsetof(drawfile_diagram, objects);
+ while (iToGo > 0 && bSuccess) {
+ pObj = (drawfile_object *)pcTmp;
+ switch (pObj->type) {
+ case drawfile_TYPE_TEXT:
+ pText = &pObj->data.text;
+ /* Compute the number of lines */
+ iLines = (iYtopPrev - pText->bbox.max.y +
+ iHeight / 2) / iHeight;
+ DBG_DEC_C(iLines < 0, iYtopPrev);
+ DBG_DEC_C(iLines < 0, pText->bbox.max.y);
+ fail(iLines < 0);
+ bIndent = iLines > 0 || bFirst;
+ bFirst = FALSE;
+ /* Print the newlines */
+ while (iLines > 0 && bSuccess) {
+ bSuccess = bWrite2File("\n",
+ 1, pFile, szFilename);
+ iLines--;
+ }
+ /* Print the indentation */
+ if (bIndent && bSuccess) {
+ for (iX = Drawfile_ScreenToDraw(8);
+ iX <= pText->bbox.min.x && bSuccess;
+ iX += Drawfile_ScreenToDraw(16)) {
+ bSuccess = bWrite2File(" ",
+ 1, pFile, szFilename);
+ }
+ }
+ if (!bSuccess) {
+ break;
+ }
+ /* Print the text object */
+ bSuccess = bWrite2File(pText->text,
+ strlen(pText->text), pFile, szFilename);
+ /* Setup for the next object */
+ iYtopPrev = pText->bbox.max.y;
+ iHeight = pText->bbox.max.y - pText->bbox.min.y;
+ break;
+ case drawfile_TYPE_FONT_TABLE:
+ case drawfile_TYPE_PATH:
+ case drawfile_TYPE_SPRITE:
+ case drawfile_TYPE_JPEG:
+ /* These are not relevant in a textfile */
+ break;
+ default:
+ DBG_DEC(pObj->type);
+ bSuccess = FALSE;
+ break;
+ }
+ pcTmp += pObj->size;
+ iToGo -= pObj->size;
+ }
+ DBG_DEC_C(iToGo != 0, iToGo);
+ if (bSuccess) {
+ bSuccess = bWrite2File("\n", 1, pFile, szFilename);
+ }
+ (void)fclose(pFile);
+ if (bSuccess) {
+ vSetFiletype(szFilename, FILETYPE_TEXT);
+ } else {
+ (void)remove(szFilename);
+ werr(0, "Unable to save textfile '%s'", szFilename);
+ }
+ return bSuccess;
+} /* end of bText2File */
+
+/*
+ * bSaveTextfile - save the diagram as a text file
+ */
+BOOL
+bSaveTextfile(event_pollblock *pEvent, void *pvReference)
+{
+ diagram_type *pDiag;
+ size_t tRecLen, tNbrRecs, tEstSize;
+
+ TRACE_MSG("bSaveTextfile");
+
+ fail(pEvent == NULL);
+ fail(pvReference == NULL);
+
+ pDiag = (diagram_type *)pvReference;
+
+ switch (pEvent->type) {
+ case event_SEND: /* From a menu */
+ fail(pEvent->data.message.header.action != message_MENUWARN);
+ if (menu_currentopen != pDiag->pSaveMenu ||
+ pEvent->data.message.data.menuwarn.selection[0] !=
+ SAVEMENU_SAVETEXT) {
+ return FALSE;
+ }
+ break;
+ case event_KEY: /* From a key short cut */
+ if (pEvent->data.key.caret.window != pDiag->tMainWindow) {
+ return FALSE;
+ }
+ break;
+ default:
+ DBG_DEC(pEvent->type);
+ return FALSE;
+ }
+
+ tRecLen = sizeof(drawfile_text) + DEFAULT_SCREEN_WIDTH * 2 / 3;
+ tNbrRecs = pDiag->tInfo.length / tRecLen + 1;
+ tEstSize = tNbrRecs * DEFAULT_SCREEN_WIDTH * 2 / 3;
+ DBG_DEC(tEstSize);
+
+ saveas(FILETYPE_TEXT, "WordText", tEstSize, bText2File, pDiag);
+ return TRUE;
+} /* end of bSaveTextfile */
+
+/*
+ * bDraw2File - Save the generated draw file to a Draw file
+ *
+ * Remark: This is not a simple copy action. The origin of the
+ * coordinates (0,0) must move from the top-left corner to the
+ * bottom-left corner.
+ */
+static BOOL
+bDraw2File(char *szFilename, void *pvHandle)
+{
+ FILE *pFile;
+ diagram_type *pDiagram;
+ wimp_box *pBbox;
+ drawfile_object *pObj;
+ drawfile_text *pText;
+ drawfile_path *pPath;
+ drawfile_sprite *pSprite;
+ drawfile_jpeg *pJpeg;
+ int *piPath;
+ char *pcTmp;
+ int iYadd, iToGo, iSize;
+ BOOL bSuccess;
+
+ TRACE_MSG("bDraw2File");
+
+ fail(szFilename == NULL || szFilename[0] == '\0');
+ fail(pvHandle == NULL);
+
+ NO_DBG_MSG(szFilename);
+
+ pDiagram = (diagram_type *)pvHandle;
+ pFile = fopen(szFilename, "wb");
+ if (pFile == NULL) {
+ werr(0, "I can't open '%s' for writing", szFilename);
+ return FALSE;
+ }
+ iToGo = pDiagram->tInfo.length;
+ DBG_DEC(iToGo);
+ pcTmp = pDiagram->tInfo.data;
+ bSuccess = bWrite2File(pcTmp,
+ offsetof(drawfile_diagram, bbox), pFile, szFilename);
+ if (bSuccess) {
+ pcTmp += offsetof(drawfile_diagram, bbox);
+ iToGo -= offsetof(drawfile_diagram, bbox);
+ pBbox = (wimp_box *)pcTmp;
+ iYadd = -pBbox->min.y;
+ pBbox->min.y += iYadd;
+ pBbox->max.y += iYadd;
+ bSuccess = bWrite2File(pcTmp,
+ sizeof(*pBbox), pFile, szFilename);
+ iToGo -= sizeof(*pBbox);
+ DBG_DEC(iToGo);
+ pcTmp += sizeof(*pBbox);
+ } else {
+ iYadd = 0;
+ }
+ while (iToGo > 0 && bSuccess) {
+ pObj = (drawfile_object *)pcTmp;
+ iSize = pObj->size;
+ switch (pObj->type) {
+ case drawfile_TYPE_FONT_TABLE:
+ bSuccess = bWrite2File(pcTmp,
+ iSize, pFile, szFilename);
+ pcTmp += iSize;
+ iToGo -= iSize;
+ break;
+ case drawfile_TYPE_TEXT:
+ pText = &pObj->data.text;
+ /* First correct the coordinates */
+ pText->bbox.min.y += iYadd;
+ pText->bbox.max.y += iYadd;
+ pText->base.y += iYadd;
+ /* Now write the information to file */
+ bSuccess = bWrite2File(pcTmp,
+ iSize, pFile, szFilename);
+ pcTmp += pObj->size;
+ iToGo -= pObj->size;
+ break;
+ case drawfile_TYPE_PATH:
+ pPath = &pObj->data.path;
+ /* First correct the coordinates */
+ pPath->bbox.min.y += iYadd;
+ pPath->bbox.max.y += iYadd;
+ /* Now write the information to file */
+ bSuccess = bWrite2File(pPath,
+ sizeof(*pPath), pFile, szFilename);
+ pcTmp += sizeof(*pPath);
+ iSize = pObj->size - sizeof(*pPath);
+ fail(iSize < 14 * sizeof(int));
+ /* Second correct the path coordinates */
+ piPath = xmalloc(iSize);
+ memcpy(piPath, pcTmp, iSize);
+ piPath[ 2] += iYadd;
+ piPath[ 5] += iYadd;
+ piPath[ 8] += iYadd;
+ piPath[11] += iYadd;
+ if (bSuccess) {
+ bSuccess = bWrite2File(piPath,
+ iSize, pFile, szFilename);
+ pcTmp += iSize;
+ }
+ piPath = xfree(piPath);
+ iToGo -= pObj->size;
+ break;
+ case drawfile_TYPE_SPRITE:
+ pSprite = &pObj->data.sprite;
+ /* First correct the coordinates */
+ pSprite->bbox.min.y += iYadd;
+ pSprite->bbox.max.y += iYadd;
+ /* Now write the information to file */
+ bSuccess = bWrite2File(pcTmp,
+ iSize, pFile, szFilename);
+ pcTmp += pObj->size;
+ iToGo -= pObj->size;
+ break;
+ case drawfile_TYPE_JPEG:
+ pJpeg = &pObj->data.jpeg;
+ /* First correct the coordinates */
+ pJpeg->bbox.min.y += iYadd;
+ pJpeg->bbox.max.y += iYadd;
+ pJpeg->trfm.entries[2][1] += iYadd;
+ /* Now write the information to file */
+ bSuccess = bWrite2File(pcTmp,
+ iSize, pFile, szFilename);
+ pcTmp += pObj->size;
+ iToGo -= pObj->size;
+ break;
+ default:
+ DBG_DEC(pObj->type);
+ bSuccess = FALSE;
+ break;
+ }
+ }
+ DBG_DEC_C(iToGo != 0, iToGo);
+ (void)fclose(pFile);
+ if (bSuccess) {
+ vSetFiletype(szFilename, FILETYPE_DRAW);
+ } else {
+ (void)remove(szFilename);
+ werr(0, "Unable to save drawfile '%s'", szFilename);
+ }
+ return bSuccess;
+} /* end of bDraw2File */
+
+/*
+ * bSaveDrawfile - save the diagram as a draw file
+ */
+BOOL
+bSaveDrawfile(event_pollblock *pEvent, void *pvReference)
+{
+ diagram_type *pDiag;
+ size_t tEstSize;
+
+ TRACE_MSG("bSaveDrawfile");
+
+ fail(pEvent == NULL);
+ fail(pvReference == NULL);
+
+ pDiag = (diagram_type *)pvReference;
+
+ switch (pEvent->type) {
+ case event_SEND: /* From a menu */
+ fail(pEvent->data.message.header.action != message_MENUWARN);
+ if (menu_currentopen != pDiag->pSaveMenu ||
+ pEvent->data.message.data.menuwarn.selection[0] !=
+ SAVEMENU_SAVEDRAW) {
+ return FALSE;
+ }
+ break;
+ case event_KEY: /* From a key short cut */
+ if (pEvent->data.key.caret.window != pDiag->tMainWindow) {
+ return FALSE;
+ }
+ break;
+ default:
+ DBG_DEC(pEvent->type);
+ return FALSE;
+ }
+
+ tEstSize = pDiag->tInfo.length;
+ DBG_DEC(tEstSize);
+
+ saveas(FILETYPE_DRAW, "WordDraw", tEstSize, bDraw2File, pDiag);
+ return TRUE;
+} /* end of bSaveDrawfile */
diff --git a/sys/src/cmd/aux/antiword/sectlist.c b/sys/src/cmd/aux/antiword/sectlist.c
new file mode 100755
index 000000000..016d1b89a
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/sectlist.c
@@ -0,0 +1,165 @@
+/*
+ * sectlist.c
+ * Copyright (C) 2001-2004 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Build, read and destroy list(s) of Word section information
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include "antiword.h"
+
+
+/*
+ * Private structure to hide the way the information
+ * is stored from the rest of the program
+ */
+typedef struct section_mem_tag {
+ section_block_type tInfo;
+ ULONG ulCharPos;
+ struct section_mem_tag *pNext;
+} section_mem_type;
+
+/* Variables needed to write the Section Information List */
+static section_mem_type *pAnchor = NULL;
+static section_mem_type *pSectionLast = NULL;
+
+
+/*
+ * vDestroySectionInfoList - destroy the Section Information List
+ */
+void
+vDestroySectionInfoList(void)
+{
+ section_mem_type *pCurr, *pNext;
+
+ DBG_MSG("vDestroySectionInfoList");
+
+ /* Free the Section Information List */
+ pCurr = pAnchor;
+ while (pCurr != NULL) {
+ pNext = pCurr->pNext;
+ pCurr = xfree(pCurr);
+ pCurr = pNext;
+ }
+ pAnchor = NULL;
+ /* Reset all control variables */
+ pSectionLast = NULL;
+} /* end of vDestroySectionInfoList */
+
+/*
+ * vAdd2SectionInfoList - Add an element to the Section Information List
+ */
+void
+vAdd2SectionInfoList(const section_block_type *pSection, ULONG ulCharPos)
+{
+ section_mem_type *pListMember;
+
+ fail(pSection == NULL);
+
+ /* Create list member */
+ pListMember = xmalloc(sizeof(section_mem_type));
+ /* Fill the list member */
+ pListMember->tInfo = *pSection;
+ pListMember->ulCharPos = ulCharPos;
+ pListMember->pNext = NULL;
+ /* Add the new member to the list */
+ if (pAnchor == NULL) {
+ pAnchor = pListMember;
+ } else {
+ fail(pSectionLast == NULL);
+ pSectionLast->pNext = pListMember;
+ }
+ pSectionLast = pListMember;
+} /* vAdd2SectionInfoList */
+
+/*
+ * vGetDefaultSection - fill the section struct with default values
+ */
+void
+vGetDefaultSection(section_block_type *pSection)
+{
+ (void)memset(pSection, 0, sizeof(*pSection));
+ pSection->bNewPage = TRUE;
+} /* end of vGetDefaultSection */
+
+/*
+ * vDefault2SectionInfoList - Add a default to the Section Information List
+ */
+void
+vDefault2SectionInfoList(ULONG ulCharPos)
+{
+ section_block_type tSection;
+
+ vGetDefaultSection(&tSection);
+ vAdd2SectionInfoList(&tSection, ulCharPos);
+} /* end of vDefault2SectionInfoList */
+
+/*
+ * pGetSectionInfo - get the section information
+ */
+const section_block_type *
+pGetSectionInfo(const section_block_type *pOld, ULONG ulCharPos)
+{
+ const section_mem_type *pCurr;
+
+ if (pOld == NULL || ulCharPos == 0) {
+ if (pAnchor == NULL) {
+ /* There are no records, make one */
+ vDefault2SectionInfoList(0);
+ fail(pAnchor == NULL);
+ }
+ /* The first record */
+ NO_DBG_MSG("First record");
+ return &pAnchor->tInfo;
+ }
+
+ NO_DBG_HEX(ulCharPos);
+ for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
+ NO_DBG_HEX(pCurr->ulCharPos);
+ if (ulCharPos == pCurr->ulCharPos ||
+ ulCharPos + 1 == pCurr->ulCharPos) {
+ NO_DBG_HEX(pCurr->ulCharPos);
+ return &pCurr->tInfo;
+ }
+ }
+ return pOld;
+} /* end of pGetSectionInfo */
+
+/*
+ * tGetNumberOfSections - get the number of sections
+ */
+size_t
+tGetNumberOfSections(void)
+{
+ const section_mem_type *pCurr;
+ size_t tCounter;
+
+ for (tCounter = 0, pCurr = pAnchor;
+ pCurr != NULL;
+ tCounter++, pCurr = pCurr->pNext)
+ ; /* Empty */
+ return tCounter;
+} /* end of tGetNumberOfSections */
+
+/*
+ * ucGetSepHdrFtrSpecification - get the Heder/footer specification
+ */
+UCHAR
+ucGetSepHdrFtrSpecification(size_t tSectionNumber)
+{
+ const section_mem_type *pCurr;
+ size_t tIndex;
+
+ for (tIndex = 0, pCurr = pAnchor;
+ tIndex < tSectionNumber && pCurr != NULL;
+ tIndex++, pCurr = pCurr->pNext)
+ ; /* Empty */
+ if (pCurr == NULL) {
+ DBG_DEC(tSectionNumber);
+ DBG_FIXME();
+ return 0x00;
+ }
+ return pCurr->tInfo.ucHdrFtrSpecification;
+} /* end of ucGetSepHdrFtrSpecification */
diff --git a/sys/src/cmd/aux/antiword/startup.c b/sys/src/cmd/aux/antiword/startup.c
new file mode 100755
index 000000000..7e1b6d7d7
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/startup.c
@@ -0,0 +1,145 @@
+/*
+ * startup.c
+ * Copyright (C) 1998-2001 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Try to force a single startup of !Antiword
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "DeskLib:Error.h"
+#include "DeskLib:Event.h"
+#include "DeskLib:SWI.h"
+#include "antiword.h"
+
+
+#if !defined(TaskManager_EnumerateTasks)
+#define TaskManager_EnumerateTasks 0x042681
+#endif /* TaskManager_EnumerateTasks */
+
+/*
+ * bIsMatch - decide whether the two strings match
+ *
+ * like strcmp, but this one ignores case
+ */
+static BOOL
+bIsMatch(const char *szStr1, const char *szStr2)
+{
+ const char *pcTmp1, *pcTmp2;
+
+ for (pcTmp1 = szStr1, pcTmp2 = szStr2;
+ *pcTmp1 != '\0';
+ pcTmp1++, pcTmp2++) {
+ if (toupper(*pcTmp1) != toupper(*pcTmp2)) {
+ return FALSE;
+ }
+ }
+ return *pcTmp2 == '\0';
+} /* end of bIsMatch */
+
+/*
+ * tGetTaskHandle - get the task handle of the given task
+ *
+ * returns the task handle when found, otherwise 0
+ */
+static task_handle
+tGetTaskHandle(const char *szTaskname)
+{
+ const char *pcTmp;
+ int iReg0, iIndex;
+ int aiBuffer[4];
+ char szTmp[21];
+
+ iReg0 = 0;
+ do {
+ /* Get info on the next task */
+ Error_CheckFatal(SWI(3, 1, TaskManager_EnumerateTasks | XOS_Bit,
+ iReg0, aiBuffer, sizeof(aiBuffer), &iReg0));
+ /* Copy the (control character terminated) task name */
+ for (iIndex = 0, pcTmp = (const char *)aiBuffer[1];
+ iIndex < elementsof(szTmp);
+ iIndex++, pcTmp++) {
+ if (iscntrl(*pcTmp)) {
+ szTmp[iIndex] = '\0';
+ break;
+ }
+ szTmp[iIndex] = *pcTmp;
+ }
+ szTmp[elementsof(szTmp) - 1] = '\0';
+ if (bIsMatch(szTmp, szTaskname)) {
+ /* Task found */
+ return (task_handle)aiBuffer[0];
+ }
+ } while (iReg0 >= 0);
+
+ /* Task not found */
+ return 0;
+} /* end of tGetTaskHandle */
+
+int
+main(int argc, char **argv)
+{
+ message_block tMsg;
+ task_handle tTaskHandle;
+ size_t tArgLen;
+ int aiMessages[] = {0};
+ char szCommand[512];
+
+ Event_Initialise3("StartUp", 310, aiMessages);
+
+ if (argc > 1) {
+ tArgLen = strlen(argv[1]);
+ } else {
+ tArgLen = 0;
+ }
+ if (tArgLen >= sizeof(tMsg.data.dataload.filename)) {
+ werr(1, "Input filename too long");
+ return EXIT_FAILURE;
+ }
+
+ tTaskHandle = tGetTaskHandle("antiword");
+
+ if (tTaskHandle == 0) {
+ /* Antiword is not active */
+ strcpy(szCommand, "chain:<Antiword$Dir>.!Antiword");
+ if (argc > 1) {
+ strcat(szCommand, " ");
+ strcat(szCommand, argv[1]);
+ }
+#if defined(DEBUG)
+ strcat(szCommand, " ");
+ strcat(szCommand, "2><Antiword$Dir>.Debug");
+#endif /* DEBUG */
+ system(szCommand);
+ /* If we reach here something has gone wrong */
+ return EXIT_FAILURE;
+ }
+
+ /* Antiword is active */
+ if (argc > 1) {
+ /*
+ * Send the argument to Antiword by imitating a
+ * drag-and-drop to Antiword's iconbar icon
+ */
+ memset(&tMsg, 0, sizeof(tMsg));
+ tMsg.header.size = ROUND4(offsetof(message_block, data) +
+ offsetof(message_dataload, filename) +
+ 1 + tArgLen);
+ tMsg.header.yourref = 0;
+ tMsg.header.action = message_DATALOAD;
+ tMsg.data.dataload.window = window_ICONBAR;
+ tMsg.data.dataload.icon = -1;
+ tMsg.data.dataload.size = 0;
+ tMsg.data.dataload.filetype = FILETYPE_MSWORD;
+ strcpy(tMsg.data.dataload.filename, argv[1]);
+ Error_CheckFatal(Wimp_SendMessage(event_SEND,
+ &tMsg, tTaskHandle, 0));
+ return EXIT_SUCCESS;
+ } else {
+ /* Give an error message and return */
+ werr(1, "Antiword is already running");
+ return EXIT_FAILURE;
+ }
+} /* end of main */
diff --git a/sys/src/cmd/aux/antiword/stylelist.c b/sys/src/cmd/aux/antiword/stylelist.c
new file mode 100755
index 000000000..09b5ab5a5
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/stylelist.c
@@ -0,0 +1,487 @@
+/*
+ * stylelist.c
+ * Copyright (C) 1998-2005 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Build, read and destroy a list of Word style information
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <ctype.h>
+#include "antiword.h"
+
+
+/*
+ * Private structure to hide the way the information
+ * is stored from the rest of the program
+ */
+typedef struct style_mem_tag {
+ style_block_type tInfo;
+ ULONG ulSequenceNumber;
+ struct style_mem_tag *pNext;
+} style_mem_type;
+
+/* Variables needed to write the Style Information List */
+static style_mem_type *pAnchor = NULL;
+static style_mem_type *pStyleLast = NULL;
+/* The type of conversion */
+static conversion_type eConversionType = conversion_unknown;
+/* The character set encoding */
+static encoding_type eEncoding = encoding_neutral;
+/* Values for efficiency reasons */
+static const style_mem_type *pMidPtr = NULL;
+static BOOL bMoveMidPtr = FALSE;
+static BOOL bInSequence = TRUE;
+
+
+/*
+ * vDestroyStyleInfoList - destroy the Style Information List
+ */
+void
+vDestroyStyleInfoList(void)
+{
+ style_mem_type *pCurr, *pNext;
+
+ DBG_MSG("vDestroyStyleInfoList");
+
+ /* Free the Style Information List */
+ pCurr = pAnchor;
+ while (pCurr != NULL) {
+ pNext = pCurr->pNext;
+ pCurr = xfree(pCurr);
+ pCurr = pNext;
+ }
+ pAnchor = NULL;
+ /* Reset all control variables */
+ pStyleLast = NULL;
+ pMidPtr = NULL;
+ bMoveMidPtr = FALSE;
+ bInSequence = TRUE;
+} /* end of vDestroyStyleInfoList */
+
+/*
+ * vConvertListCharacter - convert the list character
+ */
+static void
+vConvertListCharacter(UCHAR ucNFC, USHORT usListChar, char *szListChar)
+{
+ options_type tOptions;
+ size_t tLen;
+
+ fail(szListChar == NULL);
+ fail(szListChar[0] != '\0');
+
+ if (usListChar < 0x80 && isprint((int)usListChar)) {
+ DBG_CHR_C(isalnum((int)usListChar), usListChar);
+ szListChar[0] = (char)usListChar;
+ szListChar[1] = '\0';
+ return;
+ }
+
+ if (ucNFC != LIST_SPECIAL &&
+ ucNFC != LIST_SPECIAL2 &&
+ ucNFC != LIST_BULLETS) {
+ szListChar[0] = '.';
+ szListChar[1] = '\0';
+ return;
+ }
+
+ if (eConversionType == conversion_unknown ||
+ eEncoding == encoding_neutral) {
+ vGetOptions(&tOptions);
+ eConversionType = tOptions.eConversionType;
+ eEncoding = tOptions.eEncoding;
+ }
+
+ switch (usListChar) {
+ case 0x0000: case 0x00b7: case 0x00fe: case 0xf021: case 0xf043:
+ case 0xf06c: case 0xf093: case 0xf0b7:
+ usListChar = 0x2022; /* BULLET */
+ break;
+ case 0x0096: case 0xf02d:
+ usListChar = 0x2013; /* EN DASH */
+ break;
+ case 0x00a8:
+ usListChar = 0x2666; /* BLACK DIAMOND SUIT */
+ break;
+ case 0x00de:
+ usListChar = 0x21d2; /* RIGHTWARDS DOUBLE ARROW */
+ break;
+ case 0x00e0: case 0xf074:
+ usListChar = 0x25ca; /* LOZENGE */
+ break;
+ case 0x00e1:
+ usListChar = 0x2329; /* LEFT ANGLE BRACKET */
+ break;
+ case 0xf020:
+ usListChar = 0x0020; /* SPACE */
+ break;
+ case 0xf041:
+ usListChar = 0x270c; /* VICTORY HAND */
+ break;
+ case 0xf066:
+ usListChar = 0x03d5; /* GREEK PHI SYMBOL */
+ break;
+ case 0xf06e:
+ usListChar = 0x25a0; /* BLACK SQUARE */
+ break;
+ case 0xf06f: case 0xf070: case 0xf0a8:
+ usListChar = 0x25a1; /* WHITE SQUARE */
+ break;
+ case 0xf071:
+ usListChar = 0x2751; /* LOWER RIGHT SHADOWED WHITE SQUARE */
+ break;
+ case 0xf075: case 0xf077:
+ usListChar = 0x25c6; /* BLACK DIAMOND */
+ break;
+ case 0xf076:
+ usListChar = 0x2756; /* BLACK DIAMOND MINUS WHITE X */
+ break;
+ case 0xf0a7:
+ usListChar = 0x25aa; /* BLACK SMALL SQUARE */
+ break;
+ case 0xf0d8:
+ usListChar = 0x27a2; /* RIGHTWARDS ARROWHEAD */
+ break;
+ case 0xf0e5:
+ usListChar = 0x2199; /* SOUTH WEST ARROW */
+ break;
+ case 0xf0f0:
+ usListChar = 0x21e8; /* RIGHTWARDS WHITE ARROW */
+ break;
+ case 0xf0fc:
+ usListChar = 0x2713; /* CHECK MARK */
+ break;
+ default:
+ if ((usListChar >= 0xe000 && usListChar < 0xf900) ||
+ (usListChar < 0x80 && !isprint((int)usListChar))) {
+ /*
+ * All remaining private area characters and all
+ * remaining non-printable ASCII characters to their
+ * default bullet character
+ */
+ DBG_HEX(usListChar);
+ DBG_FIXME();
+ if (ucNFC == LIST_SPECIAL || ucNFC == LIST_SPECIAL2) {
+ usListChar = 0x2190; /* LEFTWARDS ARROW */
+ } else {
+ usListChar = 0x2022; /* BULLET */
+ }
+ }
+ break;
+ }
+
+ if (eEncoding == encoding_utf_8) {
+ tLen = tUcs2Utf8(usListChar, szListChar, 4);
+ szListChar[tLen] = '\0';
+ } else {
+ switch (usListChar) {
+ case 0x03d5: case 0x25a1: case 0x25c6: case 0x25ca:
+ case 0x2751:
+ szListChar[0] = 'o';
+ break;
+ case 0x2013: case 0x2500:
+ szListChar[0] = '-';
+ break;
+ case 0x2190: case 0x2199: case 0x2329:
+ szListChar[0] = '<';
+ break;
+ case 0x21d2:
+ szListChar[0] = '=';
+ break;
+ case 0x21e8: case 0x27a2:
+ szListChar[0] = '>';
+ break;
+ case 0x25a0: case 0x25aa:
+ szListChar[0] = '.';
+ break;
+ case 0x2666:
+ szListChar[0] = OUR_DIAMOND;
+ break;
+ case 0x270c:
+ szListChar[0] = 'x';
+ break;
+ case 0x2713:
+ szListChar[0] = 'V';
+ break;
+ case 0x2756:
+ szListChar[0] = '*';
+ break;
+ case 0x2022:
+ default:
+ vGetBulletValue(eConversionType, eEncoding,
+ szListChar, 2);
+ break;
+ }
+ tLen = 1;
+ }
+ szListChar[tLen] = '\0';
+} /* end of vConvertListCharacter */
+
+/*
+ * eGetNumType - get the level type from the given level number
+ *
+ * Returns the level type
+ */
+level_type_enum
+eGetNumType(UCHAR ucNumLevel)
+{
+ switch (ucNumLevel) {
+ case 1: case 2: case 3: case 4: case 5:
+ case 6: case 7: case 8: case 9:
+ return level_type_outline;
+ case 10:
+ return level_type_numbering;
+ case 11:
+ return level_type_sequence;
+ case 12:
+ return level_type_pause;
+ default:
+ return level_type_none;
+ }
+} /* end of eGetNumType */
+
+/*
+ * vCorrectStyleValues - correct style values that Antiword can't use
+ */
+void
+vCorrectStyleValues(style_block_type *pStyleBlock)
+{
+ if (pStyleBlock->usBeforeIndent > 0x7fff) {
+ pStyleBlock->usBeforeIndent = 0;
+ } else if (pStyleBlock->usBeforeIndent > 2160) {
+ /* 2160 twips = 1.5 inches or 38.1 mm */
+ DBG_DEC(pStyleBlock->usBeforeIndent);
+ pStyleBlock->usBeforeIndent = 2160;
+ }
+ if (pStyleBlock->usIstd >= 1 &&
+ pStyleBlock->usIstd <= 9 &&
+ pStyleBlock->usBeforeIndent < HEADING_GAP) {
+ NO_DBG_DEC(pStyleBlock->usBeforeIndent);
+ pStyleBlock->usBeforeIndent = HEADING_GAP;
+ }
+
+ if (pStyleBlock->usAfterIndent > 0x7fff) {
+ pStyleBlock->usAfterIndent = 0;
+ } else if (pStyleBlock->usAfterIndent > 2160) {
+ /* 2160 twips = 1.5 inches or 38.1 mm */
+ DBG_DEC(pStyleBlock->usAfterIndent);
+ pStyleBlock->usAfterIndent = 2160;
+ }
+ if (pStyleBlock->usIstd >= 1 &&
+ pStyleBlock->usIstd <= 9 &&
+ pStyleBlock->usAfterIndent < HEADING_GAP) {
+ NO_DBG_DEC(pStyleBlock->usAfterIndent);
+ pStyleBlock->usAfterIndent = HEADING_GAP;
+ }
+
+ if (pStyleBlock->sLeftIndent < 0) {
+ pStyleBlock->sLeftIndent = 0;
+ }
+ if (pStyleBlock->sRightIndent > 0) {
+ pStyleBlock->sRightIndent = 0;
+ }
+ vConvertListCharacter(pStyleBlock->ucNFC,
+ pStyleBlock->usListChar,
+ pStyleBlock->szListChar);
+} /* end of vCorrectStyleValues */
+
+/*
+ * vAdd2StyleInfoList - Add an element to the Style Information List
+ */
+void
+vAdd2StyleInfoList(const style_block_type *pStyleBlock)
+{
+ style_mem_type *pListMember;
+
+ fail(pStyleBlock == NULL);
+
+ NO_DBG_MSG("bAdd2StyleInfoList");
+
+ if (pStyleBlock->ulFileOffset == FC_INVALID) {
+ NO_DBG_DEC(pStyleBlock->usIstd);
+ return;
+ }
+
+ NO_DBG_HEX(pStyleBlock->ulFileOffset);
+ NO_DBG_DEC_C(pStyleBlock->sLeftIndent != 0,
+ pStyleBlock->sLeftIndent);
+ NO_DBG_DEC_C(pStyleBlock->sRightIndent != 0,
+ pStyleBlock->sRightIndent);
+ NO_DBG_DEC_C(pStyleBlock->bNumPause, pStyleBlock->bNumPause);
+ NO_DBG_DEC_C(pStyleBlock->usIstd != 0, pStyleBlock->usIstd);
+ NO_DBG_DEC_C(pStyleBlock->usStartAt != 1, pStyleBlock->usStartAt);
+ NO_DBG_DEC_C(pStyleBlock->usAfterIndent != 0,
+ pStyleBlock->usAfterIndent);
+ NO_DBG_DEC_C(pStyleBlock->ucAlignment != 0, pStyleBlock->ucAlignment);
+ NO_DBG_DEC(pStyleBlock->ucNFC);
+ NO_DBG_HEX(pStyleBlock->usListChar);
+
+ if (pStyleLast != NULL &&
+ pStyleLast->tInfo.ulFileOffset == pStyleBlock->ulFileOffset) {
+ /*
+ * If two consecutive styles share the same
+ * offset, remember only the last style
+ */
+ fail(pStyleLast->pNext != NULL);
+ pStyleLast->tInfo = *pStyleBlock;
+ /* Correct the values where needed */
+ vCorrectStyleValues(&pStyleLast->tInfo);
+ return;
+ }
+
+ /* Create list member */
+ pListMember = xmalloc(sizeof(style_mem_type));
+ /* Fill the list member */
+ pListMember->tInfo = *pStyleBlock;
+ pListMember->pNext = NULL;
+ /* Add the sequence number */
+ pListMember->ulSequenceNumber =
+ ulGetSeqNumber(pListMember->tInfo.ulFileOffset);
+ /* Correct the values where needed */
+ vCorrectStyleValues(&pListMember->tInfo);
+ /* Add the new member to the list */
+ if (pAnchor == NULL) {
+ pAnchor = pListMember;
+ /* For efficiency */
+ pMidPtr = pAnchor;
+ bMoveMidPtr = FALSE;
+ bInSequence = TRUE;
+ } else {
+ fail(pStyleLast == NULL);
+ pStyleLast->pNext = pListMember;
+ /* For efficiency */
+ if (bMoveMidPtr) {
+ pMidPtr = pMidPtr->pNext;
+ bMoveMidPtr = FALSE;
+ } else {
+ bMoveMidPtr = TRUE;
+ }
+ if (bInSequence) {
+ bInSequence = pListMember->ulSequenceNumber >
+ pStyleLast->ulSequenceNumber;
+ }
+ }
+ pStyleLast = pListMember;
+} /* end of vAdd2StyleInfoList */
+
+/*
+ * Get the record that follows the given recored in the Style Information List
+ */
+const style_block_type *
+pGetNextStyleInfoListItem(const style_block_type *pCurr)
+{
+ const style_mem_type *pRecord;
+ size_t tOffset;
+
+ if (pCurr == NULL) {
+ if (pAnchor == NULL) {
+ /* There are no records */
+ return NULL;
+ }
+ /* The first record is the only one without a predecessor */
+ return &pAnchor->tInfo;
+ }
+ tOffset = offsetof(style_mem_type, tInfo);
+ /* Many casts to prevent alignment warnings */
+ pRecord = (style_mem_type *)(void *)((char *)pCurr - tOffset);
+ fail(pCurr != &pRecord->tInfo);
+ if (pRecord->pNext == NULL) {
+ /* The last record has no successor */
+ return NULL;
+ }
+ return &pRecord->pNext->tInfo;
+} /* end of pGetNextStyleInfoListItem */
+
+/*
+ * Get the next text style
+ */
+const style_block_type *
+pGetNextTextStyle(const style_block_type *pCurr)
+{
+ const style_block_type *pRecord;
+
+ pRecord = pCurr;
+ do {
+ pRecord = pGetNextStyleInfoListItem(pRecord);
+ } while (pRecord != NULL &&
+ (pRecord->eListID == hdrftr_list ||
+ pRecord->eListID == macro_list ||
+ pRecord->eListID == annotation_list));
+ return pRecord;
+} /* end of pGetNextTextStyle */
+
+/*
+ * usGetIstd - get the istd that belongs to the given file offset
+ */
+USHORT
+usGetIstd(ULONG ulFileOffset)
+{
+ const style_mem_type *pCurr, *pBest, *pStart;
+ ULONG ulSeq, ulBest;
+
+ ulSeq = ulGetSeqNumber(ulFileOffset);
+ if (ulSeq == FC_INVALID) {
+ return ISTD_NORMAL;
+ }
+ NO_DBG_HEX(ulFileOffset);
+ NO_DBG_DEC(ulSeq);
+
+ if (bInSequence &&
+ pMidPtr != NULL &&
+ ulSeq > pMidPtr->ulSequenceNumber) {
+ /* The istd is in the second half of the chained list */
+ pStart = pMidPtr;
+ } else {
+ pStart = pAnchor;
+ }
+
+ pBest = NULL;
+ ulBest = 0;
+ for (pCurr = pStart; pCurr != NULL; pCurr = pCurr->pNext) {
+ if (pCurr->ulSequenceNumber != FC_INVALID &&
+ (pBest == NULL || pCurr->ulSequenceNumber > ulBest) &&
+ pCurr->ulSequenceNumber <= ulSeq) {
+ pBest = pCurr;
+ ulBest = pCurr->ulSequenceNumber;
+ }
+ if (bInSequence && pCurr->ulSequenceNumber > ulSeq) {
+ break;
+ }
+ }
+ NO_DBG_DEC(ulBest);
+
+ if (pBest == NULL) {
+ return ISTD_NORMAL;
+ }
+
+ NO_DBG_DEC(pBest->tInfo.usIstd);
+ return pBest->tInfo.usIstd;
+} /* end of usGetIstd */
+
+/*
+ * bStyleImpliesList - does style info implies being part of a list
+ *
+ * Decide whether the style information implies that the given paragraph is
+ * part of a list
+ *
+ * Returns TRUE when the paragraph is part of a list, otherwise FALSE
+ */
+BOOL
+bStyleImpliesList(const style_block_type *pStyle, int iWordVersion)
+{
+ fail(pStyle == NULL);
+ fail(iWordVersion < 0);
+
+ if (pStyle->usIstd >= 1 && pStyle->usIstd <= 9) {
+ /* These are heading levels */
+ return FALSE;
+ }
+ if (iWordVersion < 8) {
+ /* Check for old style lists */
+ return pStyle->ucNumLevel != 0;
+ }
+ /* Check for new style lists */
+ return pStyle->usListIndex != 0;
+} /* end of bStyleImpliesList */
diff --git a/sys/src/cmd/aux/antiword/stylesheet.c b/sys/src/cmd/aux/antiword/stylesheet.c
new file mode 100755
index 000000000..0cb4cc336
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/stylesheet.c
@@ -0,0 +1,838 @@
+/*
+ * stylesheet.c
+ * Copyright (C) 2001-2004 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Build, read and destroy a list of stylesheet information
+ *
+ */
+
+#include <string.h>
+#include "antiword.h"
+
+
+#define SGC_PAP 1
+#define SGC_CHP 2
+
+/* Variables needed to describe the stylesheet list */
+static style_block_type *atStyleInfo = NULL;
+static font_block_type *atFontInfo = NULL;
+static BOOL *abFilled = NULL;
+static size_t tStdCount = 0;
+
+
+/*
+ * vDestroyStylesheetList - destroy the stylesheet list
+ */
+void
+vDestroyStylesheetList(void)
+{
+ DBG_MSG("vDestroyStylesheetList");
+
+ tStdCount = 0;
+ atStyleInfo = xfree(atStyleInfo);
+ atFontInfo = xfree(atFontInfo);
+ abFilled = xfree(abFilled);
+} /* end of vDestroyStylesheetList */
+
+/*
+ * vGetDefaultStyle - fill the style struct with default values
+ */
+static void
+vGetDefaultStyle(style_block_type *pStyle)
+{
+ (void)memset(pStyle, 0, sizeof(*pStyle));
+ pStyle->usIstd = ISTD_INVALID;
+ pStyle->usIstdNext = ISTD_INVALID;
+ pStyle->usStartAt = 1;
+ pStyle->ucListLevel = 9;
+} /* end of vGetDefaultStyle */
+
+/*
+ * vGetDefaultFont - fill the font struct with default values
+ */
+static void
+vGetDefaultFont(font_block_type *pFont, USHORT usDefaultFontNumber)
+{
+ (void)memset(pFont, 0, sizeof(*pFont));
+ pFont->usFontSize = DEFAULT_FONT_SIZE;
+ if (usDefaultFontNumber <= (USHORT)UCHAR_MAX) {
+ pFont->ucFontNumber = (UCHAR)usDefaultFontNumber;
+ } else {
+ DBG_DEC(usDefaultFontNumber);
+ DBG_FIXME();
+ pFont->ucFontNumber = 0;
+ }
+} /* end of vGetDefaultFont */
+
+/*
+ * iGetStyleIndex - get the index of the record with the specified istd
+ *
+ * returns the index when found, otherwise -1
+ */
+static int
+iGetStyleIndex(USHORT usIstd)
+{
+ int iIndex;
+
+ fail(abFilled == NULL);
+
+ if (usIstd == ISTD_INVALID || abFilled == NULL) {
+ return -1;
+ }
+
+ for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
+ if (abFilled[iIndex] && atStyleInfo[iIndex].usIstd == usIstd) {
+ /* The record is filled and the istd matches */
+ return iIndex;
+ }
+ }
+ return -1;
+} /* end of iGetStyleIndex */
+
+/*
+ * Get a build-in style for Winword 1/2
+ */
+static void
+vGetBuildinStyle(UCHAR ucStc, style_block_type *pStyle)
+{
+ fail(pStyle == NULL);
+
+ /* Start with de defaults */
+ vGetDefaultStyle(pStyle);
+
+ /* Add the build-in style info */
+ switch (ucStc) {
+ case 246:
+ case 247:
+ case 248:
+ case 249:
+ case 250:
+ case 255:
+ pStyle->sLeftIndent = 720;
+ break;
+ case 251:
+ case 252:
+ pStyle->sLeftIndent = 360;
+ break;
+ case 253:
+ pStyle->usBeforeIndent = 120;
+ break;
+ case 254:
+ pStyle->usBeforeIndent = 240;
+ break;
+ default:
+ if (ucStc >= 233 && ucStc <= 239) {
+ pStyle->sLeftIndent = (239 - (short)ucStc) * 360;
+ }
+ if (ucStc >= 225 && ucStc <= 232) {
+ pStyle->sLeftIndent = (232 - (short)ucStc) * 720;
+ pStyle->sRightIndent = 720;
+ }
+ break;
+ }
+} /* end of vGetBuildinStyle */
+
+/*
+ * Get a build-in fontstyle for Winword 1/2
+ */
+static void
+vGetBuildinFont(UCHAR ucStc, font_block_type *pFont)
+{
+ fail(pFont == NULL);
+
+ /* Start with de defaults */
+ vGetDefaultFont(pFont, 0);
+
+ /* Add the build-in fontstyle info */
+ switch (ucStc) {
+ case 223:
+ case 244:
+ pFont->usFontSize = 16;
+ break;
+ case 246:
+ case 247:
+ case 248:
+ pFont->usFontStyle |= FONT_ITALIC;
+ break;
+ case 249:
+ pFont->usFontStyle |= FONT_UNDERLINE;
+ break;
+ case 250:
+ pFont->usFontStyle |= FONT_BOLD;
+ break;
+ case 251:
+ pFont->usFontStyle |= FONT_UNDERLINE;
+ pFont->usFontSize = 24;
+ break;
+ case 252:
+ pFont->usFontStyle |= FONT_BOLD;
+ pFont->usFontSize = 24;
+ break;
+ case 253:
+ pFont->ucFontNumber = 2;
+ pFont->usFontStyle |= FONT_BOLD;
+ pFont->usFontSize = 24;
+ break;
+ case 254:
+ pFont->ucFontNumber = 2;
+ pFont->usFontStyle |= (FONT_BOLD|FONT_UNDERLINE);
+ pFont->usFontSize = 24;
+ break;
+ default:
+ break;
+ }
+} /* end of vGetBuildinFont */
+
+/*
+ * Convert a stylecode (stc) as used by WinWord 1/2 into a styleindex (istd)
+ * as used by Word 6 and up
+ */
+USHORT
+usStc2istd(UCHAR ucStc)
+{
+ /* Old nil style to new nil style */
+ if (ucStc == 222) {
+ return STI_NIL;
+ }
+
+ /* Heading 1 through 9 must become istd 1 through 9 */
+ /* so 254 through 246 must become 1 through 9 and vice versa */
+ if ((ucStc >= 1 && ucStc <= 9) ||
+ (ucStc >= 246 && ucStc <= 254)) {
+ return 255 - (USHORT)ucStc;
+ }
+ return (USHORT)ucStc;
+} /* end of usStd2istd */
+
+/*
+ * Build the lists with Stylesheet Information for WinWord 1/2 files
+ */
+void
+vGet2Stylesheet(FILE *pFile, int iWordVersion, const UCHAR *aucHeader)
+{
+ style_block_type *pStyle;
+ font_block_type *pFont;
+ UCHAR *aucBuffer;
+ ULONG ulBeginStshInfo;
+ size_t tStshInfoLen, tName, tChpx, tPapx, tMaxIndex;
+ int iStIndex, iChpxIndex, iPapxIndex, iSt, iChpx, iPapx;
+ int iStd, iIndex, iBaseStyleIndex, iCounter;
+ USHORT usBaseStyle;
+ UCHAR ucStc, ucStcNext, ucStcBase;
+
+ fail(pFile == NULL || aucHeader == NULL);
+ fail(iWordVersion != 1 && iWordVersion != 2);
+
+ ulBeginStshInfo = ulGetLong(0x5e, aucHeader); /* fcStshf */
+ NO_DBG_HEX(ulBeginStshInfo);
+ tStshInfoLen = (size_t)usGetWord(0x62, aucHeader); /* cbStshf */
+ NO_DBG_DEC(tStshInfoLen);
+
+ aucBuffer = xmalloc(tStshInfoLen);
+ if (!bReadBytes(aucBuffer, tStshInfoLen, ulBeginStshInfo, pFile)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tStshInfoLen);
+
+ fail(2 > tStshInfoLen);
+ iStd = (int)usGetWord(0, aucBuffer);
+
+ fail(2 + 2 > tStshInfoLen);
+ tName = (size_t)usGetWord(2, aucBuffer);
+
+ fail(2 + tName + 2 > tStshInfoLen);
+ tChpx = (size_t)usGetWord(2 + tName, aucBuffer);
+
+ fail(2 + tName + tChpx + 2 > tStshInfoLen);
+ tPapx = (size_t)usGetWord(2 + tName + tChpx, aucBuffer);
+
+ fail(2 + tName + tChpx + tPapx + 2 > tStshInfoLen);
+ tStdCount = (size_t)usGetWord(2 + tName + tChpx + tPapx, aucBuffer);
+
+ NO_DBG_HEX(tStdCount);
+
+ atStyleInfo = xcalloc(tStdCount, sizeof(style_block_type));
+ atFontInfo = xcalloc(tStdCount, sizeof(font_block_type));
+ abFilled = xcalloc(tStdCount, sizeof(BOOL));
+
+ do {
+ iCounter = 0;
+ iStIndex = 2 + 2;
+ iChpxIndex = 2 + (int)tName + 2;
+ iPapxIndex = 2 + (int)tName + (int)tChpx + 2;
+ tMaxIndex = 2 + tName + tChpx + tPapx + 2;
+ /* Read the styles one-by-one */
+ for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
+ pStyle = &atStyleInfo[iIndex];
+ pFont = &atFontInfo[iIndex];
+ iSt = (int)ucGetByte(iStIndex, aucBuffer);
+ iChpx = (int)ucGetByte(iChpxIndex, aucBuffer);
+ iPapx = (int)ucGetByte(iPapxIndex, aucBuffer);
+ NO_DBG_HEX(iSt);
+ NO_DBG_HEX(iChpx);
+ NO_DBG_HEX(iPapx);
+ if (iSt == 0xff || tMaxIndex + 1 >= tStshInfoLen) {
+ /* Undefined style or no information */
+ iStIndex++;
+ iChpxIndex++;
+ iPapxIndex++;
+ tMaxIndex += 2;
+ if (!abFilled[iIndex]) {
+ DBG_HEX_C(iChpx != 0xff, iChpx);
+ DBG_HEX_C(iPapx != 0xff, iPapx);
+ vGetDefaultStyle(pStyle);
+ vGetDefaultFont(pFont, 0);
+ abFilled[iIndex] = TRUE;
+ }
+ continue;
+ }
+
+ NO_DBG_STRN(aucBuffer + iStIndex + 1, iSt);
+ iStIndex += iSt + 1;
+
+ ucStcNext = ucGetByte(tMaxIndex, aucBuffer);
+ ucStcBase = ucGetByte(tMaxIndex + 1, aucBuffer);
+ ucStc = (UCHAR)((iIndex - iStd) & 0xff);
+ NO_DBG_DEC(ucStc);
+
+ if (iChpx == 0xff || iPapx == 0xff) {
+ /* Use a build-in style */
+ iChpxIndex++;
+ iPapxIndex++;
+ tMaxIndex += 2;
+ if (!abFilled[iIndex]) {
+ DBG_HEX_C(iChpx != 0xff, iChpx);
+ DBG_HEX_C(iPapx != 0xff, iPapx);
+ vGetBuildinStyle(ucStc, pStyle);
+ pStyle->usIstd = usStc2istd(ucStc);
+ pStyle->usIstdNext =
+ usStc2istd(ucStcNext);
+ vGetBuildinFont(ucStc, pFont);
+ abFilled[iIndex] = TRUE;
+ }
+ continue;
+ }
+
+ if (abFilled[iIndex]) {
+ /* This record has already been filled */
+ iChpxIndex += iChpx + 1;
+ iPapxIndex += iPapx + 1;
+ tMaxIndex += 2;
+ continue;
+ }
+
+ usBaseStyle = usStc2istd(ucStcBase);
+
+ if (usBaseStyle == STI_NIL) {
+ /* Based on the Nil style */
+ vGetDefaultStyle(pStyle);
+ vGetDefaultFont(pFont, 0);
+ } else {
+ iBaseStyleIndex = iGetStyleIndex(usBaseStyle);
+ NO_DBG_DEC(iBaseStyleIndex);
+ if (iBaseStyleIndex < 0) {
+ /* This style is not known yet */
+ iChpxIndex += iChpx + 1;
+ iPapxIndex += iPapx + 1;
+ tMaxIndex += 2;
+ continue;
+ }
+ fail(iBaseStyleIndex >= (int)tStdCount);
+ fail(!abFilled[iBaseStyleIndex]);
+ /* Based on the specified base style */
+ *pStyle = atStyleInfo[iBaseStyleIndex];
+ *pFont = atFontInfo[iBaseStyleIndex];
+ }
+ pStyle->usIstd = usStc2istd(ucStc);
+ pStyle->usIstdNext = usStc2istd(ucStcNext);
+
+ abFilled[iIndex] = TRUE;
+ iCounter++;
+
+ /* Add the changes if any */
+ switch (iChpx) {
+ case 0x00:
+ case 0xff:
+ iChpxIndex++;
+ break;
+ default:
+ NO_DBG_PRINT_BLOCK(aucBuffer + iChpxIndex + 1,
+ iChpx);
+ if (iWordVersion == 1) {
+ vGet1FontInfo(0,
+ aucBuffer + iChpxIndex + 1,
+ (size_t)iChpx, pFont);
+ } else {
+ vGet2FontInfo(0,
+ aucBuffer + iChpxIndex + 1,
+ (size_t)iChpx, pFont);
+ }
+ iChpxIndex += iChpx + 1;
+ break;
+ }
+
+ switch (iPapx) {
+ case 0x00:
+ case 0xff:
+ iPapxIndex++;
+ break;
+ default:
+ NO_DBG_PRINT_BLOCK(aucBuffer + iPapxIndex + 8,
+ iPapx - 7);
+ vGet2StyleInfo(0, aucBuffer + iPapxIndex + 8,
+ iPapx - 7, pStyle);
+ iPapxIndex += iPapx + 1;
+ break;
+ }
+ tMaxIndex += 2;
+
+ }
+ NO_DBG_DEC(iCounter);
+ } while (iCounter > 0);
+
+ /* Fill records that are still empty */
+ for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
+ if (!abFilled[iIndex]) {
+ NO_DBG_DEC(iIndex);
+ vGetDefaultStyle(&atStyleInfo[iIndex]);
+ vGetDefaultFont(&atFontInfo[iIndex], 0);
+ }
+ }
+
+ /* Clean up before you leave */
+ abFilled = xfree(abFilled);
+ aucBuffer = xfree(aucBuffer);
+} /* end of vGet2Stylesheet */
+
+/*
+ * Build the lists with Stylesheet Information for Word 6/7 files
+ */
+void
+vGet6Stylesheet(FILE *pFile, ULONG ulStartBlock,
+ const ULONG *aulBBD, size_t tBBDLen, const UCHAR *aucHeader)
+{
+ style_block_type *pStyle;
+ font_block_type *pFont;
+ UCHAR *aucBuffer;
+ ULONG ulBeginStshInfo;
+ size_t tStshInfoLen, tOffset, tStdLen, tStdBaseInFile;
+ size_t tPos, tNameLen, tUpxLen;
+ int iIndex, iBaseStyleIndex, iCounter;
+ USHORT usTmp, usUpxCount, usStyleType, usBaseStyle;
+ USHORT usFtcStandardChpStsh;
+
+ fail(pFile == NULL || aucHeader == NULL);
+ fail(ulStartBlock > MAX_BLOCKNUMBER && ulStartBlock != END_OF_CHAIN);
+ fail(aulBBD == NULL);
+
+ ulBeginStshInfo = ulGetLong(0x60, aucHeader); /* fcStshf */
+ NO_DBG_HEX(ulBeginStshInfo);
+ tStshInfoLen = (size_t)ulGetLong(0x64, aucHeader); /* lcbStshf */
+ NO_DBG_DEC(tStshInfoLen);
+
+ aucBuffer = xmalloc(tStshInfoLen);
+ if (!bReadBuffer(pFile, ulStartBlock,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucBuffer, ulBeginStshInfo, tStshInfoLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tStshInfoLen);
+
+ tStdCount = (size_t)usGetWord(2, aucBuffer);
+ NO_DBG_DEC(tStdCount);
+ tStdBaseInFile = (size_t)usGetWord(4, aucBuffer);
+ usFtcStandardChpStsh = usGetWord(14, aucBuffer);
+ NO_DBG_DEC(usFtcStandardChpStsh);
+
+ atStyleInfo = xcalloc(tStdCount, sizeof(style_block_type));
+ atFontInfo = xcalloc(tStdCount, sizeof(font_block_type));
+ abFilled = xcalloc(tStdCount, sizeof(BOOL));
+
+ do {
+ iCounter = 0;
+ /* Read the styles one-by-one */
+ for (iIndex = 0, tOffset = 2 + (size_t)usGetWord(0, aucBuffer);
+ iIndex < (int)tStdCount;
+ iIndex++, tOffset += 2 + tStdLen) {
+ NO_DBG_DEC(tOffset);
+ tStdLen = (size_t)usGetWord(tOffset, aucBuffer);
+ NO_DBG_DEC(tStdLen);
+ if (abFilled[iIndex]) {
+ /* This record has already been filled */
+ continue;
+ }
+ pStyle = &atStyleInfo[iIndex];
+ pFont = &atFontInfo[iIndex];
+ if (tStdLen == 0) {
+ /* Empty record */
+ vGetDefaultStyle(pStyle);
+ vGetDefaultFont(pFont, usFtcStandardChpStsh);
+ abFilled[iIndex] = TRUE;
+ continue;
+ }
+ usTmp = usGetWord(tOffset + 4, aucBuffer);
+ usStyleType = usTmp % 16;
+ usBaseStyle = usTmp / 16;
+ NO_DBG_DEC(usStyleType);
+ NO_DBG_DEC(usBaseStyle);
+ if (usBaseStyle == STI_NIL || usBaseStyle == STI_USER) {
+ /* Based on the Nil style */
+ vGetDefaultStyle(pStyle);
+ vGetDefaultFont(pFont, usFtcStandardChpStsh);
+ } else {
+ iBaseStyleIndex = iGetStyleIndex(usBaseStyle);
+ NO_DBG_DEC(iBaseStyleIndex);
+ if (iBaseStyleIndex < 0) {
+ /* This base style is not known yet */
+ continue;
+ }
+ fail(iBaseStyleIndex >= (int)tStdCount);
+ fail(!abFilled[iBaseStyleIndex]);
+ /* Based on the specified base style */
+ *pStyle = atStyleInfo[iBaseStyleIndex];
+ pStyle->usIstd = ISTD_INVALID;
+ *pFont = atFontInfo[iBaseStyleIndex];
+ }
+ abFilled[iIndex] = TRUE;
+ iCounter++;
+ /* STD */
+ usTmp = usGetWord(tOffset + 6, aucBuffer);
+ usUpxCount = usTmp % 16;
+ pStyle->usIstdNext = usTmp / 16;;
+ NO_DBG_DEC(usUpxCount);
+ tPos = 2 + tStdBaseInFile;
+ NO_DBG_DEC(tPos);
+ tNameLen = (size_t)ucGetByte(tOffset + tPos, aucBuffer);
+ NO_DBG_DEC(tNameLen);
+ NO_DBG_STRN(aucBuffer + tOffset + tPos + 1, tNameLen);
+ tNameLen++; /* Include the ASCII NULL character */
+ tPos += 1 + tNameLen;
+ if (odd(tPos)) {
+ tPos++;
+ }
+ NO_DBG_DEC(tPos);
+ if (tPos >= tStdLen) {
+ continue;
+ }
+ tUpxLen = (size_t)usGetWord(tOffset + tPos, aucBuffer);
+ NO_DBG_DEC(tUpxLen);
+ if (tPos + tUpxLen > tStdLen) {
+ /* UPX length too large to be a record */
+ DBG_DEC_C(tPos + tUpxLen > tStdLen,
+ tPos + tUpxLen);
+ continue;
+ }
+ if (usStyleType == SGC_PAP && usUpxCount >= 1) {
+ if (tUpxLen >= 2) {
+ NO_DBG_PRINT_BLOCK(
+ aucBuffer + tOffset + tPos + 2,
+ tUpxLen);
+ pStyle->usIstd = usGetWord(
+ tOffset + tPos + 2, aucBuffer);
+ NO_DBG_DEC(pStyle->usIstd);
+ NO_DBG_DEC(pStyle->usIstdNext);
+ vGet6StyleInfo(0,
+ aucBuffer + tOffset + tPos + 4,
+ tUpxLen - 2, pStyle);
+ NO_DBG_DEC(pStyle->sLeftIndent);
+ NO_DBG_DEC(pStyle->sRightIndent);
+ NO_DBG_HEX(pStyle->ucAlignment);
+ }
+ tPos += 2 + tUpxLen;
+ if (odd(tPos)) {
+ tPos++;
+ }
+ NO_DBG_DEC(tPos);
+ tUpxLen = (size_t)usGetWord(
+ tOffset + tPos, aucBuffer);
+ NO_DBG_DEC(tUpxLen);
+ }
+ if (tUpxLen == 0 || tPos + tUpxLen > tStdLen) {
+ /* Too small or too large to be a record */
+ DBG_DEC_C(tPos + tUpxLen > tStdLen,
+ tPos + tUpxLen);
+ continue;
+ }
+ if ((usStyleType == SGC_PAP && usUpxCount >= 2) ||
+ (usStyleType == SGC_CHP && usUpxCount >= 1)) {
+ NO_DBG_PRINT_BLOCK(
+ aucBuffer + tOffset + tPos + 2,
+ tUpxLen);
+ vGet6FontInfo(0, ISTD_INVALID,
+ aucBuffer + tOffset + tPos + 2,
+ (int)tUpxLen, pFont);
+ NO_DBG_DEC(pFont->usFontSize);
+ NO_DBG_DEC(pFont->ucFontcolor);
+ NO_DBG_HEX(pFont->usFontStyle);
+ }
+ }
+ NO_DBG_DEC(iCounter);
+ } while (iCounter > 0);
+
+ /* Fill records that are still empty */
+ for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
+ if (!abFilled[iIndex]) {
+ NO_DBG_DEC(iIndex);
+ vGetDefaultStyle(&atStyleInfo[iIndex]);
+ vGetDefaultFont(&atFontInfo[iIndex],
+ usFtcStandardChpStsh);
+ }
+ }
+
+ /* Clean up before you leave */
+ abFilled = xfree(abFilled);
+ aucBuffer = xfree(aucBuffer);
+} /* end of vGet6Stylesheet */
+
+/*
+ * Build the lists with Stylesheet Information for Word 8/9/10 files
+ */
+void
+vGet8Stylesheet(FILE *pFile, const pps_info_type *pPPS,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ const UCHAR *aucHeader)
+{
+ style_block_type *pStyle;
+ font_block_type *pFont;
+ const ULONG *aulBlockDepot;
+ UCHAR *aucBuffer;
+ ULONG ulBeginStshInfo;
+ size_t tStshInfoLen, tBlockDepotLen, tOffset, tStdLen, tStdBaseInFile;
+ size_t tBlockSize, tPos, tNameLen, tUpxLen;
+ int iIndex, iBaseStyleIndex, iCounter;
+ USHORT usTmp, usUpxCount, usStyleType, usBaseStyle;
+ USHORT usFtcStandardChpStsh;
+
+ fail(pFile == NULL || pPPS == NULL || aucHeader == NULL);
+ fail(aulBBD == NULL || aulSBD == NULL);
+
+ ulBeginStshInfo = ulGetLong(0xa2, aucHeader); /* fcStshf */
+ NO_DBG_HEX(ulBeginStshInfo);
+ tStshInfoLen = (size_t)ulGetLong(0xa6, aucHeader); /* lcbStshf */
+ NO_DBG_DEC(tStshInfoLen);
+
+ NO_DBG_DEC(pPPS->tTable.ulSB);
+ NO_DBG_HEX(pPPS->tTable.ulSize);
+ if (pPPS->tTable.ulSize == 0) {
+ DBG_MSG("No stylesheet information");
+ return;
+ }
+
+ if (pPPS->tTable.ulSize < MIN_SIZE_FOR_BBD_USE) {
+ /* Use the Small Block Depot */
+ aulBlockDepot = aulSBD;
+ tBlockDepotLen = tSBDLen;
+ tBlockSize = SMALL_BLOCK_SIZE;
+ } else {
+ /* Use the Big Block Depot */
+ aulBlockDepot = aulBBD;
+ tBlockDepotLen = tBBDLen;
+ tBlockSize = BIG_BLOCK_SIZE;
+ }
+ aucBuffer = xmalloc(tStshInfoLen);
+ if (!bReadBuffer(pFile, pPPS->tTable.ulSB,
+ aulBlockDepot, tBlockDepotLen, tBlockSize,
+ aucBuffer, ulBeginStshInfo, tStshInfoLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tStshInfoLen);
+
+ tStdCount = (size_t)usGetWord(2, aucBuffer);
+ NO_DBG_DEC(tStdCount);
+ tStdBaseInFile = (size_t)usGetWord(4, aucBuffer);
+ usFtcStandardChpStsh = usGetWord(14, aucBuffer);
+ NO_DBG_DEC(usFtcStandardChpStsh);
+
+ atStyleInfo = xcalloc(tStdCount, sizeof(style_block_type));
+ atFontInfo = xcalloc(tStdCount, sizeof(font_block_type));
+ abFilled = xcalloc(tStdCount, sizeof(BOOL));
+
+ do {
+ iCounter = 0;
+ /* Read the styles one-by-one */
+ for (iIndex = 0, tOffset = 2 + (size_t)usGetWord(0, aucBuffer);
+ iIndex < (int)tStdCount;
+ iIndex++, tOffset += 2 + tStdLen) {
+ NO_DBG_DEC(tOffset);
+ tStdLen = (size_t)usGetWord(tOffset, aucBuffer);
+ NO_DBG_DEC(tStdLen);
+ if (abFilled[iIndex]) {
+ /* This record has already been filled */
+ continue;
+ }
+ pStyle = &atStyleInfo[iIndex];
+ pFont = &atFontInfo[iIndex];
+ if (tStdLen == 0) {
+ /* Empty record */
+ vGetDefaultStyle(pStyle);
+ vGetDefaultFont(pFont, usFtcStandardChpStsh);
+ abFilled[iIndex] = TRUE;
+ continue;
+ }
+ usTmp = usGetWord(tOffset + 4, aucBuffer);
+ usStyleType = usTmp % 16;
+ usBaseStyle = usTmp / 16;
+ NO_DBG_DEC(usStyleType);
+ NO_DBG_DEC(usBaseStyle);
+ if (usBaseStyle == STI_NIL || usBaseStyle == STI_USER) {
+ /* Based on the Nil style */
+ vGetDefaultStyle(pStyle);
+ vGetDefaultFont(pFont, usFtcStandardChpStsh);
+ } else {
+ iBaseStyleIndex = iGetStyleIndex(usBaseStyle);
+ NO_DBG_DEC(iBaseStyleIndex);
+ if (iBaseStyleIndex < 0) {
+ /* This base style is not known yet */
+ continue;
+ }
+ fail(iBaseStyleIndex >= (int)tStdCount);
+ fail(!abFilled[iBaseStyleIndex]);
+ /* Based on the specified base style */
+ *pStyle = atStyleInfo[iBaseStyleIndex];
+ pStyle->usIstd = ISTD_INVALID;
+ *pFont = atFontInfo[iBaseStyleIndex];
+ }
+ abFilled[iIndex] = TRUE;
+ iCounter++;
+ /* STD */
+ usTmp = usGetWord(tOffset + 6, aucBuffer);
+ usUpxCount = usTmp % 16;
+ pStyle->usIstdNext = usTmp / 16;
+ NO_DBG_DEC(usUpxCount);
+ tPos = 2 + tStdBaseInFile;
+ NO_DBG_DEC(tPos);
+ tNameLen = (size_t)usGetWord(tOffset + tPos, aucBuffer);
+ NO_DBG_DEC(tNameLen);
+ tNameLen *= 2; /* From Unicode characters to bytes */
+ NO_DBG_UNICODE_N(aucBuffer + tOffset + tPos + 2,
+ tNameLen);
+ tNameLen += 2; /* Include the Unicode NULL character */
+ tPos += 2 + tNameLen;
+ if (odd(tPos)) {
+ tPos++;
+ }
+ NO_DBG_DEC(tPos);
+ if (tPos >= tStdLen) {
+ continue;
+ }
+ tUpxLen = (size_t)usGetWord(tOffset + tPos, aucBuffer);
+ NO_DBG_DEC(tUpxLen);
+ if (tPos + tUpxLen > tStdLen) {
+ /* UPX length too large to be a record */
+ DBG_DEC_C(tPos + tUpxLen > tStdLen,
+ tPos + tUpxLen);
+ continue;
+ }
+ if (usStyleType == SGC_PAP && usUpxCount >= 1) {
+ if (tUpxLen >= 2) {
+ NO_DBG_PRINT_BLOCK(
+ aucBuffer + tOffset + tPos + 2,
+ tUpxLen);
+ pStyle->usIstd = usGetWord(
+ tOffset + tPos + 2, aucBuffer);
+ NO_DBG_DEC(pStyle->usIstd);
+ NO_DBG_DEC(pStyle->usIstdNext);
+ vGet8StyleInfo(0,
+ aucBuffer + tOffset + tPos + 4,
+ tUpxLen - 2, pStyle);
+ NO_DBG_DEC(pStyle->sLeftIndent);
+ NO_DBG_DEC(pStyle->sRightIndent);
+ NO_DBG_HEX(pStyle->ucAlignment);
+ }
+ tPos += 2 + tUpxLen;
+ if (odd(tPos)) {
+ tPos++;
+ }
+ NO_DBG_DEC(tPos);
+ tUpxLen = (size_t)usGetWord(
+ tOffset + tPos, aucBuffer);
+ NO_DBG_DEC(tUpxLen);
+ }
+ if (tUpxLen == 0 || tPos + tUpxLen > tStdLen) {
+ /* Too small or too large to be a record */
+ DBG_DEC_C(tPos + tUpxLen > tStdLen,
+ tPos + tUpxLen);
+ continue;
+ }
+ if ((usStyleType == SGC_PAP && usUpxCount >= 2) ||
+ (usStyleType == SGC_CHP && usUpxCount >= 1)) {
+ NO_DBG_PRINT_BLOCK(
+ aucBuffer + tOffset + tPos + 2,
+ tUpxLen);
+ vGet8FontInfo(0, ISTD_INVALID,
+ aucBuffer + tOffset + tPos + 2,
+ (int)tUpxLen, pFont);
+ NO_DBG_DEC(pFont->usFontSize);
+ NO_DBG_DEC(pFont->ucFontcolor);
+ NO_DBG_HEX(pFont->usFontStyle);
+ }
+ }
+ NO_DBG_DEC(iCounter);
+ } while (iCounter > 0);
+
+ /* Fill records that are still empty */
+ for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
+ if (!abFilled[iIndex]) {
+ NO_DBG_DEC(iIndex);
+ vGetDefaultStyle(&atStyleInfo[iIndex]);
+ vGetDefaultFont(&atFontInfo[iIndex],
+ usFtcStandardChpStsh);
+ }
+ }
+
+ /* Clean up before you leave */
+ abFilled = xfree(abFilled);
+ aucBuffer = xfree(aucBuffer);
+} /* end of vGet8Stylesheet */
+
+/*
+ * vFillStyleFromStylesheet - fill a style struct with stylesheet info
+ */
+void
+vFillStyleFromStylesheet(USHORT usIstd, style_block_type *pStyle)
+{
+ int iIndex;
+
+ fail(pStyle == NULL);
+
+ if (usIstd != ISTD_INVALID && usIstd != STI_NIL && usIstd != STI_USER) {
+ for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
+ if (atStyleInfo[iIndex].usIstd == usIstd) {
+ /* Right index found; return style */
+ *pStyle = atStyleInfo[iIndex];
+ return;
+ }
+ }
+ }
+
+ vGetDefaultStyle(pStyle);
+ pStyle->usIstd = usIstd;
+} /* end of vFillStyleFromStylesheet */
+
+/*
+ * vFillFontFromStylesheet - fill a font struct with stylesheet info
+ */
+void
+vFillFontFromStylesheet(USHORT usIstd, font_block_type *pFont)
+{
+ int iIndex;
+
+ fail(pFont == NULL);
+
+ if (usIstd != ISTD_INVALID && usIstd != STI_NIL && usIstd != STI_USER) {
+ for (iIndex = 0; iIndex < (int)tStdCount; iIndex++) {
+ if (atStyleInfo[iIndex].usIstd == usIstd) {
+ /* Right index found; return font */
+ *pFont = atFontInfo[iIndex];
+ return;
+ }
+ }
+ }
+
+ vGetDefaultFont(pFont, 0);
+} /* end of vFillFontFromStylesheet */
diff --git a/sys/src/cmd/aux/antiword/summary.c b/sys/src/cmd/aux/antiword/summary.c
new file mode 100755
index 000000000..d9ee68767
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/summary.c
@@ -0,0 +1,888 @@
+/*
+ * summary.c
+ * Copyright (C) 2002-2005 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Read the summary information of a Word document
+ */
+
+#include <time.h>
+#include <string.h>
+#include "antiword.h"
+
+#define P_HEADER_SZ 28
+#define P_SECTIONLIST_SZ 20
+#define P_LENGTH_SZ 4
+#define P_SECTION_MAX_SZ (2 * P_SECTIONLIST_SZ + P_LENGTH_SZ)
+#define P_SECTION_SZ(x) ((x) * P_SECTIONLIST_SZ + P_LENGTH_SZ)
+
+#define PID_TITLE 2
+#define PID_SUBJECT 3
+#define PID_AUTHOR 4
+#define PID_CREATE_DTM 12
+#define PID_LASTSAVE_DTM 13
+#define PID_APPNAME 18
+
+#define PIDD_MANAGER 14
+#define PIDD_COMPANY 15
+
+#define VT_LPSTR 30
+#define VT_FILETIME 64
+
+#define TIME_OFFSET_HI 0x019db1de
+#define TIME_OFFSET_LO 0xd53e8000
+
+static char *szTitle = NULL;
+static char *szSubject = NULL;
+static char *szAuthor = NULL;
+static time_t tCreateDtm = (time_t)-1;
+static time_t tLastSaveDtm= (time_t)-1;
+static char *szAppName = NULL;
+static char *szManager = NULL;
+static char *szCompany = NULL;
+static USHORT usLid = (USHORT)-1;
+
+
+/*
+ * vDestroySummaryInfo - destroy the summary information
+ */
+void
+vDestroySummaryInfo(void)
+{
+ TRACE_MSG("vDestroySummaryInfo");
+
+ szTitle = xfree(szTitle);
+ szSubject = xfree(szSubject);
+ szAuthor = xfree(szAuthor);
+ tCreateDtm = (time_t)-1;
+ tLastSaveDtm = (time_t)-1;
+ szAppName = xfree(szAppName);
+ szManager = xfree(szManager);
+ szCompany = xfree(szCompany);
+ usLid = (USHORT)-1;
+} /* end of vDestroySummaryInfo */
+
+/*
+ * tConvertDosDate - convert DOS date format
+ *
+ * returns Unix time_t or -1
+ */
+static time_t
+tConvertDosDate(const char *szDosDate)
+{
+ struct tm tTime;
+ const char *pcTmp;
+ time_t tResult;
+
+ memset(&tTime, 0, sizeof(tTime));
+ pcTmp = szDosDate;
+ /* Get the month */
+ if (!isdigit(*pcTmp)) {
+ return (time_t)-1;
+ }
+ tTime.tm_mon = (int)(*pcTmp - '0');
+ pcTmp++;
+ if (isdigit(*pcTmp)) {
+ tTime.tm_mon *= 10;
+ tTime.tm_mon += (int)(*pcTmp - '0');
+ pcTmp++;
+ }
+ /* Get the first separater */
+ if (isalnum(*pcTmp)) {
+ return (time_t)-1;
+ }
+ pcTmp++;
+ /* Get the day */
+ if (!isdigit(*pcTmp)) {
+ return (time_t)-1;
+ }
+ tTime.tm_mday = (int)(*pcTmp - '0');
+ pcTmp++;
+ if (isdigit(*pcTmp)) {
+ tTime.tm_mday *= 10;
+ tTime.tm_mday += (int)(*pcTmp - '0');
+ pcTmp++;
+ }
+ /* Get the second separater */
+ if (isalnum(*pcTmp)) {
+ return (time_t)-1;
+ }
+ pcTmp++;
+ /* Get the year */
+ if (!isdigit(*pcTmp)) {
+ return (time_t)-1;
+ }
+ tTime.tm_year = (int)(*pcTmp - '0');
+ pcTmp++;
+ if (isdigit(*pcTmp)) {
+ tTime.tm_year *= 10;
+ tTime.tm_year += (int)(*pcTmp - '0');
+ pcTmp++;
+ }
+ /* Check the values */
+ if (tTime.tm_mon == 0 || tTime.tm_mday == 0 || tTime.tm_mday > 31) {
+ return (time_t)-1;
+ }
+ /* Correct the values */
+ tTime.tm_mon--; /* From 01-12 to 00-11 */
+ if (tTime.tm_year < 80) {
+ tTime.tm_year += 100; /* 00 means 2000 is 100 */
+ }
+ tTime.tm_isdst = -1;
+ tResult = mktime(&tTime);
+ NO_DBG_MSG(ctime(&tResult));
+ return tResult;
+} /* end of tConvertDosDate */
+
+/*
+ * szLpstr - get a zero terminate string property
+ */
+static char *
+szLpstr(ULONG ulOffset, const UCHAR *aucBuffer)
+{
+ char *szStart, *szResult, *szTmp;
+ size_t tSize;
+
+ tSize = (size_t)ulGetLong(ulOffset + 4, aucBuffer);
+ NO_DBG_DEC(tSize);
+ if (tSize == 0) {
+ return NULL;
+ }
+ /* Remove white space from the start of the string */
+ szStart = (char *)aucBuffer + ulOffset + 8;
+ NO_DBG_MSG(szStart);
+ fail(strlen(szStart) >= tSize);
+ while (isspace(*szStart)) {
+ szStart++;
+ }
+ if (szStart[0] == '\0') {
+ return NULL;
+ }
+ szResult = xstrdup(szStart);
+ /* Remove white space from the end of the string */
+ szTmp = szResult + strlen(szResult) - 1;
+ while (isspace(*szTmp)) {
+ *szTmp = '\0';
+ szTmp--;
+ }
+ NO_DBG_MSG(szResult);
+ return szResult;
+} /* end of szLpstr */
+
+/*
+ * tFiletime - get a filetime property
+ */
+static time_t
+tFiletime(ULONG ulOffset, const UCHAR *aucBuffer)
+{
+ double dHi, dLo, dTmp;
+ ULONG ulHi, ulLo;
+ time_t tResult;
+
+ ulLo = ulGetLong(ulOffset + 4, aucBuffer);
+ ulHi = ulGetLong(ulOffset + 8, aucBuffer);
+ NO_DBG_HEX(ulHi);
+ NO_DBG_HEX(ulLo);
+
+ /* Move the starting point from 01 Jan 1601 to 01 Jan 1970 */
+ dHi = (double)ulHi - (double)TIME_OFFSET_HI;
+ dLo = (double)ulLo - (double)TIME_OFFSET_LO;
+ NO_DBG_FLT(dHi);
+ NO_DBG_FLT(dLo);
+
+ /* Combine the values and divide by 10^7 to get seconds */
+ dTmp = dLo / 10000000.0; /* 10^7 */
+ dTmp += dHi * 429.4967926; /* 2^32 / 10^7 */
+ NO_DBG_FLT(dTmp);
+
+ /* Make a time_t */
+ if (dTmp - 0.5 < TIME_T_MIN || dTmp + 0.5 > TIME_T_MAX) {
+ return (time_t)-1;
+ }
+ tResult = dTmp < 0.0 ? (time_t)(dTmp - 0.5) : (time_t)(dTmp + 0.5);
+ NO_DBG_MSG(ctime(&tResult));
+ return tResult;
+} /* end of tFiletime */
+
+/*
+ * vAnalyseSummaryInfo - analyse the summary information
+ */
+static void
+vAnalyseSummaryInfo(const UCHAR *aucBuffer)
+{
+ ULONG ulOffset;
+ size_t tIndex, tCount, tPropID, tPropType;
+
+ tCount = (size_t)ulGetLong(4, aucBuffer);
+ DBG_DEC(tCount);
+ for (tIndex = 0; tIndex < tCount; tIndex++) {
+ tPropID = (size_t)ulGetLong(8 + tIndex * 8, aucBuffer);
+ ulOffset = ulGetLong(12 + tIndex * 8, aucBuffer);
+ NO_DBG_DEC(tPropID);
+ NO_DBG_HEX(ulOffset);
+ tPropType = (size_t)ulGetLong(ulOffset, aucBuffer);
+ NO_DBG_DEC(tPropType);
+ switch (tPropID) {
+ case PID_TITLE:
+ if (tPropType == VT_LPSTR && szTitle == NULL) {
+ szTitle = szLpstr(ulOffset, aucBuffer);
+ }
+ break;
+ case PID_SUBJECT:
+ if (tPropType == VT_LPSTR && szSubject == NULL) {
+ szSubject = szLpstr(ulOffset, aucBuffer);
+ }
+ break;
+ case PID_AUTHOR:
+ if (tPropType == VT_LPSTR && szAuthor == NULL) {
+ szAuthor = szLpstr(ulOffset, aucBuffer);
+ }
+ break;
+ case PID_CREATE_DTM:
+ if (tPropType == VT_FILETIME &&
+ tCreateDtm == (time_t)-1) {
+ tCreateDtm = tFiletime(ulOffset, aucBuffer);
+ }
+ break;
+ case PID_LASTSAVE_DTM:
+ if (tPropType == VT_FILETIME &&
+ tLastSaveDtm == (time_t)-1) {
+ tLastSaveDtm = tFiletime(ulOffset, aucBuffer);
+ }
+ break;
+ case PID_APPNAME:
+ if (tPropType == VT_LPSTR && szAppName == NULL) {
+ szAppName = szLpstr(ulOffset, aucBuffer);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+} /* end of vAnalyseSummaryInfo */
+
+/*
+ * vAnalyseDocumentSummaryInfo - analyse the document summary information
+ */
+static void
+vAnalyseDocumentSummaryInfo(const UCHAR *aucBuffer)
+{
+ ULONG ulOffset;
+ size_t tIndex, tCount, tPropID, tPropType;
+
+ tCount = (size_t)ulGetLong(4, aucBuffer);
+ DBG_DEC(tCount);
+ for (tIndex = 0; tIndex < tCount; tIndex++) {
+ tPropID = (size_t)ulGetLong(8 + tIndex * 8, aucBuffer);
+ ulOffset = ulGetLong(12 + tIndex * 8, aucBuffer);
+ NO_DBG_DEC(tPropID);
+ NO_DBG_HEX(ulOffset);
+ tPropType = (size_t)ulGetLong(ulOffset, aucBuffer);
+ NO_DBG_DEC(tPropType);
+ switch (tPropID) {
+ case PIDD_MANAGER:
+ if (tPropType == VT_LPSTR && szManager == NULL) {
+ szManager = szLpstr(ulOffset, aucBuffer);
+ }
+ break;
+ case PIDD_COMPANY:
+ if (tPropType == VT_LPSTR && szCompany == NULL) {
+ szCompany = szLpstr(ulOffset, aucBuffer);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+} /* end of vAnalyseDocumentSummaryInfo */
+
+/*
+ * pucAnalyseSummaryInfoHeader-
+ */
+static UCHAR *
+pucAnalyseSummaryInfoHeader(FILE *pFile,
+ ULONG ulStartBlock, ULONG ulSize,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen)
+{
+ const ULONG *aulBlockDepot;
+ UCHAR *aucBuffer;
+ size_t tBlockDepotLen, tBlockSize, tSectionCount, tLength;
+ ULONG ulTmp, ulOffset;
+ USHORT usLittleEndian, usEmpty, usOS, usVersion;
+ UCHAR aucHdr[P_HEADER_SZ], aucSecLst[P_SECTION_MAX_SZ];
+
+ if (ulSize < MIN_SIZE_FOR_BBD_USE) {
+ /* Use the Small Block Depot */
+ aulBlockDepot = aulSBD;
+ tBlockDepotLen = tSBDLen;
+ tBlockSize = SMALL_BLOCK_SIZE;
+ } else {
+ /* Use the Big Block Depot */
+ aulBlockDepot = aulBBD;
+ tBlockDepotLen = tBBDLen;
+ tBlockSize = BIG_BLOCK_SIZE;
+ }
+
+ if (tBlockDepotLen == 0) {
+ DBG_MSG("The Block Depot length is zero");
+ return NULL;
+ }
+
+ /* Read the Summery Information header */
+ if (!bReadBuffer(pFile, ulStartBlock,
+ aulBlockDepot, tBlockDepotLen, tBlockSize,
+ aucHdr, 0, P_HEADER_SZ)) {
+ return NULL;
+ }
+ NO_DBG_PRINT_BLOCK(aucHdr, P_HEADER_SZ);
+
+ /* Analyse the Summery Information header */
+ usLittleEndian = usGetWord(0, aucHdr);
+ if (usLittleEndian != 0xfffe) {
+ DBG_HEX(usLittleEndian);
+ DBG_MSG_C(usLittleEndian == 0xfeff, "Big endian");
+ return NULL;
+ }
+ usEmpty = usGetWord(2, aucHdr);
+ if (usEmpty != 0x0000) {
+ DBG_DEC(usEmpty);
+ return NULL;
+ }
+ ulTmp = ulGetLong(4, aucHdr);
+ DBG_HEX(ulTmp);
+ usOS = (USHORT)(ulTmp >> 16);
+ usVersion = (USHORT)(ulTmp & 0xffff);
+ switch (usOS) {
+ case 0:
+ DBG_MSG("Win16");
+ DBG_HEX(usVersion);
+ break;
+ case 1:
+ DBG_MSG("MacOS");
+ DBG_HEX(usVersion);
+ break;
+ case 2:
+ DBG_MSG("Win32");
+ DBG_HEX(usVersion);
+ break;
+ default:
+ DBG_DEC(usOS);
+ DBG_HEX(usVersion);
+ break;
+ }
+ tSectionCount = (size_t)ulGetLong(24, aucHdr);
+ DBG_DEC_C(tSectionCount != 1 && tSectionCount != 2, tSectionCount);
+ if (tSectionCount != 1 && tSectionCount != 2) {
+ return NULL;
+ }
+
+ /* Read the Summery Information Section Lists */
+ if (!bReadBuffer(pFile, ulStartBlock,
+ aulBlockDepot, tBlockDepotLen, tBlockSize,
+ aucSecLst, P_HEADER_SZ, P_SECTION_SZ(tSectionCount))) {
+ return NULL;
+ }
+ NO_DBG_PRINT_BLOCK(aucSecLst, P_SECTION_SZ(tSectionCount));
+
+ ulTmp = ulGetLong(0, aucSecLst);
+ DBG_HEX(ulTmp);
+ ulTmp = ulGetLong(4, aucSecLst);
+ DBG_HEX(ulTmp);
+ ulTmp = ulGetLong(8, aucSecLst);
+ DBG_HEX(ulTmp);
+ ulTmp = ulGetLong(12, aucSecLst);
+ DBG_HEX(ulTmp);
+ ulOffset = ulGetLong(16, aucSecLst);
+ DBG_DEC_C(ulOffset != P_HEADER_SZ + P_SECTIONLIST_SZ &&
+ ulOffset != P_HEADER_SZ + 2 * P_SECTIONLIST_SZ,
+ ulOffset);
+ fail(ulOffset != P_HEADER_SZ + P_SECTIONLIST_SZ &&
+ ulOffset != P_HEADER_SZ + 2 * P_SECTIONLIST_SZ);
+ tLength =
+ (size_t)ulGetLong(tSectionCount * P_SECTIONLIST_SZ, aucSecLst);
+ NO_DBG_HEX(tLength);
+ fail(ulOffset + tLength > ulSize);
+
+ /* Read the Summery Information */
+ aucBuffer = xmalloc(tLength);
+ if (!bReadBuffer(pFile, ulStartBlock,
+ aulBlockDepot, tBlockDepotLen, tBlockSize,
+ aucBuffer, ulOffset, tLength)) {
+ aucBuffer = xfree(aucBuffer);
+ return NULL;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tLength);
+ return aucBuffer;
+} /* end of pucAnalyseSummaryInfoHeader */
+
+/*
+ * vSet0SummaryInfo - set summary information from a Word for DOS file
+ */
+void
+vSet0SummaryInfo(FILE *pFile, const UCHAR *aucHeader)
+{
+ UCHAR *aucBuffer;
+ ULONG ulBeginSumdInfo, ulBeginNextBlock;
+ size_t tLen;
+ USHORT usCodepage, usOffset;
+
+ TRACE_MSG("vSet0SummaryInfo");
+
+ fail(pFile == NULL || aucHeader == NULL);
+
+ /* First check the header */
+ usCodepage = usGetWord(0x7e, aucHeader);
+ DBG_DEC(usCodepage);
+ switch (usCodepage) {
+ case 850: usLid = 0x0809; break; /* Latin1 -> British English */
+ case 862: usLid = 0x040d; break; /* Hebrew */
+ case 866: usLid = 0x0419; break; /* Russian */
+ case 0:
+ case 437:
+ default: usLid = 0x0409; break; /* ASCII -> American English */
+ }
+
+ /* Second check the summary information block */
+ ulBeginSumdInfo = 128 * (ULONG)usGetWord(0x1c, aucHeader);
+ DBG_HEX(ulBeginSumdInfo);
+ ulBeginNextBlock = 128 * (ULONG)usGetWord(0x6a, aucHeader);
+ DBG_HEX(ulBeginNextBlock);
+
+ if (ulBeginSumdInfo >= ulBeginNextBlock || ulBeginNextBlock == 0) {
+ /* There is no summary information block */
+ return;
+ }
+ tLen = (size_t)(ulBeginNextBlock - ulBeginSumdInfo);
+ aucBuffer = xmalloc(tLen);
+ /* Read the summary information block */
+ if (!bReadBytes(aucBuffer, tLen, ulBeginSumdInfo, pFile)) {
+ return;
+ }
+ usOffset = usGetWord(0, aucBuffer);
+ if (aucBuffer[usOffset] != 0) {
+ NO_DBG_MSG(aucBuffer + usOffset);
+ szTitle = xstrdup((char *)aucBuffer + usOffset);
+ }
+ usOffset = usGetWord(2, aucBuffer);
+ if (aucBuffer[usOffset] != 0) {
+ NO_DBG_MSG(aucBuffer + usOffset);
+ szAuthor = xstrdup((char *)aucBuffer + usOffset);
+ }
+ usOffset = usGetWord(12, aucBuffer);
+ if (aucBuffer[usOffset] != 0) {
+ NO_DBG_STRN(aucBuffer + usOffset, 8);
+ tLastSaveDtm = tConvertDosDate((char *)aucBuffer + usOffset);
+ }
+ usOffset = usGetWord(14, aucBuffer);
+ if (aucBuffer[usOffset] != 0) {
+ NO_DBG_STRN(aucBuffer + usOffset, 8);
+ tCreateDtm = tConvertDosDate((char *)aucBuffer + usOffset);
+ }
+ aucBuffer = xfree(aucBuffer);
+} /* end of vSet0SummaryInfo */
+
+/*
+ * vSet2SummaryInfo - set summary information from a WinWord 1/2 file
+ */
+void
+vSet2SummaryInfo(FILE *pFile, int iWordVersion, const UCHAR *aucHeader)
+{
+ UCHAR *aucBuffer;
+ ULONG ulBeginSumdInfo, ulBeginDocpInfo, ulTmp;
+ size_t tSumdInfoLen, tDocpInfoLen, tLen, tCounter, tStart;
+
+ TRACE_MSG("vSet2SummaryInfo");
+
+ fail(pFile == NULL || aucHeader == NULL);
+ fail(iWordVersion != 1 && iWordVersion != 2);
+
+ /* First check the header */
+ usLid = usGetWord(0x06, aucHeader); /* Language IDentification */
+ DBG_HEX(usLid);
+ if (usLid < 999 && iWordVersion == 1) {
+ switch (usLid) {
+ case 1: usLid = 0x0409; break; /* American English */
+ case 2: usLid = 0x0c0c; break; /* Canadian French */
+ case 31: usLid = 0x0413; break; /* Dutch */
+ case 33: usLid = 0x040c; break; /* French */
+ case 34: usLid = 0x040a; break; /* Spanish */
+ case 36: usLid = 0x040e; break; /* Hungarian */
+ case 39: usLid = 0x0410; break; /* Italian */
+ case 44: usLid = 0x0809; break; /* British English */
+ case 45: usLid = 0x0406; break; /* Danish */
+ case 46: usLid = 0x041f; break; /* Swedish */
+ case 47: usLid = 0x0414; break; /* Norwegian */
+ case 48: usLid = 0x0415; break; /* Polish */
+ case 49: usLid = 0x0407; break; /* German */
+ case 351: usLid = 0x0816; break; /* Portuguese */
+ case 358: usLid = 0x040b; break; /* Finnish */
+ default:
+ DBG_DEC(usLid);
+ DBG_FIXME();
+ usLid = 0x0409; /* American English */
+ break;
+ }
+ }
+
+ if (iWordVersion != 2) {
+ /* Unknown where to find the associated strings */
+ return;
+ }
+
+ /* Second check the associated strings */
+ ulBeginSumdInfo = ulGetLong(0x118, aucHeader); /* fcSttbfAssoc */
+ DBG_HEX(ulBeginSumdInfo);
+ tSumdInfoLen = (size_t)usGetWord(0x11c, aucHeader); /* cbSttbfAssoc */
+ DBG_DEC(tSumdInfoLen);
+
+ if (tSumdInfoLen == 0) {
+ /* There is no summary information */
+ return;
+ }
+
+ aucBuffer = xmalloc(tSumdInfoLen);
+ if (!bReadBytes(aucBuffer, tSumdInfoLen, ulBeginSumdInfo, pFile)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ NO_DBG_PRINT_BLOCK(aucBuffer, tSumdInfoLen);
+ tLen = (size_t)ucGetByte(0, aucBuffer);
+ DBG_DEC_C(tSumdInfoLen != tLen, tSumdInfoLen);
+ DBG_DEC_C(tSumdInfoLen != tLen, tLen);
+ tStart = 1;
+ for (tCounter = 0; tCounter < 17; tCounter++) {
+ if (tStart >= tSumdInfoLen) {
+ break;
+ }
+ tLen = (size_t)ucGetByte(tStart, aucBuffer);
+ if (tLen != 0) {
+ NO_DBG_DEC(tCounter);
+ NO_DBG_STRN(aucBuffer + tStart + 1, tLen);
+ switch (tCounter) {
+ case 3:
+ szTitle = xmalloc(tLen + 1);
+ strncpy(szTitle,
+ (char *)aucBuffer + tStart + 1, tLen);
+ szTitle[tLen] = '\0';
+ break;
+ case 4:
+ szSubject = xmalloc(tLen + 1);
+ strncpy(szSubject,
+ (char *)aucBuffer + tStart + 1, tLen);
+ szSubject[tLen] = '\0';
+ break;
+ case 7:
+ szAuthor = xmalloc(tLen + 1);
+ strncpy(szAuthor,
+ (char *)aucBuffer + tStart + 1, tLen);
+ szAuthor[tLen] = '\0';
+ break;
+ default:
+ break;
+ }
+ }
+ tStart += tLen + 1;
+ }
+ aucBuffer = xfree(aucBuffer);
+
+ /* Third check the document properties */
+ ulBeginDocpInfo = ulGetLong(0x112, aucHeader); /* fcDop */
+ DBG_HEX(ulBeginDocpInfo);
+ tDocpInfoLen = (size_t)usGetWord(0x116, aucHeader); /* cbDop */
+ DBG_DEC(tDocpInfoLen);
+ if (tDocpInfoLen < 12) {
+ return;
+ }
+
+ aucBuffer = xmalloc(tDocpInfoLen);
+ if (!bReadBytes(aucBuffer, tDocpInfoLen, ulBeginDocpInfo, pFile)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ ulTmp = ulGetLong(0x14, aucBuffer); /* dttmCreated */
+ tCreateDtm = tConvertDTTM(ulTmp);
+ ulTmp = ulGetLong(0x18, aucBuffer); /* dttmRevised */
+ tLastSaveDtm = tConvertDTTM(ulTmp);
+ aucBuffer = xfree(aucBuffer);
+} /* end of vSet2SummaryInfo */
+
+/*
+ * vSetSummaryInfoOLE - set summary information from a Word 6+ file
+ */
+static void
+vSetSummaryInfoOLE(FILE *pFile, const pps_info_type *pPPS,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen)
+{
+ UCHAR *pucBuffer;
+
+ fail(pFile == NULL || pPPS == NULL);
+ fail(aulBBD == NULL || aulSBD == NULL);
+
+ /* Summary Information */
+ pucBuffer = pucAnalyseSummaryInfoHeader(pFile,
+ pPPS->tSummaryInfo.ulSB, pPPS->tSummaryInfo.ulSize,
+ aulBBD, tBBDLen, aulSBD, tSBDLen);
+ if (pucBuffer != NULL) {
+ vAnalyseSummaryInfo(pucBuffer);
+ pucBuffer = xfree(pucBuffer);
+ }
+
+ /* Document Summary Information */
+ pucBuffer = pucAnalyseSummaryInfoHeader(pFile,
+ pPPS->tDocSummaryInfo.ulSB, pPPS->tDocSummaryInfo.ulSize,
+ aulBBD, tBBDLen, aulSBD, tSBDLen);
+ if (pucBuffer != NULL) {
+ vAnalyseDocumentSummaryInfo(pucBuffer);
+ pucBuffer = xfree(pucBuffer);
+ }
+} /* end of vSetSummaryInfoOLE */
+
+/*
+ * vSet6SummaryInfo - set summary information from a Word 6/7 file
+ */
+void
+vSet6SummaryInfo(FILE *pFile, const pps_info_type *pPPS,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ const UCHAR *aucHeader)
+{
+ TRACE_MSG("vSet6SummaryInfo");
+
+ /* Header Information */
+ usLid = usGetWord(0x06, aucHeader); /* Language IDentification */
+ DBG_HEX(usLid);
+
+ /* Summery Information */
+ vSetSummaryInfoOLE(pFile, pPPS, aulBBD, tBBDLen, aulSBD, tSBDLen);
+} /* end of vSet6SummaryInfo */
+
+/*
+ * vSet8SummaryInfo - set summary information a Word 8/9/10 file
+ */
+void
+vSet8SummaryInfo(FILE *pFile, const pps_info_type *pPPS,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ const UCHAR *aucHeader)
+{
+ USHORT usTmp;
+
+ TRACE_MSG("vSet8SummaryInfo");
+
+ /* Header Information */
+ usTmp = usGetWord(0x0a, aucHeader);
+ if (usTmp & BIT(14)) {
+ /* Language IDentification Far East */
+ usLid = usGetWord(0x3c, aucHeader);
+ } else {
+ /* Language IDentification */
+ usLid = usGetWord(0x06, aucHeader);
+ }
+ DBG_HEX(usLid);
+
+ /* Summery Information */
+ vSetSummaryInfoOLE(pFile, pPPS, aulBBD, tBBDLen, aulSBD, tSBDLen);
+} /* end of vSet8SummaryInfo */
+
+/*
+ * szGetTitle - get the title field
+ */
+const char *
+szGetTitle(void)
+{
+ return szTitle;
+} /* end of szGetTitle */
+
+/*
+ * szGetSubject - get the subject field
+ */
+const char *
+szGetSubject(void)
+{
+ return szSubject;
+} /* end of szGetSubject */
+
+/*
+ * szGetAuthor - get the author field
+ */
+const char *
+szGetAuthor(void)
+{
+ return szAuthor;
+} /* end of szGetAuthor */
+
+/*
+ * szGetLastSaveDtm - get the last save date field
+ */
+const char *
+szGetLastSaveDtm(void)
+{
+ static char szTime[12];
+ struct tm *pTime;
+
+ if (tLastSaveDtm == (time_t)-1) {
+ return NULL;
+ }
+ pTime = localtime(&tLastSaveDtm);
+ if (pTime == NULL) {
+ return NULL;
+ }
+ sprintf(szTime, "%04d-%02d-%02d",
+ pTime->tm_year + 1900, pTime->tm_mon + 1, pTime->tm_mday);
+ return szTime;
+} /* end of szGetLastSaveDtm */
+
+/*
+ * szGetModDate - get the last save date field
+ */
+const char *
+szGetModDate(void)
+{
+ static char szTime[20];
+ struct tm *pTime;
+
+ if (tLastSaveDtm == (time_t)-1) {
+ return NULL;
+ }
+ pTime = localtime(&tLastSaveDtm);
+ if (pTime == NULL) {
+ return NULL;
+ }
+ sprintf(szTime, "D:%04d%02d%02d%02d%02d",
+ pTime->tm_year + 1900, pTime->tm_mon + 1, pTime->tm_mday,
+ pTime->tm_hour, pTime->tm_min);
+ return szTime;
+} /* end of szGetModDate */
+
+/*
+ * szGetCreationDate - get the last save date field
+ */
+const char *
+szGetCreationDate(void)
+{
+ static char szTime[20];
+ struct tm *pTime;
+
+ if (tCreateDtm == (time_t)-1) {
+ return NULL;
+ }
+ pTime = localtime(&tCreateDtm);
+ if (pTime == NULL) {
+ return NULL;
+ }
+ sprintf(szTime, "D:%04d%02d%02d%02d%02d",
+ pTime->tm_year + 1900, pTime->tm_mon + 1, pTime->tm_mday,
+ pTime->tm_hour, pTime->tm_min);
+ return szTime;
+} /* end of szGetCreationDate */
+
+/*
+ * szGetCompany - get the company field
+ */
+const char *
+szGetCompany(void)
+{
+ return szCompany;
+} /* end of szGetCompany */
+
+/*
+ * szGetLanguage - get de language field
+ */
+const char *
+szGetLanguage(void)
+{
+ if (usLid == (USHORT)-1) {
+ /* No Language IDentification */
+ return NULL;
+ }
+ if (usLid < 999) {
+ /* This is a Locale, not a Language IDentification */
+ DBG_DEC(usLid);
+ return NULL;
+ }
+
+ /* Exceptions to the general rule */
+ switch (usLid) {
+ case 0x0404: return "zh_TW"; /* Traditional Chinese */
+ case 0x0804: return "zh_CN"; /* Simplified Chinese */
+ case 0x0c04: return "zh_HK"; /* Hong Kong Chinese */
+ case 0x1004: return "zh_SG"; /* Singapore Chinese */
+ case 0x0807: return "de_CH"; /* Swiss German */
+ case 0x0409: return "en_US"; /* American English */
+ case 0x0809: return "en_GB"; /* British English */
+ case 0x0c09: return "en_AU"; /* Australian English */
+ case 0x080a: return "es_MX"; /* Mexican Spanish */
+ case 0x080c: return "fr_BE"; /* Belgian French */
+ case 0x0c0c: return "fr_CA"; /* Canadian French */
+ case 0x100c: return "fr_CH"; /* Swiss French */
+ case 0x0810: return "it_CH"; /* Swiss Italian */
+ case 0x0813: return "nl_BE"; /* Belgian Dutch */
+ case 0x0416: return "pt_BR"; /* Brazilian Portuguese */
+ case 0x081a:
+ case 0x0c1a: return "sr"; /* Serbian */
+ case 0x081d: return "sv_FI"; /* Finland Swedish */
+ default:
+ break;
+ }
+
+ /* The general rule */
+ switch (usLid & 0x00ff) {
+ case 0x01: return "ar"; /* Arabic */
+ case 0x02: return "bg"; /* Bulgarian */
+ case 0x03: return "ca"; /* Catalan */
+ case 0x04: return "zh"; /* Chinese */
+ case 0x05: return "cs"; /* Czech */
+ case 0x06: return "da"; /* Danish */
+ case 0x07: return "de"; /* German */
+ case 0x08: return "el"; /* Greek */
+ case 0x09: return "en"; /* English */
+ case 0x0a: return "es"; /* Spanish */
+ case 0x0b: return "fi"; /* Finnish */
+ case 0x0c: return "fr"; /* French */
+ case 0x0d: return "he"; /* Hebrew */
+ case 0x0e: return "hu"; /* Hungarian */
+ case 0x0f: return "is"; /* Icelandic */
+ case 0x10: return "it"; /* Italian */
+ case 0x11: return "ja"; /* Japanese */
+ case 0x12: return "ko"; /* Korean */
+ case 0x13: return "nl"; /* Dutch */
+ case 0x14: return "no"; /* Norwegian */
+ case 0x15: return "pl"; /* Polish */
+ case 0x16: return "pt"; /* Portuguese */
+ case 0x17: return "rm"; /* Rhaeto-Romance */
+ case 0x18: return "ro"; /* Romanian */
+ case 0x19: return "ru"; /* Russian */
+ case 0x1a: return "hr"; /* Croatian */
+ case 0x1b: return "sk"; /* Slovak */
+ case 0x1c: return "sq"; /* Albanian */
+ case 0x1d: return "sv"; /* Swedish */
+ case 0x1e: return "th"; /* Thai */
+ case 0x1f: return "tr"; /* Turkish */
+ case 0x20: return "ur"; /* Urdu */
+ case 0x21: return "id"; /* Indonesian */
+ case 0x22: return "uk"; /* Ukrainian */
+ case 0x23: return "be"; /* Belarusian */
+ case 0x24: return "sl"; /* Slovenian */
+ case 0x25: return "et"; /* Estonian */
+ case 0x26: return "lv"; /* Latvian */
+ case 0x27: return "lt"; /* Lithuanian */
+ case 0x29: return "fa"; /* Farsi */
+ case 0x2a: return "vi"; /* Viet Nam */
+ case 0x2b: return "hy"; /* Armenian */
+ case 0x2c: return "az"; /* Azeri */
+ case 0x2d: return "eu"; /* Basque */
+ case 0x2f: return "mk"; /* Macedonian */
+ case 0x36: return "af"; /* Afrikaans */
+ case 0x37: return "ka"; /* Georgian */
+ case 0x38: return "fo"; /* Faeroese */
+ case 0x39: return "hi"; /* Hindi */
+ case 0x3e: return "ms"; /* Malay */
+ case 0x3f: return "kk"; /* Kazakh */
+ default:
+ DBG_HEX(usLid);
+ DBG_FIXME();
+ return NULL;
+ }
+} /* end of szGetLanguage */
diff --git a/sys/src/cmd/aux/antiword/tabstop.c b/sys/src/cmd/aux/antiword/tabstop.c
new file mode 100755
index 000000000..604d94923
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/tabstop.c
@@ -0,0 +1,212 @@
+/*
+ * tabstops.c
+ * Copyright (C) 1999-2004 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Read the tab stop information from a MS Word file
+ */
+
+#include <stdio.h>
+#include "antiword.h"
+
+#define HALF_INCH 36000L /* In millipoints */
+
+static long lDefaultTabWidth = HALF_INCH;
+
+
+/*
+ * vSet0DefaultTabWidth -
+ */
+static void
+vSet0DefaultTabWidth(const UCHAR *aucHeader)
+{
+ USHORT usTmp;
+
+ fail(aucHeader == NULL);
+
+ usTmp = usGetWord(0x70, aucHeader); /* dxaTab */
+ DBG_DEC(usTmp);
+ lDefaultTabWidth = usTmp == 0 ? HALF_INCH : lTwips2MilliPoints(usTmp);
+ DBG_DEC(lDefaultTabWidth);
+} /* end of vSet0DefaultTabWidth */
+
+/*
+ * vSet2DefaultTabWidth -
+ */
+static void
+vSet2DefaultTabWidth(FILE *pFile, const UCHAR *aucHeader)
+{
+ UCHAR *aucBuffer;
+ ULONG ulBeginDocpInfo;
+ size_t tDocpInfoLen;
+ USHORT usTmp;
+
+ fail(pFile == NULL || aucHeader == NULL);
+
+ ulBeginDocpInfo = ulGetLong(0x112, aucHeader); /* fcDop */
+ DBG_HEX(ulBeginDocpInfo);
+ tDocpInfoLen = (size_t)usGetWord(0x116, aucHeader); /* cbDop */
+ DBG_DEC(tDocpInfoLen);
+ if (tDocpInfoLen < 12) {
+ DBG_MSG("No TAB information");
+ return;
+ }
+
+ aucBuffer = xmalloc(tDocpInfoLen);
+ if (!bReadBytes(aucBuffer, tDocpInfoLen, ulBeginDocpInfo, pFile)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ usTmp = usGetWord(0x0a, aucBuffer); /* dxaTab */
+ lDefaultTabWidth = usTmp == 0 ? HALF_INCH : lTwips2MilliPoints(usTmp);
+ DBG_DEC(lDefaultTabWidth);
+ aucBuffer = xfree(aucBuffer);
+} /* end of vSet2DefaultTabWidth */
+
+/*
+ * vSet6DefaultTabWidth -
+ */
+static void
+vSet6DefaultTabWidth(FILE *pFile, ULONG ulStartBlock,
+ const ULONG *aulBBD, size_t tBBDLen, const UCHAR *aucHeader)
+{
+ UCHAR *aucBuffer;
+ ULONG ulBeginDocpInfo;
+ size_t tDocpInfoLen;
+ USHORT usTmp;
+
+ ulBeginDocpInfo = ulGetLong(0x150, aucHeader); /* fcDop */
+ DBG_HEX(ulBeginDocpInfo);
+ tDocpInfoLen = (size_t)ulGetLong(0x154, aucHeader); /* lcbDop */
+ DBG_DEC(tDocpInfoLen);
+ if (tDocpInfoLen < 12) {
+ DBG_MSG("No TAB information");
+ return;
+ }
+
+ aucBuffer = xmalloc(tDocpInfoLen);
+ if (!bReadBuffer(pFile, ulStartBlock,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucBuffer, ulBeginDocpInfo, tDocpInfoLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ usTmp = usGetWord(0x0a, aucBuffer); /* dxaTab */
+ lDefaultTabWidth = usTmp == 0 ? HALF_INCH : lTwips2MilliPoints(usTmp);
+ DBG_DEC(lDefaultTabWidth);
+ aucBuffer = xfree(aucBuffer);
+} /* end of vSet6DefaultTabWidth */
+
+/*
+ * vSet8DefaultTabWidth -
+ */
+static void
+vSet8DefaultTabWidth(FILE *pFile, const pps_info_type *pPPS,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ const UCHAR *aucHeader)
+{
+ const ULONG *aulBlockDepot;
+ UCHAR *aucBuffer;
+ ULONG ulBeginDocpInfo;
+ size_t tDocpInfoLen, tBlockDepotLen, tBlockSize;
+ USHORT usTmp;
+
+ ulBeginDocpInfo = ulGetLong(0x192, aucHeader); /* fcDop */
+ DBG_HEX(ulBeginDocpInfo);
+ tDocpInfoLen = (size_t)ulGetLong(0x196, aucHeader); /* lcbDop */
+ DBG_DEC(tDocpInfoLen);
+ if (tDocpInfoLen < 12) {
+ DBG_MSG("No TAB information");
+ return;
+ }
+
+ DBG_DEC(pPPS->tTable.ulSB);
+ DBG_HEX(pPPS->tTable.ulSize);
+ if (pPPS->tTable.ulSize == 0) {
+ DBG_MSG("No TAB information");
+ return;
+ }
+
+ if (pPPS->tTable.ulSize < MIN_SIZE_FOR_BBD_USE) {
+ /* Use the Small Block Depot */
+ aulBlockDepot = aulSBD;
+ tBlockDepotLen = tSBDLen;
+ tBlockSize = SMALL_BLOCK_SIZE;
+ } else {
+ /* Use the Big Block Depot */
+ aulBlockDepot = aulBBD;
+ tBlockDepotLen = tBBDLen;
+ tBlockSize = BIG_BLOCK_SIZE;
+ }
+ aucBuffer = xmalloc(tDocpInfoLen);
+ if (!bReadBuffer(pFile, pPPS->tTable.ulSB,
+ aulBlockDepot, tBlockDepotLen, tBlockSize,
+ aucBuffer, ulBeginDocpInfo, tDocpInfoLen)) {
+ aucBuffer = xfree(aucBuffer);
+ return;
+ }
+ usTmp = usGetWord(0x0a, aucBuffer); /* dxaTab */
+ lDefaultTabWidth = usTmp == 0 ? HALF_INCH : lTwips2MilliPoints(usTmp);
+ DBG_DEC(lDefaultTabWidth);
+ aucBuffer = xfree(aucBuffer);
+} /* end of vSet8DefaultTabWidth */
+
+/*
+ * vSetDefaultTabWidth -
+ */
+void
+vSetDefaultTabWidth(FILE *pFile, const pps_info_type *pPPS,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ const UCHAR *aucHeader, int iWordVersion)
+{
+ fail(pFile == NULL && iWordVersion >= 1);
+ fail(pPPS == NULL && iWordVersion >= 6);
+ fail(aulBBD == NULL && tBBDLen != 0);
+ fail(aulSBD == NULL && tSBDLen != 0);
+ fail(aucHeader == NULL);
+
+ /* Reset to the default default value */
+ lDefaultTabWidth = HALF_INCH;
+
+ switch (iWordVersion) {
+ case 0:
+ vSet0DefaultTabWidth(aucHeader);
+ break;
+ case 1:
+ case 2:
+ vSet2DefaultTabWidth(pFile, aucHeader);
+ break;
+ case 4:
+ case 5:
+ break;
+ case 6:
+ case 7:
+ vSet6DefaultTabWidth(pFile, pPPS->tWordDocument.ulSB,
+ aulBBD, tBBDLen, aucHeader);
+ break;
+ case 8:
+ vSet8DefaultTabWidth(pFile, pPPS,
+ aulBBD, tBBDLen, aulSBD, tSBDLen, aucHeader);
+ break;
+ default:
+ werr(0, "Sorry, no TAB information");
+ break;
+ }
+} /* end of vSetDefaultTabWidth */
+
+#if 0
+/*
+ * lGetDefaultTabWidth - Get the default tabwidth in millipoints
+ */
+long
+lGetDefaultTabWidth(void)
+{
+ if (lDefaultTabWidth <= 0) {
+ DBG_DEC(lDefaultTabWidth);
+ return lTwips2MilliPoints(1);
+ }
+ return lDefaultTabWidth;
+} /* end of lGetDefaultTabWidth */
+#endif
diff --git a/sys/src/cmd/aux/antiword/text.c b/sys/src/cmd/aux/antiword/text.c
new file mode 100755
index 000000000..bd3dc9219
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/text.c
@@ -0,0 +1,182 @@
+/*
+ * text.c
+ * Copyright (C) 1999-2004 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Functions to deal with the Text format
+ *
+ */
+
+#include <string.h>
+#include "antiword.h"
+
+/* The character set */
+static encoding_type eEncoding = encoding_neutral;
+/* Current vertical position information */
+static long lYtopCurr = 0;
+/* Local representation of the non-breaking space */
+static UCHAR ucNbsp = 0;
+
+
+/*
+ * vPrologueTXT - set options and perform the Text initialization
+ */
+void
+vPrologueTXT(diagram_type *pDiag, const options_type *pOptions)
+{
+ fail(pDiag == NULL);
+ fail(pOptions == NULL);
+
+ eEncoding = pOptions->eEncoding;
+ pDiag->lXleft = 0;
+ pDiag->lYtop = 0;
+ lYtopCurr = 0;
+} /* end of vPrologueTXT */
+
+/*
+ * vEpilogueTXT - clean up after everything is done
+ */
+void
+vEpilogueTXT(FILE *pOutFile)
+{
+ fail(pOutFile == NULL);
+
+ fprintf(pOutFile, "\n");
+} /* end of vEpilogueTXT */
+
+/*
+ * vPrintTXT - print a Text string
+ */
+static void
+vPrintTXT(FILE *pFile, const char *szString, size_t tStringLength)
+{
+ const UCHAR *ucBytes;
+ size_t tCount;
+
+ fail(szString == NULL);
+
+ if (szString == NULL || szString[0] == '\0' || tStringLength == 0) {
+ return;
+ }
+
+ if (eEncoding == encoding_utf_8) {
+ fprintf(pFile, "%.*s", (int)tStringLength, szString);
+ return;
+ }
+
+ if (ucNbsp == 0) {
+ ucNbsp = ucGetNbspCharacter();
+ DBG_HEX_C(ucNbsp != 0xa0, ucNbsp);
+ }
+
+ ucBytes = (UCHAR *)szString;
+ for (tCount = 0; tCount < tStringLength ; tCount++) {
+ if (ucBytes[tCount] == ucNbsp) {
+ (void)putc(' ', pFile);
+ } else {
+ (void)putc(szString[tCount], pFile);
+ }
+ }
+} /* end of vPrintTXT */
+
+/*
+ * vMoveTo - move to the given X,Y coordinates
+ *
+ * Move the current position of the given diagram to its X,Y coordinates,
+ * start on a new page if needed
+ */
+static void
+vMoveTo(diagram_type *pDiag)
+{
+ int iCount, iNbr;
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+
+ if (pDiag->lYtop != lYtopCurr) {
+ iNbr = iDrawUnits2Char(pDiag->lXleft);
+ for (iCount = 0; iCount < iNbr; iCount++) {
+ (void)putc(FILLER_CHAR, pDiag->pOutFile);
+ }
+ lYtopCurr = pDiag->lYtop;
+ }
+} /* end of vMoveTo */
+
+/*
+ * vMove2NextLineTXT - move to the next line
+ */
+void
+vMove2NextLineTXT(diagram_type *pDiag)
+{
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+
+ pDiag->lYtop++;
+ (void)fprintf(pDiag->pOutFile, "\n");
+} /* end of vMove2NextLineTXT */
+
+/*
+ * vSubstringTXT - print a sub string
+ */
+void
+vSubstringTXT(diagram_type *pDiag,
+ const char *szString, size_t tStringLength, long lStringWidth)
+{
+ fail(pDiag == NULL || szString == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(pDiag->lXleft < 0);
+ fail(tStringLength != strlen(szString));
+
+ if (szString[0] == '\0' || tStringLength == 0) {
+ return;
+ }
+
+ vMoveTo(pDiag);
+ vPrintTXT(pDiag->pOutFile, szString, tStringLength);
+ pDiag->lXleft += lStringWidth;
+} /* end of vSubstringTXT */
+
+/*
+ * Create an start of paragraph by moving the y-top mark
+ */
+void
+vStartOfParagraphTXT(diagram_type *pDiag, long lBeforeIndentation)
+{
+ fail(pDiag == NULL);
+ fail(lBeforeIndentation < 0);
+
+ if (lBeforeIndentation >= lTwips2MilliPoints(HEADING_GAP)) {
+ /* A large gap is replaced by an empty line */
+ vMove2NextLineTXT(pDiag);
+ }
+} /* end of vStartOfParagraphTXT */
+
+/*
+ * Create an end of paragraph by moving the y-top mark
+ */
+void
+vEndOfParagraphTXT(diagram_type *pDiag, long lAfterIndentation)
+{
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(lAfterIndentation < 0);
+
+ if (pDiag->lXleft > 0) {
+ /* To the start of the line */
+ vMove2NextLineTXT(pDiag);
+ }
+
+ if (lAfterIndentation >= lTwips2MilliPoints(HEADING_GAP)) {
+ /* A large gap is replaced by an empty line */
+ vMove2NextLineTXT(pDiag);
+ }
+} /* end of vEndOfParagraphTXT */
+
+/*
+ * Create an end of page
+ */
+void
+vEndOfPageTXT(diagram_type *pDiag, long lAfterIndentation)
+{
+ vEndOfParagraphTXT(pDiag, lAfterIndentation);
+} /* end of vEndOfPageTXT */
diff --git a/sys/src/cmd/aux/antiword/unix.c b/sys/src/cmd/aux/antiword/unix.c
new file mode 100755
index 000000000..3da3964cc
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/unix.c
@@ -0,0 +1,45 @@
+/*
+ * unix.c
+ * Copyright (C) 1998-2000 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Unix approximations of RISC-OS functions
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include "antiword.h"
+
+
+/*
+ * werr - write an error message and exit if needed
+ */
+void
+werr(int iFatal, const char *szFormat, ...)
+{
+ va_list tArg;
+
+ va_start(tArg, szFormat);
+ (void)vfprintf(stderr, szFormat, tArg);
+ va_end(tArg);
+ fprintf(stderr, "\n");
+ switch (iFatal) {
+ case 0: /* The message is just a warning, so no exit */
+ return;
+ case 1: /* Fatal error with a standard exit */
+ exit(EXIT_FAILURE);
+ default: /* Fatal error with a non-standard exit */
+ exit(iFatal);
+ }
+} /* end of werr */
+
+void
+Hourglass_On(void)
+{
+} /* end of Hourglass_On */
+
+void
+Hourglass_Off(void)
+{
+} /* end of Hourglass_Off */
diff --git a/sys/src/cmd/aux/antiword/utf8.c b/sys/src/cmd/aux/antiword/utf8.c
new file mode 100755
index 000000000..2cc219143
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/utf8.c
@@ -0,0 +1,260 @@
+/*
+ * utf8.c
+ * Copyright (C) 2001-2004 A.J. van Os; Released under GPL
+ *
+ *====================================================================
+ * This part of the software is based on:
+ * An implementation of wcwidth() as defined in
+ * "The Single UNIX Specification, Version 2, The Open Group, 1997"
+ * <http://www.UNIX-systems.org/online.html>
+ * Markus Kuhn -- 2001-01-12 -- public domain
+ *====================================================================
+ * The credit should go to him, but all the bugs are mine.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "antiword.h"
+
+struct interval {
+ USHORT first;
+ USHORT last;
+};
+/* Sorted list of non-overlapping intervals of non-spacing characters */
+static const struct interval combining[] = {
+ { 0x0300, 0x034E }, { 0x0360, 0x0362 }, { 0x0483, 0x0486 },
+ { 0x0488, 0x0489 }, { 0x0591, 0x05A1 }, { 0x05A3, 0x05B9 },
+ { 0x05BB, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
+ { 0x05C4, 0x05C4 }, { 0x064B, 0x0655 }, { 0x0670, 0x0670 },
+ { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
+ { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
+ { 0x07A6, 0x07B0 }, { 0x0901, 0x0902 }, { 0x093C, 0x093C },
+ { 0x0941, 0x0948 }, { 0x094D, 0x094D }, { 0x0951, 0x0954 },
+ { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, { 0x09BC, 0x09BC },
+ { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 },
+ { 0x0A02, 0x0A02 }, { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 },
+ { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, { 0x0A70, 0x0A71 },
+ { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, { 0x0AC1, 0x0AC5 },
+ { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, { 0x0B01, 0x0B01 },
+ { 0x0B3C, 0x0B3C }, { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 },
+ { 0x0B4D, 0x0B4D }, { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 },
+ { 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 },
+ { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 },
+ { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
+ { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, { 0x0DCA, 0x0DCA },
+ { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, { 0x0E31, 0x0E31 },
+ { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, { 0x0EB1, 0x0EB1 },
+ { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, { 0x0EC8, 0x0ECD },
+ { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 },
+ { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, { 0x0F80, 0x0F84 },
+ { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, { 0x0F99, 0x0FBC },
+ { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, { 0x1032, 0x1032 },
+ { 0x1036, 0x1037 }, { 0x1039, 0x1039 }, { 0x1058, 0x1059 },
+ { 0x1160, 0x11FF }, { 0x17B7, 0x17BD }, { 0x17C6, 0x17C6 },
+ { 0x17C9, 0x17D3 }, { 0x180B, 0x180E }, { 0x18A9, 0x18A9 },
+ { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x206A, 0x206F },
+ { 0x20D0, 0x20E3 }, { 0x302A, 0x302F }, { 0x3099, 0x309A },
+ { 0xFB1E, 0xFB1E }, { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF },
+ { 0xFFF9, 0xFFFB }
+};
+
+/* Auxiliary function for binary search in interval table */
+static BOOL
+bIsZeroWidthChar(ULONG ucs)
+{
+ int low = 0;
+ int high = elementsof(combining) - 1;
+ int mid;
+
+ if (ucs < (ULONG)combining[low].first ||
+ ucs > (ULONG)combining[high].last) {
+ return FALSE;
+ }
+
+ while (high >= low) {
+ mid = (low + high) / 2;
+ if (ucs > (ULONG)combining[mid].last) {
+ low = mid + 1;
+ } else if (ucs < (ULONG)combining[mid].first) {
+ high = mid - 1;
+ } else {
+ return TRUE;
+ }
+ }
+ return FALSE;
+} /* end of bIsZeroWidthChar */
+
+/* The following functions define the column width of an ISO 10646
+ * character as follows:
+ *
+ * - The null character (U+0000) has a column width of 0.
+ *
+ * - Other C0/C1 control characters and DEL will lead to a return
+ * value of -1.
+ *
+ * - Non-spacing and enclosing combining characters (general
+ * category code Mn or Me in the Unicode database) have a
+ * column width of 0.
+ *
+ * - Other format characters (general category code Cf in the Unicode
+ * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
+ *
+ * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
+ * have a column width of 0.
+ *
+ * - Spacing characters in the East Asian Wide (W) or East Asian
+ * FullWidth (F) category as defined in Unicode Technical
+ * Report #11 have a column width of 2.
+ *
+ * - All remaining characters (including all printable
+ * ISO 8859-1 and WGL4 characters, Unicode control characters,
+ * etc.) have a column width of 1.
+ *
+ * This implementation assumes that all characters are encoded
+ * in ISO 10646.
+ *
+ * This function is not named wcwidth() to prevent name clashes
+ */
+static int
+iWcWidth(ULONG ucs)
+{
+ /* Test for 8-bit control characters */
+ if (ucs == 0) {
+ return 0;
+ }
+ if (ucs < 0x20 || (ucs >= 0x7f && ucs < 0xa0)) {
+ NO_DBG_HEX(ucs);
+ return -1;
+ }
+
+ /* Binary search in table of non-spacing characters */
+ if (bIsZeroWidthChar(ucs)) {
+ return 0;
+ }
+
+ /* Ucs is not a combining or C0/C1 control character */
+
+ return 1 +
+ (ucs >= 0x1100 &&
+ (ucs <= 0x115f || /* Hangul Jamo init. consonants */
+ (ucs >= 0x2e80 && ucs <= 0xa4cf && (ucs & ~0x0011) != 0x300a &&
+ ucs != 0x303f) || /* CJK ... Yi */
+ (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
+ (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
+ (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
+ (ucs >= 0xff00 && ucs <= 0xff5f) || /* Fullwidth Forms */
+ (ucs >= 0xffe0 && ucs <= 0xffe6) ||
+ (ucs >= 0x20000 && ucs <= 0x2ffff)));
+} /* end of iWcWidth */
+
+/*
+ * utf8_to_ucs - convert from UTF-8 to UCS
+ *
+ * Returns the UCS character,
+ * Fills in the number of bytes in the UTF-8 character
+ */
+static ULONG
+utf8_to_ucs(const char *p, int iStrLen, int *piUtfLen)
+{
+ ULONG ulUcs;
+ int iIndex, iCharLen;
+
+ fail(p == NULL || piUtfLen == NULL);
+ fail(iStrLen < 1);
+
+ ulUcs = (ULONG)(UCHAR)p[0];
+
+ if (ulUcs < 0x80) {
+ *piUtfLen = 1;
+ return ulUcs;
+ }
+
+ if (ulUcs < 0xe0){
+ iCharLen = 2;
+ ulUcs &= 0x1f;
+ } else if (ulUcs < 0xf0){
+ iCharLen = 3;
+ ulUcs &= 0x0f;
+ } else if (ulUcs < 0xf8){
+ iCharLen = 4;
+ ulUcs &= 0x07;
+ } else if (ulUcs < 0xfc){
+ iCharLen = 5;
+ ulUcs &= 0x03;
+ } else {
+ iCharLen = 6;
+ ulUcs &= 0x01;
+ }
+ for (iIndex = 1; iIndex < iCharLen; iIndex++) {
+ ulUcs <<= 6;
+ if (iIndex < iStrLen) {
+ ulUcs |= (ULONG)(UCHAR)p[iIndex] & 0x3f;
+ }
+ }
+ *piUtfLen = iCharLen;
+ return ulUcs;
+} /* end of utf8_to_ucs */
+
+/*
+ * utf8_strwidth - compute the string width of an UTF-8 string
+ *
+ * Returns the string width in columns
+ */
+long
+utf8_strwidth(const char *pcString, size_t tNumchars)
+{
+ ULONG ulUcs;
+ long lTotal;
+ int iToGo, iWidth, iUtflen;
+
+ fail(pcString == NULL || tNumchars > (size_t)INT_MAX);
+
+ lTotal = 0;
+ iToGo = (int)tNumchars;
+
+ while (iToGo > 0 && *pcString != '\0') {
+ ulUcs = utf8_to_ucs(pcString, iToGo, &iUtflen);
+ iWidth = iWcWidth(ulUcs);
+ if (iWidth > 0) {
+ lTotal += iWidth;
+ }
+ pcString += iUtflen;
+ iToGo -= iUtflen;
+ }
+ NO_DBG_DEC(lTotal);
+ return lTotal;
+} /* end of utf8_strwidth */
+
+/*
+ * utf8_chrlength - get the number of bytes in an UTF-8 character
+ *
+ * Returns the number of bytes
+ */
+int
+utf8_chrlength(const char *p)
+{
+ int iUtflen;
+
+ fail(p == NULL);
+
+ iUtflen = -1; /* Just to make sure */
+ (void)utf8_to_ucs(p, INT_MAX, &iUtflen);
+ NO_DBG_DEC(iUtflen);
+ return iUtflen;
+} /* end of utf8_chrlength */
+
+/*
+ * is_locale_utf8 - return TRUE if the locale is UTF-8
+ */
+BOOL
+is_locale_utf8(void)
+{
+ char szCodeset[20];
+
+ szCodeset[0] = '\0';
+ if (!bGetNormalizedCodeset(szCodeset, sizeof(szCodeset), NULL)) {
+ return FALSE;
+ }
+ DBG_MSG(szCodeset);
+ return STREQ(szCodeset, "utf8");
+} /* end of is_locale_utf8 */
diff --git a/sys/src/cmd/aux/antiword/version.h b/sys/src/cmd/aux/antiword/version.h
new file mode 100755
index 000000000..01ed70979
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/version.h
@@ -0,0 +1,37 @@
+/*
+ * version.h
+ * Copyright (C) 1998-2005 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Version and release information
+ */
+
+#if !defined(__version_h)
+#define __version_h 1
+
+/* Strings for the info box */
+#define PURPOSESTRING "Display MS-Word files"
+
+#if defined(__riscos)
+#define AUTHORSTRING "© 1998-2005 Adri van Os"
+#else
+#define AUTHORSTRING "(C) 1998-2005 Adri van Os"
+#endif /* __riscos */
+
+#define VERSIONSTRING "0.37 (21 Oct 2005)"
+
+#if defined(__dos)
+#if defined(__DJGPP__)
+#define VERSIONSTRING2 " # 32-bit Protected Mode"
+#else
+#define VERSIONSTRING2 " # 16-bit Real Mode"
+#endif /* __DJGPP__ */
+#endif /* __dos */
+
+#if defined(DEBUG)
+#define STATUSSTRING "DEBUG version"
+#else
+#define STATUSSTRING "GNU General Public License"
+#endif /* DEBUG */
+
+#endif /* __version_h */
diff --git a/sys/src/cmd/aux/antiword/word2text.c b/sys/src/cmd/aux/antiword/word2text.c
new file mode 100755
index 000000000..62b8964c8
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/word2text.c
@@ -0,0 +1,1505 @@
+/*
+ * word2text.c
+ * Copyright (C) 1998-2005 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * MS Word to "text" functions
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#if defined(__riscos)
+#include "DeskLib:Hourglass.h"
+#include "drawfile.h"
+#endif /* __riscos */
+#include "antiword.h"
+
+
+#define INITIAL_SIZE 40
+#define EXTENTION_SIZE 20
+
+
+/* Macros to make sure all such statements will be identical */
+#define OUTPUT_LINE() \
+ do {\
+ vAlign2Window(pDiag, pAnchor, lWidthMax, ucAlignment);\
+ TRACE_MSG("after vAlign2Window");\
+ pAnchor = pStartNewOutput(pAnchor, NULL);\
+ pOutput = pAnchor;\
+ } while(0)
+
+#define RESET_LINE() \
+ do {\
+ pAnchor = pStartNewOutput(pAnchor, NULL);\
+ pOutput = pAnchor;\
+ } while(0)
+
+#if defined(__riscos)
+/* Length of the document in characters */
+static ULONG ulDocumentLength;
+/* Number of characters processed so far */
+static ULONG ulCharCounter;
+static int iCurrPct, iPrevPct;
+#endif /* __riscos */
+/* The document is in the format belonging to this version of Word */
+static int iWordVersion = -1;
+/* Special treatment for files from Word 4/5/6 on an Apple Macintosh */
+static BOOL bOldMacFile = FALSE;
+/* Section Information */
+static const section_block_type *pSection = NULL;
+static const section_block_type *pSectionNext = NULL;
+/* All the (command line) options */
+static options_type tOptions;
+/* Needed for reading a complete table row */
+static const row_block_type *pRowInfo = NULL;
+static BOOL bStartRow = FALSE;
+static BOOL bEndRowNorm = FALSE;
+static BOOL bEndRowFast = FALSE;
+static BOOL bIsTableRow = FALSE;
+/* Index of the next style and font information */
+static USHORT usIstdNext = ISTD_NORMAL;
+/* Needed for finding the start of a style */
+static const style_block_type *pStyleInfo = NULL;
+static style_block_type tStyleNext;
+static BOOL bStartStyle = FALSE;
+static BOOL bStartStyleNext = FALSE;
+/* Needed for finding the start of a font */
+static const font_block_type *pFontInfo = NULL;
+static font_block_type tFontNext;
+static BOOL bStartFont = FALSE;
+static BOOL bStartFontNext = FALSE;
+/* Needed for finding an image */
+static ULONG ulFileOffsetImage = FC_INVALID;
+
+
+/*
+ * vUpdateCounters - Update the counters for the hourglass
+ */
+static void
+vUpdateCounters(void)
+{
+#if defined(__riscos)
+ ulCharCounter++;
+ iCurrPct = (int)((ulCharCounter * 100) / ulDocumentLength);
+ if (iCurrPct != iPrevPct) {
+ Hourglass_Percentage(iCurrPct);
+ iPrevPct = iCurrPct;
+ }
+#endif /* __riscos */
+} /* end of vUpdateCounters */
+
+/*
+ * bOutputContainsText - see if the output contains more than white space
+ */
+BOOL
+bOutputContainsText(const output_type *pAnchor)
+{
+ const output_type *pCurr;
+ size_t tIndex;
+
+ fail(pAnchor == NULL);
+
+ for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
+ fail(pCurr->lStringWidth < 0);
+ for (tIndex = 0; tIndex < pCurr->tNextFree; tIndex++) {
+ if (isspace((int)(UCHAR)pCurr->szStorage[tIndex])) {
+ continue;
+ }
+#if defined(DEBUG)
+ if (pCurr->szStorage[tIndex] == FILLER_CHAR) {
+ continue;
+ }
+#endif /* DEBUG */
+ return TRUE;
+ }
+ }
+ return FALSE;
+} /* end of bOutputContainsText */
+
+/*
+ * lTotalStringWidth - compute the total width of the output string
+ */
+static long
+lTotalStringWidth(const output_type *pAnchor)
+{
+ const output_type *pCurr;
+ long lTotal;
+
+ lTotal = 0;
+ for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
+ DBG_DEC_C(pCurr->lStringWidth < 0, pCurr->lStringWidth);
+ fail(pCurr->lStringWidth < 0);
+ lTotal += pCurr->lStringWidth;
+ }
+ return lTotal;
+} /* end of lTotalStringWidth */
+
+/*
+ * vStoreByte - store one byte
+ */
+static void
+vStoreByte(UCHAR ucChar, output_type *pOutput)
+{
+ fail(pOutput == NULL);
+
+ if (ucChar == 0) {
+ pOutput->szStorage[pOutput->tNextFree] = '\0';
+ return;
+ }
+
+ while (pOutput->tNextFree + 2 > pOutput->tStorageSize) {
+ pOutput->tStorageSize += EXTENTION_SIZE;
+ pOutput->szStorage = xrealloc(pOutput->szStorage,
+ pOutput->tStorageSize);
+ }
+ pOutput->szStorage[pOutput->tNextFree] = (char)ucChar;
+ pOutput->szStorage[pOutput->tNextFree + 1] = '\0';
+ pOutput->tNextFree++;
+} /* end of vStoreByte */
+
+/*
+ * vStoreChar - store a character as one or more bytes
+ */
+static void
+vStoreChar(ULONG ulChar, BOOL bChangeAllowed, output_type *pOutput)
+{
+ char szResult[4];
+ size_t tIndex, tLen;
+
+ fail(pOutput == NULL);
+
+ if (tOptions.eEncoding == encoding_utf_8 && bChangeAllowed) {
+ DBG_HEX_C(ulChar > 0xffff, ulChar);
+ fail(ulChar > 0xffff);
+ tLen = tUcs2Utf8(ulChar, szResult, sizeof(szResult));
+ for (tIndex = 0; tIndex < tLen; tIndex++) {
+ vStoreByte((UCHAR)szResult[tIndex], pOutput);
+ }
+ } else {
+ DBG_HEX_C(ulChar > 0xff, ulChar);
+ fail(ulChar > 0xff);
+ vStoreByte((UCHAR)ulChar, pOutput);
+ tLen = 1;
+ }
+ pOutput->lStringWidth += lComputeStringWidth(
+ pOutput->szStorage + pOutput->tNextFree - tLen,
+ tLen,
+ pOutput->tFontRef,
+ pOutput->usFontSize);
+} /* end of vStoreChar */
+
+/*
+ * vStoreCharacter - store one character
+ */
+static void
+vStoreCharacter(ULONG ulChar, output_type *pOutput)
+{
+ vStoreChar(ulChar, TRUE, pOutput);
+} /* end of vStoreCharacter */
+
+/*
+ * vStoreString - store a string
+ */
+static void
+vStoreString(const char *szString, size_t tStringLength, output_type *pOutput)
+{
+ size_t tIndex;
+
+ fail(szString == NULL || pOutput == NULL);
+
+ for (tIndex = 0; tIndex < tStringLength; tIndex++) {
+ vStoreCharacter((ULONG)(UCHAR)szString[tIndex], pOutput);
+ }
+} /* end of vStoreString */
+
+/*
+ * vStoreNumberAsDecimal - store a number as a decimal number
+ */
+static void
+vStoreNumberAsDecimal(UINT uiNumber, output_type *pOutput)
+{
+ size_t tLen;
+ char szString[3 * sizeof(UINT) + 1];
+
+ fail(uiNumber == 0);
+ fail(pOutput == NULL);
+
+ tLen = (size_t)sprintf(szString, "%u", uiNumber);
+ vStoreString(szString, tLen, pOutput);
+} /* end of vStoreNumberAsDecimal */
+
+/*
+ * vStoreNumberAsRoman - store a number as a roman numerical
+ */
+static void
+vStoreNumberAsRoman(UINT uiNumber, output_type *pOutput)
+{
+ size_t tLen;
+ char szString[15];
+
+ fail(uiNumber == 0);
+ fail(pOutput == NULL);
+
+ tLen = tNumber2Roman(uiNumber, FALSE, szString);
+ vStoreString(szString, tLen, pOutput);
+} /* end of vStoreNumberAsRoman */
+
+/*
+ * vStoreStyle - store a style
+ */
+static void
+vStoreStyle(diagram_type *pDiag, output_type *pOutput,
+ const style_block_type *pStyle)
+{
+ size_t tLen;
+ char szString[120];
+
+ fail(pDiag == NULL);
+ fail(pOutput == NULL);
+ fail(pStyle == NULL);
+
+ if (tOptions.eConversionType == conversion_xml) {
+ vSetHeaders(pDiag, pStyle->usIstd);
+ } else {
+ tLen = tStyle2Window(szString, sizeof(szString),
+ pStyle, pSection);
+ vStoreString(szString, tLen, pOutput);
+ }
+} /* end of vStoreStyle */
+
+/*
+ * vPutIndentation - output the specified amount of indentation
+ */
+static void
+vPutIndentation(diagram_type *pDiag, output_type *pOutput,
+ BOOL bNoMarks, BOOL bFirstLine,
+ UINT uiListNumber, UCHAR ucNFC, const char *szListChar,
+ long lLeftIndentation, long lLeftIndentation1)
+{
+ long lWidth;
+ size_t tIndex, tNextFree;
+ char szLine[30];
+
+ fail(pDiag == NULL);
+ fail(pOutput == NULL);
+ fail(szListChar == NULL);
+ fail(lLeftIndentation < 0);
+
+ if (tOptions.eConversionType == conversion_xml) {
+ /* XML does its own indentation at rendering time */
+ return;
+ }
+
+ if (bNoMarks) {
+ if (bFirstLine) {
+ lLeftIndentation += lLeftIndentation1;
+ }
+ if (lLeftIndentation < 0) {
+ lLeftIndentation = 0;
+ }
+ vSetLeftIndentation(pDiag, lLeftIndentation);
+ return;
+ }
+ if (lLeftIndentation <= 0) {
+ DBG_HEX_C(ucNFC != 0x00, ucNFC);
+ vSetLeftIndentation(pDiag, 0);
+ return;
+ }
+
+#if defined(DEBUG)
+ if (tOptions.eEncoding == encoding_utf_8) {
+ fail(strlen(szListChar) > 3);
+ } else {
+ DBG_HEX_C(iscntrl((int)szListChar[0]), szListChar[0]);
+ fail(iscntrl((int)szListChar[0]));
+ fail(szListChar[1] != '\0');
+ }
+#endif /* DEBUG */
+
+ switch (ucNFC) {
+ case LIST_ARABIC_NUM:
+ case LIST_NUMBER_TXT:
+ tNextFree = (size_t)sprintf(szLine, "%u", uiListNumber);
+ break;
+ case LIST_UPPER_ROMAN:
+ case LIST_LOWER_ROMAN:
+ tNextFree = tNumber2Roman(uiListNumber,
+ ucNFC == LIST_UPPER_ROMAN, szLine);
+ break;
+ case LIST_UPPER_ALPHA:
+ case LIST_LOWER_ALPHA:
+ tNextFree = tNumber2Alpha(uiListNumber,
+ ucNFC == LIST_UPPER_ALPHA, szLine);
+ break;
+ case LIST_ORDINAL_NUM:
+ case LIST_ORDINAL_TXT:
+ if (uiListNumber % 10 == 1 && uiListNumber != 11) {
+ tNextFree =
+ (size_t)sprintf(szLine, "%ust", uiListNumber);
+ } else if (uiListNumber % 10 == 2 && uiListNumber != 12) {
+ tNextFree =
+ (size_t)sprintf(szLine, "%und", uiListNumber);
+ } else if (uiListNumber % 10 == 3 && uiListNumber != 13) {
+ tNextFree =
+ (size_t)sprintf(szLine, "%urd", uiListNumber);
+ } else {
+ tNextFree =
+ (size_t)sprintf(szLine, "%uth", uiListNumber);
+ }
+ break;
+ case LIST_OUTLINE_NUM:
+ tNextFree = (size_t)sprintf(szLine, "%02u", uiListNumber);
+ break;
+ case LIST_SPECIAL:
+ case LIST_SPECIAL2:
+ case LIST_BULLETS:
+ tNextFree = 0;
+ break;
+ default:
+ DBG_HEX(ucNFC);
+ DBG_FIXME();
+ tNextFree = (size_t)sprintf(szLine, "%u", uiListNumber);
+ break;
+ }
+ tNextFree += (size_t)sprintf(szLine + tNextFree, "%.3s", szListChar);
+ szLine[tNextFree++] = ' ';
+ szLine[tNextFree] = '\0';
+ lWidth = lComputeStringWidth(szLine, tNextFree,
+ pOutput->tFontRef, pOutput->usFontSize);
+ lLeftIndentation -= lWidth;
+ if (lLeftIndentation < 0) {
+ lLeftIndentation = 0;
+ }
+ vSetLeftIndentation(pDiag, lLeftIndentation);
+ for (tIndex = 0; tIndex < tNextFree; tIndex++) {
+ vStoreChar((ULONG)(UCHAR)szLine[tIndex], FALSE, pOutput);
+ }
+} /* end of vPutIndentation */
+
+/*
+ * vPutSeparatorLine - output a separator line
+ *
+ * A separator line is a horizontal line two inches long.
+ * Two inches equals 144000 millipoints.
+ */
+static void
+vPutSeparatorLine(output_type *pOutput)
+{
+ long lCharWidth;
+ int iCounter, iChars;
+ char szOne[2];
+
+ fail(pOutput == NULL);
+
+ szOne[0] = OUR_EM_DASH;
+ szOne[1] = '\0';
+ lCharWidth = lComputeStringWidth(szOne, 1,
+ pOutput->tFontRef, pOutput->usFontSize);
+ NO_DBG_DEC(lCharWidth);
+ iChars = (int)((144000 + lCharWidth / 2) / lCharWidth);
+ NO_DBG_DEC(iChars);
+ for (iCounter = 0; iCounter < iChars; iCounter++) {
+ vStoreCharacter((ULONG)(UCHAR)OUR_EM_DASH, pOutput);
+ }
+} /* end of vPutSeparatorLine */
+
+/*
+ * pStartNextOutput - start the next output record
+ *
+ * returns a pointer to the next record
+ */
+static output_type *
+pStartNextOutput(output_type *pCurrent)
+{
+ output_type *pNew;
+
+ TRACE_MSG("pStartNextOutput");
+
+ if (pCurrent->tNextFree == 0) {
+ /* The current record is empty, re-use */
+ fail(pCurrent->szStorage[0] != '\0');
+ fail(pCurrent->lStringWidth != 0);
+ return pCurrent;
+ }
+ /* The current record is in use, make a new one */
+ pNew = xmalloc(sizeof(*pNew));
+ pCurrent->pNext = pNew;
+ pNew->tStorageSize = INITIAL_SIZE;
+ pNew->szStorage = xmalloc(pNew->tStorageSize);
+ pNew->szStorage[0] = '\0';
+ pNew->tNextFree = 0;
+ pNew->lStringWidth = 0;
+ pNew->ucFontColor = FONT_COLOR_DEFAULT;
+ pNew->usFontStyle = FONT_REGULAR;
+ pNew->tFontRef = (drawfile_fontref)0;
+ pNew->usFontSize = DEFAULT_FONT_SIZE;
+ pNew->pPrev = pCurrent;
+ pNew->pNext = NULL;
+ return pNew;
+} /* end of pStartNextOutput */
+
+/*
+ * pStartNewOutput
+ */
+static output_type *
+pStartNewOutput(output_type *pAnchor, output_type *pLeftOver)
+{
+ output_type *pCurr, *pNext;
+ USHORT usFontStyle, usFontSize;
+ drawfile_fontref tFontRef;
+ UCHAR ucFontColor;
+
+ TRACE_MSG("pStartNewOutput");
+
+ ucFontColor = FONT_COLOR_DEFAULT;
+ usFontStyle = FONT_REGULAR;
+ tFontRef = (drawfile_fontref)0;
+ usFontSize = DEFAULT_FONT_SIZE;
+ /* Free the old output space */
+ pCurr = pAnchor;
+ while (pCurr != NULL) {
+ TRACE_MSG("Free the old output space");
+ pNext = pCurr->pNext;
+ pCurr->szStorage = xfree(pCurr->szStorage);
+ if (pCurr->pNext == NULL) {
+ ucFontColor = pCurr->ucFontColor;
+ usFontStyle = pCurr->usFontStyle;
+ tFontRef = pCurr->tFontRef;
+ usFontSize = pCurr->usFontSize;
+ }
+ pCurr = xfree(pCurr);
+ pCurr = pNext;
+ }
+ if (pLeftOver == NULL) {
+ /* Create new output space */
+ TRACE_MSG("Create new output space");
+ pLeftOver = xmalloc(sizeof(*pLeftOver));
+ pLeftOver->tStorageSize = INITIAL_SIZE;
+ NO_DBG_DEC(pLeftOver->tStorageSize);
+ TRACE_MSG("before 2nd xmalloc");
+ pLeftOver->szStorage = xmalloc(pLeftOver->tStorageSize);
+ TRACE_MSG("after 2nd xmalloc");
+ pLeftOver->szStorage[0] = '\0';
+ pLeftOver->tNextFree = 0;
+ pLeftOver->lStringWidth = 0;
+ pLeftOver->ucFontColor = ucFontColor;
+ pLeftOver->usFontStyle = usFontStyle;
+ pLeftOver->tFontRef = tFontRef;
+ pLeftOver->usFontSize = usFontSize;
+ pLeftOver->pPrev = NULL;
+ pLeftOver->pNext = NULL;
+ }
+ fail(!bCheckDoubleLinkedList(pLeftOver));
+ return pLeftOver;
+} /* end of pStartNewOutput */
+
+/*
+ * ulGetChar - get the next character from the specified list
+ *
+ * returns the next character of EOF
+ */
+static ULONG
+ulGetChar(FILE *pFile, list_id_enum eListID)
+{
+ const font_block_type *pCurr;
+ ULONG ulChar, ulFileOffset, ulCharPos;
+ row_info_enum eRowInfo;
+ USHORT usChar, usPropMod;
+ BOOL bSkip;
+
+ fail(pFile == NULL);
+
+ pCurr = pFontInfo;
+ bSkip = FALSE;
+ for (;;) {
+ usChar = usNextChar(pFile, eListID,
+ &ulFileOffset, &ulCharPos, &usPropMod);
+ if (usChar == (USHORT)EOF) {
+ return (ULONG)EOF;
+ }
+
+ vUpdateCounters();
+
+ eRowInfo = ePropMod2RowInfo(usPropMod, iWordVersion);
+ if (!bStartRow) {
+#if 0
+ bStartRow = eRowInfo == found_a_cell ||
+ (pRowInfo != NULL &&
+ ulFileOffset == pRowInfo->ulFileOffsetStart &&
+ eRowInfo != found_not_a_cell);
+#else
+ bStartRow = pRowInfo != NULL &&
+ ulFileOffset == pRowInfo->ulFileOffsetStart;
+#endif
+ NO_DBG_HEX_C(bStartRow, pRowInfo->ulFileOffsetStart);
+ }
+ if (!bEndRowNorm) {
+#if 0
+ bEndRow = eRowInfo == found_end_of_row ||
+ (pRowInfo != NULL &&
+ ulFileOffset == pRowInfo->ulFileOffsetEnd &&
+ eRowInfo != found_not_end_of_row);
+#else
+ bEndRowNorm = pRowInfo != NULL &&
+ ulFileOffset == pRowInfo->ulFileOffsetEnd;
+#endif
+ NO_DBG_HEX_C(bEndRowNorm, pRowInfo->ulFileOffsetEnd);
+ }
+ if (!bEndRowFast) {
+ bEndRowFast = eRowInfo == found_end_of_row;
+ NO_DBG_HEX_C(bEndRowFast, pRowInfo->ulFileOffsetEnd);
+ }
+
+ if (!bStartStyle) {
+ bStartStyle = pStyleInfo != NULL &&
+ ulFileOffset == pStyleInfo->ulFileOffset;
+ NO_DBG_HEX_C(bStartStyle, ulFileOffset);
+ }
+ if (pCurr != NULL && ulFileOffset == pCurr->ulFileOffset) {
+ bStartFont = TRUE;
+ NO_DBG_HEX(ulFileOffset);
+ pFontInfo = pCurr;
+ pCurr = pGetNextFontInfoListItem(pCurr);
+ }
+
+ /* Skip embedded characters */
+ if (usChar == START_EMBEDDED) {
+ bSkip = TRUE;
+ continue;
+ }
+ if (usChar == END_IGNORE || usChar == END_EMBEDDED) {
+ bSkip = FALSE;
+ continue;
+ }
+ if (bSkip) {
+ continue;
+ }
+ ulChar = ulTranslateCharacters(usChar,
+ ulFileOffset,
+ iWordVersion,
+ tOptions.eConversionType,
+ tOptions.eEncoding,
+ bOldMacFile);
+ if (ulChar == IGNORE_CHARACTER) {
+ continue;
+ }
+ if (ulChar == PICTURE) {
+ ulFileOffsetImage = ulGetPictInfoListItem(ulFileOffset);
+ } else {
+ ulFileOffsetImage = FC_INVALID;
+ }
+ if (ulChar == PAR_END) {
+ /* End of paragraph seen, prepare for the next */
+ vFillStyleFromStylesheet(usIstdNext, &tStyleNext);
+ vCorrectStyleValues(&tStyleNext);
+ bStartStyleNext = TRUE;
+ vFillFontFromStylesheet(usIstdNext, &tFontNext);
+ vCorrectFontValues(&tFontNext);
+ bStartFontNext = TRUE;
+ }
+ if (ulChar == PAGE_BREAK) {
+ /* Might be the start of a new section */
+ pSectionNext = pGetSectionInfo(pSection, ulCharPos);
+ }
+ return ulChar;
+ }
+} /* end of ulGetChar */
+
+/*
+ * lGetWidthMax - get the maximum line width from the paragraph break value
+ *
+ * Returns the maximum line width in millipoints
+ */
+static long
+lGetWidthMax(int iParagraphBreak)
+{
+ fail(iParagraphBreak < 0);
+
+ if (iParagraphBreak == 0) {
+ return LONG_MAX;
+ }
+ if (iParagraphBreak < MIN_SCREEN_WIDTH) {
+ return lChar2MilliPoints(MIN_SCREEN_WIDTH);
+ }
+ if (iParagraphBreak > MAX_SCREEN_WIDTH) {
+ return lChar2MilliPoints(MAX_SCREEN_WIDTH);
+ }
+ return lChar2MilliPoints(iParagraphBreak);
+} /* end of lGetWidthMax */
+
+/*
+ * bWordDecryptor - turn Word to something more useful
+ *
+ * returns TRUE when succesful, otherwise FALSE
+ */
+BOOL
+bWordDecryptor(FILE *pFile, long lFilesize, diagram_type *pDiag)
+{
+ imagedata_type tImage;
+ const style_block_type *pStyleTmp;
+ const font_block_type *pFontTmp;
+ const char *szListChar;
+ output_type *pAnchor, *pOutput, *pLeftOver;
+ ULONG ulChar;
+ long lBeforeIndentation, lAfterIndentation;
+ long lLeftIndentation, lLeftIndentation1, lRightIndentation;
+ long lWidthCurr, lWidthMax, lDefaultTabWidth, lHalfSpaceWidth, lTmp;
+ list_id_enum eListID;
+ image_info_enum eRes;
+ UINT uiFootnoteNumber, uiEndnoteNumber, uiTmp;
+ int iListSeqNumber;
+ BOOL bWasTableRow, bTableFontClosed, bWasEndOfParagraph;
+ BOOL bInList, bWasInList, bNoMarks, bFirstLine;
+ BOOL bAllCapitals, bHiddenText, bMarkDelText, bSuccess;
+ USHORT usListNumber;
+ USHORT usFontStyle, usFontStyleMinimal, usFontSize, usTmp;
+ UCHAR ucFontNumber, ucFontColor;
+ UCHAR ucNFC, ucAlignment;
+
+ fail(pFile == NULL || lFilesize <= 0 || pDiag == NULL);
+
+ TRACE_MSG("bWordDecryptor");
+
+ iWordVersion = iInitDocument(pFile, lFilesize);
+ if (iWordVersion < 0) {
+ DBG_DEC(iWordVersion);
+ return FALSE;
+ }
+
+ vGetOptions(&tOptions);
+ bOldMacFile = bIsOldMacFile();
+ vPrepareHdrFtrText(pFile);
+ vPrepareFootnoteText(pFile);
+
+ vPrologue2(pDiag, iWordVersion);
+
+ /* Initialisation */
+#if defined(__riscos)
+ ulCharCounter = 0;
+ iCurrPct = 0;
+ iPrevPct = -1;
+ ulDocumentLength = ulGetDocumentLength();
+#endif /* __riscos */
+ pSection = pGetSectionInfo(NULL, 0);
+ pSectionNext = pSection;
+ lDefaultTabWidth = lGetDefaultTabWidth();
+ DBG_DEC_C(lDefaultTabWidth != 36000, lDefaultTabWidth);
+ pRowInfo = pGetNextRowInfoListItem();
+ DBG_HEX_C(pRowInfo != NULL, pRowInfo->ulFileOffsetStart);
+ DBG_HEX_C(pRowInfo != NULL, pRowInfo->ulFileOffsetEnd);
+ DBG_MSG_C(pRowInfo == NULL, "No rows at all");
+ bStartRow = FALSE;
+ bEndRowNorm = FALSE;
+ bEndRowFast = FALSE;
+ bIsTableRow = FALSE;
+ bWasTableRow = FALSE;
+ vResetStyles();
+ pStyleInfo = pGetNextTextStyle(NULL);
+ bStartStyle = FALSE;
+ bInList = FALSE;
+ bWasInList = FALSE;
+ iListSeqNumber = 0;
+ usIstdNext = ISTD_NORMAL;
+ pAnchor = NULL;
+ pFontInfo = pGetNextFontInfoListItem(NULL);
+ DBG_HEX_C(pFontInfo != NULL, pFontInfo->ulFileOffset);
+ DBG_MSG_C(pFontInfo == NULL, "No fonts at all");
+ bStartFont = FALSE;
+ ucFontNumber = 0;
+ usFontStyleMinimal = FONT_REGULAR;
+ usFontStyle = FONT_REGULAR;
+ usFontSize = DEFAULT_FONT_SIZE;
+ ucFontColor = FONT_COLOR_DEFAULT;
+ pAnchor = pStartNewOutput(pAnchor, NULL);
+ pOutput = pAnchor;
+ pOutput->ucFontColor = ucFontColor;
+ pOutput->usFontStyle = usFontStyle;
+ pOutput->tFontRef = tOpenFont(ucFontNumber, usFontStyle, usFontSize);
+ pOutput->usFontSize = usFontSize;
+ bTableFontClosed = TRUE;
+ lBeforeIndentation = 0;
+ lAfterIndentation = 0;
+ lLeftIndentation = 0;
+ lLeftIndentation1 = 0;
+ lRightIndentation = 0;
+ bWasEndOfParagraph = TRUE;
+ bNoMarks = TRUE;
+ bFirstLine = TRUE;
+ ucNFC = LIST_BULLETS;
+ if (pStyleInfo != NULL) {
+ szListChar = pStyleInfo->szListChar;
+ pStyleTmp = pStyleInfo;
+ } else {
+ if (tStyleNext.szListChar[0] == '\0') {
+ vGetBulletValue(tOptions.eConversionType,
+ tOptions.eEncoding, tStyleNext.szListChar, 4);
+ }
+ szListChar = tStyleNext.szListChar;
+ pStyleTmp = &tStyleNext;
+ }
+ usListNumber = 0;
+ ucAlignment = ALIGNMENT_LEFT;
+ bAllCapitals = FALSE;
+ bHiddenText = FALSE;
+ bMarkDelText = FALSE;
+ lWidthMax = lGetWidthMax(tOptions.iParagraphBreak);
+ NO_DBG_DEC(lWidthMax);
+
+ Hourglass_On();
+
+ uiFootnoteNumber = 0;
+ uiEndnoteNumber = 0;
+ eListID = text_list;
+ for(;;) {
+ ulChar = ulGetChar(pFile, eListID);
+ if (ulChar == (ULONG)EOF) {
+ if (bOutputContainsText(pAnchor)) {
+ OUTPUT_LINE();
+ } else {
+ RESET_LINE();
+ }
+ switch (eListID) {
+ case text_list:
+ if (tOptions.eConversionType !=
+ conversion_xml) {
+ eListID = footnote_list;
+ if (uiFootnoteNumber != 0) {
+ vPutSeparatorLine(pAnchor);
+ OUTPUT_LINE();
+ uiFootnoteNumber = 0;
+ }
+ break;
+ }
+ /* No break or return */
+ case footnote_list:
+ eListID = endnote_list;
+ if (uiEndnoteNumber != 0) {
+ vPutSeparatorLine(pAnchor);
+ OUTPUT_LINE();
+ uiEndnoteNumber = 0;
+ }
+ break;
+ case endnote_list:
+ eListID = textbox_list;
+ if (bExistsTextBox()) {
+ vPutSeparatorLine(pAnchor);
+ OUTPUT_LINE();
+ }
+ break;
+ case textbox_list:
+ eListID = hdrtextbox_list;
+ if (bExistsHdrTextBox()) {
+ vPutSeparatorLine(pAnchor);
+ OUTPUT_LINE();
+ }
+ break;
+ case hdrtextbox_list:
+ default:
+ eListID = end_of_lists;
+ break;
+ }
+ if (eListID == end_of_lists) {
+ break;
+ }
+ continue;
+ }
+
+ if (ulChar == UNKNOWN_NOTE_CHAR) {
+ switch (eListID) {
+ case footnote_list:
+ ulChar = FOOTNOTE_CHAR;
+ break;
+ case endnote_list:
+ ulChar = ENDNOTE_CHAR;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (bStartRow) {
+ /* Begin of a tablerow found */
+ if (bOutputContainsText(pAnchor)) {
+ OUTPUT_LINE();
+ } else {
+ RESET_LINE();
+ }
+ fail(pAnchor != pOutput);
+ if (bTableFontClosed) {
+ /* Start special table font */
+ vCloseFont();
+ /*
+ * Compensate for the fact that Word uses
+ * proportional fonts for its tables and we
+ * only one fixed-width font
+ */
+ uiTmp = ((UINT)usFontSize * 5 + 3) / 6;
+ if (uiTmp < MIN_TABLEFONT_SIZE) {
+ uiTmp = MIN_TABLEFONT_SIZE;
+ } else if (uiTmp > MAX_TABLEFONT_SIZE) {
+ uiTmp = MAX_TABLEFONT_SIZE;
+ }
+ pOutput->usFontSize = (USHORT)uiTmp;
+ pOutput->tFontRef =
+ tOpenTableFont(pOutput->usFontSize);
+ pOutput->usFontStyle = FONT_REGULAR;
+ pOutput->ucFontColor = FONT_COLOR_BLACK;
+ bTableFontClosed = FALSE;
+ }
+ bIsTableRow = TRUE;
+ bStartRow = FALSE;
+ }
+
+ if (bWasTableRow &&
+ !bIsTableRow &&
+ ulChar != PAR_END &&
+ ulChar != HARD_RETURN &&
+ ulChar != PAGE_BREAK &&
+ ulChar != COLUMN_FEED) {
+ /*
+ * The end of a table should be followed by an
+ * empty line, like the end of a paragraph
+ */
+ OUTPUT_LINE();
+ vEndOfParagraph(pDiag,
+ pOutput->tFontRef,
+ pOutput->usFontSize,
+ (long)pOutput->usFontSize * 600);
+ }
+
+ switch (ulChar) {
+ case PAGE_BREAK:
+ case COLUMN_FEED:
+ if (bIsTableRow) {
+ /* Ignore when in a table */
+ break;
+ }
+ if (bOutputContainsText(pAnchor)) {
+ OUTPUT_LINE();
+ } else {
+ RESET_LINE();
+ }
+ if (ulChar == PAGE_BREAK) {
+ vEndOfPage(pDiag, lAfterIndentation,
+ pSection != pSectionNext);
+ } else {
+ vEndOfParagraph(pDiag,
+ pOutput->tFontRef,
+ pOutput->usFontSize,
+ lAfterIndentation);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (bStartFont || (bStartFontNext && ulChar != PAR_END)) {
+ /* Begin of a font found */
+ if (bStartFont) {
+ /* bStartFont takes priority */
+ fail(pFontInfo == NULL);
+ pFontTmp = pFontInfo;
+ } else {
+ pFontTmp = &tFontNext;
+ }
+ bAllCapitals = bIsCapitals(pFontTmp->usFontStyle);
+ bHiddenText = bIsHidden(pFontTmp->usFontStyle);
+ bMarkDelText = bIsMarkDel(pFontTmp->usFontStyle);
+ usTmp = pFontTmp->usFontStyle &
+ (FONT_BOLD|FONT_ITALIC|FONT_UNDERLINE|
+ FONT_STRIKE|FONT_MARKDEL|
+ FONT_SUPERSCRIPT|FONT_SUBSCRIPT);
+ if (!bIsTableRow &&
+ (usFontSize != pFontTmp->usFontSize ||
+ ucFontNumber != pFontTmp->ucFontNumber ||
+ usFontStyleMinimal != usTmp ||
+ ucFontColor != pFontTmp->ucFontColor)) {
+ pOutput = pStartNextOutput(pOutput);
+ vCloseFont();
+ pOutput->ucFontColor = pFontTmp->ucFontColor;
+ pOutput->usFontStyle = pFontTmp->usFontStyle;
+ pOutput->usFontSize = pFontTmp->usFontSize;
+ pOutput->tFontRef = tOpenFont(
+ pFontTmp->ucFontNumber,
+ pFontTmp->usFontStyle,
+ pFontTmp->usFontSize);
+ fail(!bCheckDoubleLinkedList(pAnchor));
+ }
+ ucFontNumber = pFontTmp->ucFontNumber;
+ usFontSize = pFontTmp->usFontSize;
+ ucFontColor = pFontTmp->ucFontColor;
+ usFontStyle = pFontTmp->usFontStyle;
+ usFontStyleMinimal = usTmp;
+ if (bStartFont) {
+ /* Get the next font info */
+ pFontInfo = pGetNextFontInfoListItem(pFontInfo);
+ NO_DBG_HEX_C(pFontInfo != NULL,
+ pFontInfo->ulFileOffset);
+ DBG_MSG_C(pFontInfo == NULL, "No more fonts");
+ }
+ bStartFont = FALSE;
+ bStartFontNext = FALSE;
+ }
+
+ if (bStartStyle || (bStartStyleNext && ulChar != PAR_END)) {
+ bFirstLine = TRUE;
+ /* Begin of a style found */
+ if (bStartStyle) {
+ /* bStartStyle takes priority */
+ fail(pStyleInfo == NULL);
+ pStyleTmp = pStyleInfo;
+ } else {
+ pStyleTmp = &tStyleNext;
+ }
+ if (!bIsTableRow) {
+ vStoreStyle(pDiag, pOutput, pStyleTmp);
+ }
+ usIstdNext = pStyleTmp->usIstdNext;
+ lBeforeIndentation =
+ lTwips2MilliPoints(pStyleTmp->usBeforeIndent);
+ lAfterIndentation =
+ lTwips2MilliPoints(pStyleTmp->usAfterIndent);
+ lLeftIndentation =
+ lTwips2MilliPoints(pStyleTmp->sLeftIndent);
+ lLeftIndentation1 =
+ lTwips2MilliPoints(pStyleTmp->sLeftIndent1);
+ lRightIndentation =
+ lTwips2MilliPoints(pStyleTmp->sRightIndent);
+ bInList = bStyleImpliesList(pStyleTmp, iWordVersion);
+ bNoMarks = !bInList || pStyleTmp->bNumPause;
+ ucNFC = pStyleTmp->ucNFC;
+ szListChar = pStyleTmp->szListChar;
+ ucAlignment = pStyleTmp->ucAlignment;
+ if (bInList && !bWasInList) {
+ /* Start of a list */
+ iListSeqNumber++;
+ vStartOfList(pDiag, ucNFC,
+ bWasTableRow && !bIsTableRow);
+ }
+ if (!bInList && bWasInList) {
+ /* End of a list */
+ vEndOfList(pDiag);
+ }
+ bWasInList = bInList;
+ if (bStartStyle) {
+ pStyleInfo = pGetNextTextStyle(pStyleInfo);
+ NO_DBG_HEX_C(pStyleInfo != NULL,
+ pStyleInfo->ulFileOffset);
+ DBG_MSG_C(pStyleInfo == NULL,
+ "No more styles");
+ }
+ bStartStyle = FALSE;
+ bStartStyleNext = FALSE;
+ }
+
+ if (bWasEndOfParagraph) {
+ vStartOfParagraph1(pDiag, lBeforeIndentation);
+ }
+
+ if (!bIsTableRow &&
+ lTotalStringWidth(pAnchor) == 0) {
+ if (!bNoMarks) {
+ usListNumber = usGetListValue(iListSeqNumber,
+ iWordVersion,
+ pStyleTmp);
+ }
+ if (bInList && bFirstLine) {
+ vStartOfListItem(pDiag, bNoMarks);
+ }
+ vPutIndentation(pDiag, pAnchor, bNoMarks, bFirstLine,
+ usListNumber, ucNFC, szListChar,
+ lLeftIndentation, lLeftIndentation1);
+ bFirstLine = FALSE;
+ /* One number or mark per paragraph will do */
+ bNoMarks = TRUE;
+ }
+
+ if (bWasEndOfParagraph) {
+ vStartOfParagraph2(pDiag);
+ bWasEndOfParagraph = FALSE;
+ }
+
+ switch (ulChar) {
+ case PICTURE:
+ (void)memset(&tImage, 0, sizeof(tImage));
+ eRes = eExamineImage(pFile, ulFileOffsetImage, &tImage);
+ switch (eRes) {
+ case image_no_information:
+ bSuccess = FALSE;
+ break;
+ case image_minimal_information:
+ case image_full_information:
+#if 0
+ if (bOutputContainsText(pAnchor)) {
+ OUTPUT_LINE();
+ } else {
+ RESET_LINE();
+ }
+#endif
+ bSuccess = bTranslateImage(pDiag, pFile,
+ eRes == image_minimal_information,
+ ulFileOffsetImage, &tImage);
+ break;
+ default:
+ DBG_DEC(eRes);
+ bSuccess = FALSE;
+ break;
+ }
+ if (!bSuccess) {
+ vStoreString("[pic]", 5, pOutput);
+ }
+ break;
+ case FOOTNOTE_CHAR:
+ uiFootnoteNumber++;
+ if (tOptions.eConversionType == conversion_xml) {
+ vStoreCharacter((ULONG)FOOTNOTE_OR_ENDNOTE,
+ pOutput);
+ break;
+ }
+ vStoreCharacter((ULONG)'[', pOutput);
+ vStoreNumberAsDecimal(uiFootnoteNumber, pOutput);
+ vStoreCharacter((ULONG)']', pOutput);
+ break;
+ case ENDNOTE_CHAR:
+ uiEndnoteNumber++;
+ vStoreCharacter((ULONG)'[', pOutput);
+ vStoreNumberAsRoman(uiEndnoteNumber, pOutput);
+ vStoreCharacter((ULONG)']', pOutput);
+ break;
+ case UNKNOWN_NOTE_CHAR:
+ vStoreString("[?]", 3, pOutput);
+ break;
+ case PAR_END:
+ if (bIsTableRow) {
+ vStoreCharacter((ULONG)'\n', pOutput);
+ break;
+ }
+ if (bOutputContainsText(pAnchor)) {
+ OUTPUT_LINE();
+ } else {
+ vMove2NextLine(pDiag,
+ pOutput->tFontRef, pOutput->usFontSize);
+ RESET_LINE();
+ }
+ vEndOfParagraph(pDiag,
+ pOutput->tFontRef,
+ pOutput->usFontSize,
+ lAfterIndentation);
+ bWasEndOfParagraph = TRUE;
+ break;
+ case HARD_RETURN:
+ if (bIsTableRow) {
+ vStoreCharacter((ULONG)'\n', pOutput);
+ break;
+ }
+ if (bOutputContainsText(pAnchor)) {
+ OUTPUT_LINE();
+ } else {
+ vMove2NextLine(pDiag,
+ pOutput->tFontRef, pOutput->usFontSize);
+ RESET_LINE();
+ }
+ break;
+ case PAGE_BREAK:
+ case COLUMN_FEED:
+ pSection = pSectionNext;
+ break;
+ case TABLE_SEPARATOR:
+ if (bIsTableRow) {
+ vStoreCharacter(ulChar, pOutput);
+ break;
+ }
+ vStoreCharacter((ULONG)' ', pOutput);
+ vStoreCharacter((ULONG)TABLE_SEPARATOR_CHAR, pOutput);
+ break;
+ case TAB:
+ if (bIsTableRow ||
+ tOptions.eConversionType == conversion_xml) {
+ vStoreCharacter((ULONG)' ', pOutput);
+ break;
+ }
+ if (tOptions.iParagraphBreak == 0 &&
+ (tOptions.eConversionType == conversion_text ||
+ tOptions.eConversionType == conversion_fmt_text)) {
+ /* No logical lines, so no tab expansion */
+ vStoreCharacter(TAB, pOutput);
+ break;
+ }
+ lHalfSpaceWidth = (lComputeSpaceWidth(
+ pOutput->tFontRef,
+ pOutput->usFontSize) + 1) / 2;
+ lTmp = lTotalStringWidth(pAnchor);
+ lTmp += lDrawUnits2MilliPoints(pDiag->lXleft);
+ lTmp /= lDefaultTabWidth;
+ do {
+ vStoreCharacter((ULONG)FILLER_CHAR, pOutput);
+ lWidthCurr = lTotalStringWidth(pAnchor);
+ lWidthCurr +=
+ lDrawUnits2MilliPoints(pDiag->lXleft);
+ } while (lTmp == lWidthCurr / lDefaultTabWidth &&
+ lWidthCurr < lWidthMax + lRightIndentation);
+ break;
+ default:
+ if (bHiddenText && tOptions.bHideHiddenText) {
+ continue;
+ }
+ if (bMarkDelText && tOptions.bRemoveRemovedText) {
+ continue;
+ }
+ if (ulChar == UNICODE_ELLIPSIS &&
+ tOptions.eEncoding != encoding_utf_8) {
+ vStoreString("...", 3, pOutput);
+ } else {
+ if (bAllCapitals) {
+ ulChar = ulToUpper(ulChar);
+ }
+ vStoreCharacter(ulChar, pOutput);
+ }
+ break;
+ }
+
+ if (bWasTableRow && !bIsTableRow) {
+ /* End of a table */
+ vEndOfTable(pDiag);
+ /* Resume normal font */
+ NO_DBG_MSG("End of table font");
+ vCloseFont();
+ bTableFontClosed = TRUE;
+ pOutput->ucFontColor = ucFontColor;
+ pOutput->usFontStyle = usFontStyle;
+ pOutput->usFontSize = usFontSize;
+ pOutput->tFontRef = tOpenFont(
+ ucFontNumber, usFontStyle, usFontSize);
+ }
+ bWasTableRow = bIsTableRow;
+
+ if (bIsTableRow) {
+ fail(pAnchor != pOutput);
+ if (!bEndRowNorm && !bEndRowFast) {
+ continue;
+ }
+ /* End of a table row */
+ if (bEndRowNorm) {
+ fail(pRowInfo == NULL);
+ vTableRow2Window(pDiag, pAnchor, pRowInfo,
+ tOptions.eConversionType,
+ tOptions.iParagraphBreak);
+ } else {
+ fail(!bEndRowFast);
+ }
+ /* Reset */
+ pAnchor = pStartNewOutput(pAnchor, NULL);
+ pOutput = pAnchor;
+ if (bEndRowNorm) {
+ pRowInfo = pGetNextRowInfoListItem();
+ }
+ bIsTableRow = FALSE;
+ bEndRowNorm = FALSE;
+ bEndRowFast = FALSE;
+ NO_DBG_HEX_C(pRowInfo != NULL,
+ pRowInfo->ulFileOffsetStart);
+ NO_DBG_HEX_C(pRowInfo != NULL,
+ pRowInfo->ulFileOffsetEnd);
+ continue;
+ }
+ lWidthCurr = lTotalStringWidth(pAnchor);
+ lWidthCurr += lDrawUnits2MilliPoints(pDiag->lXleft);
+ if (lWidthCurr < lWidthMax + lRightIndentation) {
+ continue;
+ }
+ pLeftOver = pSplitList(pAnchor);
+ vJustify2Window(pDiag, pAnchor,
+ lWidthMax, lRightIndentation, ucAlignment);
+ pAnchor = pStartNewOutput(pAnchor, pLeftOver);
+ for (pOutput = pAnchor;
+ pOutput->pNext != NULL;
+ pOutput = pOutput->pNext)
+ ; /* EMPTY */
+ fail(pOutput == NULL);
+ if (lTotalStringWidth(pAnchor) > 0) {
+ vSetLeftIndentation(pDiag, lLeftIndentation);
+ }
+ }
+
+ pAnchor = pStartNewOutput(pAnchor, NULL);
+ pAnchor->szStorage = xfree(pAnchor->szStorage);
+ pAnchor = xfree(pAnchor);
+ vCloseFont();
+ vFreeDocument();
+ Hourglass_Off();
+ return TRUE;
+} /* end of bWordDecryptor */
+
+/*
+ * lLastStringWidth - compute the width of the last part of the output string
+ */
+static long
+lLastStringWidth(const output_type *pAnchor)
+{
+ const output_type *pCurr, *pStart;
+
+ pStart = NULL;
+ for (pCurr = pAnchor; pCurr != NULL; pCurr = pCurr->pNext) {
+ if (pCurr->tNextFree == 1 &&
+ (pCurr->szStorage[0] == PAR_END ||
+ pCurr->szStorage[0] == HARD_RETURN)) {
+ /* Found a separator. Start after the separator */
+ pStart = pCurr->pNext;
+ }
+ }
+ if (pStart == NULL) {
+ /* No separators. Use the whole output string */
+ pStart = pAnchor;
+ }
+ return lTotalStringWidth(pStart);
+} /* end of lLastStringWidth */
+
+/*
+ * pHdrFtrDecryptor - turn a header/footer list element to something useful
+ */
+output_type *
+pHdrFtrDecryptor(FILE *pFile, ULONG ulCharPosStart, ULONG ulCharPosNext)
+{
+ output_type *pAnchor, *pOutput, *pLeftOver;
+ ULONG ulChar, ulFileOffset, ulCharPos;
+ long lWidthCurr, lWidthMax;
+ long lRightIndentation;
+ USHORT usChar;
+ UCHAR ucAlignment;
+ BOOL bSkip;
+
+ fail(iWordVersion < 0);
+ fail(tOptions.eConversionType == conversion_unknown);
+ fail(tOptions.eEncoding == 0);
+
+ if (ulCharPosStart == ulCharPosNext) {
+ /* There are no bytes to decrypt */
+ return NULL;
+ }
+
+ lRightIndentation = 0;
+ ucAlignment = ALIGNMENT_LEFT;
+ bSkip = FALSE;
+ lWidthMax = lGetWidthMax(tOptions.iParagraphBreak);
+ pAnchor = pStartNewOutput(NULL, NULL);
+ pOutput = pAnchor;
+ pOutput->tFontRef = tOpenFont(0, FONT_REGULAR, DEFAULT_FONT_SIZE);
+ usChar = usToHdrFtrPosition(pFile, ulCharPosStart);
+ ulCharPos = ulCharPosStart;
+ ulFileOffset = ulCharPos2FileOffset(ulCharPos);
+ while (usChar != (USHORT)EOF && ulCharPos != ulCharPosNext) {
+ /* Skip embedded characters */
+ if (usChar == START_EMBEDDED) {
+ bSkip = TRUE;
+ } else if (usChar == END_IGNORE || usChar == END_EMBEDDED) {
+ bSkip = FALSE;
+ }
+ /* Translate character */
+ if (bSkip || usChar == END_IGNORE || usChar == END_EMBEDDED) {
+ ulChar = IGNORE_CHARACTER;
+ } else {
+ ulChar = ulTranslateCharacters(usChar,
+ ulFileOffset,
+ iWordVersion,
+ tOptions.eConversionType,
+ tOptions.eEncoding,
+ bOldMacFile);
+ }
+ /* Process character */
+ if (ulChar != IGNORE_CHARACTER) {
+ switch (ulChar) {
+ case PICTURE:
+ vStoreString("[pic]", 5, pOutput);
+ break;
+ case PAR_END:
+ case HARD_RETURN:
+ case PAGE_BREAK:
+ case COLUMN_FEED:
+ /* To the next substring */
+ pOutput = pStartNextOutput(pOutput);
+ vCloseFont();
+ pOutput->tFontRef = tOpenFont(0,
+ FONT_REGULAR, DEFAULT_FONT_SIZE);
+ /* A substring with just one character */
+ if (ulChar == HARD_RETURN) {
+ vStoreCharacter(HARD_RETURN, pOutput);
+ } else {
+ vStoreCharacter(PAR_END, pOutput);
+ }
+ /* To the next substring */
+ pOutput = pStartNextOutput(pOutput);
+ vCloseFont();
+ pOutput->tFontRef = tOpenFont(0,
+ FONT_REGULAR, DEFAULT_FONT_SIZE);
+ fail(!bCheckDoubleLinkedList(pAnchor));
+ break;
+ case TABLE_SEPARATOR:
+ vStoreCharacter((ULONG)' ', pOutput);
+ vStoreCharacter((ULONG)TABLE_SEPARATOR_CHAR,
+ pOutput);
+ break;
+ case TAB:
+ vStoreCharacter((ULONG)FILLER_CHAR, pOutput);
+ break;
+ default:
+ vStoreCharacter(ulChar, pOutput);
+ break;
+ }
+ }
+ lWidthCurr = lLastStringWidth(pAnchor);
+ if (lWidthCurr >= lWidthMax + lRightIndentation) {
+ pLeftOver = pSplitList(pAnchor);
+ for (pOutput = pAnchor;
+ pOutput->pNext != NULL;
+ pOutput = pOutput->pNext)
+ ; /* EMPTY */
+ fail(pOutput == NULL);
+ /* To the next substring */
+ pOutput = pStartNextOutput(pOutput);
+ /* A substring with just one HARD_RETURN */
+ vStoreCharacter(HARD_RETURN, pOutput);
+ /* Put the leftover piece(s) at the end */
+ pOutput->pNext = pLeftOver;
+ if (pLeftOver != NULL) {
+ pLeftOver->pPrev = pOutput;
+ }
+ fail(!bCheckDoubleLinkedList(pAnchor));
+ for (pOutput = pAnchor;
+ pOutput->pNext != NULL;
+ pOutput = pOutput->pNext)
+ ; /* EMPTY */
+ fail(pOutput == NULL);
+ }
+ usChar = usNextChar(pFile, hdrftr_list,
+ &ulFileOffset, &ulCharPos, NULL);
+ }
+ vCloseFont();
+ if (bOutputContainsText(pAnchor)) {
+ return pAnchor;
+ }
+ pAnchor = pStartNewOutput(pAnchor, NULL);
+ pAnchor->szStorage = xfree(pAnchor->szStorage);
+ pAnchor = xfree(pAnchor);
+ return NULL;
+} /* end of pHdrFtrDecryptor */
+
+/*
+ * pFootnoteDecryptor - turn a footnote text list element into text
+ */
+char *
+szFootnoteDecryptor(FILE *pFile, ULONG ulCharPosStart, ULONG ulCharPosNext)
+{
+ char *szText;
+ ULONG ulChar, ulFileOffset, ulCharPos;
+ USHORT usChar;
+ size_t tLen, tIndex, tNextFree, tStorageSize;
+ char szResult[6];
+ BOOL bSkip;
+
+ fail(iWordVersion < 0);
+ fail(tOptions.eConversionType == conversion_unknown);
+ fail(tOptions.eEncoding == 0);
+
+ if (ulCharPosStart == ulCharPosNext) {
+ /* There are no bytes to decrypt */
+ return NULL;
+ }
+
+ if (tOptions.eConversionType != conversion_xml) {
+ /* Only implemented for XML output */
+ return NULL;
+ }
+
+ bSkip = FALSE;
+
+ /* Initialise the text buffer */
+ tStorageSize = INITIAL_SIZE;
+ szText = xmalloc(tStorageSize);
+ tNextFree = 0;
+ szText[tNextFree] = '\0';
+
+ /* Goto the start */
+ usChar = usToFootnotePosition(pFile, ulCharPosStart);
+ ulCharPos = ulCharPosStart;
+ ulFileOffset = ulCharPos2FileOffset(ulCharPos);
+ /* Skip the unwanted starting characters */
+ while (usChar != (USHORT)EOF && ulCharPos != ulCharPosNext &&
+ (usChar == FOOTNOTE_OR_ENDNOTE ||
+ usChar == PAR_END ||
+ usChar == TAB ||
+ usChar == (USHORT)' ')) {
+ usChar = usNextChar(pFile, footnote_list,
+ &ulFileOffset, &ulCharPos, NULL);
+ }
+ /* Process the footnote text */
+ while (usChar != (USHORT)EOF && ulCharPos != ulCharPosNext) {
+ /* Skip embedded characters */
+ if (usChar == START_EMBEDDED) {
+ bSkip = TRUE;
+ } else if (usChar == END_IGNORE || usChar == END_EMBEDDED) {
+ bSkip = FALSE;
+ }
+ /* Translate character */
+ if (bSkip ||
+ usChar == END_IGNORE ||
+ usChar == END_EMBEDDED ||
+ usChar == FOOTNOTE_OR_ENDNOTE) {
+ ulChar = IGNORE_CHARACTER;
+ } else {
+ ulChar = ulTranslateCharacters(usChar,
+ ulFileOffset,
+ iWordVersion,
+ tOptions.eConversionType,
+ tOptions.eEncoding,
+ bOldMacFile);
+ }
+ /* Process character */
+ if (ulChar == PICTURE) {
+ tLen = 5;
+ strcpy(szResult, "[pic]");
+ } else if (ulChar == IGNORE_CHARACTER) {
+ tLen = 0;
+ szResult[0] = '\0';
+ } else {
+ switch (ulChar) {
+ case PAR_END:
+ case HARD_RETURN:
+ case PAGE_BREAK:
+ case COLUMN_FEED:
+ ulChar = (ULONG)PAR_END;
+ break;
+ case TAB:
+ ulChar = (ULONG)' ';
+ break;
+ default:
+ break;
+ }
+ tLen = tUcs2Utf8(ulChar, szResult, sizeof(szResult));
+ }
+ /* Add the results to the text */
+ if (tNextFree + tLen + 1 > tStorageSize) {
+ tStorageSize += EXTENTION_SIZE;
+ szText = xrealloc(szText, tStorageSize);
+ }
+ for (tIndex = 0; tIndex < tLen; tIndex++) {
+ szText[tNextFree++] = szResult[tIndex];
+ }
+ szText[tNextFree] = '\0';
+ /* Next character */
+ usChar = usNextChar(pFile, footnote_list,
+ &ulFileOffset, &ulCharPos, NULL);
+ }
+ /* Remove redundant spaces */
+ while (tNextFree != 0 && szText[tNextFree - 1] == ' ') {
+ szText[tNextFree - 1] = '\0';
+ tNextFree--;
+ }
+ if (tNextFree == 0) {
+ /* No text */
+ szText = xfree(szText);
+ return NULL;
+ }
+ return szText;
+} /* end of szFootnoteDecryptor */
diff --git a/sys/src/cmd/aux/antiword/wordconst.h b/sys/src/cmd/aux/antiword/wordconst.h
new file mode 100755
index 000000000..739f11bf6
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/wordconst.h
@@ -0,0 +1,321 @@
+/*
+ * wordconst.h
+ * Copyright (C) 1998-2004 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Constants and macros for the interpretation of MS Word files
+ */
+
+#if !defined(__wordconst_h)
+#define __wordconst_h 1
+
+/*
+ * A bit odd definition of the type Boolean, but RISC OS insists
+ * on this and Linux/Unix doesn't mind.
+ */
+#if !defined(BOOL)
+#define BOOL int
+#define TRUE 1
+#define FALSE 0
+#endif /* !BOOL */
+
+/* Block sizes */
+#define HEADER_SIZE 768
+#define BIG_BLOCK_SIZE 512
+#define PROPERTY_SET_STORAGE_SIZE 128
+#define SMALL_BLOCK_SIZE 64
+/* Switch size of Depot use */
+#define MIN_SIZE_FOR_BBD_USE 0x1000
+/* Table sizes */
+#define TABLE_COLUMN_MAX 31
+/* Maximum number of tabs positions in a paragraph */
+#define NUMBER_OF_TABS_MAX 64
+/* Font sizes (in half-points) */
+#define MIN_FONT_SIZE 8
+#define DEFAULT_FONT_SIZE 20
+#define MAX_FONT_SIZE 240
+#define MIN_TABLEFONT_SIZE 16
+#define MAX_TABLEFONT_SIZE 20
+/* Font styles */
+#define FONT_REGULAR 0x0000
+#define FONT_BOLD 0x0001
+#define FONT_ITALIC 0x0002
+#define FONT_UNDERLINE 0x0004
+#define FONT_CAPITALS 0x0008
+#define FONT_SMALL_CAPITALS 0x0010
+#define FONT_STRIKE 0x0020
+#define FONT_HIDDEN 0x0040
+#define FONT_MARKDEL 0x0080
+#define FONT_SUPERSCRIPT 0x0100
+#define FONT_SUBSCRIPT 0x0200
+/* Font colors */
+#define FONT_COLOR_DEFAULT 0
+#define FONT_COLOR_BLACK 1
+#define FONT_COLOR_BLUE 2
+#define FONT_COLOR_CYAN 3
+#define FONT_COLOR_GREEN 4
+#define FONT_COLOR_MAGENTA 5
+#define FONT_COLOR_RED 6
+#define FONT_COLOR_YELLOW 7
+#define FONT_COLOR_WHITE 8
+/* Special block numbers */
+#define END_OF_CHAIN 0xfffffffeUL
+#define UNUSED_BLOCK 0xffffffffUL
+/* Blocksize (512 bytes) and maximum filesize (4 GB) gives 0..7fffff */
+#define MAX_BLOCKNUMBER 0x007fffffUL
+/* Invalid character position */
+#define CP_INVALID 0xffffffffUL
+/* Invalid file offset */
+#define FC_INVALID 0xffffffffUL
+/* Special istd values */
+#define ISTD_INVALID USHRT_MAX
+#define ISTD_NORMAL 0
+/* Properties modifier without value */
+#define IGNORE_PROPMOD 0
+/* Types of lists */
+#define LIST_ARABIC_NUM 0x00
+#define LIST_UPPER_ROMAN 0x01
+#define LIST_LOWER_ROMAN 0x02
+#define LIST_UPPER_ALPHA 0x03
+#define LIST_LOWER_ALPHA 0x04
+#define LIST_ORDINAL_NUM 0x05
+#define LIST_NUMBER_TXT 0x06
+#define LIST_ORDINAL_TXT 0x07
+#define LIST_OUTLINE_NUM 0x16
+#define LIST_SPECIAL 0x17
+#define LIST_SPECIAL2 0x19
+#define LIST_BULLETS 0xff
+/* Types of paragraph alignment */
+#define ALIGNMENT_LEFT 0x00
+#define ALIGNMENT_CENTER 0x01
+#define ALIGNMENT_RIGHT 0x02
+#define ALIGNMENT_JUSTIFY 0x03
+/* Minimum vertical space before and after a heading line */
+#define HEADING_GAP 120 /* twips */
+/* Style identifier */
+#define STI_USER 0xffe
+#define STI_NIL 0xfff
+/* Table border style codes */
+#define TABLE_BORDER_TOP 0x01
+#define TABLE_BORDER_LEFT 0x02
+#define TABLE_BORDER_BOTTOM 0x04
+#define TABLE_BORDER_RIGHT 0x08
+
+/* Macros */
+ /* Get macros */
+#define ucGetByte(i,a) ((unsigned char)(a[i]))
+#define usGetWord(i,a) ((unsigned short)\
+ ((unsigned int)(a[(i)+1])<<8|\
+ (unsigned int)(a[i])))
+#define ulGetLong(i,a) ((unsigned long)(a[i])|\
+ (unsigned long)(a[(i)+1])<<8|\
+ (unsigned long)(a[(i)+2])<<16|\
+ (unsigned long)(a[(i)+3])<<24)
+#define usGetWordBE(i,a) ((unsigned short)\
+ ((unsigned int)(a[i])<<8|\
+ (unsigned int)(a[(i)+1])))
+#define ulGetLongBE(i,a) ((unsigned long)(a[(i)+3])|\
+ (unsigned long)(a[(i)+2])<<8|\
+ (unsigned long)(a[(i)+1])<<16|\
+ (unsigned long)(a[i])<<24)
+ /* Font style macros */
+#define bIsBold(x) (((x) & FONT_BOLD) == FONT_BOLD)
+#define bIsItalic(x) (((x) & FONT_ITALIC) == FONT_ITALIC)
+#define bIsUnderline(x) (((x) & FONT_UNDERLINE) == FONT_UNDERLINE)
+#define bIsCapitals(x) (((x) & FONT_CAPITALS) == FONT_CAPITALS)
+#define bIsSmallCapitals(x) (((x) & FONT_SMALL_CAPITALS) == FONT_SMALL_CAPITALS)
+#define bIsStrike(x) (((x) & FONT_STRIKE) == FONT_STRIKE)
+#define bIsHidden(x) (((x) & FONT_HIDDEN) == FONT_HIDDEN)
+#define bIsMarkDel(x) (((x) & FONT_MARKDEL) == FONT_MARKDEL)
+#define bIsSuperscript(x) (((x) & FONT_SUPERSCRIPT) == FONT_SUPERSCRIPT)
+#define bIsSubscript(x) (((x) & FONT_SUBSCRIPT) == FONT_SUBSCRIPT)
+ /* Table border style code macros */
+#define bIsTableBorderTop(x) (((x) & TABLE_BORDER_TOP) == TABLE_BORDER_TOP)
+#define bIsTableBorderLeft(x) (((x) & TABLE_BORDER_LEFT) == TABLE_BORDER_LEFT)
+#define bIsTableBorderBottom(x) (((x) & TABLE_BORDER_BOTTOM) == TABLE_BORDER_BOTTOM)
+#define bIsTableBorderRight(x) (((x) & TABLE_BORDER_RIGHT) == TABLE_BORDER_RIGHT)
+ /* Computation macros */
+#if defined(__riscos)
+/* From Words half-points to draw units (plus a percentage) */
+#define lWord2DrawUnits00(x) ((long)(x) * 320)
+#define lWord2DrawUnits20(x) ((long)(x) * 384)
+#define lToBaseLine(x) ((long)(x) * 45)
+#endif /* __riscos */
+/* From twips (1/20 of a point) to millipoints */
+#define lTwips2MilliPoints(x) ((long)(x) * 50)
+/* From twips (1/20 of a point) to points */
+#define dTwips2Points(x) ((double)(x) / 20.0)
+/* From default characters (16 OS units wide) to millipoints */
+#define lChar2MilliPoints(x) ((long)(x) * 6400)
+#define iMilliPoints2Char(x) (int)(((long)(x) + 3200) / 6400)
+#define iDrawUnits2Char(x) (int)(((long)(x) + 2048) / 4096)
+/* From draw units (1/180*256 inch) to millipoints (1/72*1000 inch) */
+#define lDrawUnits2MilliPoints(x) (((long)(x) * 25 + 8) / 16)
+#define lMilliPoints2DrawUnits(x) (((long)(x) * 16 + 12) / 25)
+#define lPoints2DrawUnits(x) ((long)(x) * 640)
+#define dDrawUnits2Points(x) ((double)(x) / 640.0)
+
+/* Special characters */
+#define IGNORE_CHARACTER 0x00 /* ^@ */
+#define PICTURE 0x01 /* ^A */
+#define FOOTNOTE_OR_ENDNOTE 0x02 /* ^B */
+#define FOOTNOTE_SEPARATOR 0x03 /* ^C */
+#define FOOTNOTE_CONTINUATION 0x04 /* ^D */
+#define ANNOTATION 0x05 /* ^E */
+#define TABLE_SEPARATOR 0x07 /* ^G */
+#define FRAME 0x08 /* ^H */
+#define TAB 0x09 /* ^I */
+/* End of line characters */
+#define LINE_FEED 0x0a /* ^J */
+#define HARD_RETURN 0x0b /* ^K */
+#define PAGE_BREAK 0x0c /* ^L */
+#define PAR_END 0x0d /* ^M */
+#define COLUMN_FEED 0x0e /* ^N */
+/* Embedded stuff */
+#define START_EMBEDDED 0x13 /* ^S */
+#define END_IGNORE 0x14 /* ^T */
+#define END_EMBEDDED 0x15 /* ^U */
+/* Special characters */
+#if defined(DEBUG)
+#define FILLER_CHAR '~'
+#else
+#define FILLER_CHAR ' '
+#endif /* DEBUG */
+#define TABLE_SEPARATOR_CHAR '|'
+/* Pseudo characters. These must be outside the Unicode range */
+#define FOOTNOTE_CHAR ((unsigned long)0xffff + 1)
+#define ENDNOTE_CHAR ((unsigned long)0xffff + 2)
+#define UNKNOWN_NOTE_CHAR ((unsigned long)0xffff + 3)
+
+/* Charactercodes as used by Word */
+#define WORD_UNBREAKABLE_JOIN 0x1e
+#define WORD_SOFT_HYPHEN 0x1f
+
+/* Unicode characters */
+#define UNICODE_DOUBLE_LEFT_ANGLE_QMARK 0x00ab
+#define UNICODE_MIDDLE_DOT 0x00b7
+#define UNICODE_DOUBLE_RIGHT_ANGLE_QMARK 0x00bb
+#define UNICODE_CAPITAL_D_WITH_STROKE 0x0110
+#define UNICODE_SMALL_D_WITH_STROKE 0x0111
+#define UNICODE_CAPITAL_LIGATURE_OE 0x0152
+#define UNICODE_SMALL_LIGATURE_OE 0x0153
+#define UNICODE_SMALL_F_HOOK 0x0192
+#define UNICODE_GREEK_CAPITAL_CHI 0x03a7
+#define UNICODE_GREEK_SMALL_UPSILON 0x03c5
+#define UNICODE_MODIFIER_CIRCUMFLEX 0x02c6
+#define UNICODE_SMALL_TILDE 0x02dc
+#define UNICODE_SMALL_LETTER_OMEGA 0x03c9
+#define UNICODE_EN_QUAD 0x2000
+#define UNICODE_EM_QUAD 0x2001
+#define UNICODE_EN_SPACE 0x2002
+#define UNICODE_EM_SPACE 0x2003
+#define UNICODE_THREE_PER_EM_SPACE 0x2004
+#define UNICODE_FOUR_PER_EM_SPACE 0x2005
+#define UNICODE_SIX_PER_EM_SPACE 0x2006
+#define UNICODE_FIGURE_SPACE 0x2007
+#define UNICODE_PUNCTUATION_SPACE 0x2008
+#define UNICODE_THIN_SPACE 0x2009
+#define UNICODE_HAIR_SPACE 0x200a
+#define UNICODE_ZERO_WIDTH_SPACE 0x200b
+#define UNICODE_ZERO_WIDTH_NON_JOINER 0x200c
+#define UNICODE_ZERO_WIDTH_JOINER 0x200d
+#define UNICODE_LEFT_TO_RIGHT_MARK 0x200e
+#define UNICODE_RIGHT_TO_LEFT_MARK 0x200f
+#define UNICODE_HYPHEN 0x2010
+#define UNICODE_NON_BREAKING_HYPHEN 0x2011
+#define UNICODE_FIGURE_DASH 0x2012
+#define UNICODE_EN_DASH 0x2013
+#define UNICODE_EM_DASH 0x2014
+#define UNICODE_HORIZONTAL_BAR 0x2015
+#define UNICODE_DOUBLE_VERTICAL_LINE 0x2016
+#define UNICODE_DOUBLE_LOW_LINE 0x2017
+#define UNICODE_LEFT_SINGLE_QMARK 0x2018
+#define UNICODE_RIGHT_SINGLE_QMARK 0x2019
+#define UNICODE_SINGLE_LOW_9_QMARK 0x201a
+#define UNICODE_SINGLE_HIGH_REV_9_QMARK 0x201b
+#define UNICODE_LEFT_DOUBLE_QMARK 0x201c
+#define UNICODE_RIGHT_DOUBLE_QMARK 0x201d
+#define UNICODE_DOUBLE_LOW_9_QMARK 0x201e
+#define UNICODE_DOUBLE_HIGH_REV_9_QMARK 0x201f
+#define UNICODE_DAGGER 0x2020
+#define UNICODE_DOUBLE_DAGGER 0x2021
+#define UNICODE_BULLET 0x2022
+#define UNICODE_TRIANGULAR_BULLET 0x2023
+#define UNICODE_ONE_DOT_LEADER 0x2024
+#define UNICODE_TWO_DOT_LEADER 0x2025
+#define UNICODE_ELLIPSIS 0x2026
+#define UNICODE_HYPHENATION_POINT 0x2027
+#define UNICODE_LEFT_TO_RIGHT_EMBEDDING 0x202a
+#define UNICODE_RIGHT_TO_LEFT_EMBEDDING 0x202b
+#define UNICODE_POP_DIRECTIONAL_FORMATTING 0x202c
+#define UNICODE_LEFT_TO_RIGHT_OVERRIDE 0x202d
+#define UNICODE_RIGHT_TO_LEFT_OVERRIDE 0x202e
+#define UNICODE_NARROW_NO_BREAK_SPACE 0x202f
+#define UNICODE_PER_MILLE_SIGN 0x2030
+#define UNICODE_PRIME 0x2032
+#define UNICODE_DOUBLE_PRIME 0x2033
+#define UNICODE_SINGLE_LEFT_ANGLE_QMARK 0x2039
+#define UNICODE_SINGLE_RIGHT_ANGLE_QMARK 0x203a
+#define UNICODE_UNDERTIE 0x203f
+#define UNICODE_FRACTION_SLASH 0x2044
+#define UNICODE_EURO_SIGN 0x20ac
+#define UNICODE_CIRCLE 0x20dd
+#define UNICODE_SQUARE 0x20de
+#define UNICODE_DIAMOND 0x20df
+#define UNICODE_NUMERO_SIGN 0x2116
+#define UNICODE_TRADEMARK_SIGN 0x2122
+#define UNICODE_KELVIN_SIGN 0x212a
+#define UNICODE_LEFTWARDS_ARROW 0x2190
+#define UNICODE_UPWARDS_ARROW 0x2191
+#define UNICODE_RIGHTWARDS_ARROW 0x2192
+#define UNICODE_DOWNWARDS_ARROW 0x2193
+#define UNICODE_N_ARY_SUMMATION 0x2211
+#define UNICODE_MINUS_SIGN 0x2212
+#define UNICODE_DIVISION_SLASH 0x2215
+#define UNICODE_ASTERISK_OPERATOR 0x2217
+#define UNICODE_BULLET_OPERATOR 0x2219
+#define UNICODE_RATIO 0x2236
+#define UNICODE_TILDE_OPERATOR 0x223c
+#define UNICODE_BD_LIGHT_HORIZONTAL 0x2500
+#define UNICODE_BD_LIGHT_VERTICAL 0x2502
+#define UNICODE_BD_LIGHT_DOWN_RIGHT 0x250c
+#define UNICODE_BD_LIGHT_DOWN_AND_LEFT 0x2510
+#define UNICODE_BD_LIGHT_UP_AND_RIGHT 0x2514
+#define UNICODE_BD_LIGHT_UP_AND_LEFT 0x2518
+#define UNICODE_BD_LIGHT_VERTICAL_AND_RIGHT 0x251c
+#define UNICODE_BD_LIGHT_VERTICAL_AND_LEFT 0x2524
+#define UNICODE_BD_LIGHT_DOWN_AND_HORIZONTAL 0x252c
+#define UNICODE_BD_LIGHT_UP_AND_HORIZONTAL 0x2534
+#define UNICODE_BD_LIGHT_VERTICAL_AND_HORIZONTAL 0x253c
+#define UNICODE_BD_DOUBLE_HORIZONTAL 0x2550
+#define UNICODE_BD_DOUBLE_VERTICAL 0x2551
+#define UNICODE_BD_DOUBLE_DOWN_AND_RIGHT 0x2554
+#define UNICODE_BD_DOUBLE_DOWN_AND_LEFT 0x2557
+#define UNICODE_BD_DOUBLE_UP_AND_RIGHT 0x255a
+#define UNICODE_BD_DOUBLE_UP_AND_LEFT 0x255d
+#define UNICODE_BD_DOUBLE_VERTICAL_AND_RIGHT 0x2560
+#define UNICODE_BD_DOUBLE_VERTICAL_AND_LEFT 0x2563
+#define UNICODE_BD_DOUBLE_DOWN_AND_HORIZONTAL 0x2566
+#define UNICODE_BD_DOUBLE_UP_AND_HORIZONTAL 0x2569
+#define UNICODE_BD_DOUBLE_VERTICAL_AND_HORIZONTAL 0x256c
+#define UNICODE_LIGHT_SHADE 0x2591
+#define UNICODE_MEDIUM_SHADE 0x2592
+#define UNICODE_DARK_SHADE 0x2593
+#define UNICODE_BLACK_SQUARE 0x25a0
+#define UNICODE_BLACK_CLUB_SUIT 0x2663
+#define UNICODE_SMALL_LIGATURE_FI 0xfb01
+#define UNICODE_SMALL_LIGATURE_FL 0xfb02
+#define UNICODE_ZERO_WIDTH_NO_BREAK_SPACE 0xfeff
+
+#if defined(__riscos)
+#define OUR_ELLIPSIS 0x8c
+#define OUR_EM_DASH 0x98
+#define OUR_UNBREAKABLE_JOIN 0x99
+#else
+#define OUR_ELLIPSIS '.'
+#define OUR_EM_DASH '-'
+#define OUR_UNBREAKABLE_JOIN '-'
+#endif /* __riscos */
+#define OUR_DIAMOND '-'
+
+#endif /* __wordconst_h */
diff --git a/sys/src/cmd/aux/antiword/worddos.c b/sys/src/cmd/aux/antiword/worddos.c
new file mode 100755
index 000000000..c0e0142a0
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/worddos.c
@@ -0,0 +1,110 @@
+/*
+ * worddos.c
+ * Copyright (C) 2002-2005 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Deal with the DOS internals of a MS Word file
+ */
+
+#include "antiword.h"
+
+
+/*
+ * bGetDocumentText - make a list of the text blocks of a Word document
+ *
+ * Return TRUE when succesful, otherwise FALSE
+ */
+static BOOL
+bGetDocumentText(FILE *pFile, long lFilesize, const UCHAR *aucHeader)
+{
+ text_block_type tTextBlock;
+ ULONG ulTextLen;
+ BOOL bFastSaved;
+ UCHAR ucDocStatus, ucVersion;
+
+ fail(pFile == NULL);
+ fail(lFilesize < 128);
+ fail(aucHeader == NULL);
+
+ /* Get the status flags from the header */
+ ucDocStatus = ucGetByte(0x75, aucHeader);
+ DBG_HEX(ucDocStatus);
+ bFastSaved = (ucDocStatus & BIT(1)) != 0;
+ DBG_MSG_C(bFastSaved, "This document is Fast Saved");
+ ucVersion = ucGetByte(0x74, aucHeader);
+ DBG_DEC(ucVersion);
+ DBG_MSG_C(ucVersion == 0, "Written by Word 4.0 or earlier");
+ DBG_MSG_C(ucVersion == 3, "Word 5.0 format, but not written by Word");
+ DBG_MSG_C(ucVersion == 4, "Written by Word 5.x");
+ if (bFastSaved) {
+ werr(0, "Word for DOS: autosave documents are not supported");
+ return FALSE;
+ }
+
+ /* Get length information */
+ ulTextLen = ulGetLong(0x0e, aucHeader);
+ DBG_HEX(ulTextLen);
+ ulTextLen -= 128;
+ DBG_DEC(ulTextLen);
+ tTextBlock.ulFileOffset = 128;
+ tTextBlock.ulCharPos = 128;
+ tTextBlock.ulLength = ulTextLen;
+ tTextBlock.bUsesUnicode = FALSE;
+ tTextBlock.usPropMod = IGNORE_PROPMOD;
+ if (!bAdd2TextBlockList(&tTextBlock)) {
+ DBG_HEX(tTextBlock.ulFileOffset);
+ DBG_HEX(tTextBlock.ulCharPos);
+ DBG_DEC(tTextBlock.ulLength);
+ DBG_DEC(tTextBlock.bUsesUnicode);
+ DBG_DEC(tTextBlock.usPropMod);
+ return FALSE;
+ }
+ return TRUE;
+} /* end of bGetDocumentText */
+
+/*
+ * iInitDocumentDOS - initialize an DOS document
+ *
+ * Returns the version of Word that made the document or -1
+ */
+int
+iInitDocumentDOS(FILE *pFile, long lFilesize)
+{
+ int iWordVersion;
+ BOOL bSuccess;
+ USHORT usIdent;
+ UCHAR aucHeader[128];
+
+ fail(pFile == NULL);
+
+ if (lFilesize < 128) {
+ return -1;
+ }
+
+ /* Read the headerblock */
+ if (!bReadBytes(aucHeader, 128, 0x00, pFile)) {
+ return -1;
+ }
+ /* Get the "magic number" from the header */
+ usIdent = usGetWord(0x00, aucHeader);
+ DBG_HEX(usIdent);
+ fail(usIdent != 0xbe31); /* Word for DOS */
+ iWordVersion = iGetVersionNumber(aucHeader);
+ if (iWordVersion != 0) {
+ werr(0, "This file is not from 'Word for DOS'.");
+ return -1;
+ }
+ bSuccess = bGetDocumentText(pFile, lFilesize, aucHeader);
+ if (bSuccess) {
+ vGetPropertyInfo(pFile, NULL,
+ NULL, 0, NULL, 0,
+ aucHeader, iWordVersion);
+ vSetDefaultTabWidth(pFile, NULL,
+ NULL, 0, NULL, 0,
+ aucHeader, iWordVersion);
+ vGetNotesInfo(pFile, NULL,
+ NULL, 0, NULL, 0,
+ aucHeader, iWordVersion);
+ }
+ return bSuccess ? iWordVersion : -1;
+} /* end of iInitDocumentDOS */
diff --git a/sys/src/cmd/aux/antiword/wordlib.c b/sys/src/cmd/aux/antiword/wordlib.c
new file mode 100755
index 000000000..d8471d62c
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/wordlib.c
@@ -0,0 +1,359 @@
+/*
+ * wordlib.c
+ * Copyright (C) 1998-2004 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Deal with the internals of a MS Word file
+ */
+
+#include "antiword.h"
+
+static BOOL bOldMacFile = FALSE;
+
+
+/*
+ * Common part of the file checking functions
+ */
+static BOOL
+bCheckBytes(FILE *pFile, const UCHAR *aucBytes, size_t tBytes)
+{
+ int iIndex, iChar;
+
+ fail(pFile == NULL || aucBytes == NULL || tBytes == 0);
+
+ rewind(pFile);
+
+ for (iIndex = 0; iIndex < (int)tBytes; iIndex++) {
+ iChar = getc(pFile);
+ if (iChar == EOF || iChar != (int)aucBytes[iIndex]) {
+ NO_DBG_HEX(iChar);
+ NO_DBG_HEX(aucBytes[iIndex]);
+ return FALSE;
+ }
+ }
+ return TRUE;
+} /* end of bCheckBytes */
+
+/*
+ * This function checks whether the given file is or is not a "Word for DOS"
+ * document
+ */
+BOOL
+bIsWordForDosFile(FILE *pFile, long lFilesize)
+{
+ static UCHAR aucBytes[] =
+ { 0x31, 0xbe, 0x00, 0x00, 0x00, 0xab }; /* Word for DOS */
+
+ DBG_MSG("bIsWordForDosFile");
+
+ if (pFile == NULL || lFilesize < 0) {
+ DBG_MSG("No proper file given");
+ return FALSE;
+ }
+ if (lFilesize < 128) {
+ DBG_MSG("File too small to be a Word document");
+ return FALSE;
+ }
+ return bCheckBytes(pFile, aucBytes, elementsof(aucBytes));
+} /* end of bIsWordForDosFile */
+
+/*
+ * This function checks whether the given file is or is not a file with an
+ * OLE envelope (That is a document made by Word 6 or later)
+ */
+static BOOL
+bIsWordFileWithOLE(FILE *pFile, long lFilesize)
+{
+ static UCHAR aucBytes[] =
+ { 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 };
+ int iTailLen;
+
+ if (pFile == NULL || lFilesize < 0) {
+ DBG_MSG("No proper file given");
+ return FALSE;
+ }
+ if (lFilesize < (long)BIG_BLOCK_SIZE * 3) {
+ DBG_MSG("This file is too small to be a Word document");
+ return FALSE;
+ }
+
+ iTailLen = (int)(lFilesize % BIG_BLOCK_SIZE);
+ switch (iTailLen) {
+ case 0: /* No tail, as it should be */
+ break;
+ case 1:
+ case 2: /* Filesize mismatch or a buggy email program */
+ if ((int)(lFilesize % 3) == iTailLen) {
+ DBG_DEC(lFilesize);
+ return FALSE;
+ }
+ /*
+ * Ignore extra bytes caused by buggy email programs.
+ * They have bugs in their base64 encoding or decoding.
+ * 3 bytes -> 4 ascii chars -> 3 bytes
+ */
+ DBG_MSG("Document with extra bytes");
+ break;
+ default: /* Wrong filesize for a Word document */
+ DBG_DEC(lFilesize);
+ DBG_DEC(iTailLen);
+ return FALSE;
+ }
+ return bCheckBytes(pFile, aucBytes, elementsof(aucBytes));
+} /* end of bIsWordFileWithOLE */
+
+/*
+ * This function checks whether the given file is or is not a RTF document
+ */
+BOOL
+bIsRtfFile(FILE *pFile)
+{
+ static UCHAR aucBytes[] =
+ { '{', '\\', 'r', 't', 'f', '1' };
+
+ DBG_MSG("bIsRtfFile");
+
+ return bCheckBytes(pFile, aucBytes, elementsof(aucBytes));
+} /* end of bIsRtfFile */
+
+/*
+ * This function checks whether the given file is or is not a WP document
+ */
+BOOL
+bIsWordPerfectFile(FILE *pFile)
+{
+ static UCHAR aucBytes[] =
+ { 0xff, 'W', 'P', 'C' };
+
+ DBG_MSG("bIsWordPerfectFile");
+
+ return bCheckBytes(pFile, aucBytes, elementsof(aucBytes));
+} /* end of bIsWordPerfectFile */
+
+/*
+ * This function checks whether the given file is or is not a "Win Word 1 or 2"
+ * document
+ */
+BOOL
+bIsWinWord12File(FILE *pFile, long lFilesize)
+{
+ static UCHAR aucBytes[2][4] = {
+ { 0x9b, 0xa5, 0x21, 0x00 }, /* Win Word 1.x */
+ { 0xdb, 0xa5, 0x2d, 0x00 }, /* Win Word 2.0 */
+ };
+ int iIndex;
+
+ DBG_MSG("bIsWinWord12File");
+
+ if (pFile == NULL || lFilesize < 0) {
+ DBG_MSG("No proper file given");
+ return FALSE;
+ }
+ if (lFilesize < 384) {
+ DBG_MSG("This file is too small to be a Word document");
+ return FALSE;
+ }
+
+ for (iIndex = 0; iIndex < (int)elementsof(aucBytes); iIndex++) {
+ if (bCheckBytes(pFile,
+ aucBytes[iIndex],
+ elementsof(aucBytes[iIndex]))) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+} /* end of bIsWinWord12File */
+
+/*
+ * This function checks whether the given file is or is not a "Mac Word 4 or 5"
+ * document
+ */
+BOOL
+bIsMacWord45File(FILE *pFile)
+{
+ static UCHAR aucBytes[2][6] = {
+ { 0xfe, 0x37, 0x00, 0x1c, 0x00, 0x00 }, /* Mac Word 4 */
+ { 0xfe, 0x37, 0x00, 0x23, 0x00, 0x00 }, /* Mac Word 5 */
+ };
+ int iIndex;
+
+ DBG_MSG("bIsMacWord45File");
+
+ for (iIndex = 0; iIndex < (int)elementsof(aucBytes); iIndex++) {
+ if (bCheckBytes(pFile,
+ aucBytes[iIndex],
+ elementsof(aucBytes[iIndex]))) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+} /* end of bIsMacWord45File */
+
+/*
+ * iGuessVersionNumber - guess the Word version number from first few bytes
+ *
+ * Returns the guessed version number or -1 when no guess it possible
+ */
+int
+iGuessVersionNumber(FILE *pFile, long lFilesize)
+{
+ if(bIsWordForDosFile(pFile, lFilesize)) {
+ return 0;
+ }
+ if (bIsWinWord12File(pFile, lFilesize)) {
+ return 2;
+ }
+ if (bIsMacWord45File(pFile)) {
+ return 5;
+ }
+ if (bIsWordFileWithOLE(pFile, lFilesize)) {
+ return 6;
+ }
+ return -1;
+} /* end of iGuessVersionNumber */
+
+/*
+ * iGetVersionNumber - get the Word version number from the header
+ *
+ * Returns the version number or -1 when unknown
+ */
+int
+iGetVersionNumber(const UCHAR *aucHeader)
+{
+ USHORT usFib, usChse;
+
+ usFib = usGetWord(0x02, aucHeader);
+ if (usFib >= 0x1000) {
+ /* To big: must be MacWord using Big Endian */
+ DBG_HEX(usFib);
+ usFib = usGetWordBE(0x02, aucHeader);
+ }
+ DBG_DEC(usFib);
+ bOldMacFile = FALSE;
+ switch (usFib) {
+ case 0:
+ DBG_MSG("Word for DOS");
+ return 0;
+ case 28:
+ DBG_MSG("Word 4 for Macintosh");
+ bOldMacFile = TRUE;
+ return 4;
+ case 33:
+ DBG_MSG("Word 1.x for Windows");
+ return 1;
+ case 35:
+ DBG_MSG("Word 5 for Macintosh");
+ bOldMacFile = TRUE;
+ return 5;
+ case 45:
+ DBG_MSG("Word 2 for Windows");
+ return 2;
+ case 101:
+ case 102:
+ DBG_MSG("Word 6 for Windows");
+ return 6;
+ case 103:
+ case 104:
+ usChse = usGetWord(0x14, aucHeader);
+ DBG_DEC(usChse);
+ switch (usChse) {
+ case 0:
+ DBG_MSG("Word 7 for Win95");
+ return 7;
+ case 256:
+ DBG_MSG("Word 6 for Macintosh");
+ bOldMacFile = TRUE;
+ return 6;
+ default:
+ DBG_FIXME();
+ if ((int)ucGetByte(0x05, aucHeader) == 0xe0) {
+ DBG_MSG("Word 7 for Win95");
+ return 7;
+ }
+ DBG_MSG("Word 6 for Macintosh");
+ bOldMacFile = TRUE;
+ return 6;
+ }
+ default:
+ usChse = usGetWord(0x14, aucHeader);
+ DBG_DEC(usChse);
+ if (usFib < 192) {
+ /* Unknown or unsupported version of Word */
+ DBG_DEC(usFib);
+ return -1;
+ }
+ DBG_MSG_C(usChse != 256, "Word97 for Win95/98/NT");
+ DBG_MSG_C(usChse == 256, "Word98 for Macintosh");
+ return 8;
+ }
+} /* end of iGetVersionNumber */
+
+/*
+ * TRUE if the current file was made by Word version 6 or older on an
+ * Apple Macintosh, otherwise FALSE.
+ * This function hides the methode of how to find out from the rest of the
+ * program.
+ */
+BOOL
+bIsOldMacFile(void)
+{
+ return bOldMacFile;
+} /* end of bIsOldMacFile */
+
+/*
+ * iInitDocument - initialize a document
+ *
+ * Returns the version of Word that made the document or -1
+ */
+int
+iInitDocument(FILE *pFile, long lFilesize)
+{
+ int iGuess, iWordVersion;
+
+ iGuess = iGuessVersionNumber(pFile, lFilesize);
+ switch (iGuess) {
+ case 0:
+ iWordVersion = iInitDocumentDOS(pFile, lFilesize);
+ break;
+ case 2:
+ iWordVersion = iInitDocumentWIN(pFile, lFilesize);
+ break;
+ case 5:
+ iWordVersion = iInitDocumentMAC(pFile, lFilesize);
+ break;
+ case 6:
+ iWordVersion = iInitDocumentOLE(pFile, lFilesize);
+ break;
+ default:
+ DBG_DEC(iGuess);
+ iWordVersion = -1;
+ break;
+ }
+ return iWordVersion;
+} /* end of iInitDocument */
+
+/*
+ * vFreeDocument - free a document by free-ing its parts
+ */
+void
+vFreeDocument(void)
+{
+ DBG_MSG("vFreeDocument");
+
+ /* Free the memory */
+ vDestroyTextBlockList();
+ vDestroyDataBlockList();
+ vDestroyListInfoList();
+ vDestroyRowInfoList();
+ vDestroyStyleInfoList();
+ vDestroyFontInfoList();
+ vDestroyStylesheetList();
+ vDestroyPictInfoList();
+ vDestroyDocumentInfoList();
+ vDestroySectionInfoList();
+ vDestroyHdrFtrInfoList();
+ vDestroyPropModList();
+ vDestroyNotesInfoLists();
+ vDestroyFontTable();
+ vDestroySummaryInfo();
+} /* end of vFreeDocument */
diff --git a/sys/src/cmd/aux/antiword/wordmac.c b/sys/src/cmd/aux/antiword/wordmac.c
new file mode 100755
index 000000000..c6a8f2620
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/wordmac.c
@@ -0,0 +1,108 @@
+/*
+ * wordmac.c
+ * Copyright (C) 2002-2004 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Deal with the MAC internals of a MS Word file
+ */
+
+#include "antiword.h"
+
+
+/*
+ * bGetDocumentText - make a list of the text blocks of a Word document
+ *
+ * Return TRUE when succesful, otherwise FALSE
+ */
+static BOOL
+bGetDocumentText(FILE *pFile, const UCHAR *aucHeader)
+{
+ text_block_type tTextBlock;
+ ULONG ulBeginOfText, ulEndOfText;
+ ULONG ulTextLen;
+ UCHAR ucDocStatus;
+ BOOL bFastSaved;
+
+ fail(pFile == NULL);
+ fail(aucHeader == NULL);
+
+ DBG_MSG("bGetDocumentText");
+
+ NO_DBG_PRINT_BLOCK(aucHeader, 0x20);
+
+ /* Get the status flags from the header */
+ ucDocStatus = ucGetByte(0x0a, aucHeader);
+ DBG_HEX(ucDocStatus);
+ bFastSaved = (ucDocStatus & BIT(5)) != 0;
+ DBG_MSG_C(bFastSaved, "This document is Fast Saved");
+ if (bFastSaved) {
+ werr(0, "MacWord: fast saved documents are not supported yet");
+ return FALSE;
+ }
+
+ /* Get length information */
+ ulBeginOfText = ulGetLongBE(0x14, aucHeader);
+ DBG_HEX(ulBeginOfText);
+ ulEndOfText = ulGetLongBE(0x18, aucHeader);
+ DBG_HEX(ulEndOfText);
+ ulTextLen = ulEndOfText - ulBeginOfText;
+ DBG_DEC(ulTextLen);
+ tTextBlock.ulFileOffset = ulBeginOfText;
+ tTextBlock.ulCharPos = ulBeginOfText;
+ tTextBlock.ulLength = ulTextLen;
+ tTextBlock.bUsesUnicode = FALSE;
+ tTextBlock.usPropMod = IGNORE_PROPMOD;
+ if (!bAdd2TextBlockList(&tTextBlock)) {
+ DBG_HEX(tTextBlock.ulFileOffset);
+ DBG_HEX(tTextBlock.ulCharPos);
+ DBG_DEC(tTextBlock.ulLength);
+ DBG_DEC(tTextBlock.bUsesUnicode);
+ DBG_DEC(tTextBlock.usPropMod);
+ return FALSE;
+ }
+ return TRUE;
+} /* end of bGetDocumentText */
+
+/*
+ * iInitDocumentMAC - initialize an MAC document
+ *
+ * Returns the version of Word that made the document or -1
+ */
+int
+iInitDocumentMAC(FILE *pFile, long lFilesize)
+{
+ int iWordVersion;
+ BOOL bSuccess;
+ USHORT usIdent;
+ UCHAR aucHeader[256];
+
+ fail(pFile == NULL);
+
+ if (lFilesize < 256) {
+ return -1;
+ }
+
+ /* Read the headerblock */
+ if (!bReadBytes(aucHeader, 256, 0x00, pFile)) {
+ return -1;
+ }
+ /* Get the "magic number" from the header */
+ usIdent = usGetWord(0x00, aucHeader);
+ DBG_HEX(usIdent);
+ fail(usIdent != 0x37fe); /* MacWord 4 and 5 */
+ iWordVersion = iGetVersionNumber(aucHeader);
+ if (iWordVersion != 4 && iWordVersion != 5) {
+ werr(0, "This file is not from ''Mac Word 4 or 5'.");
+ return -1;
+ }
+ bSuccess = bGetDocumentText(pFile, aucHeader);
+ if (bSuccess) {
+ vGetPropertyInfo(pFile, NULL,
+ NULL, 0, NULL, 0,
+ aucHeader, iWordVersion);
+ vSetDefaultTabWidth(pFile, NULL,
+ NULL, 0, NULL, 0,
+ aucHeader, iWordVersion);
+ }
+ return bSuccess ? iWordVersion : -1;
+} /* end of iInitDocumentMAC */
diff --git a/sys/src/cmd/aux/antiword/wordole.c b/sys/src/cmd/aux/antiword/wordole.c
new file mode 100755
index 000000000..8a95fb9ed
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/wordole.c
@@ -0,0 +1,804 @@
+/*
+ * wordole.c
+ * Copyright (C) 1998-2004 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Deal with the OLE internals of a MS Word file
+ */
+
+#include <string.h>
+#include "antiword.h"
+
+/* Private type for Property Set Storage entries */
+typedef struct pps_entry_tag {
+ ULONG ulNext;
+ ULONG ulPrevious;
+ ULONG ulDir;
+ ULONG ulSB;
+ ULONG ulSize;
+ int iLevel;
+ char szName[32];
+ UCHAR ucType;
+} pps_entry_type;
+
+/* Show that a PPS number or index should not be used */
+#define PPS_NUMBER_INVALID 0xffffffffUL
+
+
+/* Macro to make sure all such statements will be identical */
+#define FREE_ALL() \
+ do {\
+ vDestroySmallBlockList();\
+ aulRootList = xfree(aulRootList);\
+ aulSbdList = xfree(aulSbdList);\
+ aulBbdList = xfree(aulBbdList);\
+ aulSBD = xfree(aulSBD);\
+ aulBBD = xfree(aulBBD);\
+ } while(0)
+
+
+/*
+ * ulReadLong - read four bytes from the given file and offset
+ */
+static ULONG
+ulReadLong(FILE *pFile, ULONG ulOffset)
+{
+ UCHAR aucBytes[4];
+
+ fail(pFile == NULL);
+
+ if (!bReadBytes(aucBytes, 4, ulOffset, pFile)) {
+ werr(1, "Read long 0x%lx not possible", ulOffset);
+ }
+ return ulGetLong(0, aucBytes);
+} /* end of ulReadLong */
+
+/*
+ * vName2String - turn the name into a proper string.
+ */
+static void
+vName2String(char *szName, const UCHAR *aucBytes, size_t tNameSize)
+{
+ char *pcChar;
+ size_t tIndex;
+
+ fail(aucBytes == NULL || szName == NULL);
+
+ if (tNameSize < 2) {
+ szName[0] = '\0';
+ return;
+ }
+ for (tIndex = 0, pcChar = szName;
+ tIndex < 2 * tNameSize;
+ tIndex += 2, pcChar++) {
+ *pcChar = (char)aucBytes[tIndex];
+ }
+ szName[tNameSize - 1] = '\0';
+} /* end of vName2String */
+
+/*
+ * tReadBlockIndices - read the Big/Small Block Depot indices
+ *
+ * Returns the number of indices read
+ */
+static size_t
+tReadBlockIndices(FILE *pFile, ULONG *aulBlockDepot,
+ size_t tMaxRec, ULONG ulOffset)
+{
+ size_t tDone;
+ int iIndex;
+ UCHAR aucBytes[BIG_BLOCK_SIZE];
+
+ fail(pFile == NULL || aulBlockDepot == NULL);
+ fail(tMaxRec == 0);
+
+ /* Read a big block with BBD or SBD indices */
+ if (!bReadBytes(aucBytes, BIG_BLOCK_SIZE, ulOffset, pFile)) {
+ werr(0, "Reading big block from 0x%lx is not possible",
+ ulOffset);
+ return 0;
+ }
+ /* Split the big block into indices, an index is four bytes */
+ tDone = min(tMaxRec, (size_t)BIG_BLOCK_SIZE / 4);
+ for (iIndex = 0; iIndex < (int)tDone; iIndex++) {
+ aulBlockDepot[iIndex] = ulGetLong(4 * iIndex, aucBytes);
+ NO_DBG_DEC(aulBlockDepot[iIndex]);
+ }
+ return tDone;
+} /* end of tReadBlockIndices */
+
+/*
+ * bGetBBD - get the Big Block Depot indices from the index-blocks
+ */
+static BOOL
+bGetBBD(FILE *pFile, const ULONG *aulDepot, size_t tDepotLen,
+ ULONG *aulBBD, size_t tBBDLen)
+{
+ ULONG ulBegin;
+ size_t tToGo, tDone;
+ int iIndex;
+
+ fail(pFile == NULL || aulDepot == NULL || aulBBD == NULL);
+
+ DBG_MSG("bGetBBD");
+
+ tToGo = tBBDLen;
+ for (iIndex = 0; iIndex < (int)tDepotLen && tToGo != 0; iIndex++) {
+ ulBegin = (aulDepot[iIndex] + 1) * BIG_BLOCK_SIZE;
+ NO_DBG_HEX(ulBegin);
+ tDone = tReadBlockIndices(pFile, aulBBD, tToGo, ulBegin);
+ fail(tDone > tToGo);
+ if (tDone == 0) {
+ return FALSE;
+ }
+ aulBBD += tDone;
+ tToGo -= tDone;
+ }
+ return tToGo == 0;
+} /* end of bGetBBD */
+
+/*
+ * bGetSBD - get the Small Block Depot indices from the index-blocks
+ */
+static BOOL
+bGetSBD(FILE *pFile, const ULONG *aulDepot, size_t tDepotLen,
+ ULONG *aulSBD, size_t tSBDLen)
+{
+ ULONG ulBegin;
+ size_t tToGo, tDone;
+ int iIndex;
+
+ fail(pFile == NULL || aulDepot == NULL || aulSBD == NULL);
+
+ DBG_MSG("bGetSBD");
+
+ tToGo = tSBDLen;
+ for (iIndex = 0; iIndex < (int)tDepotLen && tToGo != 0; iIndex++) {
+ fail(aulDepot[iIndex] >= ULONG_MAX / BIG_BLOCK_SIZE);
+ ulBegin = (aulDepot[iIndex] + 1) * BIG_BLOCK_SIZE;
+ NO_DBG_HEX(ulBegin);
+ tDone = tReadBlockIndices(pFile, aulSBD, tToGo, ulBegin);
+ fail(tDone > tToGo);
+ if (tDone == 0) {
+ return FALSE;
+ }
+ aulSBD += tDone;
+ tToGo -= tDone;
+ }
+ return tToGo == 0;
+} /* end of bGetSBD */
+
+/*
+ * vComputePPSlevels - compute the levels of the Property Set Storage entries
+ */
+static void
+vComputePPSlevels(pps_entry_type *atPPSlist, pps_entry_type *pNode,
+ int iLevel, int iRecursionLevel)
+{
+ fail(atPPSlist == NULL || pNode == NULL);
+ fail(iLevel < 0 || iRecursionLevel < 0);
+
+ if (iRecursionLevel > 25) {
+ /* This removes the possibility of an infinite recursion */
+ DBG_DEC(iRecursionLevel);
+ return;
+ }
+ if (pNode->iLevel <= iLevel) {
+ /* Avoid entering a loop */
+ DBG_DEC(iLevel);
+ DBG_DEC(pNode->iLevel);
+ return;
+ }
+
+ pNode->iLevel = iLevel;
+
+ if (pNode->ulDir != PPS_NUMBER_INVALID) {
+ vComputePPSlevels(atPPSlist,
+ &atPPSlist[pNode->ulDir],
+ iLevel + 1,
+ iRecursionLevel + 1);
+ }
+ if (pNode->ulNext != PPS_NUMBER_INVALID) {
+ vComputePPSlevels(atPPSlist,
+ &atPPSlist[pNode->ulNext],
+ iLevel,
+ iRecursionLevel + 1);
+ }
+ if (pNode->ulPrevious != PPS_NUMBER_INVALID) {
+ vComputePPSlevels(atPPSlist,
+ &atPPSlist[pNode->ulPrevious],
+ iLevel,
+ iRecursionLevel + 1);
+ }
+} /* end of vComputePPSlevels */
+
+/*
+ * bGetPPS - search the Property Set Storage for three sets
+ *
+ * Return TRUE if the WordDocument PPS is found
+ */
+static BOOL
+bGetPPS(FILE *pFile,
+ const ULONG *aulRootList, size_t tRootListLen, pps_info_type *pPPS)
+{
+ pps_entry_type *atPPSlist;
+ ULONG ulBegin, ulOffset, ulTmp;
+ size_t tNbrOfPPS, tNameSize;
+ int iIndex, iStartBlock, iRootIndex;
+ BOOL bWord, bExcel;
+ UCHAR aucBytes[PROPERTY_SET_STORAGE_SIZE];
+
+ fail(pFile == NULL || aulRootList == NULL || pPPS == NULL);
+
+ DBG_MSG("bGetPPS");
+
+ NO_DBG_DEC(tRootListLen);
+
+ bWord = FALSE;
+ bExcel = FALSE;
+ (void)memset(pPPS, 0, sizeof(*pPPS));
+
+ /* Read and store all the Property Set Storage entries */
+
+ tNbrOfPPS = tRootListLen * BIG_BLOCK_SIZE / PROPERTY_SET_STORAGE_SIZE;
+ atPPSlist = xcalloc(tNbrOfPPS, sizeof(pps_entry_type));
+ iRootIndex = 0;
+
+ for (iIndex = 0; iIndex < (int)tNbrOfPPS; iIndex++) {
+ ulTmp = (ULONG)iIndex * PROPERTY_SET_STORAGE_SIZE;
+ iStartBlock = (int)(ulTmp / BIG_BLOCK_SIZE);
+ ulOffset = ulTmp % BIG_BLOCK_SIZE;
+ ulBegin = (aulRootList[iStartBlock] + 1) * BIG_BLOCK_SIZE +
+ ulOffset;
+ NO_DBG_HEX(ulBegin);
+ if (!bReadBytes(aucBytes, PROPERTY_SET_STORAGE_SIZE,
+ ulBegin, pFile)) {
+ werr(0, "Reading PPS %d is not possible", iIndex);
+ atPPSlist = xfree(atPPSlist);
+ return FALSE;
+ }
+ tNameSize = (size_t)usGetWord(0x40, aucBytes);
+ tNameSize = (tNameSize + 1) / 2;
+ vName2String(atPPSlist[iIndex].szName, aucBytes, tNameSize);
+ atPPSlist[iIndex].ucType = ucGetByte(0x42, aucBytes);
+ if (atPPSlist[iIndex].ucType == 5) {
+ iRootIndex = iIndex;
+ }
+ atPPSlist[iIndex].ulPrevious = ulGetLong(0x44, aucBytes);
+ atPPSlist[iIndex].ulNext = ulGetLong(0x48, aucBytes);
+ atPPSlist[iIndex].ulDir = ulGetLong(0x4c, aucBytes);
+ atPPSlist[iIndex].ulSB = ulGetLong(0x74, aucBytes);
+ atPPSlist[iIndex].ulSize = ulGetLong(0x78, aucBytes);
+ atPPSlist[iIndex].iLevel = INT_MAX;
+ if ((atPPSlist[iIndex].ulPrevious >= (ULONG)tNbrOfPPS &&
+ atPPSlist[iIndex].ulPrevious != PPS_NUMBER_INVALID) ||
+ (atPPSlist[iIndex].ulNext >= (ULONG)tNbrOfPPS &&
+ atPPSlist[iIndex].ulNext != PPS_NUMBER_INVALID) ||
+ (atPPSlist[iIndex].ulDir >= (ULONG)tNbrOfPPS &&
+ atPPSlist[iIndex].ulDir != PPS_NUMBER_INVALID)) {
+ DBG_DEC(iIndex);
+ DBG_DEC(atPPSlist[iIndex].ulPrevious);
+ DBG_DEC(atPPSlist[iIndex].ulNext);
+ DBG_DEC(atPPSlist[iIndex].ulDir);
+ DBG_DEC(tNbrOfPPS);
+ werr(0, "The Property Set Storage is damaged");
+ atPPSlist = xfree(atPPSlist);
+ return FALSE;
+ }
+ }
+
+#if 0 /* defined(DEBUG) */
+ DBG_MSG("Before");
+ for (iIndex = 0; iIndex < (int)tNbrOfPPS; iIndex++) {
+ DBG_MSG(atPPSlist[iIndex].szName);
+ DBG_HEX(atPPSlist[iIndex].ulDir);
+ DBG_HEX(atPPSlist[iIndex].ulPrevious);
+ DBG_HEX(atPPSlist[iIndex].ulNext);
+ DBG_DEC(atPPSlist[iIndex].ulSB);
+ DBG_HEX(atPPSlist[iIndex].ulSize);
+ DBG_DEC(atPPSlist[iIndex].iLevel);
+ }
+#endif /* DEBUG */
+
+ /* Add level information to each entry */
+ vComputePPSlevels(atPPSlist, &atPPSlist[iRootIndex], 0, 0);
+
+ /* Check the entries on level 1 for the required information */
+ NO_DBG_MSG("After");
+ for (iIndex = 0; iIndex < (int)tNbrOfPPS; iIndex++) {
+#if 0 /* defined(DEBUG) */
+ DBG_MSG(atPPSlist[iIndex].szName);
+ DBG_HEX(atPPSlist[iIndex].ulDir);
+ DBG_HEX(atPPSlist[iIndex].ulPrevious);
+ DBG_HEX(atPPSlist[iIndex].ulNext);
+ DBG_DEC(atPPSlist[iIndex].ulSB);
+ DBG_HEX(atPPSlist[iIndex].ulSize);
+ DBG_DEC(atPPSlist[iIndex].iLevel);
+#endif /* DEBUG */
+ if (atPPSlist[iIndex].iLevel != 1 ||
+ atPPSlist[iIndex].ucType != 2 ||
+ atPPSlist[iIndex].szName[0] == '\0' ||
+ atPPSlist[iIndex].ulSize == 0) {
+ /* This entry can be ignored */
+ continue;
+ }
+ if (pPPS->tWordDocument.ulSize == 0 &&
+ STREQ(atPPSlist[iIndex].szName, "WordDocument")) {
+ pPPS->tWordDocument.ulSB = atPPSlist[iIndex].ulSB;
+ pPPS->tWordDocument.ulSize = atPPSlist[iIndex].ulSize;
+ bWord = TRUE;
+ } else if (pPPS->tData.ulSize == 0 &&
+ STREQ(atPPSlist[iIndex].szName, "Data")) {
+ pPPS->tData.ulSB = atPPSlist[iIndex].ulSB;
+ pPPS->tData.ulSize = atPPSlist[iIndex].ulSize;
+ } else if (pPPS->t0Table.ulSize == 0 &&
+ STREQ(atPPSlist[iIndex].szName, "0Table")) {
+ pPPS->t0Table.ulSB = atPPSlist[iIndex].ulSB;
+ pPPS->t0Table.ulSize = atPPSlist[iIndex].ulSize;
+ } else if (pPPS->t1Table.ulSize == 0 &&
+ STREQ(atPPSlist[iIndex].szName, "1Table")) {
+ pPPS->t1Table.ulSB = atPPSlist[iIndex].ulSB;
+ pPPS->t1Table.ulSize = atPPSlist[iIndex].ulSize;
+ } else if (pPPS->tSummaryInfo.ulSize == 0 &&
+ STREQ(atPPSlist[iIndex].szName,
+ "\005SummaryInformation")) {
+ pPPS->tSummaryInfo.ulSB = atPPSlist[iIndex].ulSB;
+ pPPS->tSummaryInfo.ulSize = atPPSlist[iIndex].ulSize;
+ } else if (pPPS->tDocSummaryInfo.ulSize == 0 &&
+ STREQ(atPPSlist[iIndex].szName,
+ "\005DocumentSummaryInformation")) {
+ pPPS->tDocSummaryInfo.ulSB = atPPSlist[iIndex].ulSB;
+ pPPS->tDocSummaryInfo.ulSize = atPPSlist[iIndex].ulSize;
+ } else if (STREQ(atPPSlist[iIndex].szName, "Book") ||
+ STREQ(atPPSlist[iIndex].szName, "Workbook")) {
+ bExcel = TRUE;
+ }
+ }
+
+ /* Free the space for the Property Set Storage entries */
+ atPPSlist = xfree(atPPSlist);
+
+ /* Draw your conclusions */
+ if (bWord) {
+ return TRUE;
+ }
+
+ if (bExcel) {
+ werr(0, "Sorry, but this is an Excel spreadsheet");
+ } else {
+ werr(0, "This OLE file does not contain a Word document");
+ }
+ return FALSE;
+} /* end of bGetPPS */
+
+/*
+ * vGetBbdList - make a list of the places to find big blocks
+ */
+static void
+vGetBbdList(FILE *pFile, int iNbr, ULONG *aulBbdList, ULONG ulOffset)
+{
+ int iIndex;
+
+ fail(pFile == NULL);
+ fail(iNbr > 127);
+ fail(aulBbdList == NULL);
+
+ NO_DBG_DEC(iNbr);
+ for (iIndex = 0; iIndex < iNbr; iIndex++) {
+ aulBbdList[iIndex] =
+ ulReadLong(pFile, ulOffset + 4 * (ULONG)iIndex);
+ NO_DBG_DEC(iIndex);
+ NO_DBG_HEX(aulBbdList[iIndex]);
+ }
+} /* end of vGetBbdList */
+
+/*
+ * bGetDocumentText - make a list of the text blocks of a Word document
+ *
+ * Return TRUE when succesful, otherwise FALSE
+ */
+static BOOL
+bGetDocumentText(FILE *pFile, const pps_info_type *pPPS,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const ULONG *aulSBD, size_t tSBDLen,
+ const UCHAR *aucHeader, int iWordVersion)
+{
+ ULONG ulBeginOfText;
+ ULONG ulTextLen, ulFootnoteLen, ulEndnoteLen;
+ ULONG ulHdrFtrLen, ulMacroLen, ulAnnotationLen;
+ ULONG ulTextBoxLen, ulHdrTextBoxLen;
+ UINT uiQuickSaves;
+ BOOL bFarEastWord, bTemplate, bFastSaved, bEncrypted, bSuccess;
+ USHORT usIdent, usDocStatus;
+
+ fail(pFile == NULL || pPPS == NULL);
+ fail(aulBBD == NULL);
+ fail(aulSBD == NULL);
+
+ DBG_MSG("bGetDocumentText");
+
+ /* Get the "magic number" from the header */
+ usIdent = usGetWord(0x00, aucHeader);
+ DBG_HEX(usIdent);
+ bFarEastWord = usIdent == 0x8098 || usIdent == 0x8099 ||
+ usIdent == 0xa697 || usIdent == 0xa699;
+ /* Get the status flags from the header */
+ usDocStatus = usGetWord(0x0a, aucHeader);
+ DBG_HEX(usDocStatus);
+ bTemplate = (usDocStatus & BIT(0)) != 0;
+ DBG_MSG_C(bTemplate, "This document is a Template");
+ bFastSaved = (usDocStatus & BIT(2)) != 0;
+ uiQuickSaves = (UINT)(usDocStatus & 0x00f0) >> 4;
+ DBG_MSG_C(bFastSaved, "This document is Fast Saved");
+ DBG_DEC_C(bFastSaved, uiQuickSaves);
+ bEncrypted = (usDocStatus & BIT(8)) != 0;
+ if (bEncrypted) {
+ werr(0, "Encrypted documents are not supported");
+ return FALSE;
+ }
+
+ /* Get length information */
+ ulBeginOfText = ulGetLong(0x18, aucHeader);
+ DBG_HEX(ulBeginOfText);
+ switch (iWordVersion) {
+ case 6:
+ case 7:
+ ulTextLen = ulGetLong(0x34, aucHeader);
+ ulFootnoteLen = ulGetLong(0x38, aucHeader);
+ ulHdrFtrLen = ulGetLong(0x3c, aucHeader);
+ ulMacroLen = ulGetLong(0x40, aucHeader);
+ ulAnnotationLen = ulGetLong(0x44, aucHeader);
+ ulEndnoteLen = ulGetLong(0x48, aucHeader);
+ ulTextBoxLen = ulGetLong(0x4c, aucHeader);
+ ulHdrTextBoxLen = ulGetLong(0x50, aucHeader);
+ break;
+ case 8:
+ ulTextLen = ulGetLong(0x4c, aucHeader);
+ ulFootnoteLen = ulGetLong(0x50, aucHeader);
+ ulHdrFtrLen = ulGetLong(0x54, aucHeader);
+ ulMacroLen = ulGetLong(0x58, aucHeader);
+ ulAnnotationLen = ulGetLong(0x5c, aucHeader);
+ ulEndnoteLen = ulGetLong(0x60, aucHeader);
+ ulTextBoxLen = ulGetLong(0x64, aucHeader);
+ ulHdrTextBoxLen = ulGetLong(0x68, aucHeader);
+ break;
+ default:
+ werr(0, "This version of Word is not supported");
+ return FALSE;
+ }
+ DBG_DEC(ulTextLen);
+ DBG_DEC(ulFootnoteLen);
+ DBG_DEC(ulHdrFtrLen);
+ DBG_DEC(ulMacroLen);
+ DBG_DEC(ulAnnotationLen);
+ DBG_DEC(ulEndnoteLen);
+ DBG_DEC(ulTextBoxLen);
+ DBG_DEC(ulHdrTextBoxLen);
+
+ /* Make a list of the text blocks */
+ switch (iWordVersion) {
+ case 6:
+ case 7:
+ if (bFastSaved) {
+ bSuccess = bGet6DocumentText(pFile,
+ bFarEastWord,
+ pPPS->tWordDocument.ulSB,
+ aulBBD, tBBDLen,
+ aucHeader);
+ } else {
+ bSuccess = bAddTextBlocks(ulBeginOfText,
+ ulTextLen +
+ ulFootnoteLen +
+ ulHdrFtrLen +
+ ulMacroLen + ulAnnotationLen +
+ ulEndnoteLen +
+ ulTextBoxLen + ulHdrTextBoxLen,
+ bFarEastWord,
+ IGNORE_PROPMOD,
+ pPPS->tWordDocument.ulSB,
+ aulBBD, tBBDLen);
+ }
+ break;
+ case 8:
+ bSuccess = bGet8DocumentText(pFile,
+ pPPS,
+ aulBBD, tBBDLen, aulSBD, tSBDLen,
+ aucHeader);
+ break;
+ default:
+ werr(0, "This version of Word is not supported");
+ bSuccess = FALSE;
+ break;
+ }
+
+ if (bSuccess) {
+ vSplitBlockList(pFile,
+ ulTextLen,
+ ulFootnoteLen,
+ ulHdrFtrLen,
+ ulMacroLen,
+ ulAnnotationLen,
+ ulEndnoteLen,
+ ulTextBoxLen,
+ ulHdrTextBoxLen,
+ !bFastSaved && iWordVersion == 8);
+ } else {
+ vDestroyTextBlockList();
+ werr(0, "I can't find the text of this document");
+ }
+ return bSuccess;
+} /* end of bGetDocumentText */
+
+/*
+ * vGetDocumentData - make a list of the data blocks of a Word document
+ */
+static void
+vGetDocumentData(FILE *pFile, const pps_info_type *pPPS,
+ const ULONG *aulBBD, size_t tBBDLen,
+ const UCHAR *aucHeader, int iWordVersion)
+{
+ options_type tOptions;
+ ULONG ulBeginOfText;
+ BOOL bFastSaved, bHasImages, bSuccess;
+ USHORT usDocStatus;
+
+ fail(pFile == NULL);
+ fail(pPPS == NULL);
+ fail(aulBBD == NULL);
+
+ /* Get the options */
+ vGetOptions(&tOptions);
+
+ /* Get the status flags from the header */
+ usDocStatus = usGetWord(0x0a, aucHeader);
+ DBG_HEX(usDocStatus);
+ bFastSaved = (usDocStatus & BIT(2)) != 0;
+ bHasImages = (usDocStatus & BIT(3)) != 0;
+
+ if (!bHasImages ||
+ tOptions.eConversionType == conversion_text ||
+ tOptions.eConversionType == conversion_fmt_text ||
+ tOptions.eConversionType == conversion_xml ||
+ tOptions.eImageLevel == level_no_images) {
+ /*
+ * No images in the document or text-only output or
+ * no images wanted, so no data blocks will be needed
+ */
+ vDestroyDataBlockList();
+ return;
+ }
+
+ /* Get length information */
+ ulBeginOfText = ulGetLong(0x18, aucHeader);
+ DBG_HEX(ulBeginOfText);
+
+ /* Make a list of the data blocks */
+ switch (iWordVersion) {
+ case 6:
+ case 7:
+ /*
+ * The data blocks are in the text stream. The text stream
+ * is in "fast saved" format or "normal saved" format
+ */
+ if (bFastSaved) {
+ bSuccess = bGet6DocumentData(pFile,
+ pPPS->tWordDocument.ulSB,
+ aulBBD, tBBDLen,
+ aucHeader);
+ } else {
+ bSuccess = bAddDataBlocks(ulBeginOfText,
+ (ULONG)LONG_MAX,
+ pPPS->tWordDocument.ulSB,
+ aulBBD, tBBDLen);
+ }
+ break;
+ case 8:
+ /*
+ * The data blocks are in the data stream. The data stream
+ * is always in "normal saved" format
+ */
+ bSuccess = bAddDataBlocks(0, (ULONG)LONG_MAX,
+ pPPS->tData.ulSB, aulBBD, tBBDLen);
+ break;
+ default:
+ werr(0, "This version of Word is not supported");
+ bSuccess = FALSE;
+ break;
+ }
+
+ if (!bSuccess) {
+ vDestroyDataBlockList();
+ werr(0, "I can't find the data of this document");
+ }
+} /* end of vGetDocumentData */
+
+/*
+ * iInitDocumentOLE - initialize an OLE document
+ *
+ * Returns the version of Word that made the document or -1
+ */
+int
+iInitDocumentOLE(FILE *pFile, long lFilesize)
+{
+ pps_info_type PPS_info;
+ ULONG *aulBBD, *aulSBD;
+ ULONG *aulRootList, *aulBbdList, *aulSbdList;
+ ULONG ulBdbListStart, ulAdditionalBBDlist;
+ ULONG ulRootStartblock, ulSbdStartblock, ulSBLstartblock;
+ ULONG ulStart, ulTmp;
+ long lMaxBlock;
+ size_t tBBDLen, tSBDLen, tNumBbdBlocks, tRootListLen;
+ int iWordVersion, iIndex, iToGo;
+ BOOL bSuccess;
+ USHORT usIdent, usDocStatus;
+ UCHAR aucHeader[HEADER_SIZE];
+
+ fail(pFile == NULL);
+
+ lMaxBlock = lFilesize / BIG_BLOCK_SIZE - 2;
+ DBG_DEC(lMaxBlock);
+ if (lMaxBlock < 1) {
+ return -1;
+ }
+ tBBDLen = (size_t)(lMaxBlock + 1);
+ tNumBbdBlocks = (size_t)ulReadLong(pFile, 0x2c);
+ DBG_DEC(tNumBbdBlocks);
+ ulRootStartblock = ulReadLong(pFile, 0x30);
+ DBG_DEC(ulRootStartblock);
+ ulSbdStartblock = ulReadLong(pFile, 0x3c);
+ DBG_DEC(ulSbdStartblock);
+ ulAdditionalBBDlist = ulReadLong(pFile, 0x44);
+ DBG_HEX(ulAdditionalBBDlist);
+ ulSBLstartblock = ulReadLong(pFile,
+ (ulRootStartblock + 1) * BIG_BLOCK_SIZE + 0x74);
+ DBG_DEC(ulSBLstartblock);
+ tSBDLen = (size_t)(ulReadLong(pFile,
+ (ulRootStartblock + 1) * BIG_BLOCK_SIZE + 0x78) /
+ SMALL_BLOCK_SIZE);
+ /* All to be xcalloc-ed pointers to NULL */
+ aulRootList = NULL;
+ aulSbdList = NULL;
+ aulBbdList = NULL;
+ aulSBD = NULL;
+ aulBBD = NULL;
+/* Big Block Depot */
+ aulBbdList = xcalloc(tNumBbdBlocks, sizeof(ULONG));
+ aulBBD = xcalloc(tBBDLen, sizeof(ULONG));
+ iToGo = (int)tNumBbdBlocks;
+ vGetBbdList(pFile, min(iToGo, 109), aulBbdList, 0x4c);
+ ulStart = 109;
+ iToGo -= 109;
+ while (ulAdditionalBBDlist != END_OF_CHAIN && iToGo > 0) {
+ ulBdbListStart = (ulAdditionalBBDlist + 1) * BIG_BLOCK_SIZE;
+ vGetBbdList(pFile, min(iToGo, 127),
+ aulBbdList + ulStart, ulBdbListStart);
+ ulAdditionalBBDlist = ulReadLong(pFile,
+ ulBdbListStart + 4 * 127);
+ DBG_DEC(ulAdditionalBBDlist);
+ DBG_HEX(ulAdditionalBBDlist);
+ ulStart += 127;
+ iToGo -= 127;
+ }
+ if (!bGetBBD(pFile, aulBbdList, tNumBbdBlocks, aulBBD, tBBDLen)) {
+ FREE_ALL();
+ return -1;
+ }
+ aulBbdList = xfree(aulBbdList);
+/* Small Block Depot */
+ aulSbdList = xcalloc(tBBDLen, sizeof(ULONG));
+ aulSBD = xcalloc(tSBDLen, sizeof(ULONG));
+ for (iIndex = 0, ulTmp = ulSbdStartblock;
+ iIndex < (int)tBBDLen && ulTmp != END_OF_CHAIN;
+ iIndex++, ulTmp = aulBBD[ulTmp]) {
+ if (ulTmp >= (ULONG)tBBDLen) {
+ DBG_DEC(ulTmp);
+ DBG_DEC(tBBDLen);
+ werr(1, "The Big Block Depot is damaged");
+ }
+ aulSbdList[iIndex] = ulTmp;
+ NO_DBG_HEX(aulSbdList[iIndex]);
+ }
+ if (!bGetSBD(pFile, aulSbdList, tBBDLen, aulSBD, tSBDLen)) {
+ FREE_ALL();
+ return -1;
+ }
+ aulSbdList = xfree(aulSbdList);
+/* Root list */
+ for (tRootListLen = 0, ulTmp = ulRootStartblock;
+ tRootListLen < tBBDLen && ulTmp != END_OF_CHAIN;
+ tRootListLen++, ulTmp = aulBBD[ulTmp]) {
+ if (ulTmp >= (ULONG)tBBDLen) {
+ DBG_DEC(ulTmp);
+ DBG_DEC(tBBDLen);
+ werr(1, "The Big Block Depot is damaged");
+ }
+ }
+ if (tRootListLen == 0) {
+ werr(0, "No Rootlist found");
+ FREE_ALL();
+ return -1;
+ }
+ aulRootList = xcalloc(tRootListLen, sizeof(ULONG));
+ for (iIndex = 0, ulTmp = ulRootStartblock;
+ iIndex < (int)tBBDLen && ulTmp != END_OF_CHAIN;
+ iIndex++, ulTmp = aulBBD[ulTmp]) {
+ if (ulTmp >= (ULONG)tBBDLen) {
+ DBG_DEC(ulTmp);
+ DBG_DEC(tBBDLen);
+ werr(1, "The Big Block Depot is damaged");
+ }
+ aulRootList[iIndex] = ulTmp;
+ NO_DBG_DEC(aulRootList[iIndex]);
+ }
+ fail(tRootListLen != (size_t)iIndex);
+ bSuccess = bGetPPS(pFile, aulRootList, tRootListLen, &PPS_info);
+ aulRootList = xfree(aulRootList);
+ if (!bSuccess) {
+ FREE_ALL();
+ return -1;
+ }
+/* Small block list */
+ if (!bCreateSmallBlockList(ulSBLstartblock, aulBBD, tBBDLen)) {
+ FREE_ALL();
+ return -1;
+ }
+
+ if (PPS_info.tWordDocument.ulSize < MIN_SIZE_FOR_BBD_USE) {
+ DBG_DEC(PPS_info.tWordDocument.ulSize);
+ FREE_ALL();
+ werr(0, "I'm afraid the text stream of this file "
+ "is too small to handle.");
+ return -1;
+ }
+ /* Read the headerblock */
+ if (!bReadBuffer(pFile, PPS_info.tWordDocument.ulSB,
+ aulBBD, tBBDLen, BIG_BLOCK_SIZE,
+ aucHeader, 0, HEADER_SIZE)) {
+ FREE_ALL();
+ return -1;
+ }
+ usIdent = usGetWord(0x00, aucHeader);
+ DBG_HEX(usIdent);
+ fail(usIdent != 0x8098 && /* Word 7 for oriental languages */
+ usIdent != 0x8099 && /* Word 7 for oriental languages */
+ usIdent != 0xa5dc && /* Word 6 & 7 */
+ usIdent != 0xa5ec && /* Word 7 & 97 & 98 */
+ usIdent != 0xa697 && /* Word 7 for oriental languages */
+ usIdent != 0xa699); /* Word 7 for oriental languages */
+ iWordVersion = iGetVersionNumber(aucHeader);
+ if (iWordVersion < 6) {
+ FREE_ALL();
+ werr(0, "This file is from a version of Word before Word 6.");
+ return -1;
+ }
+
+ /* Get the status flags from the header */
+ usDocStatus = usGetWord(0x0a, aucHeader);
+ if (usDocStatus & BIT(9)) {
+ PPS_info.tTable = PPS_info.t1Table;
+ } else {
+ PPS_info.tTable = PPS_info.t0Table;
+ }
+ /* Clean the entries that should not be used */
+ memset(&PPS_info.t0Table, 0, sizeof(PPS_info.t0Table));
+ memset(&PPS_info.t1Table, 0, sizeof(PPS_info.t1Table));
+
+ bSuccess = bGetDocumentText(pFile, &PPS_info,
+ aulBBD, tBBDLen, aulSBD, tSBDLen,
+ aucHeader, iWordVersion);
+ if (bSuccess) {
+ vGetDocumentData(pFile, &PPS_info,
+ aulBBD, tBBDLen, aucHeader, iWordVersion);
+ vGetPropertyInfo(pFile, &PPS_info,
+ aulBBD, tBBDLen, aulSBD, tSBDLen,
+ aucHeader, iWordVersion);
+ vSetDefaultTabWidth(pFile, &PPS_info,
+ aulBBD, tBBDLen, aulSBD, tSBDLen,
+ aucHeader, iWordVersion);
+ vGetNotesInfo(pFile, &PPS_info,
+ aulBBD, tBBDLen, aulSBD, tSBDLen,
+ aucHeader, iWordVersion);
+ }
+ FREE_ALL();
+ return bSuccess ? iWordVersion : -1;
+} /* end of iInitDocumentOLE */
diff --git a/sys/src/cmd/aux/antiword/wordtypes.h b/sys/src/cmd/aux/antiword/wordtypes.h
new file mode 100755
index 000000000..d71dc8f6d
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/wordtypes.h
@@ -0,0 +1,317 @@
+/*
+ * wordtypes.h
+ * Copyright (C) 1998-2004 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Typedefs for the interpretation of MS Word files
+ */
+
+#if !defined(__wordtypes_h)
+#define __wordtypes_h 1
+
+#include <time.h>
+#if defined(__riscos)
+#include "DeskLib:Font.h"
+#include "DeskLib:Wimp.h"
+#endif /* __riscos */
+
+typedef unsigned char UCHAR;
+typedef unsigned short USHORT;
+typedef unsigned int UINT;
+typedef unsigned long ULONG;
+
+#if defined(__riscos)
+typedef struct diagram_tag {
+ drawfile_info tInfo;
+ window_handle tMainWindow;
+ window_handle tScaleWindow;
+ menu_ptr pSaveMenu;
+ long lXleft; /* In DrawUnits */
+ long lYtop; /* In DrawUnits */
+ size_t tMemorySize;
+ int iScaleFactorCurr; /* In percentage */
+ int iScaleFactorTemp; /* In percentage */
+ char szFilename[19+1];
+} diagram_type;
+#else
+typedef struct diagram_tag {
+ FILE *pOutFile;
+ long lXleft; /* In DrawUnits */
+ long lYtop; /* In DrawUnits */
+} diagram_type;
+typedef UCHAR drawfile_fontref;
+#endif /* __riscos */
+
+typedef struct output_tag {
+ char *szStorage;
+ long lStringWidth; /* In millipoints */
+ size_t tStorageSize;
+ size_t tNextFree;
+ USHORT usFontStyle;
+ USHORT usFontSize;
+ UCHAR ucFontColor;
+ drawfile_fontref tFontRef;
+ struct output_tag *pPrev;
+ struct output_tag *pNext;
+} output_type;
+
+/* Types of conversion */
+typedef enum conversion_tag {
+ conversion_unknown = 0,
+ conversion_text,
+ conversion_draw,
+ conversion_ps,
+ conversion_xml,
+ conversion_pdf,
+ conversion_fmt_text
+} conversion_type;
+
+/* Types of encoding */
+typedef enum encoding_tag {
+ encoding_neutral = 100,
+ encoding_latin_1 = 801,
+ encoding_latin_2 = 802,
+ encoding_cyrillic = 805,
+ encoding_utf_8 = 1601
+} encoding_type;
+
+/* Font translation table entry */
+typedef struct font_table_tag {
+ USHORT usFontStyle;
+ UCHAR ucWordFontNumber;
+ UCHAR ucFFN;
+ UCHAR ucEmphasis;
+ UCHAR ucInUse;
+ char szWordFontname[65];
+ char szOurFontname[33];
+} font_table_type;
+
+/* Options */
+typedef enum image_level_tag {
+ level_gs_special = 0,
+ level_no_images,
+ level_ps_2,
+ level_ps_3,
+ level_default = level_ps_2
+} image_level_enum;
+
+typedef struct options_tag {
+ int iParagraphBreak;
+ conversion_type eConversionType;
+ BOOL bHideHiddenText;
+ BOOL bRemoveRemovedText;
+ BOOL bUseLandscape;
+ encoding_type eEncoding;
+ int iPageHeight; /* In points */
+ int iPageWidth; /* In points */
+ image_level_enum eImageLevel;
+#if defined(__riscos)
+ BOOL bAutofiletypeAllowed;
+ int iScaleFactor; /* As a percentage */
+#endif /* __riscos */
+} options_type;
+
+/* Property Set Storage */
+typedef struct pps_tag {
+ ULONG ulSB;
+ ULONG ulSize;
+} pps_type;
+typedef struct pps_info_tag {
+ pps_type tWordDocument; /* Text stream */
+ pps_type tData; /* Data stream */
+ pps_type tTable; /* Table stream */
+ pps_type tSummaryInfo; /* Summary Information */
+ pps_type tDocSummaryInfo;/* Document Summary Information */
+ pps_type t0Table; /* Table 0 stream */
+ pps_type t1Table; /* Table 1 stream */
+} pps_info_type;
+
+/* Record of data block information */
+typedef struct data_block_tag {
+ ULONG ulFileOffset;
+ ULONG ulDataPos;
+ ULONG ulLength;
+} data_block_type;
+
+/* Record of text block information */
+typedef struct text_block_tag {
+ ULONG ulFileOffset;
+ ULONG ulCharPos;
+ ULONG ulLength;
+ BOOL bUsesUnicode; /* This block uses 16 bits per character */
+ USHORT usPropMod;
+} text_block_type;
+
+/* Record of the document block information */
+typedef struct document_block_tag {
+ time_t tCreateDate; /* Unix timestamp */
+ time_t tRevisedDate; /* Unix timestamp */
+ USHORT usDefaultTabWidth; /* In twips */
+ UCHAR ucHdrFtrSpecification;
+} document_block_type;
+
+/* Record of table-row block information */
+typedef struct row_block_tag {
+ ULONG ulFileOffsetStart;
+ ULONG ulFileOffsetEnd;
+ ULONG ulCharPosStart;
+ ULONG ulCharPosEnd;
+ short asColumnWidth[TABLE_COLUMN_MAX+1]; /* In twips */
+ UCHAR ucNumberOfColumns;
+ UCHAR ucBorderInfo;
+} row_block_type;
+
+/* Various level types */
+typedef enum level_type_tag {
+ level_type_none = 0,
+ level_type_outline,
+ level_type_numbering,
+ level_type_sequence,
+ level_type_pause
+} level_type_enum;
+
+typedef enum list_id_tag {
+ no_list = 0,
+ text_list,
+ footnote_list,
+ hdrftr_list,
+ macro_list,
+ annotation_list,
+ endnote_list,
+ textbox_list,
+ hdrtextbox_list,
+ end_of_lists
+} list_id_enum;
+
+/* Linked list of style description information */
+typedef struct style_block_tag {
+ ULONG ulFileOffset; /* The style start with this character */
+ list_id_enum eListID;/* The fileoffset is in this list */
+ BOOL bNumPause;
+ BOOL bNoRestart; /* Don't restart by more significant levels */
+ USHORT usIstd; /* Current style */
+ USHORT usIstdNext; /* Next style unless overruled */
+ USHORT usStartAt; /* Number at the start of a list */
+ USHORT usBeforeIndent; /* Vertical indent before paragraph in twips */
+ USHORT usAfterIndent; /* Vertical indent after paragraph in twips */
+ USHORT usListIndex; /* Before Word 8 this field was not filled */
+ USHORT usListChar; /* Character for an itemized list (Unicode) */
+ short sLeftIndent; /* Left indentation in twips */
+ short sLeftIndent1; /* First line left indentation in twips */
+ short sRightIndent; /* Right indentation in twips */
+ UCHAR ucAlignment;
+ UCHAR ucNFC; /* Number format code */
+ UCHAR ucNumLevel;
+ UCHAR ucListLevel; /* Before Word 8 this field was not filled */
+ char szListChar[4]; /* Character for an itemized list */
+} style_block_type;
+
+/* Font description information */
+typedef struct font_block_tag {
+ ULONG ulFileOffset;
+ USHORT usFontStyle;
+ USHORT usFontSize;
+ UCHAR ucFontNumber;
+ UCHAR ucFontColor;
+} font_block_type;
+
+/* Picture description information */
+typedef struct picture_block_tag {
+ ULONG ulFileOffset;
+ ULONG ulFileOffsetPicture;
+ ULONG ulPictureOffset;
+} picture_block_type;
+
+/* Section description information */
+typedef struct section_block_tag {
+ BOOL bNewPage;
+ USHORT usNeedPrevLvl; /* Print previous level numbers */
+ USHORT usHangingIndent;
+ UCHAR aucNFC[9]; /* Number format code */
+ UCHAR ucHdrFtrSpecification; /* Which headers/footers Word < 8 */
+} section_block_type;
+
+/* Header/footer description information */
+typedef struct hdrftr_block_tag {
+ output_type *pText;
+ long lHeight; /* In DrawUnits */
+} hdrftr_block_type;
+
+/* Footnote description information */
+typedef struct footnote_block_tag {
+ char *szText;
+} footnote_block_type;
+
+/* List description information */
+typedef struct list_block_tag {
+ ULONG ulStartAt; /* Number at the start of a list */
+ BOOL bNoRestart; /* Don't restart by more significant levels */
+ USHORT usListChar; /* Character for an itemized list (Unicode) */
+ short sLeftIndent; /* Left indentation in twips */
+ UCHAR ucNFC; /* Number format code */
+} list_block_type;
+
+/* Types of images */
+typedef enum imagetype_tag {
+ imagetype_is_unknown = 0,
+ imagetype_is_external,
+ imagetype_is_emf,
+ imagetype_is_wmf,
+ imagetype_is_pict,
+ imagetype_is_jpeg,
+ imagetype_is_png,
+ imagetype_is_dib
+} imagetype_enum;
+
+/* Types of compression */
+typedef enum compression_tag {
+ compression_unknown = 0,
+ compression_none,
+ compression_rle4,
+ compression_rle8,
+ compression_jpeg,
+ compression_zlib
+} compression_enum;
+
+/* Image information */
+typedef struct imagedata_tag {
+ /* The type of the image */
+ imagetype_enum eImageType;
+ /* Information from the Word document */
+ size_t tPosition;
+ size_t tLength;
+ int iHorSizeScaled; /* Size in points */
+ int iVerSizeScaled; /* Size in points */
+ /* Information from the image */
+ int iWidth; /* Size in pixels */
+ int iHeight; /* Size in pixels */
+ int iComponents; /* Number of color components */
+ UINT uiBitsPerComponent; /* Bits per color component */
+ BOOL bAdobe; /* Image includes Adobe comment marker */
+ compression_enum eCompression; /* Type of compression */
+ BOOL bColorImage; /* Is color image */
+ int iColorsUsed; /* 0 = uses the maximum number of colors */
+ UCHAR aucPalette[256][3]; /* RGB palette */
+} imagedata_type;
+
+typedef enum row_info_tag {
+ found_nothing,
+ found_a_cell,
+ found_not_a_cell,
+ found_end_of_row,
+ found_not_end_of_row
+} row_info_enum;
+
+typedef enum notetype_tag {
+ notetype_is_footnote,
+ notetype_is_endnote,
+ notetype_is_unknown
+} notetype_enum;
+
+typedef enum image_info_tag {
+ image_no_information,
+ image_minimal_information,
+ image_full_information
+} image_info_enum;
+
+#endif /* __wordtypes_h */
diff --git a/sys/src/cmd/aux/antiword/wordwin.c b/sys/src/cmd/aux/antiword/wordwin.c
new file mode 100755
index 000000000..d31b7be5e
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/wordwin.c
@@ -0,0 +1,209 @@
+/*
+ * wordwin.c
+ * Copyright (C) 2002-2005 A.J. van Os; Released under GPL
+ *
+ * Description:
+ * Deal with the WIN internals of a MS Word file
+ */
+
+#include "antiword.h"
+
+
+/*
+ * bGetDocumentText - make a list of the text blocks of a Word document
+ *
+ * Return TRUE when succesful, otherwise FALSE
+ */
+static BOOL
+bGetDocumentText(FILE *pFile, const UCHAR *aucHeader)
+{
+ text_block_type tTextBlock;
+ ULONG ulBeginOfText;
+ ULONG ulTextLen, ulFootnoteLen;
+ ULONG ulHdrFtrLen, ulMacroLen, ulAnnotationLen;
+ UINT uiQuickSaves;
+ USHORT usDocStatus;
+ BOOL bTemplate, bFastSaved, bEncrypted, bSuccess;
+
+ fail(pFile == NULL);
+ fail(aucHeader == NULL);
+
+ DBG_MSG("bGetDocumentText");
+
+ /* Get the status flags from the header */
+ usDocStatus = usGetWord(0x0a, aucHeader);
+ DBG_HEX(usDocStatus);
+ bTemplate = (usDocStatus & BIT(0)) != 0;
+ DBG_MSG_C(bTemplate, "This document is a Template");
+ bFastSaved = (usDocStatus & BIT(2)) != 0;
+ uiQuickSaves = (UINT)(usDocStatus & 0x00f0) >> 4;
+ DBG_MSG_C(bFastSaved, "This document is Fast Saved");
+ DBG_DEC_C(bFastSaved, uiQuickSaves);
+ if (bFastSaved) {
+ werr(0, "Word2: fast saved documents are not supported yet");
+ return FALSE;
+ }
+ bEncrypted = (usDocStatus & BIT(8)) != 0;
+ if (bEncrypted) {
+ werr(0, "Encrypted documents are not supported");
+ return FALSE;
+ }
+
+ /* Get length information */
+ ulBeginOfText = ulGetLong(0x18, aucHeader);
+ DBG_HEX(ulBeginOfText);
+ ulTextLen = ulGetLong(0x34, aucHeader);
+ ulFootnoteLen = ulGetLong(0x38, aucHeader);
+ ulHdrFtrLen = ulGetLong(0x3c, aucHeader);
+ ulMacroLen = ulGetLong(0x40, aucHeader);
+ ulAnnotationLen = ulGetLong(0x44, aucHeader);
+ DBG_DEC(ulTextLen);
+ DBG_DEC(ulFootnoteLen);
+ DBG_DEC(ulHdrFtrLen);
+ DBG_DEC(ulMacroLen);
+ DBG_DEC(ulAnnotationLen);
+ if (bFastSaved) {
+ bSuccess = FALSE;
+ } else {
+ tTextBlock.ulFileOffset = ulBeginOfText;
+ tTextBlock.ulCharPos = ulBeginOfText;
+ tTextBlock.ulLength = ulTextLen +
+ ulFootnoteLen +
+ ulHdrFtrLen + ulMacroLen + ulAnnotationLen;
+ tTextBlock.bUsesUnicode = FALSE;
+ tTextBlock.usPropMod = IGNORE_PROPMOD;
+ bSuccess = bAdd2TextBlockList(&tTextBlock);
+ DBG_HEX_C(!bSuccess, tTextBlock.ulFileOffset);
+ DBG_HEX_C(!bSuccess, tTextBlock.ulCharPos);
+ DBG_DEC_C(!bSuccess, tTextBlock.ulLength);
+ DBG_DEC_C(!bSuccess, tTextBlock.bUsesUnicode);
+ DBG_DEC_C(!bSuccess, tTextBlock.usPropMod);
+ }
+
+ if (bSuccess) {
+ vSplitBlockList(pFile,
+ ulTextLen,
+ ulFootnoteLen,
+ ulHdrFtrLen,
+ ulMacroLen,
+ ulAnnotationLen,
+ 0,
+ 0,
+ 0,
+ FALSE);
+ } else {
+ vDestroyTextBlockList();
+ werr(0, "I can't find the text of this document");
+ }
+ return bSuccess;
+} /* end of bGetDocumentText */
+
+/*
+ * vGetDocumentData - make a list of the data blocks of a Word document
+ */
+static void
+vGetDocumentData(FILE *pFile, const UCHAR *aucHeader)
+{
+ data_block_type tDataBlock;
+ options_type tOptions;
+ ULONG ulEndOfText, ulBeginCharInfo;
+ BOOL bFastSaved, bHasImages, bSuccess;
+ USHORT usDocStatus;
+
+ /* Get the options */
+ vGetOptions(&tOptions);
+
+ /* Get the status flags from the header */
+ usDocStatus = usGetWord(0x0a, aucHeader);
+ DBG_HEX(usDocStatus);
+ bFastSaved = (usDocStatus & BIT(2)) != 0;
+ bHasImages = (usDocStatus & BIT(3)) != 0;
+
+ if (!bHasImages ||
+ tOptions.eConversionType == conversion_text ||
+ tOptions.eConversionType == conversion_fmt_text ||
+ tOptions.eConversionType == conversion_xml ||
+ tOptions.eImageLevel == level_no_images) {
+ /*
+ * No images in the document or text-only output or
+ * no images wanted, so no data blocks will be needed
+ */
+ vDestroyDataBlockList();
+ return;
+ }
+
+ if (bFastSaved) {
+ bSuccess = FALSE;
+ } else {
+ /* This datablock is too big, but it contains all images */
+ ulEndOfText = ulGetLong(0x1c, aucHeader);
+ DBG_HEX(ulEndOfText);
+ ulBeginCharInfo = ulGetLong(0xa0, aucHeader);
+ DBG_HEX(ulBeginCharInfo);
+ if (ulBeginCharInfo > ulEndOfText) {
+ tDataBlock.ulFileOffset = ulEndOfText;
+ tDataBlock.ulDataPos = ulEndOfText;
+ tDataBlock.ulLength = ulBeginCharInfo - ulEndOfText;
+ bSuccess = bAdd2DataBlockList(&tDataBlock);
+ DBG_HEX_C(!bSuccess, tDataBlock.ulFileOffset);
+ DBG_HEX_C(!bSuccess, tDataBlock.ulDataPos);
+ DBG_DEC_C(!bSuccess, tDataBlock.ulLength);
+ } else {
+ bSuccess = ulBeginCharInfo == ulEndOfText;
+ }
+ }
+
+ if (!bSuccess) {
+ vDestroyDataBlockList();
+ werr(0, "I can't find the data of this document");
+ }
+} /* end of vGetDocumentData */
+
+/*
+ * iInitDocumentWIN - initialize an WIN document
+ *
+ * Returns the version of Word that made the document or -1
+ */
+int
+iInitDocumentWIN(FILE *pFile, long lFilesize)
+{
+ int iWordVersion;
+ BOOL bSuccess;
+ USHORT usIdent;
+ UCHAR aucHeader[384];
+
+ fail(pFile == NULL);
+
+ if (lFilesize < 384) {
+ return -1;
+ }
+
+ /* Read the headerblock */
+ if (!bReadBytes(aucHeader, 384, 0x00, pFile)) {
+ return -1;
+ }
+ /* Get the "magic number" from the header */
+ usIdent = usGetWord(0x00, aucHeader);
+ DBG_HEX(usIdent);
+ fail(usIdent != 0xa59b && /* WinWord 1.x */
+ usIdent != 0xa5db); /* WinWord 2.0 */
+ iWordVersion = iGetVersionNumber(aucHeader);
+ if (iWordVersion != 1 && iWordVersion != 2) {
+ werr(0, "This file is not from ''Win Word 1 or 2'.");
+ return -1;
+ }
+ bSuccess = bGetDocumentText(pFile, aucHeader);
+ if (bSuccess) {
+ vGetDocumentData(pFile, aucHeader);
+ vGetPropertyInfo(pFile, NULL,
+ NULL, 0, NULL, 0,
+ aucHeader, iWordVersion);
+ vSetDefaultTabWidth(pFile, NULL,
+ NULL, 0, NULL, 0,
+ aucHeader, iWordVersion);
+ vGetNotesInfo(pFile, NULL,
+ NULL, 0, NULL, 0,
+ aucHeader, iWordVersion);
+ }
+ return bSuccess ? iWordVersion : -1;
+} /* end of iInitDocumentWIN */
diff --git a/sys/src/cmd/aux/antiword/xmalloc.c b/sys/src/cmd/aux/antiword/xmalloc.c
new file mode 100755
index 000000000..b64bc44e5
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/xmalloc.c
@@ -0,0 +1,136 @@
+/*
+ * xmalloc.c
+ * Copyright (C) 1998-2005 A.J. van Os
+ *
+ * Description:
+ * Extended malloc and friends
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "antiword.h"
+
+static char *szMessage =
+ "Memory allocation failed, unable to continue";
+#if defined(__dos) && !defined(__DJGPP__)
+static char *szDosMessage =
+ "DOS can't allocate this kind of memory, unable to continue";
+#endif /* __dos && !__DJGPP__ */
+
+
+/*
+ * xmalloc - Allocates dynamic memory
+ *
+ * See malloc(3), but unlike malloc(3) xmalloc does not return in case
+ * of error.
+ */
+void *
+xmalloc(size_t tSize)
+{
+ void *pvTmp;
+
+ TRACE_MSG("xmalloc");
+
+ if (tSize == 0) {
+ tSize = 1;
+ }
+ pvTmp = malloc(tSize);
+ if (pvTmp == NULL) {
+ DBG_MSG("xmalloc returned NULL");
+ DBG_DEC(tSize);
+ werr(1, szMessage);
+ }
+ return pvTmp;
+} /* end of xmalloc */
+
+/*
+ * xcalloc - Allocates and zeros dynamic memory
+ *
+ * See calloc(3), but unlike calloc(3) xcalloc does not return in case of error
+ */
+void *
+xcalloc(size_t tNmemb, size_t tSize)
+{
+ void *pvTmp;
+
+ TRACE_MSG("xcalloc");
+
+#if defined(__dos) && !defined(__DJGPP__)
+ if ((ULONG)tNmemb * (ULONG)tSize > 0xffffUL) {
+ DBG_DEC((ULONG)tNmemb * (ULONG)tSize);
+ werr(1, szDosMessage);
+ }
+#endif /* __dos && !__DJGPP__ */
+
+ if (tNmemb == 0 || tSize == 0) {
+ tNmemb = 1;
+ tSize = 1;
+ }
+ pvTmp = calloc(tNmemb, tSize);
+ if (pvTmp == NULL) {
+ DBG_MSG("xcalloc returned NULL");
+ werr(1, szMessage);
+ }
+ return pvTmp;
+} /* end of xcalloc */
+
+/*
+ * xrealloc - Changes the size of a memory object
+ *
+ * See realloc(3), but unlike realloc(3) xrealloc does not return in case
+ * of error.
+ */
+void *
+xrealloc(void *pvArg, size_t tSize)
+{
+ void *pvTmp;
+
+ TRACE_MSG("xrealloc");
+
+ pvTmp = realloc(pvArg, tSize);
+ if (pvTmp == NULL) {
+ DBG_MSG("realloc returned NULL");
+ werr(1, szMessage);
+ }
+ return pvTmp;
+} /* end of xrealloc */
+
+/*
+ * xstrdup - Duplicate a string
+ *
+ * See strdup(3), but unlike strdup(3) xstrdup does not return in case
+ * of error.
+ *
+ * NOTE:
+ * Does not use strdup(3), because some systems don't have it.
+ */
+char *
+xstrdup(const char *szArg)
+{
+ char *szTmp;
+
+ TRACE_MSG("xstrdup");
+
+ szTmp = xmalloc(strlen(szArg) + 1);
+ strcpy(szTmp, szArg);
+ return szTmp;
+} /* end of xstrdup */
+
+/*
+ * xfree - Deallocates dynamic memory
+ *
+ * See free(3).
+ *
+ * returns NULL;
+ * This makes p=xfree(p) possible, free memory and overwrite the pointer to it.
+ */
+void *
+xfree(void *pvArg)
+{
+ TRACE_MSG("xfree");
+
+ if (pvArg != NULL) {
+ free(pvArg);
+ }
+ return NULL;
+} /* end of xfree */
diff --git a/sys/src/cmd/aux/antiword/xml.c b/sys/src/cmd/aux/antiword/xml.c
new file mode 100755
index 000000000..92048ad64
--- /dev/null
+++ b/sys/src/cmd/aux/antiword/xml.c
@@ -0,0 +1,1438 @@
+/*
+ * xml.c
+ * Copyright (C) 2002-2005 A.J. van Os; Released under GNU GPL
+ *
+ * Description:
+ * Functions to deal with the XML/DocBook format
+ *
+ */
+
+#include <string.h>
+#include "antiword.h"
+
+
+#define vAddEndTagsUntil1(p,t) vAddEndTagsUntil2(p,t,TAG_NOTAG)
+
+#if defined(DEBUG)
+#define vStackTrace() __vStackTrace(__LINE__)
+#else
+#define vStackTrace() /* EMPTY */
+#endif /* DEBUG */
+
+/* The character set */
+static encoding_type eEncoding = encoding_neutral;
+/* Word version */
+static int iWordVersion = -1;
+/* Special treatment for files from Word 4/5/6 on an Apple Macintosh */
+static BOOL bOldMacFile = FALSE;
+/* Text is emphasised */
+static BOOL bEmphasisOpen = FALSE;
+/* Text is superscript */
+static BOOL bSuperscriptOpen = FALSE;
+/* Text is subscript */
+static BOOL bSubscriptOpen = FALSE;
+/* Title is open */
+static BOOL bTitleOpen = FALSE;
+/* Table is open */
+static BOOL bTableOpen = FALSE;
+/* Footnote is open */
+static BOOL bFootnoteOpen = FALSE;
+/* Current paragraph level */
+static UINT uiParagraphLevel = 0;
+/* Current list level */
+static UINT uiListLevel = 0;
+/* Current list level is still empty */
+static BOOL bEmptyListLevel = TRUE;
+/* Current header level */
+static USHORT usHeaderLevelCurrent = 0;
+/* Current header level is still empty */
+static BOOL bEmptyHeaderLevel = TRUE;
+/* Number of columns in the current table */
+static int iTableColumnsCurrent = 0;
+/* Footnote number */
+static UINT uiFootnoteNumber = 0;
+
+/* Constants for the stack */
+#define INITIAL_STACK_SIZE 10
+#if defined(DEBUG)
+#define EXTENSION_STACK_SIZE 2
+#else
+#define EXTENSION_STACK_SIZE 10
+#endif /* DEBUG */
+
+/* Variables for the stack */
+static UCHAR *aucStack = NULL;
+static size_t tStacksize = 0;
+static size_t tStackNextFree = 0;
+
+/* Constants for the tags */
+#define TAG_NOTAG (UCHAR)0
+#define TAG_AUTHOR (UCHAR)1
+#define TAG_BEGINPAGE (UCHAR)2
+#define TAG_BOOK (UCHAR)3
+#define TAG_BOOKINFO (UCHAR)4
+#define TAG_CHAPTER (UCHAR)5
+#define TAG_COLSPEC (UCHAR)6
+#define TAG_CORPNAME (UCHAR)7
+#define TAG_DATE (UCHAR)8
+#define TAG_EMPHASIS (UCHAR)9
+#define TAG_ENTRY (UCHAR)10
+#define TAG_FILENAME (UCHAR)11
+#define TAG_FOOTNOTE (UCHAR)12
+#define TAG_INFORMALTABLE (UCHAR)13
+#define TAG_ITEMIZEDLIST (UCHAR)14
+#define TAG_LISTITEM (UCHAR)15
+#define TAG_ORDEREDLIST (UCHAR)16
+#define TAG_PARA (UCHAR)17
+#define TAG_ROW (UCHAR)18
+#define TAG_SECT1 (UCHAR)19
+#define TAG_SECT2 (UCHAR)20
+#define TAG_SECT3 (UCHAR)21
+#define TAG_SECT4 (UCHAR)22
+#define TAG_SECT5 (UCHAR)23
+#define TAG_SUBSCRIPT (UCHAR)24
+#define TAG_SUBTITLE (UCHAR)25
+#define TAG_SUPERSCRIPT (UCHAR)26
+#define TAG_SURNAME (UCHAR)27
+#define TAG_TBODY (UCHAR)28
+#define TAG_TGROUP (UCHAR)29
+#define TAG_TITLE (UCHAR)30
+
+typedef struct docbooktags_tag {
+ UCHAR ucTagnumber;
+ char szTagname[15];
+ BOOL bAddNewlineStart;
+ BOOL bAddNewlineEnd;
+} docbooktags_type;
+
+static const docbooktags_type atDocBookTags[] = {
+ { TAG_NOTAG, "!ERROR!", TRUE, TRUE },
+ { TAG_AUTHOR, "author", TRUE, TRUE },
+ { TAG_BEGINPAGE, "beginpage", TRUE, TRUE },
+ { TAG_BOOK, "book", TRUE, TRUE },
+ { TAG_BOOKINFO, "bookinfo", TRUE, TRUE },
+ { TAG_CHAPTER, "chapter", TRUE, TRUE },
+ { TAG_COLSPEC, "colspec", TRUE, TRUE },
+ { TAG_CORPNAME, "corpname", FALSE, FALSE },
+ { TAG_DATE, "date", FALSE, FALSE },
+ { TAG_EMPHASIS, "emphasis", FALSE, FALSE },
+ { TAG_ENTRY, "entry", TRUE, TRUE },
+ { TAG_FILENAME, "filename", FALSE, FALSE },
+ { TAG_FOOTNOTE, "footnote", FALSE, FALSE },
+ { TAG_INFORMALTABLE, "informaltable",TRUE, TRUE },
+ { TAG_ITEMIZEDLIST, "itemizedlist", TRUE, TRUE },
+ { TAG_LISTITEM, "listitem", TRUE, TRUE },
+ { TAG_ORDEREDLIST, "orderedlist", TRUE, TRUE },
+ { TAG_PARA, "para", TRUE, TRUE },
+ { TAG_ROW, "row", TRUE, TRUE },
+ { TAG_SECT1, "sect1", TRUE, TRUE },
+ { TAG_SECT2, "sect2", TRUE, TRUE },
+ { TAG_SECT3, "sect3", TRUE, TRUE },
+ { TAG_SECT4, "sect4", TRUE, TRUE },
+ { TAG_SECT5, "sect5", TRUE, TRUE },
+ { TAG_SUBSCRIPT, "subscript", FALSE, FALSE },
+ { TAG_SUBTITLE, "subtitle", FALSE, FALSE },
+ { TAG_SUPERSCRIPT, "superscript", FALSE, FALSE },
+ { TAG_SURNAME, "surname", FALSE, FALSE },
+ { TAG_TBODY, "tbody", TRUE, TRUE },
+ { TAG_TGROUP, "tgroup", TRUE, TRUE },
+ { TAG_TITLE, "title", FALSE, FALSE },
+};
+
+static void vAddStartTag(diagram_type *, UCHAR, const char *);
+static void vAddEndTag(diagram_type *, UCHAR);
+static void vAddCombinedTag(diagram_type *, UCHAR, const char *);
+static void vPrintChar(diagram_type *, char);
+
+
+#if defined(DEBUG)
+/*
+ * vCheckTagTable - check the tag table
+ */
+static void
+vCheckTagTable(void)
+{
+ size_t tIndex;
+
+ for (tIndex = 0; tIndex < elementsof(atDocBookTags); tIndex++) {
+ if (tIndex != (size_t)atDocBookTags[tIndex].ucTagnumber) {
+ DBG_DEC(tIndex);
+ werr(1, "Array atDocBookTags is broken");
+ }
+ }
+} /* end of vCheckTagTable */
+
+/*
+ * __vStackTrace - show a stack trace
+ */
+static void
+__vStackTrace(int iLine)
+{
+ int iIndex;
+
+ fprintf(stderr, "%s[%3d]:\n", __FILE__, iLine);
+
+ if (tStackNextFree == 0) {
+ fprintf(stderr, "The stack is empty\n");
+ return;
+ }
+ for (iIndex = (int)tStackNextFree - 1; iIndex >= 0; iIndex--) {
+ fprintf(stderr, "%2d: %2d: '%s'\n",
+ iIndex,
+ (int)atDocBookTags[(UINT)aucStack[iIndex]].ucTagnumber,
+ atDocBookTags[(UINT)aucStack[iIndex]].szTagname);
+ }
+} /* end of __vStackTrace */
+#endif /* DEBUG */
+
+/*
+ * vPushStack - push a tag onto the stack
+ */
+static void
+vPushStack(UCHAR ucTag)
+{
+ fail(tStackNextFree > tStacksize);
+
+ if (tStackNextFree == tStacksize) {
+ /* The stack is full; enlarge the stack */
+ tStacksize += EXTENSION_STACK_SIZE;
+ aucStack = xrealloc(aucStack, tStacksize * sizeof(UCHAR));
+ DBG_DEC(tStacksize);
+ }
+
+ fail(tStackNextFree >= tStacksize);
+
+ aucStack[tStackNextFree++] = ucTag;
+} /* end of vPushStack */
+
+/*
+ * vPopStack - pop a tag from the stack
+ */
+static UCHAR
+ucPopStack(void)
+{
+ DBG_DEC_C(tStackNextFree > tStacksize, tStackNextFree);
+ DBG_DEC_C(tStackNextFree > tStacksize, tStacksize);
+ fail(tStackNextFree > tStacksize);
+ fail(tStackNextFree == 0);
+
+ if (tStackNextFree == 0) {
+ werr(1, "The stack is empty, unable to continue");
+ return TAG_NOTAG;
+ }
+ return aucStack[--tStackNextFree];
+} /* end of ucPopStack */
+
+/*
+ * vReadStack - read a tag from the top of the stack
+ */
+static UCHAR
+ucReadStack(void)
+{
+ DBG_DEC_C(tStackNextFree > tStacksize, tStackNextFree);
+ DBG_DEC_C(tStackNextFree > tStacksize, tStacksize);
+ fail(tStackNextFree > tStacksize);
+
+ if (tStackNextFree == 0) {
+ /* The stack is empty */
+ return TAG_NOTAG;
+ }
+ return aucStack[tStackNextFree - 1];
+} /* end of ucReadStack */
+
+/*
+ * vPrintLevel - print the tag level
+ */
+static void
+vPrintLevel(FILE *pOutFile)
+{
+ size_t tIndex;
+
+ fail(pOutFile == NULL);
+
+ for (tIndex = 0; tIndex < tStackNextFree; tIndex++) {
+ (void)putc(' ', pOutFile);
+ }
+} /* end of vPrintLevel */
+
+/*
+ * vPrintFootnote - print a footnote
+ */
+static void
+vPrintFootnote(diagram_type *pDiag, UINT uiFootnoteIndex)
+{
+ const char *szText, *pcTmp;
+ BOOL bSuScript;
+ UCHAR ucTopTag;
+
+ TRACE_MSG("vPrintFootnote");
+
+ szText = szGetFootnootText(uiFootnoteIndex);
+
+ if (szText == NULL) {
+ szText = "";
+ }
+
+ /* Remove the subscript/superscript (if any) */
+ ucTopTag = ucReadStack();
+ bSuScript = ucTopTag == TAG_SUBSCRIPT || ucTopTag == TAG_SUPERSCRIPT;
+ if (bSuScript) {
+ vAddEndTag(pDiag, ucTopTag);
+ }
+
+ /* Start a footnote */
+ vAddStartTag(pDiag, TAG_FOOTNOTE, NULL);
+ vAddStartTag(pDiag, TAG_PARA, NULL);
+
+ /* Print a footnote */
+ for (pcTmp = szText; *pcTmp != '\0'; pcTmp++) {
+ if (*pcTmp == PAR_END) {
+ if (*(pcTmp + 1) != PAR_END && *(pcTmp + 1) != '\0') {
+ /* PAR_END is not empty and not last */
+ vAddEndTag(pDiag, TAG_PARA);
+ vAddStartTag(pDiag, TAG_PARA, NULL);
+ }
+ } else {
+ vPrintChar(pDiag, *pcTmp);
+ }
+ }
+
+ /* End a footnote */
+ vAddEndTag(pDiag, TAG_PARA);
+ vAddEndTag(pDiag, TAG_FOOTNOTE);
+
+ /* Repair the subscript/superscript (if any) */
+ if (bSuScript) {
+ vAddStartTag(pDiag, ucTopTag, NULL);
+ }
+} /* end of vPrintFootnote */
+
+/*
+ * vPrintChar - print a character with XML encoding
+ */
+static void
+vPrintChar(diagram_type *pDiag, char cChar)
+{
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+
+ switch (cChar) {
+ case FOOTNOTE_OR_ENDNOTE:
+ uiFootnoteNumber++;
+ vPrintFootnote(pDiag, uiFootnoteNumber - 1);
+ break;
+ case '<':
+ fprintf(pDiag->pOutFile, "%s", "&lt;");
+ break;
+ case '>':
+ fprintf(pDiag->pOutFile, "%s", "&gt;");
+ break;
+ case '&':
+ fprintf(pDiag->pOutFile, "%s", "&amp;");
+ break;
+ default:
+ (void)putc(cChar, pDiag->pOutFile);
+ break;
+ }
+} /* end of vPrintChar */
+
+/*
+ * vPrintSpecialChar - convert and print a character
+ */
+static void
+vPrintSpecialChar(diagram_type *pDiag, USHORT usChar)
+{
+ ULONG ulChar;
+ size_t tLen, tIndex;
+ char szResult[4];
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(iWordVersion < 0);
+ fail(eEncoding == encoding_neutral);
+
+ ulChar = ulTranslateCharacters(usChar, 0, iWordVersion,
+ conversion_xml, eEncoding, bOldMacFile);
+ tLen = tUcs2Utf8(ulChar, szResult, sizeof(szResult));
+ if (tLen == 1) {
+ vPrintChar(pDiag, szResult[0]);
+ } else {
+ for (tIndex = 0; tIndex < tLen; tIndex++) {
+ (void)putc(szResult[tIndex], pDiag->pOutFile);
+ }
+ }
+} /* end of vPrintSpecialChar */
+
+/*
+ * vPrintSpecialString - convert and print a string
+ */
+static void
+vPrintSpecialString(diagram_type *pDiag, const char *szString)
+{
+ int iIndex;
+ USHORT usChar;
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(szString == NULL);
+
+ for (iIndex = 0; szString[iIndex] != '\0'; iIndex++) {
+ usChar = (USHORT)(UCHAR)szString[iIndex];
+ vPrintSpecialChar(pDiag, usChar);
+ }
+} /* end of vPrintSpecialString */
+
+/*
+ * vAddStartTag - add the specified start tag to the file
+ */
+static void
+vAddStartTag(diagram_type *pDiag, UCHAR ucTag, const char *szAttribute)
+{
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail((size_t)ucTag >= elementsof(atDocBookTags));
+
+ if (atDocBookTags[(UINT)ucTag].bAddNewlineStart) {
+ fprintf(pDiag->pOutFile, "\n");
+ vPrintLevel(pDiag->pOutFile);
+ }
+
+ if (szAttribute == NULL || szAttribute[0] == '\0') {
+ fprintf(pDiag->pOutFile, "<%s>",
+ atDocBookTags[(UINT)ucTag].szTagname);
+ } else {
+ fprintf(pDiag->pOutFile, "<%s %s>",
+ atDocBookTags[(UINT)ucTag].szTagname, szAttribute);
+ }
+
+ if (atDocBookTags[(UINT)ucTag].bAddNewlineEnd) {
+ fprintf(pDiag->pOutFile, "\n");
+ pDiag->lXleft = 0;
+ }
+
+ vPushStack(ucTag);
+
+ /* Set global variables */
+ switch (ucTag) {
+ case TAG_CHAPTER:
+ usHeaderLevelCurrent = 1;
+ bEmptyHeaderLevel = TRUE;
+ break;
+ case TAG_SECT1:
+ usHeaderLevelCurrent = 2;
+ bEmptyHeaderLevel = TRUE;
+ break;
+ case TAG_SECT2:
+ usHeaderLevelCurrent = 3;
+ bEmptyHeaderLevel = TRUE;
+ break;
+ case TAG_SECT3:
+ usHeaderLevelCurrent = 4;
+ bEmptyHeaderLevel = TRUE;
+ break;
+ case TAG_SECT4:
+ usHeaderLevelCurrent = 5;
+ bEmptyHeaderLevel = TRUE;
+ break;
+ case TAG_SECT5:
+ usHeaderLevelCurrent = 6;
+ bEmptyHeaderLevel = TRUE;
+ break;
+ case TAG_TITLE:
+ fail(uiParagraphLevel != 0);
+ bTitleOpen = TRUE;
+ break;
+ case TAG_FOOTNOTE:
+ bFootnoteOpen = TRUE;
+ break;
+ case TAG_PARA:
+ fail(bTitleOpen && !bFootnoteOpen);
+ uiParagraphLevel++;
+ bEmptyHeaderLevel = FALSE;
+ break;
+ case TAG_EMPHASIS:
+ bEmphasisOpen = TRUE;
+ break;
+ case TAG_ITEMIZEDLIST:
+ case TAG_ORDEREDLIST:
+ uiListLevel++;
+ bEmptyListLevel = TRUE;
+ bEmptyHeaderLevel = FALSE;
+ break;
+ case TAG_LISTITEM:
+ bEmptyListLevel = FALSE;
+ break;
+ case TAG_SUPERSCRIPT:
+ bSuperscriptOpen = TRUE;
+ break;
+ case TAG_SUBSCRIPT:
+ bSubscriptOpen = TRUE;
+ break;
+ case TAG_INFORMALTABLE:
+ bTableOpen = TRUE;
+ bEmptyHeaderLevel = FALSE;
+ break;
+ default:
+ break;
+ }
+} /* end of vAddStartTag */
+
+/*
+ * vAddEndTag - add the specified end tag to the file
+ */
+static void
+vAddEndTag(diagram_type *pDiag, UCHAR ucTag)
+{
+ UCHAR ucTopTag;
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail((size_t)ucTag >= elementsof(atDocBookTags));
+
+#if defined(DEBUG)
+ ucTopTag = ucReadStack();
+ if (ucTag != ucTopTag) {
+ DBG_DEC(ucTag);
+ DBG_MSG(atDocBookTags[(UINT)ucTag].szTagname);
+ vStackTrace();
+ }
+#endif /* DEBUG */
+
+ ucTopTag = ucPopStack();
+ fail((size_t)ucTopTag >= elementsof(atDocBookTags));
+ if (ucTag != ucTopTag) {
+ DBG_DEC(ucTag);
+ DBG_DEC(ucTopTag);
+ DBG_FIXME();
+ werr(1, "Impossible tag sequence, unable to continue");
+ }
+
+ if (atDocBookTags[(UINT)ucTag].bAddNewlineEnd) {
+ fprintf(pDiag->pOutFile, "\n");
+ vPrintLevel(pDiag->pOutFile);
+ }
+
+ fprintf(pDiag->pOutFile, "</%s>", atDocBookTags[(UINT)ucTag].szTagname);
+
+ if (atDocBookTags[(UINT)ucTag].bAddNewlineStart) {
+ fprintf(pDiag->pOutFile, "\n");
+ pDiag->lXleft = 0;
+ }
+
+ /* Set global variables */
+ switch (ucTag) {
+ case TAG_CHAPTER:
+ usHeaderLevelCurrent = 0;
+ break;
+ case TAG_SECT1:
+ usHeaderLevelCurrent = 1;
+ break;
+ case TAG_SECT2:
+ usHeaderLevelCurrent = 2;
+ break;
+ case TAG_SECT3:
+ usHeaderLevelCurrent = 3;
+ break;
+ case TAG_SECT4:
+ usHeaderLevelCurrent = 4;
+ break;
+ case TAG_SECT5:
+ usHeaderLevelCurrent = 5;
+ break;
+ case TAG_TITLE:
+ bTitleOpen = FALSE;
+ break;
+ case TAG_FOOTNOTE:
+ bFootnoteOpen = FALSE;
+ break;
+ case TAG_PARA:
+ uiParagraphLevel--;
+ break;
+ case TAG_EMPHASIS:
+ bEmphasisOpen = FALSE;
+ break;
+ case TAG_SUPERSCRIPT:
+ bSuperscriptOpen = FALSE;
+ break;
+ case TAG_ITEMIZEDLIST:
+ case TAG_ORDEREDLIST:
+ uiListLevel--;
+ break;
+ case TAG_SUBSCRIPT:
+ bSubscriptOpen = FALSE;
+ break;
+ case TAG_INFORMALTABLE:
+ bTableOpen = FALSE;
+ iTableColumnsCurrent = 0;
+ break;
+ default:
+ break;
+ }
+} /* end of vAddEndTag */
+
+/*
+ * vAddEndTagOptional - add the specified end tag to the file if needed
+ */
+static void
+vAddEndTagOptional(diagram_type *pDiag, UCHAR ucTag)
+{
+ UCHAR ucTopTag;
+
+ ucTopTag = ucReadStack();
+ if (ucTag == ucTopTag) {
+ vAddEndTag(pDiag, ucTag);
+ }
+} /* end of vAddEndTagOptional */
+
+/*
+ * vAddCombinedTag - add the specified start and end tag to the file
+ */
+static void
+vAddCombinedTag(diagram_type *pDiag, UCHAR ucTag, const char *szAttribute)
+{
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail((size_t)ucTag >= elementsof(atDocBookTags));
+
+ if (atDocBookTags[(UINT)ucTag].bAddNewlineStart) {
+ fprintf(pDiag->pOutFile, "\n");
+ vPrintLevel(pDiag->pOutFile);
+ }
+
+ if (szAttribute == NULL || szAttribute[0] == '\0') {
+ fprintf(pDiag->pOutFile, "<%s/>",
+ atDocBookTags[(UINT)ucTag].szTagname);
+ } else {
+ fprintf(pDiag->pOutFile, "<%s %s/>",
+ atDocBookTags[(UINT)ucTag].szTagname, szAttribute);
+ }
+
+ if (atDocBookTags[(UINT)ucTag].bAddNewlineStart) {
+ fprintf(pDiag->pOutFile, "\n");
+ pDiag->lXleft = 0;
+ }
+} /* end of vAddCombinedTag */
+
+/*
+ * vAddEndTagsUntil2 - add end tags until one the specified tags is seen
+ */
+static void
+vAddEndTagsUntil2(diagram_type *pDiag, UCHAR ucTag1, UCHAR ucTag2)
+{
+ UCHAR ucTopTag;
+
+ do {
+ ucTopTag = ucReadStack();
+ switch (ucTopTag) {
+ case TAG_CHAPTER:
+ case TAG_SECT1:
+ case TAG_SECT2:
+ case TAG_SECT3:
+ case TAG_SECT4:
+ case TAG_SECT5:
+ if (bEmptyHeaderLevel) {
+ /*
+ * An empty chapter is legal in Word,
+ * but not in DocBook.
+ */
+ vAddCombinedTag(pDiag, TAG_PARA, NULL);
+ bEmptyHeaderLevel = FALSE;
+ }
+ break;
+ case TAG_ITEMIZEDLIST:
+ case TAG_ORDEREDLIST:
+ if (bEmptyListLevel) {
+ /*
+ * A list without items is legal in Word,
+ * but not in DocBook. (Nor are empty items)
+ */
+ vAddStartTag(pDiag, TAG_LISTITEM, NULL);
+ vAddCombinedTag(pDiag, TAG_PARA, NULL);
+ vAddEndTag(pDiag, TAG_LISTITEM);
+ bEmptyListLevel = FALSE;
+ }
+ break;
+ default:
+ break;
+ }
+ vAddEndTag(pDiag, ucTopTag);
+ } while (ucTopTag != ucTag1 && ucTopTag != ucTag2);
+} /* end of vAddEndTagsUntil2 */
+
+/*
+ * vCreateBookIntro - create title and bookinfo
+ */
+void
+vCreateBookIntro(diagram_type *pDiag, int iVersion)
+{
+ const char *szTitle, *szSubject, *szAuthor;
+ const char *szLastSaveDtm, *szCompany;
+ const char *szLanguage;
+ char szTmp[13];
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(iVersion < 0);
+ fail(eEncoding == encoding_neutral);
+
+ iWordVersion = iVersion;
+ bOldMacFile = bIsOldMacFile();
+ szTitle = szGetTitle();
+ szSubject = szGetSubject();
+ szAuthor = szGetAuthor();
+ szLastSaveDtm = szGetLastSaveDtm();
+ szCompany = szGetCompany();
+
+ /* Start Book */
+ szLanguage = szGetLanguage();
+ if (szLanguage != NULL) {
+ DBG_MSG(szLanguage);
+ sprintf(szTmp, "lang='%.5s'", szLanguage);
+ szLanguage = szTmp;
+ }
+ vAddStartTag(pDiag, TAG_BOOK, szLanguage);
+
+ /* Book title */
+ if (szTitle != NULL && szTitle[0] != '\0') {
+ vAddStartTag(pDiag, TAG_TITLE, NULL);
+ vPrintSpecialString(pDiag, szTitle);
+ vAddEndTag(pDiag, TAG_TITLE);
+ }
+ /* Bookinfo */
+ if ((szTitle != NULL && szTitle[0] != '\0') ||
+ (szSubject != NULL && szSubject[0] != '\0') ||
+ (szAuthor != NULL && szAuthor[0] != '\0') ||
+ (szLastSaveDtm != NULL && szLastSaveDtm[0] != '\0') ||
+ (szCompany != NULL && szCompany[0] != '\0')) {
+ vAddStartTag(pDiag, TAG_BOOKINFO, NULL);
+ if (szTitle != NULL && szTitle[0] != '\0') {
+ vAddStartTag(pDiag, TAG_TITLE, NULL);
+ vPrintSpecialString(pDiag, szTitle);
+ vAddEndTag(pDiag, TAG_TITLE);
+ }
+ if (szSubject != NULL && szSubject[0] != '\0') {
+ vAddStartTag(pDiag, TAG_SUBTITLE, NULL);
+ vPrintSpecialString(pDiag, szSubject);
+ vAddEndTag(pDiag, TAG_SUBTITLE);
+ }
+ if (szAuthor != NULL && szAuthor[0] != '\0') {
+ vAddStartTag(pDiag, TAG_AUTHOR, NULL);
+ vAddStartTag(pDiag, TAG_SURNAME, NULL);
+ vPrintSpecialString(pDiag, szAuthor);
+ vAddEndTag(pDiag, TAG_SURNAME);
+ vAddEndTag(pDiag, TAG_AUTHOR);
+ }
+ if (szLastSaveDtm != NULL && szLastSaveDtm[0] != '\0') {
+ vAddStartTag(pDiag, TAG_DATE, NULL);
+ vPrintSpecialString(pDiag, szLastSaveDtm);
+ vAddEndTag(pDiag, TAG_DATE);
+ }
+ if (szCompany != NULL && szCompany[0] != '\0') {
+ vAddStartTag(pDiag, TAG_CORPNAME, NULL);
+ vPrintSpecialString(pDiag, szCompany);
+ vAddEndTag(pDiag, TAG_CORPNAME);
+ }
+ vAddEndTag(pDiag, TAG_BOOKINFO);
+ }
+} /* end of vCreateBookIntro */
+
+/*
+ * vPrologueXML - perform the XML initialization
+ */
+void
+vPrologueXML(diagram_type *pDiag, const options_type *pOptions)
+{
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(pOptions == NULL);
+
+#if defined(DEBUG)
+ vCheckTagTable();
+#endif /* DEBUG */
+
+ /* Set global variables to their start values */
+ eEncoding = pOptions->eEncoding;
+ bEmphasisOpen = FALSE;
+ bSuperscriptOpen = FALSE;
+ bSubscriptOpen = FALSE;
+ bTitleOpen = FALSE;
+ bTableOpen = FALSE;
+ bFootnoteOpen = FALSE;
+ uiParagraphLevel = 0;
+ uiListLevel = 0;
+ bEmptyListLevel = TRUE;
+ usHeaderLevelCurrent = 0;
+ bEmptyHeaderLevel = TRUE;
+ iTableColumnsCurrent = 0;
+ uiFootnoteNumber = 0;
+
+ pDiag->lXleft = 0;
+ pDiag->lYtop = 0;
+
+ /* Create an empty stack */
+ tStacksize = INITIAL_STACK_SIZE;
+ aucStack = xcalloc(tStacksize, sizeof(UCHAR));
+ tStackNextFree = 0;
+} /* end of vPrologueXML */
+
+/*
+ * vEpilogueXML - clean up after everything is done
+ */
+void
+vEpilogueXML(diagram_type *pDiag)
+{
+ vStackTrace();
+
+ vAddEndTagsUntil1(pDiag, TAG_BOOK);
+
+ vStackTrace();
+
+ /* Destroy the stack */
+ fail(tStackNextFree != 0);
+ tStacksize = 0;
+ aucStack = xfree(aucStack);
+ tStackNextFree = 0;
+} /* end of vEpilogueXML */
+
+/*
+ * vPrintXML - print a XML string
+ */
+static void
+vPrintXML(diagram_type *pDiag, const char *szString, size_t tStringLength,
+ USHORT usFontstyle)
+{
+ const char *szAttr;
+ int iCount;
+ size_t tNextFree;
+ BOOL bNotReady, bEmphasisNew, bSuperscriptNew, bSubscriptNew;
+ UCHAR ucTopTag, aucStorage[3];
+
+ fail(szString == NULL);
+
+ if (szString == NULL || szString[0] == '\0' || tStringLength == 0) {
+ return;
+ }
+
+ if (tStringLength == 1 && szString[0] == FOOTNOTE_OR_ENDNOTE) {
+ /* Don't do anything special for just a single footnote */
+ bEmphasisNew = FALSE;
+ bSuperscriptNew = FALSE;
+ bSubscriptNew = FALSE;
+ } else {
+ /* Situation normal */
+ bEmphasisNew = bIsBold(usFontstyle) ||
+ bIsItalic(usFontstyle) ||
+ bIsUnderline(usFontstyle) ||
+ bIsStrike(usFontstyle);
+ bSuperscriptNew = bIsSuperscript(usFontstyle);
+ bSubscriptNew = bIsSubscript(usFontstyle);
+ }
+
+ /* End what has to be ended (or more to keep the stack happy) */
+ tNextFree = 0;
+ bNotReady = TRUE;
+ do {
+ ucTopTag = ucReadStack();
+ switch (ucTopTag) {
+ case TAG_EMPHASIS:
+ fail(!bEmphasisOpen);
+ if (bEmphasisNew) {
+ aucStorage[tNextFree++] = ucTopTag;
+ }
+ vAddEndTag(pDiag, ucTopTag);
+ break;
+ case TAG_SUPERSCRIPT:
+ fail(!bSuperscriptOpen);
+ if (bSuperscriptNew) {
+ aucStorage[tNextFree++] = ucTopTag;
+ }
+ vAddEndTag(pDiag, ucTopTag);
+ break;
+ case TAG_SUBSCRIPT:
+ fail(!bSubscriptOpen);
+ if (bSubscriptNew) {
+ aucStorage[tNextFree++] = ucTopTag;
+ }
+ vAddEndTag(pDiag, ucTopTag);
+ break;
+ default:
+ bNotReady = FALSE;
+ break;
+ }
+ fail(tNextFree > elementsof(aucStorage));
+ fail(bNotReady && tNextFree == elementsof(aucStorage));
+ } while (bNotReady);
+
+ /* Just te make sure */
+ vStartOfParagraphXML(pDiag, 1);
+
+ /* Restart to keep the stack happy */
+ for (iCount = (int)tNextFree - 1; iCount > 0; iCount--) {
+ vAddStartTag(pDiag, aucStorage[iCount], NULL);
+ }
+
+ /* Start what has to be started */
+ if (bEmphasisNew && !bEmphasisOpen) {
+ if (bIsBold(usFontstyle)) {
+ szAttr = "role='bold'";
+ } else if (bIsItalic(usFontstyle)) {
+ szAttr = NULL;
+ } else if (bIsUnderline(usFontstyle)) {
+ szAttr = "role='underline'";
+ } else if (bIsStrike(usFontstyle)) {
+ szAttr = "role='strikethrough'";
+ } else {
+ szAttr = NULL;
+ }
+ vAddStartTag(pDiag, TAG_EMPHASIS, szAttr);
+ }
+ if (bSuperscriptNew && !bSuperscriptOpen) {
+ vAddStartTag(pDiag, TAG_SUPERSCRIPT, NULL);
+ }
+ if (bSubscriptNew && !bSubscriptOpen) {
+ vAddStartTag(pDiag, TAG_SUBSCRIPT, NULL);
+ }
+
+ /* The print the string */
+ for (iCount = 0; iCount < (int)tStringLength; iCount++) {
+ vPrintChar(pDiag, szString[iCount]);
+ }
+} /* end of vPrintXML */
+
+/*
+ * vMove2NextLineXML - move to the next line
+ */
+void
+vMove2NextLineXML(diagram_type *pDiag)
+{
+ fail(pDiag == NULL);
+
+ /*
+ if (uiParagraphLevel != 0) {
+ We need something like HTML's <BR> tag
+ }
+ */
+} /* end of vMove2NextLineXML */
+
+/*
+ * vSubstringXML - put a sub string into a diagram
+ */
+void
+vSubstringXML(diagram_type *pDiag,
+ const char *szString, size_t tStringLength, long lStringWidth,
+ USHORT usFontstyle)
+{
+ fail(pDiag == NULL || szString == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(pDiag->lXleft < 0);
+ fail(tStringLength != strlen(szString));
+
+ if (szString[0] == '\0' || tStringLength == 0) {
+ return;
+ }
+
+ vPrintXML(pDiag, szString, tStringLength, usFontstyle);
+ pDiag->lXleft += lStringWidth;
+} /* end of vSubstringXML */
+
+/*
+ * Create an start of a paragraph
+ * Only works on paragraph level one, because Word doesn't allow paragraphs
+ * in paragraphs. Other paragraph levels result from DocBooks special needs.
+ */
+void
+vStartOfParagraphXML(diagram_type *pDiag, UINT uiMaxLevel)
+{
+ fail(pDiag == NULL);
+
+ if (uiParagraphLevel >= uiMaxLevel || bTitleOpen) {
+ /* In Word a title is just a paragraph */
+ return;
+ }
+ if (uiListLevel != 0 && bEmptyListLevel) {
+ /* No paragraphs in a list before the first listitem */
+ return;
+ }
+ if (usHeaderLevelCurrent == 0) {
+ /* No paragraphs without an open header */
+ vAddStartTag(pDiag, TAG_CHAPTER, NULL);
+ /* Dummy title */
+ vAddCombinedTag(pDiag, TAG_TITLE, NULL);
+ }
+ vAddStartTag(pDiag, TAG_PARA, NULL);
+} /* end of vStartOfParagraphXML */
+
+/*
+ * Create an end of a paragraph
+ * Only for paragraph level one and for titles
+ */
+void
+vEndOfParagraphXML(diagram_type *pDiag, UINT uiMaxLevel)
+{
+ UCHAR ucTopTag;
+
+ fail(pDiag == NULL);
+
+ if (uiParagraphLevel > uiMaxLevel) {
+ DBG_DEC(uiParagraphLevel);
+ return;
+ }
+
+ for(;;) {
+ ucTopTag = ucReadStack();
+ switch (ucTopTag) {
+ case TAG_EMPHASIS:
+ fail(!bEmphasisOpen);
+ vAddEndTag(pDiag, TAG_EMPHASIS);
+ break;
+ case TAG_SUPERSCRIPT:
+ fail(!bSuperscriptOpen);
+ vAddEndTag(pDiag, TAG_SUPERSCRIPT);
+ break;
+ case TAG_SUBSCRIPT:
+ fail(!bSubscriptOpen);
+ vAddEndTag(pDiag, TAG_SUBSCRIPT);
+ break;
+ case TAG_TITLE:
+ fail(!bTitleOpen);
+ vAddEndTag(pDiag, TAG_TITLE);
+ return;
+ case TAG_PARA:
+ fail(uiParagraphLevel == 0);
+ vAddEndTag(pDiag, TAG_PARA);
+ return;
+ case TAG_TBODY:
+ case TAG_TGROUP:
+ case TAG_INFORMALTABLE:
+ fail(!bTableOpen);
+ vAddEndTag(pDiag, ucTopTag);
+ break;
+ case TAG_NOTAG:
+ DBG_FIXME();
+ werr(1, "Impossible tag sequence, unable to continue");
+ break;
+ default:
+ DBG_DEC(ucTopTag);
+ DBG_MSG_C((size_t)ucTopTag < elementsof(atDocBookTags),
+ atDocBookTags[(UINT)ucTopTag].szTagname);
+ return;
+ }
+ }
+} /* end of vEndOfParagraphXML */
+
+/*
+ * Create an end of a page
+ */
+void
+vEndOfPageXML(diagram_type *pDiag)
+{
+ if (bTableOpen || usHeaderLevelCurrent == 0) {
+ /* No beginpage in a table or outside a chapter */
+ return;
+ }
+ if (bTitleOpen) {
+ /* A beginpage is not allowed when in a title */
+ /* So start a new paragraph */
+ vEndOfParagraphXML(pDiag, UINT_MAX);
+ vStartOfParagraphXML(pDiag, UINT_MAX);
+ return;
+ }
+ vAddCombinedTag(pDiag, TAG_BEGINPAGE, NULL);
+} /* end of vEndOfPageXML */
+
+/*
+ * vCloseHeaderLevels - close the specified header levels
+ */
+static void
+vCloseHeaderLevels(diagram_type *pDiag, USHORT usIstd)
+{
+ BOOL bNotReady;
+ UCHAR ucTopTag;
+
+ DBG_MSG("vCloseHeaderLevels");
+ DBG_DEC(usIstd);
+ DBG_DEC(usHeaderLevelCurrent);
+
+ vStackTrace();
+
+ bNotReady = TRUE;
+ do {
+ ucTopTag = ucReadStack();
+ switch (ucTopTag) {
+ case TAG_TITLE:
+ case TAG_PARA:
+ vAddEndTag(pDiag, ucTopTag);
+ break;
+ default:
+ bNotReady = FALSE;
+ break;
+ }
+ } while (bNotReady);
+
+ vStackTrace();
+
+ while (usHeaderLevelCurrent >= usIstd) {
+ if (bEmptyHeaderLevel) {
+ vAddCombinedTag(pDiag, TAG_PARA, NULL);
+ bEmptyHeaderLevel = FALSE;
+ }
+ switch (usHeaderLevelCurrent) {
+ case 1: vAddEndTag(pDiag, TAG_CHAPTER); break;
+ case 2: vAddEndTag(pDiag, TAG_SECT1); break;
+ case 3: vAddEndTag(pDiag, TAG_SECT2); break;
+ case 4: vAddEndTag(pDiag, TAG_SECT3); break;
+ case 5: vAddEndTag(pDiag, TAG_SECT4); break;
+ case 6: vAddEndTag(pDiag, TAG_SECT5); break;
+ default:
+ DBG_DEC(usHeaderLevelCurrent);
+ DBG_FIXME();
+ return;
+ }
+ }
+
+ DBG_DEC(usHeaderLevelCurrent);
+
+ vStackTrace();
+} /* end of vCloseHeaderLevels */
+
+/*
+ * vSetHeadersXML - set the headers
+ */
+void
+vSetHeadersXML(diagram_type *pDiag, USHORT usIstd)
+{
+ fail(pDiag == NULL);
+
+ if (usIstd == 0 || usIstd > 6) {
+ DBG_DEC_C(usIstd != 0 && usIstd <= 9, usIstd);
+ return;
+ }
+ DBG_DEC(usIstd);
+
+ if (bTableOpen || uiListLevel != 0) {
+ /* No headers when you're in a table or in a list */
+ return;
+ }
+
+ /* Close levels */
+ vCloseHeaderLevels(pDiag, usIstd);
+
+ DBG_DEC(usHeaderLevelCurrent);
+
+ /* Open levels */
+ while (usHeaderLevelCurrent < usIstd) {
+ switch (usHeaderLevelCurrent) {
+ case 0: vAddStartTag(pDiag, TAG_CHAPTER, NULL); break;
+ case 1: vAddStartTag(pDiag, TAG_SECT1, NULL); break;
+ case 2: vAddStartTag(pDiag, TAG_SECT2, NULL); break;
+ case 3: vAddStartTag(pDiag, TAG_SECT3, NULL); break;
+ case 4: vAddStartTag(pDiag, TAG_SECT4, NULL); break;
+ case 5: vAddStartTag(pDiag, TAG_SECT5, NULL); break;
+ default:
+ DBG_DEC(usHeaderLevelCurrent);
+ DBG_FIXME();
+ return;
+ }
+ fail(usIstd == 0);
+ /* The next paragraph should be a title */
+ if (usHeaderLevelCurrent < usIstd) {
+ /* This chapter level is not in the Word document */
+ vAddCombinedTag(pDiag, TAG_TITLE, NULL);
+ } else {
+ vAddStartTag(pDiag, TAG_TITLE, NULL);
+ }
+ }
+} /* end of vSetHeadersXML */
+
+/*
+ * Create a start of a list
+ */
+void
+vStartOfListXML(diagram_type *pDiag, UCHAR ucNFC, BOOL bIsEndOfTable)
+{
+ const char *szAttr;
+ UCHAR ucTag;
+
+ fail(pDiag == NULL);
+
+ if (bIsEndOfTable) {
+ /* FIXME: until a list in a table is allowed */
+ vEndOfTableXML(pDiag);
+ }
+
+ if (bTableOpen) {
+ /* FIXME: a list in a table should be allowed */
+ return;
+ }
+
+ if (usHeaderLevelCurrent == 0) {
+ /* No list without an open header */
+ vAddStartTag(pDiag, TAG_CHAPTER, NULL);
+ /* Dummy title */
+ vAddCombinedTag(pDiag, TAG_TITLE, NULL);
+ }
+
+ switch (ucNFC) {
+ case LIST_ARABIC_NUM:
+ case LIST_ORDINAL_NUM:
+ case LIST_NUMBER_TXT:
+ case LIST_ORDINAL_TXT:
+ case LIST_OUTLINE_NUM:
+ ucTag = TAG_ORDEREDLIST;
+ szAttr = "numeration='arabic'";
+ break;
+ case LIST_UPPER_ROMAN:
+ ucTag = TAG_ORDEREDLIST;
+ szAttr = "numeration='upperroman'";
+ break;
+ case LIST_LOWER_ROMAN:
+ ucTag = TAG_ORDEREDLIST;
+ szAttr = "numeration='lowerroman'";
+ break;
+ case LIST_UPPER_ALPHA:
+ ucTag = TAG_ORDEREDLIST;
+ szAttr = "numeration='upperalpha'";
+ break;
+ case LIST_LOWER_ALPHA:
+ ucTag = TAG_ORDEREDLIST;
+ szAttr = "numeration='loweralpha'";
+ break;
+ case LIST_SPECIAL:
+ case LIST_SPECIAL2:
+ case LIST_BULLETS:
+ ucTag = TAG_ITEMIZEDLIST;
+ szAttr = "mark='bullet'";
+ break;
+ default:
+ ucTag = TAG_ORDEREDLIST;
+ szAttr = "numeration='arabic'";
+ DBG_HEX(ucNFC);
+ DBG_FIXME();
+ break;
+ }
+ vAddStartTag(pDiag, ucTag, szAttr);
+} /* end of vStartOfListXML */
+
+/*
+ * Create an end of a list
+ */
+void
+vEndOfListXML(diagram_type *pDiag)
+{
+ fail(pDiag == NULL);
+
+ if (bTableOpen) {
+ /* FIXME: a list in a table should be allowed */
+ return;
+ }
+
+ if (uiListLevel != 0) {
+ vStackTrace();
+ vAddEndTagsUntil2(pDiag, TAG_ITEMIZEDLIST, TAG_ORDEREDLIST);
+ vStackTrace();
+ }
+} /* end of vEndOfListXML */
+
+/*
+ * Create a start of a list item
+ */
+void
+vStartOfListItemXML(diagram_type *pDiag, BOOL bNoMarks)
+{
+ const char *szAttr;
+ UCHAR ucTopTag;
+
+ fail(pDiag == NULL);
+
+ if (bTableOpen) {
+ /* FIXME: a list in a table should be allowed */
+ return;
+ }
+
+ ucTopTag = ucReadStack();
+ if (ucTopTag != TAG_ITEMIZEDLIST && ucTopTag != TAG_ORDEREDLIST) {
+ /* Must end a previous list item first */
+ vAddEndTagsUntil1(pDiag, TAG_LISTITEM);
+ }
+
+ DBG_DEC_C(ucReadStack() != TAG_ITEMIZEDLIST &&
+ ucReadStack() != TAG_ORDEREDLIST, ucReadStack());
+
+ /* Start a new list item */
+ szAttr = bNoMarks ? "override='none'" : NULL;
+ vAddStartTag(pDiag, TAG_LISTITEM, szAttr);
+ /* Start a new paragraph (independant of level) */
+ vAddStartTag(pDiag, TAG_PARA, NULL);
+} /* end of vStartOfListItemXML */
+
+/*
+ * Create a start of a table
+ */
+static void
+vStartOfTable(diagram_type *pDiag, UCHAR ucBorderInfo)
+{
+ const char *szFrame;
+ BOOL bNotReady;
+ UCHAR ucTopTag;
+ char cColSep, cRowSep;
+ char szAttr[40];
+
+ fail(pDiag == NULL);
+
+ /* Close elements that cannot contain a table */
+ bNotReady = TRUE;
+ do {
+ ucTopTag = ucReadStack();
+ switch (ucTopTag) {
+ case TAG_TITLE:
+ fail(!bTitleOpen);
+ vAddEndTag(pDiag, TAG_TITLE);
+ break;
+ case TAG_EMPHASIS:
+ fail(!bEmphasisOpen);
+ vAddEndTag(pDiag, TAG_EMPHASIS);
+ break;
+ case TAG_SUPERSCRIPT:
+ fail(!bSuperscriptOpen);
+ vAddEndTag(pDiag, TAG_SUPERSCRIPT);
+ break;
+ case TAG_SUBSCRIPT:
+ fail(!bSubscriptOpen);
+ vAddEndTag(pDiag, TAG_SUBSCRIPT);
+ break;
+ default:
+ bNotReady = FALSE;
+ break;
+ }
+ } while (bNotReady);
+
+ /* Create table attributes */
+ switch (ucBorderInfo) {
+ case TABLE_BORDER_TOP:
+ szFrame = "top";
+ break;
+ case TABLE_BORDER_LEFT|TABLE_BORDER_RIGHT:
+ szFrame = "sides";
+ break;
+ case TABLE_BORDER_TOP|TABLE_BORDER_BOTTOM:
+ szFrame = "topbot";
+ break;
+ case TABLE_BORDER_BOTTOM:
+ szFrame = "bottom";
+ break;
+ case TABLE_BORDER_TOP|TABLE_BORDER_LEFT|
+ TABLE_BORDER_BOTTOM|TABLE_BORDER_RIGHT:
+ szFrame = "all";
+ break;
+ default:
+ szFrame = "none";
+ break;
+ }
+ cColSep = bIsTableBorderLeft(ucBorderInfo) ||
+ bIsTableBorderRight(ucBorderInfo) ? '1' : '0';
+ cRowSep = bIsTableBorderTop(ucBorderInfo) ||
+ bIsTableBorderBottom(ucBorderInfo) ? '1' : '0';
+
+ sprintf(szAttr, "frame='%.6s' colsep='%c' rowsep='%c'",
+ szFrame, cColSep, cRowSep);
+
+ if (usHeaderLevelCurrent == 0) {
+ /* No table without an open header */
+ vAddStartTag(pDiag, TAG_CHAPTER, NULL);
+ /* Dummy title */
+ vAddCombinedTag(pDiag, TAG_TITLE, NULL);
+ }
+ vAddStartTag(pDiag, TAG_INFORMALTABLE, szAttr);
+} /* end of vStartOfTable */
+
+/*
+ * Create a start of a table group
+ */
+static void
+vStartOfTableGroup(diagram_type *pDiag,
+ int iNbrOfColumns, const short *asColumnWidth)
+{
+ double dWidth;
+ int iIndex;
+ char szCols[6 + 3 * sizeof(int) + 1 + 1];
+ char szColWidth[10 + 3 * sizeof(short) + 3 + 3 + 1];
+
+ fail(iNbrOfColumns < 1);
+ fail(asColumnWidth == NULL);
+
+ sprintf(szCols, "cols='%d'", iNbrOfColumns);
+ vAddStartTag(pDiag, TAG_TGROUP, szCols);
+
+ for (iIndex= 0; iIndex < iNbrOfColumns; iIndex++) {
+ fail(asColumnWidth[iIndex] < 0);
+ dWidth = dTwips2Points(asColumnWidth[iIndex]);
+ if (dWidth <= 1.0) {
+ strcpy(szColWidth, "colwidth='1.00pt'");
+ } else {
+ sprintf(szColWidth, "colwidth='%.2fpt'", dWidth);
+ }
+ vAddCombinedTag(pDiag, TAG_COLSPEC, szColWidth);
+ }
+} /* end of vStartOfTableGroup */
+
+/*
+ * Create an end of a table
+ */
+void
+vEndOfTableXML(diagram_type *pDiag)
+{
+ fail(pDiag == NULL);
+
+ if (bTableOpen) {
+ vAddEndTag(pDiag, TAG_TBODY);
+ vAddEndTag(pDiag, TAG_TGROUP);
+ vAddEndTag(pDiag, TAG_INFORMALTABLE);
+ }
+} /* end of vEndOfTableXML */
+
+/*
+ * Add a table row
+ */
+void
+vAddTableRowXML(diagram_type *pDiag, char **aszColTxt,
+ int iNbrOfColumns, const short *asColumnWidth, UCHAR ucBorderInfo)
+{
+ size_t tCount, tStringLength;
+ int iIndex;
+
+ fail(pDiag == NULL);
+ fail(pDiag->pOutFile == NULL);
+ fail(aszColTxt == NULL);
+ fail(iNbrOfColumns < 1);
+ fail(asColumnWidth == NULL);
+
+ if (iNbrOfColumns != iTableColumnsCurrent) {
+ /* A new number of columns */
+ /* End the old table body and table group (if they exist) */
+ vAddEndTagOptional(pDiag, TAG_TBODY);
+ vAddEndTagOptional(pDiag, TAG_TGROUP);
+ if (!bTableOpen) {
+ /* No table yet. Start a new table */
+ vStartOfTable(pDiag, ucBorderInfo);
+ }
+ /* Start a new table group and a new table body */
+ vStartOfTableGroup(pDiag, iNbrOfColumns, asColumnWidth);
+ vAddStartTag(pDiag, TAG_TBODY, NULL);
+ iTableColumnsCurrent = iNbrOfColumns;
+ }
+
+ /* Add the table row */
+ vAddStartTag(pDiag, TAG_ROW, NULL);
+ for (iIndex = 0; iIndex < iNbrOfColumns; iIndex++) {
+ /* Add a table cell */
+ fail(aszColTxt[iIndex] == NULL);
+ vAddStartTag(pDiag, TAG_ENTRY, NULL);
+ tStringLength = strlen(aszColTxt[iIndex]);
+ for (tCount = 0; tCount < tStringLength; tCount++) {
+ vPrintChar(pDiag, aszColTxt[iIndex][tCount]);
+ }
+ vAddEndTag(pDiag, TAG_ENTRY);
+ }
+ vAddEndTag(pDiag, TAG_ROW);
+} /* end of vAddTableRowXML */