/* returns TRUE on error */ static gboolean zip_child_init (GsfInfileZip *child, GError **errmsg) { static guint8 const header_signature[] = { 'P', 'K', 0x03, 0x04 }; guint8 const *data = NULL; guint16 name_len, extras_len; char *err = NULL; GsfZipDirent *dirent = child->vdir->dirent; /* skip local header * should test tons of other info, but trust that those are correct **/ if (gsf_input_seek (child->source, (gsf_off_t) dirent->offset, G_SEEK_SET)) err = g_strdup_printf ("Error seeking to zip header @ %" GSF_OFF_T_FORMAT, dirent->offset); else if (NULL == (data = gsf_input_read (child->source, ZIP_FILE_HEADER_SIZE, NULL))) err = g_strdup_printf ("Error reading %d bytes in zip header", ZIP_FILE_HEADER_SIZE); else if (0 != memcmp (data, header_signature, sizeof (header_signature))) { err = g_strdup_printf ("Error incorrect zip header @ %" GSF_OFF_T_FORMAT, dirent->offset); g_print ("Header is :\n"); gsf_mem_dump (data, sizeof (header_signature)); g_print ("Header should be :\n"); gsf_mem_dump (header_signature, sizeof (header_signature)); } if (NULL != err) { if (errmsg != NULL) *errmsg = g_error_new_literal (gsf_input_error_id (), 0, err); g_free (err); return TRUE; } name_len = GSF_LE_GET_GUINT16 (data + ZIP_FILE_HEADER_NAME_SIZE); extras_len = GSF_LE_GET_GUINT16 (data + ZIP_FILE_HEADER_EXTRAS_SIZE); dirent->data_offset = dirent->offset + ZIP_FILE_HEADER_SIZE + name_len + extras_len; child->restlen = dirent->usize; child->crestlen = dirent->csize; if (dirent->compr_method != GSF_ZIP_STORED) { int err; if (!child->stream) child->stream = g_new0 (z_stream, 1); err = inflateInit2 (child->stream, -MAX_WBITS); if (err != Z_OK) { if (errmsg != NULL) *errmsg = g_error_new (gsf_input_error_id (), 0, "problem uncompressing stream"); return TRUE; } } return FALSE; }
PangoAttrList * ms_container_read_markup (MSContainer const *c, guint8 const *data, size_t txo_len, char const *str) { TXORun txo_run; size_t str_len; XL_CHECK_CONDITION_VAL (txo_len >= 16, pango_attr_list_new ()); /* min two records */ str_len = g_utf8_strlen (str, -1); txo_run.last = G_MAXINT; txo_run.accum = NULL; for (txo_len -= 16 ; (gssize)txo_len >= 0 ; txo_len -= 8) { guint16 o = GSF_LE_GET_GUINT16 (data + txo_len); guint16 idx = GSF_LE_GET_GUINT16 (data + txo_len + 2); XL_CHECK_CONDITION_VAL (o <= str_len, txo_run.accum); txo_run.first = g_utf8_offset_to_pointer (str, o) - str; XL_CHECK_CONDITION_VAL (txo_run.first < txo_run.last, txo_run.accum); if (idx != 0) { if (!txo_run.accum) txo_run.accum = pango_attr_list_new (); pango_attr_list_filter (ms_container_get_markup (c, idx), (PangoAttrFilterFunc) append_txorun, &txo_run); } txo_run.last = txo_run.first; } return txo_run.accum; }
static guint8 const * qpro_get_record (QProReadState *state, guint16 *id, guint16 *len) { guint8 const *data; data = gsf_input_read (state->input, 4, NULL); Q_CHECK_CONDITION (data != NULL); *id = GSF_LE_GET_GUINT16 (data + 0); *len = GSF_LE_GET_GUINT16 (data + 2); #if 0 g_printerr ("%hd with %hd\n", *id, *len); #endif if (*len == 0) return ""; data = gsf_input_read (state->input, *len, NULL); switch (*id) { case QPRO_UNDOCUMENTED_837: case QPRO_UNDOCUMENTED_907: break; /* Nothing. */ default: Q_CHECK_CONDITION (*len < 0x2000); } Q_CHECK_CONDITION (data != NULL); return data; error: return NULL; }
static GsfZipDirent * zip_dirent_new_in (GsfInfileZip *zip, gsf_off_t *offset) { static guint8 const dirent_signature[] = { 'P', 'K', 0x01, 0x02 }; GsfZipDirent *dirent; guint8 const *data; guint16 name_len, extras_len, comment_len, compr_method, flags; guint32 crc32, csize, usize, off; gchar *name; /* Read data and check the header */ if (gsf_input_seek (zip->source, *offset, G_SEEK_SET) || NULL == (data = gsf_input_read (zip->source, ZIP_DIRENT_SIZE, NULL)) || 0 != memcmp (data, dirent_signature, sizeof (dirent_signature))) { return NULL; } name_len = GSF_LE_GET_GUINT16 (data + ZIP_DIRENT_NAME_SIZE); extras_len = GSF_LE_GET_GUINT16 (data + ZIP_DIRENT_EXTRAS_SIZE); comment_len = GSF_LE_GET_GUINT16 (data + ZIP_DIRENT_COMMENT_SIZE); flags = GSF_LE_GET_GUINT32 (data + ZIP_DIRENT_FLAGS); compr_method = GSF_LE_GET_GUINT16 (data + ZIP_DIRENT_COMPR_METHOD); crc32 = GSF_LE_GET_GUINT32 (data + ZIP_DIRENT_CRC32); csize = GSF_LE_GET_GUINT32 (data + ZIP_DIRENT_CSIZE); usize = GSF_LE_GET_GUINT32 (data + ZIP_DIRENT_USIZE); off = GSF_LE_GET_GUINT32 (data + ZIP_DIRENT_OFFSET); if ((data = gsf_input_read (zip->source, name_len, NULL)) == NULL) return NULL; name = g_new (gchar, (gulong) (name_len + 1)); memcpy (name, data, name_len); name[name_len] = '\0'; dirent = gsf_zip_dirent_new (); dirent->name = name; dirent->flags = flags; dirent->compr_method = compr_method; dirent->crc32 = crc32; dirent->csize = csize; dirent->usize = usize; dirent->offset = off; #if 0 g_print ("%s = 0x%x @ %" GSF_OFF_T_FORMAT "\n", name, off, *offset); #endif *offset += ZIP_DIRENT_SIZE + name_len + extras_len + comment_len; return dirent; }
/** Given a data pointer, returns a color string (like cccccc for a medium gray). * throws BOGUS_DOCUMENT on error. */ UT_String makeColor(UT_uint8* aData, UT_uint32 aDataLen) { // from tools/source/generic/color.cxx line 183ff #define COL_NAME_USER (0x8000) #define COL_RED_1B (0x0001) #define COL_RED_2B (0x0002) #define COL_GREEN_1B (0x0010) #define COL_GREEN_2B (0x0020) #define COL_BLUE_1B (0x0100) #define COL_BLUE_2B (0x0200) UT_String rv; if (aDataLen < 2) throw UT_IE_BOGUSDOCUMENT; UT_uint16 colorName = GSF_LE_GET_GUINT16(aData); if (colorName & COL_NAME_USER) { // XXX TODO. Awaiting reply in mailinglist about what CompressMode is. return "000000"; } else { if (colorName < COLOR_SIZE) { UT_String_sprintf(rv, "%02x%02x%02x", gColors[colorName].red, gColors[colorName].green, gColors[colorName].blue); return rv; } else { UT_DEBUGMSG(("SDW: COLOR OUT OF RANGE! has num %u\n", colorName)); return "000000"; } } }
static gboolean qpro_check_signature (GsfInput *input) { guint8 const *header; guint16 version; if (gsf_input_seek (input, 0, G_SEEK_SET) || NULL == (header = gsf_input_read (input, 2+2+2, NULL)) || GSF_LE_GET_GUINT16 (header + 0) != 0 || GSF_LE_GET_GUINT16 (header + 2) != 2) return FALSE; version = GSF_LE_GET_GUINT16 (header + 4); return (version == 0x1001 || /* 'WB1' format, documented */ version == 0x1002 || /* 'WB2' format, documented */ version == 0x1006 || /* qpro 6.0 ?? */ version == 0x1007); /* qpro 7.0 ?? */ }
/** * gsf_vba_inflate: * @input: stream to read from * @offset: offset into it for start byte of compressed stream * @size: size of the returned array * @add_null_terminator: whenever add or not null at the end of array * * Decompresses VBA stream. * * Return value: A pointer to guint8 array **/ guint8 * gsf_vba_inflate (GsfInput *input, gsf_off_t offset, int *size, gboolean add_null_terminator) { guint8 sig; GByteArray *res; gsf_off_t length; res = g_byte_array_new(); gsf_input_read (input, 1, &sig); if (1 != sig) /* should start with 0x01 */ return NULL; offset++; length = gsf_input_size (input); while (offset < length) { GsfInput *chunk; guint16 chunk_hdr; guint8 const *tmp; tmp = gsf_input_read (input, 2, NULL); if (!tmp) break; chunk_hdr = GSF_LE_GET_GUINT16 (tmp); offset += 2; if (0xB000 == (chunk_hdr&0xF000) && (chunk_hdr&0xFFF) > 0 && (length - offset < 4094)){ if (length < offset + (chunk_hdr&0xFFF)) break; chunk = gsf_input_proxy_new_section (input, offset, (gsf_off_t) (chunk_hdr&0xFFF) + 1); offset += (chunk_hdr&0xFFF) + 1; } else { if (length < offset + 4094){ chunk = gsf_input_proxy_new_section (input, offset, length-offset); offset = length; } else { chunk = gsf_input_proxy_new_section (input, offset, 4094); offset += 4094; } } if (chunk) { GByteArray *tmpres = gsf_msole_inflate (chunk, 0); gsf_input_seek (input, offset, G_SEEK_CUR); g_byte_array_append (res, tmpres->data, tmpres->len); g_byte_array_free (tmpres, TRUE); g_object_unref (chunk); } } if (res == NULL) return NULL; if (add_null_terminator) g_byte_array_append (res, "", 1); *size = res->len; return g_byte_array_free (res, FALSE); }
static void dump_biff_stream (GsfInput *stream) { guint8 const *data; guint16 len, opcode; unsigned pos = gsf_input_tell (stream); while (NULL != (data = gsf_input_read (stream, 4, NULL))) { gboolean enable_dump = TRUE; opcode = GSF_LE_GET_GUINT16 (data); len = GSF_LE_GET_GUINT16 (data+2); if (len > 15000) { enable_dump = TRUE; g_warning ("Suspicious import of biff record > 15,000 (0x%x) for opcode 0x%hx", len, opcode); } else if ((opcode & 0xff00) > 0x1000) { enable_dump = TRUE; g_warning ("Suspicious import of biff record with opcode 0x%hx", opcode); } if (enable_dump) printf ("Opcode 0x%3hx : %15s, length 0x%hx (=%hd)\n", opcode, get_biff_opcode_name (opcode), len, len); if (len > 0) { data = gsf_input_read (stream, len, NULL); if (data == NULL) break; if (enable_dump) gsf_mem_dump (data, len); } pos = gsf_input_tell (stream); } }
void streamRead(GsfInput* aStream, TextAttr& aAttr, gsf_off_t aEoa) throw(UT_Error) { UT_uint8 flags; gsf_off_t newPos; readFlagRec(aStream, flags, &newPos); streamRead(aStream, aAttr.which); streamRead(aStream, aAttr.ver); if (flags & 0x10) { aAttr.startSet = true; streamRead(aStream, aAttr.start); } else aAttr.startSet = false; if (flags & 0x20) { aAttr.endSet = true; streamRead(aStream, aAttr.end); } else aAttr.endSet = false; if (gsf_input_seek(aStream, newPos, G_SEEK_SET)) throw UT_IE_BOGUSDOCUMENT; gsf_off_t curPos = gsf_input_tell(aStream); if (curPos != aEoa) { // there is data aAttr.dataLen = aEoa - curPos; aAttr.data = new UT_uint8[aAttr.dataLen]; streamRead(aStream, aAttr.data, aAttr.dataLen); } // LIST OF THE VALUES: http://ooo.ximian.com/lxr/source/sw/sw/inc/hintids.hxx#086 // together with http://ooo.ximian.com/lxr/source/sw/sw/source/core/sw3io/sw3fmts.cxx#172 switch (aAttr.which) { case 0x1004: // strikethrough aAttr.attrName = "text-decoration"; if (!aAttr.data || aAttr.data[0]) aAttr.attrVal = "line-through"; else aAttr.isOff = true; break; case 0x1005: { // sub-/superscript if (aAttr.dataLen < 3) break; // first byte is size of text % of normal size UT_sint16 height = GSF_LE_GET_GINT16(aAttr.data + 1); aAttr.attrName = "text-position"; if (height > 0) aAttr.attrVal = "superscript"; else if (height < 0) aAttr.attrVal = "subscript"; else aAttr.isOff = true; break; } case 0x1006: { // font family if (!aAttr.data || aAttr.dataLen < 7) // 7 = 3 byte family etc., 2 byte name length, 2 byte style length break; aAttr.attrName = "font-family"; // XXX TODO This code here assumes that the font names are in latin1 UT_uint16 fontLen = GSF_LE_GET_GUINT16(aAttr.data + 3); UT_String_sprintf(aAttr.attrVal, "%.*s", fontLen, (aAttr.data + 5)); break; } case 0x1007: // font height // structure: | height (2 byte, twips) | prop (?) (2 byte) (if version >= 2, if ver=1 1 byte) | unit (if version>=2) | // XXX we ignore "prop" and unit for now, they seem not used much aAttr.attrName = "font-size"; if (aAttr.data) aAttr.attrVal = twipsToSizeString(GSF_LE_GET_GUINT16(aAttr.data)); break; case 0x100a: // Italic aAttr.attrName = "font-style"; if (!aAttr.data || aAttr.data[0]) // if there is data, first byte must be != 0 // abiword doesn't support oblique, so always set italic aAttr.attrVal = "italic"; else aAttr.isOff = true; break; case 0x100d: // Underline aAttr.attrName = "text-decoration"; if (!aAttr.data || aAttr.data[0]) aAttr.attrVal = "underline"; else aAttr.isOff = true; break; case 0x100e: // Bold aAttr.attrName = "font-weight"; if (!aAttr.data || aAttr.data[0] >= 8) // 8=Bold. aAttr.attrVal = "bold"; else aAttr.isOff = true; break; case 0x4000: // line spacing aAttr.attrName = "line-height"; aAttr.isPara = true; // prop space (s8) | inter space (s16) | height (u16) | rule (s8) | interrule (s8) if (aAttr.data && aAttr.dataLen >= 7) { // Abiword wants it as float value, StarOffice saves as percentage (e.g. // 150 for 1.5) float proportionalLineSpace = float(aAttr.data[0])/100; // But maybe we need to use the height - stored as twips, need points // (used for "exact" and "minimum" line spacing) // XXX inter-line spacing not supported by abiword (would be rule=0x00 // interrule=0x02, value to use=inter space, unit twips) UT_String lineHeight = twipsToSizeString(GSF_LE_GET_GINT16(aAttr.data + 3)); // We'll turn the bytes at 5 and 6 into a single integer, for easier // evaluation switch (GSF_LE_GET_GUINT16(aAttr.data + 5)) { case 0x0100: // proportional aAttr.attrVal = std_size_string(proportionalLineSpace); break; case 0x0001: case 0x0002: aAttr.attrVal = lineHeight; if (aAttr.data[5] == 2) // "minimum" case aAttr.attrVal += '+'; break; default: UT_DEBUGMSG(("Unsupported linespacing: %02x %02x\n", aAttr.data[5], aAttr.data[6])); } } break; case 0x4001: // Alignment aAttr.attrName = "text-align"; aAttr.isPara = true; if (aAttr.data) { switch (aAttr.data[0]) { case 0: aAttr.attrVal = "left"; break; case 1: aAttr.attrVal = "right"; break; case 2: case 4: // BLOCKLINE!? what's BLOCKLINE? I'm guessing justify. aAttr.attrVal = "justify"; break; case 3: aAttr.attrVal = "center"; break; } } break; case 0x4005: {// Tabstops aAttr.attrName = "tabstops"; aAttr.isPara = true; // Data structure: // Count(8) | Position (in twips) (32) | Adjustment (8) | Decimal Separator (?) (8) | Fill character (8) // (total size per tab = 7) // UT_sint8 count = aAttr.data[0]; for (UT_uint32 i = 1; (i + 6) < aAttr.dataLen; i += 7) { // Abiword wants: 12.3cm/L0, where 0 indicates what to fill with UT_uint16 posInTwips = GSF_LE_GET_GUINT32(aAttr.data + i); UT_String pos = twipsToSizeString(posInTwips); aAttr.attrVal += pos; aAttr.attrVal += '/'; if (aAttr.data[i + 4] < sizeof(sTabAlignment)/sizeof(*sTabAlignment)) aAttr.attrVal += sTabAlignment[aAttr.data[i + 4]]; else aAttr.attrVal += 'L'; // fallback char fillIndex = '0'; // Fill character switch (aAttr.data[i + 6]) { case '.': fillIndex = '1'; break; case '-': fillIndex = '2'; break; case '_': fillIndex = '3'; break; case ' ': fillIndex = '0'; break; default: UT_DEBUGMSG(("Filling with '%c' is not supported\n", aAttr.data[i + 6])); } aAttr.attrVal += fillIndex; aAttr.attrVal += ','; } } break; default: UT_DEBUGMSG(("SDW: unknown attribute 0x%x, compressed %d\n", aAttr.which, lcl_sw3io__CompressWhich(aAttr.which))); } }
static void qpro_parse_formula (QProReadState *state, int col, int row, guint8 const *data, guint8 const *end) { guint16 magic, ref_offset; #if 0 int flags = GSF_LE_GET_GUINT16 (data + 8); int length = GSF_LE_GET_GUINT16 (data + 10); #endif GnmValue *val; GSList *stack = NULL; GnmExprTop const *texpr = NULL; guint8 const *refs, *fmla; #ifdef DEBUG_MISSING dump_missing_functions (); #endif Q_CHECK_CONDITION (end - data >= 14); magic = GSF_LE_GET_GUINT16 (data + 6) & 0x7ff8; ref_offset = GSF_LE_GET_GUINT16 (data + 12); fmla = data + 14; refs = fmla + ref_offset; Q_CHECK_CONDITION (refs <= end); #if 0 puts (cell_coord_name (col, row)); gsf_mem_dump (data, 14); gsf_mem_dump (fmla, refs-fmla); gsf_mem_dump (refs, end-refs); #endif while (fmla < refs && *fmla != QPRO_OP_EOF) { QProOperators op = *fmla++; GnmExpr const *expr = NULL; #if 0 g_print ("Operator %d.\n", op); #endif switch (op) { case QPRO_OP_CONST_FLOAT: Q_CHECK_CONDITION (refs - fmla >= 8); expr = gnm_expr_new_constant (value_new_float ( gsf_le_get_double (fmla))); fmla += 8; break; case QPRO_OP_CELLREF: { GnmCellRef ref; guint16 tmp; Q_CHECK_CONDITION (end - refs >= 6); tmp = GSF_LE_GET_GUINT16 (refs + 4); ref.sheet = NULL; ref.col = *((gint8 *)(refs + 2)); ref.col_relative = (tmp & 0x4000) ? TRUE : FALSE; ref.row_relative = (tmp & 0x2000) ? TRUE : FALSE; if (ref.row_relative) ref.row = (int)(((gint16)((tmp & 0x1fff) << 3)) >> 3); else ref.row = tmp & 0x1fff; expr = gnm_expr_new_cellref (&ref); refs += 6; break; } case QPRO_OP_RANGEREF: { GnmCellRef a, b; guint16 tmp; Q_CHECK_CONDITION (end - refs >= 10); tmp = GSF_LE_GET_GUINT16 (refs + 4); a.sheet = NULL; a.col = *((gint8 *)(refs + 2)); a.col_relative = (tmp & 0x4000) ? TRUE : FALSE; a.row_relative = (tmp & 0x2000) ? TRUE : FALSE; if (a.row_relative) a.row = (int)(((gint16)((tmp & 0x1fff) << 3)) >> 3); else a.row = tmp & 0x1fff; tmp = GSF_LE_GET_GUINT16 (refs + 8); b.sheet = NULL; b.col = *((gint8 *)(refs + 6)); b.col_relative = (tmp & 0x4000) ? TRUE : FALSE; b.row_relative = (tmp & 0x2000) ? TRUE : FALSE; if (b.row_relative) b.row = (int)(((gint16)((tmp & 0x1fff) << 3)) >> 3); else b.row = tmp & 0x1fff; expr = gnm_expr_new_constant ( value_new_cellrange_unsafe (&a, &b)); refs += 10; break; }
static gboolean check_header (GsfInputGZip *input) { if (input->raw) { input->header_size = 0; input->trailer_size = 0; } else { static guint8 const signature[2] = {0x1f, 0x8b}; guint8 const *data; unsigned flags, len; /* Check signature */ if (NULL == (data = gsf_input_read (input->source, 2 + 1 + 1 + 6, NULL)) || 0 != memcmp (data, signature, sizeof (signature))) return TRUE; /* verify flags and compression type */ flags = data[3]; if (data[2] != Z_DEFLATED || (flags & ~GZIP_HEADER_FLAGS) != 0) return TRUE; /* If we have the size, don't bother seeking to the end. */ if (input->uncompressed_size < 0) { /* Get the uncompressed size */ if (gsf_input_seek (input->source, (gsf_off_t) -4, G_SEEK_END) || NULL == (data = gsf_input_read (input->source, 4, NULL))) return TRUE; /* FIXME, but how? The size read here is modulo 2^32. */ input->uncompressed_size = GSF_LE_GET_GUINT32 (data); if (input->uncompressed_size / 1000 > gsf_input_size (input->source)) { g_warning ("Suspiciously well compressed file with better than 1000:1 ratio.\n" "It is probably truncated or corrupt"); } } if (gsf_input_seek (input->source, 2 + 1 + 1 + 6, G_SEEK_SET)) return TRUE; if (flags & GZIP_EXTRA_FIELD) { if (NULL == (data = gsf_input_read (input->source, 2, NULL))) return TRUE; len = GSF_LE_GET_GUINT16 (data); if (NULL == gsf_input_read (input->source, len, NULL)) return TRUE; } if (flags & GZIP_ORIGINAL_NAME) { /* Skip over the filename (which is in ISO 8859-1 encoding). */ do { if (NULL == (data = gsf_input_read (input->source, 1, NULL))) return TRUE; } while (*data != 0); } if (flags & GZIP_HAS_COMMENT) { /* Skip over the comment (which is in ISO 8859-1 encoding). */ do { if (NULL == (data = gsf_input_read (input->source, 1, NULL))) return TRUE; } while (*data != 0); } if (flags & GZIP_HEADER_CRC && NULL == (data = gsf_input_read (input->source, 2, NULL))) return TRUE; input->header_size = input->source->cur_offset; /* the last 8 bytes are the crc and size. */ input->trailer_size = 8; } gsf_input_set_size (GSF_INPUT (input), input->uncompressed_size); if (gsf_input_remaining (input->source) < input->trailer_size) return TRUE; /* No room for payload */ return FALSE; }
/** * vba_project_read: * @vba: #GsfInfileMSVBA * @err: (allow-none): place to store a #GError if anything goes wrong * * Read an VBA dirctory and its project file. * along the way. * * Returns: %FALSE on error setting @err if it is supplied. **/ static gboolean vba_project_read (GsfInfileMSVBA *vba, GError **err) { /* NOTE : This seems constant, find some confirmation */ static guint8 const signature[] = { 0xcc, 0x61 }; static struct { guint8 const signature[4]; char const * const name; int const vba_version; gboolean const is_mac; } const versions [] = { { { 0x5e, 0x00, 0x00, 0x01 }, "Office 97", 5, FALSE}, { { 0x5f, 0x00, 0x00, 0x01 }, "Office 97 SR1", 5, FALSE }, { { 0x65, 0x00, 0x00, 0x01 }, "Office 2000 alpha?", 6, FALSE }, { { 0x6b, 0x00, 0x00, 0x01 }, "Office 2000 beta?", 6, FALSE }, { { 0x6d, 0x00, 0x00, 0x01 }, "Office 2000", 6, FALSE }, { { 0x6f, 0x00, 0x00, 0x01 }, "Office 2000", 6, FALSE }, { { 0x70, 0x00, 0x00, 0x01 }, "Office XP beta 1/2", 6, FALSE }, { { 0x73, 0x00, 0x00, 0x01 }, "Office XP", 6, FALSE }, { { 0x76, 0x00, 0x00, 0x01 }, "Office 2003", 6, FALSE }, { { 0x79, 0x00, 0x00, 0x01 }, "Office 2003", 6, FALSE }, { { 0x60, 0x00, 0x00, 0x0e }, "MacOffice 98", 5, TRUE }, { { 0x62, 0x00, 0x00, 0x0e }, "MacOffice 2001", 5, TRUE }, { { 0x63, 0x00, 0x00, 0x0e }, "MacOffice X", 6, TRUE }, { { 0x64, 0x00, 0x00, 0x0e }, "MacOffice 2004", 6, TRUE }, }; guint8 const *data; unsigned i, count, len; gunichar2 *uni_name; char *name; GsfInput *dir; dir = gsf_infile_child_by_name (vba->source, "dir"); if (dir == NULL) { if (err != NULL) *err = g_error_new (gsf_input_error_id (), 0, _("Can't find the VBA directory stream")); return FALSE; } if (gsf_input_seek (dir, 0, G_SEEK_SET) || NULL == (data = gsf_input_read (dir, VBA56_DIRENT_HEADER_SIZE, NULL)) || 0 != memcmp (data, signature, sizeof (signature))) { if (err != NULL) *err = g_error_new (gsf_input_error_id (), 0, _("No VBA signature")); return FALSE; } for (i = 0 ; i < G_N_ELEMENTS (versions); i++) if (!memcmp (data+2, versions[i].signature, 4)) break; if (i >= G_N_ELEMENTS (versions)) { if (err != NULL) *err = g_error_new (gsf_input_error_id (), 0, _("Unknown VBA version signature 0x%x%x%x%x"), data[2], data[3], data[4], data[5]); return FALSE; } puts (versions[i].name); /* these depend strings seem to come in 2 blocks */ count = GSF_LE_GET_GUINT16 (data + VBA56_DIRENT_RECORD_COUNT); for (; count > 0 ; count--) { if (NULL == ((data = gsf_input_read (dir, 2, NULL)))) break; len = GSF_LE_GET_GUINT16 (data); if (NULL == ((data = gsf_input_read (dir, len, NULL)))) { printf ("len == 0x%x ??\n", len); break; } uni_name = g_new0 (gunichar2, len/2 + 1); /* be wary about endianness */ for (i = 0 ; i < len ; i += 2) uni_name [i/2] = GSF_LE_GET_GUINT16 (data + i); name = g_utf16_to_utf8 (uni_name, -1, NULL, NULL, NULL); g_free (uni_name); printf ("%d %s\n", count, name); /* ignore this blob ???? */ if (!strncmp ("*\\G", name, 3)) { if (NULL == ((data = gsf_input_read (dir, 12, NULL)))) { printf ("len == 0x%x ??\n", len); break; } } g_free (name); } g_return_val_if_fail (count == 0, FALSE); return TRUE; }
/** * vba_dir_read: * @vba: #GsfInfileMSVBA * @err: (allow-none): place to store a #GError if anything goes wrong * * Read an VBA dirctory and its project file. * along the way. * * Returns: %FALSE on error setting @err if it is supplied. **/ static gboolean vba_dir_read (GsfInfileMSVBA *vba, GError **err) { int inflated_size, element_count = -1; char const *msg = NULL; char *name, *elem_stream = NULL; guint32 len; guint16 tag; guint8 *inflated_data, *end, *ptr; GsfInput *dir; gboolean failed = TRUE; /* 0. get the stream */ dir = gsf_infile_child_by_name (vba->source, "dir"); if (dir == NULL) { msg = _("Can't find the VBA directory stream"); goto fail_stream; } /* 1. decompress it */ ptr = inflated_data = gsf_vba_inflate (dir, 0, &inflated_size, TRUE); if (inflated_data == NULL) goto fail_compression; end = inflated_data + inflated_size; /* 2. GUESS : based on several xls with macros and XL8GARY this looks like a * series of sized records. Be _extra_ careful */ do { /* I have seen * type len data * 1 4 1 0 0 0 * 2 4 9 4 0 0 * 3 2 4 e4 * 4 <var> project name * 5 0 * 6 0 * 7 4 * 8 4 * 0x3d 0 * 0x40 0 * 0x14 4 9 4 0 0 * * 0x0f == number of elements * 0x1c == (Size 0) * 0x1e == (Size 4) * 0x48 == (Size 0) * 0x31 == stream offset of the compressed source ! * * 0x16 == an ascii dependency name * 0x3e == a unicode dependency name * 0x33 == a classid for a dependency with no trialing data * * 0x2f == a dummy classid * 0x30 == a classid * 0x0d == the classid * 0x2f, and 0x0d appear contain * uint32 classid_size; * <classid> * 00 00 00 00 00 00 * and sometimes some trailing junk **/ if ((ptr + 6) > end) { msg = _("vba project header problem"); goto fail_content; } tag = GSF_LE_GET_GUINT16 (ptr); len = GSF_LE_GET_GUINT32 (ptr + 2); ptr += 6; if ((ptr + len) > end) { msg = _("vba project header problem"); goto fail_content; } switch (tag) { case 4: name = g_strndup (ptr, len); #ifdef OLD_VBA_DUMP puts ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); printf ("<project name=\"%s\">", name); #endif g_free (name); break; case 9: /* this seems to have an extra two bytes that are not * part of the length ..?? */ len += 2; break; case 0xf : if (len != 2) { g_warning ("element count is not what we expected"); break; } if (element_count >= 0) { g_warning ("More than one element count ??"); break; } element_count = GSF_LE_GET_GUINT16 (ptr); break; /* dependencies */ case 0x0d : break; case 0x2f : break; case 0x30 : break; case 0x33 : break; case 0x3e : break; case 0x16: #if 0 name = g_strndup (ptr, len); g_print ("Depend Name : '%s'\n", name); g_free (name); #endif break; /* elements */ case 0x47 : break; case 0x32 : break; case 0x1a: #if 0 name = g_strndup (ptr, len); g_print ("Element Name : '%s'\n", name); g_free (name); #endif break; case 0x19: g_free (elem_stream); elem_stream = g_strndup (ptr, len); break; case 0x31: if (len != 4) { g_warning ("source offset property is not what we expected"); break; } vba_extract_module_source (vba, elem_stream, GSF_LE_GET_GUINT32 (ptr)); g_free (elem_stream); elem_stream = NULL; element_count--; break; default : #if 0 g_print ("tag %hx : len %u\n", tag, len); gsf_mem_dump (ptr, len); #endif break; } ptr += len; } while (tag != 0x10); if (element_count != 0) g_warning ("Number of elements differs from expectations"); failed = FALSE; fail_content : g_free (inflated_data); #ifdef OLD_VBA_DUMP puts ("</project>"); #endif fail_compression : g_object_unref (dir); fail_stream : g_free (elem_stream); if (failed) { if (err != NULL) *err = g_error_new_literal (gsf_input_error_id (), 0, msg); return FALSE; } return TRUE; }