#include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "wv.h" /* This file is a port of the Somar Software freeware DLL functions to get summary info from OLE 2.0 document files, named CPPSUM available from the Somar Software WWW site at http://www.somar.com The port (as always) is written by Caolan.McNamara@ul.ie and is released under the LGPL An example of usage of the summary stream is shown in wvSummary.c */ void wvGetPropHeader (PropHeader * header, wvStream * file) { int i; header->byteOrder = read_16ubit (file); header->wFormat = read_16ubit (file); header->osVersion1 = read_16ubit (file); header->osVersion2 = read_16ubit (file); for (i = 0; i < 16; i++) header->classId[i] = read_8ubit (file); header->cSections = read_32ubit (file); } void wvGetFIDAndOffset (FIDAndOffset * fid, wvStream * file) { int i; for (i = 0; i < 4; i++) fid->dwords[i] = read_32ubit (file); fid->dwOffset = read_32ubit (file); } void wvReleaseSummaryInfo (SummaryInfo * si) { if (si == NULL) return; if (si->aProps != NULL) wvFree (si->aProps); if (si->data != NULL) wvFree (si->data); } void wvGetSummaryInfo (SummaryInfo * si, wvStream * file, U32 offset) { U32 i; wvStream_offset (file, offset); si->cBytes = read_32ubit (file); si->cProps = read_32ubit (file); si->aProps = NULL; si->data = NULL; if (si->cProps == 0) return; si->aProps = (aPro *) wvMalloc (sizeof (aPro) * si->cProps); for (i = 0; i < si->cProps; i++) { si->aProps[i].propID = read_32ubit (file); si->aProps[i].dwOffset = read_32ubit (file); si->aProps[i].dwOffset = si->aProps[i].dwOffset - 8 - si->cProps * 8; } if (si->cBytes - 8 * si->cProps > 0) { si->data = (U8 *) wvMalloc (si->cBytes - 8 * si->cProps); for (i = 0; i < si->cBytes - 8 * si->cProps; i++) si->data[i] = read_8ubit (file); } } /* 0 is success 1 is failure -1 is wmf files, cannot be converted */ int wvSumInfoForceString (char *lpStr, U16 cbStr, U32 pid, SummaryInfo * si) { int len; PropValue Prop; U16 yr, mon, day, hr, min, sec; if (1 == wvGetProperty (&Prop, si, pid)) return (1); if (Prop.vtType == VT_I4) sprintf (lpStr, "%d", Prop.vtValue.vtLong); else if (Prop.vtType == VT_LPSTR) { len = (int) Prop.vtValue.vtBSTR.cBytes; if (len > cbStr) len = cbStr; if (len <= 0) *(lpStr) = '\0'; else { strncpy (lpStr, Prop.vtValue.vtBSTR.ch, len); *(lpStr + len - 1) = '\0'; /* len includes terminating null */ } } else if (Prop.vtType == VT_FILETIME) { wvSumInfoGetTime (&yr, &mon, &day, &hr, &min, &sec, pid, si); sprintf (lpStr, "%d/%d/%d %d:%d:%d", day, mon, yr, hr, min, sec); } else { strcpy (lpStr, "Cannot be made into a str\n"); return (-1); } wvReleaseProperty (&Prop); return (0); } int wvSumInfoGetString (char *lpStr, U16 cbStr, U32 pid, SummaryInfo * si) { int len; PropValue Prop; if (1 == wvGetProperty (&Prop, si, pid)) return (1); if (Prop.vtType != VT_LPSTR) return (1); len = (int) Prop.vtValue.vtBSTR.cBytes; if (len > cbStr) len = cbStr; if (len <= 0) *(lpStr) = '\0'; else { strncpy (lpStr, Prop.vtValue.vtBSTR.ch, len); *(lpStr + len - 1) = '\0'; /* len includes terminating null */ } wvReleaseProperty (&Prop); return (0); } int wvSumInfoGetPreview (char *lpStr, U16 cbStr, U32 pid, SummaryInfo * si) { int len, i; PropValue Prop; FILE *outfile = fopen ("preview", "w+b"); if (1 == wvGetProperty (&Prop, si, pid)) return (1); if (Prop.vtType != VT_WMF) return (1); len = (int) Prop.vtValue.vtBSTR.cBytes; #if 0 i = 0; #else /* it appears that this is a wmf file once you go 16bytes in, it might have been a clp file, but the records seem all wrong for the appropiate clp header, so we'll just skip them for now */ i = 16; #endif for (; i < len; i++) fputc (Prop.vtValue.vtBSTR.ch[i], outfile); fclose (outfile); sprintf (lpStr, "preview"); wvReleaseProperty (&Prop); return (0); } int wvSumInfoGetLong (U32 * lpLong, U32 pid, SummaryInfo * si) { int ret; PropValue Prop; if (1 == wvGetProperty (&Prop, si, pid)) return (1); if (Prop.vtType == VT_I4) { *lpLong = Prop.vtValue.vtLong; ret = 0; } else ret = 1; wvReleaseProperty (&Prop); return (ret); } int wvSumInfoGetTime (U16 * yr, U16 * mon, U16 * day, U16 * hr, U16 * min, U16 * sec, U32 pid, SummaryInfo * si) { PropValue Prop; U16 DosDate; U16 DosTime; int fBefore1980; #define JAN1980_HIGH 0x01A8E79F #define JAN1980_LOW 0xE1D58000 if (1 == wvGetProperty (&Prop, si, pid)) return (1); if (Prop.vtType != VT_FILETIME) return (1);; /* If time < Jan 1, 1980, then add FILETIME of 1980/01/01 00:00:00. This is necessary for CoFileTimeToDosDateTime to work. */ if (Prop.vtValue.vtTime.dwHighDateTime < JAN1980_HIGH) { Prop.vtValue.vtTime.dwLowDateTime += JAN1980_LOW; Prop.vtValue.vtTime.dwHighDateTime += JAN1980_HIGH; if (Prop.vtValue.vtTime.dwLowDateTime < JAN1980_LOW) Prop.vtValue.vtTime.dwHighDateTime++; /* overflow */ fBefore1980 = 1; } else fBefore1980 = 0; if (!wvFileTimeToDosDateTime (&Prop.vtValue.vtTime, &DosDate, &DosTime)) return (1); *day = DosDate & 0x001F; *mon = (DosDate & 0x01E0) >> 5; *yr = ((DosDate & 0xFE00) >> 9) + 1980; *sec = (DosTime & 0x001F) * 2; *min = (DosTime & 0x7E0) >> 5; *hr = (DosTime & 0xF800) >> 11; if (fBefore1980) { /* Suppose edittime is actually 1 day, 3 hours. Then Y/M/D will be 1980/1/2 at this point. Which should be tranlated to 0/0/1. The code below also handles cases where edittime > 1 month or even 1 year. */ *yr = *yr - 1980; *mon = *mon - 1; *day = *day - 1; if (*mon == 0 && *yr > 0) { (*yr)--; *mon = 12; } if (*day == 0 && *mon > 0) { (*mon)--; switch (*mon) { case 1: *day = 31; break; case 2: *day = 28; break; case 3: *day = 31; break; case 4: *day = 30; break; case 5: *day = 31; break; case 6: *day = 30; break; case 7: *day = 31; break; case 8: *day = 31; break; case 9: *day = 30; break; case 10: *day = 31; break; case 11: *day = 30; break; case 12: *day = 31; break; } } } return (0); } void wvReleaseProperty (PropValue * Prop) { if (Prop != NULL) return; if (Prop->vtType == VT_LPSTR) if (Prop->vtValue.vtBSTR.ch) wvFree (Prop->vtValue.vtBSTR.ch); } int wvGetProperty (PropValue * Prop, SummaryInfo * si, U32 pid) { U32 i, j; U8 *t; Prop->vtValue.vtBSTR.cBytes = 0; if (si == NULL) return (1); for (i = 0; i < si->cProps; i++) { if (si->aProps[i].propID == pid) { t = si->data + si->aProps[i].dwOffset; Prop->vtType = sread_32ubit (t); t += 4; switch (Prop->vtType) { case VT_LPSTR: case VT_WMF: Prop->vtValue.vtBSTR.cBytes = sread_32ubit (t); t += 4; if (Prop->vtValue.vtBSTR.cBytes == 0) { Prop->vtValue.vtBSTR.ch = NULL; break; } Prop->vtValue.vtBSTR.ch = (char *) wvMalloc (Prop->vtValue.vtBSTR.cBytes); for (j = 0; j < Prop->vtValue.vtBSTR.cBytes; j++) Prop->vtValue.vtBSTR.ch[j] = *t++; break; case VT_FILETIME: Prop->vtValue.vtTime.dwLowDateTime = sread_32ubit (t); t += 4; Prop->vtValue.vtTime.dwHighDateTime = sread_32ubit (t); break; case VT_I4: default: Prop->vtValue.vtLong = sread_32ubit (t); break; } return (0); } } return (1); } int wvSumInfoOpenStream (SummaryInfo * si, wvStream * stream) { PropHeader header; FIDAndOffset fid; U32 i; wvGetPropHeader (&header, stream); if (header.byteOrder != 0xFFFE) { wvError (("Bad byte order: %d\n", header.byteOrder)); return (1); } if (header.wFormat != 0) { wvError (("Bad format: %d\n", header.wFormat)); return (1); } for (i = 0; i < header.cSections; i++) { wvGetFIDAndOffset (&fid, stream); if (fid.dwords[0] == 0XF29F85E0 && fid.dwords[1] == 0X10684FF9 && fid.dwords[2] == 0X000891AB && fid.dwords[3] == 0XD9B3272B) break; } #ifdef DEBUG if (i >= header.cSections) wvTrace (("possible problem\n")); #endif wvGetSummaryInfo (si, stream, fid.dwOffset); return (0); } int wvOLESummaryStream (char *filename, wvStream ** summary) { int ret; wvStream *mainfd, *tablefd0, *tablefd1, *data; ret = wvOLEDecode (filename, &mainfd, &tablefd0, &tablefd1, &data, summary); return (ret); }