diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/aux/antiword |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/aux/antiword')
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", "<"); + break; + case '>': + fprintf(pDiag->pOutFile, "%s", ">"); + break; + case '&': + fprintf(pDiag->pOutFile, "%s", "&"); + 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 */ |