/* Abiword * Copyright (C) 2001 Christian Biesinger * * 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. */ #include #include #include #include // for struct tm and asctime #include "docinfo.h" #include "pd_Document.h" #include "ie_imp_StarOffice.h" #include "ie_imp_StarOffice_encodings.h" #include "ut_debugmsg.h" #include "ut_iconv.h" #include "ut_string_class.h" #include "ut_assert.h" SDWDocInfo::SDWDocInfo() {} SDWDocInfo::~SDWDocInfo() {} /** Reads a bytestring, followed by a padding. aMaxlen is the max. number of bytes to read. */ static void readPaddedByteString(GsfInput* aStream, UT_UCS4String& aString, UT_iconv_t aConverter, UT_uint32 aMaxlen) throw(UT_Error) { UT_UCS4Char* str; readByteString(aStream, str, aConverter); aString = str; free(str); // XXX need original length, not ucs4 length UT_uint32 len = aString.size(); if (len > aMaxlen) throw UT_IE_BOGUSDOCUMENT; if (gsf_input_seek(aStream, aMaxlen-len, G_SEEK_CUR)) throw UT_IE_BOGUSDOCUMENT; } class AutoGsfInput { public: AutoGsfInput(GsfInput* aStream = NULL) : mStream(aStream) {} ~AutoGsfInput() { close(); } void close() { if (mStream) g_object_unref(G_OBJECT(mStream)); } GsfInput*& operator=(GsfInput* aStream) { close(); mStream = aStream; return mStream; } operator GsfInput*() { return mStream; } operator GsfInput**() { close(); return &mStream; } private: GsfInput* mStream; }; /** StarOffice's Timestamp - first, a bytestring, then date, then time */ class TimeStamp { public: TimeStamp(UT_iconv_t aConverter) : mDate(0), mTime(0), mConverter(aConverter) {} void load(GsfInput* aStream); UT_uint32 mDate; UT_uint32 mTime; UT_UCS4String mString; /** Converts this timestamp to a human-readable string */ UT_UTF8String ToString() const; private: UT_iconv_t mConverter; enum { TimeStampLen = 31 }; }; void TimeStamp::load(GsfInput* aStream) { readPaddedByteString(aStream, mString, mConverter, TimeStampLen); streamRead(aStream, mDate); streamRead(aStream, mTime); } UT_UTF8String TimeStamp::ToString() const { struct tm theDate; theDate.tm_sec = (mTime / 100) % 100; theDate.tm_min = (mTime / 10000) % 100; theDate.tm_hour = (mTime / 1000000) % 100; theDate.tm_mday = mDate % 100; theDate.tm_mon = ((mDate / 100) % 100) - 1; theDate.tm_year = (mDate / 10000) - 1900; theDate.tm_isdst = -1; mktime(&theDate); char buf[64]; strftime(buf, sizeof(buf), "%x %X", &theDate); UT_DEBUGMSG(("SDW: (TimeStamp is %s)\n", buf)); return UT_UTF8String(buf); } // set an UCS-4 Metadata by converting it to UTF-8 and treating it as ASCII static inline void do_SetMetadata(PD_Document* aDoc, const UT_String& aKey, UT_UCS4String aData) { UT_UTF8String str(aData); aDoc->setMetaDataProp(aKey, str); } void SDWDocInfo::load(GsfInfile* aDoc, PD_Document* aPDDoc) throw(UT_Error) { char* headStr = NULL; try { UT_DEBUGMSG(("SDW: Loading Docinfo...\n")); // firstly, set StarOffice as generator aPDDoc->setMetaDataProp(PD_META_KEY_GENERATOR, UT_UTF8String("StarOffice")); AutoGsfInput docInfo = gsf_infile_child_by_name(aDoc, "SfxDocumentInfo"); if (!(GsfInput*)docInfo) throw UT_IE_BOGUSDOCUMENT; readByteString(docInfo, headStr); if (strcmp(headStr, "SfxDocumentInfo") != 0) throw UT_IE_BOGUSDOCUMENT; UT_uint16 version; streamRead(docInfo, version); bool pwProtect; streamRead(docInfo, pwProtect); UT_uint16 charset; streamRead(docInfo, charset); auto_iconv converter(findConverter((UT_uint8)charset)); if (!UT_iconv_isValid(converter)) throw UT_IE_BOGUSDOCUMENT; bool graphPortable, queryTemplateReload; streamRead(docInfo, graphPortable); streamRead(docInfo, queryTemplateReload); TimeStamp stamp(converter); stamp.load(docInfo); // creator do_SetMetadata(aPDDoc, PD_META_KEY_CREATOR, stamp.mString); aPDDoc->setMetaDataProp(PD_META_KEY_DATE, stamp.ToString()); stamp.load(docInfo); // modifier // (ab-)using Contributor as the person who last modified the doc... do_SetMetadata(aPDDoc, PD_META_KEY_CONTRIBUTOR, stamp.mString); aPDDoc->setMetaDataProp(PD_META_KEY_DATE_LAST_CHANGED, stamp.ToString()); stamp.load(docInfo); // printer (person, not device) UT_UCS4String data; readPaddedByteString(docInfo, data, converter, 63); do_SetMetadata(aPDDoc, PD_META_KEY_TITLE, data); readPaddedByteString(docInfo, data, converter, 63); do_SetMetadata(aPDDoc, PD_META_KEY_SUBJECT, data); readPaddedByteString(docInfo, data, converter, 255); do_SetMetadata(aPDDoc, PD_META_KEY_DESCRIPTION, data); readPaddedByteString(docInfo, data, converter, 127); do_SetMetadata(aPDDoc, PD_META_KEY_KEYWORDS, data); // Read user-defined data for (int i = 0; i < 4; i++) { UT_UCS4String key, value; readPaddedByteString(docInfo, key, converter, 19); readPaddedByteString(docInfo, value, converter, 19); UT_String prefixedKey = CUSTOM_META_PREFIX + UT_String(UT_UTF8String(key).utf8_str()); do_SetMetadata(aPDDoc, prefixedKey, value); } // rest of the stream contains no useful information delete [] headStr; UT_DEBUGMSG(("SDW: Docinfo done loading\n")); } catch(UT_Error & e) { if(headStr) { delete [] headStr; } throw e; } }