/** * gsf_open_pkg_open_rel_by_id: * @opkg: #GsfInput * @id: target id * @err: optionally %NULL * * New in 1.14.7 * * Open @opkg's relation @id * * Returns: (transfer full): A new GsfInput or %NULL, and sets @err if possible. **/ GsfInput * gsf_open_pkg_open_rel_by_id (GsfInput *opkg, char const *id, GError **err) { GsfOpenPkgRel *rel = gsf_open_pkg_lookup_rel_by_id (opkg, id); if (rel) return gsf_open_pkg_open_rel (opkg, rel, err); if (err) *err = g_error_new (gsf_input_error_id(), gsf_open_pkg_error_id (), _("Unable to find part id='%s' for '%s'"), id, gsf_input_name (opkg) ); return NULL; }
/** * gsf_open_pkg_open_rel_by_id : * @opkg : #GsfInput * @id : target id * @err : optionally %NULL * * New in 1.14.7 * * Open @opkg's relation @id * * Returns: A new GsfInput or %NULL, and sets @err if possible. **/ GsfInput * gsf_open_pkg_open_rel_by_id (GsfInput *opkg, char const *id, GError **err) { GsfOpenPkgRel *rel = NULL; GsfOpenPkgRels *rels = gsf_open_pkg_get_rels (opkg); if (NULL != rels && NULL != (rel = g_hash_table_lookup (rels->by_id, id))) return gsf_open_pkg_open_rel (opkg, rel, err); if (err) *err = g_error_new (gsf_input_error_id(), gsf_open_pkg_error_id (), _("Unable to find part id='%s' for '%s'"), id, gsf_input_name (opkg) ); return NULL; }
static gsf_off_t unpack_octal (GsfInfileTar *tar, const char *s, size_t len) { gsf_off_t res = 0; while (len--) { unsigned char c = *s++; if (c == 0) break; if (c < '0' || c > '7') { tar->err = g_error_new (gsf_input_error_id (), 0, "Invalid tar header"); return 0; } res = (res << 3) + (c - '0'); } return res; }
GsfInfile * gsf_infile_msvba_new (GsfInfile *source, GError **err) { GsfInfileMSVBA *vba; g_return_val_if_fail (GSF_IS_INFILE (source), NULL); vba = g_object_new (GSF_INFILE_MSVBA_TYPE, NULL); vba->source = g_object_ref (source); /* vba_project_read (vba, err); */ /* find the name offset pairs */ if (vba_dir_read (vba, err)) return GSF_INFILE (vba); if (err != NULL && *err == NULL) *err = g_error_new (gsf_input_error_id (), 0, _("Unable to parse VBA header")); g_object_unref (vba); return NULL; }
/** * tar_init_info : * @tar : #GsfInfileTar * * Read tar headers and do some sanity checking * along the way. **/ static void tar_init_info (GsfInfileTar *tar) { TarHeader end; const TarHeader *header; gsf_off_t pos0 = gsf_input_tell (tar->source); char *pending_longname = NULL; memset (&end, 0, sizeof (end)); while (tar->err == NULL && (header = (const TarHeader *)gsf_input_read (tar->source, HEADER_SIZE, NULL))) { char *name; gsf_off_t length; gsf_off_t offset; if (memcmp (header->filler, end.filler, sizeof (end.filler))) { tar->err = g_error_new (gsf_input_error_id (), 0, "Invalid tar header"); break; } if (memcmp (header, &end, HEADER_SIZE) == 0) break; if (pending_longname) { name = pending_longname; pending_longname = NULL; } else name = g_strndup (header->name, sizeof (header->name)); length = unpack_octal (tar, header->size, sizeof (header->size)); offset = gsf_input_tell (tar->source); #if 0 g_printerr ("[%s]: %d\n", name, (int)length); #endif switch (header->typeflag) { case '0': case 0: { /* Regular file. */ GsfInfileTar *dir; const char *n = name, *s; TarChild c; /* This is deliberately slash-only. */ while ((s = strchr (n, '/'))) n = s + 1; c.name = g_strdup (n); c.offset = offset; c.length = length; c.dir = NULL; dir = tar_directory_for_file (tar, name, FALSE); g_array_append_val (dir->children, c); break; } case '5': { /* Directory */ (void)tar_directory_for_file (tar, name, TRUE); break; } case 'L': { const char *n; if (pending_longname || strcmp (name, MAGIC_LONGNAME) != 0) { tar->err = g_error_new (gsf_input_error_id (), 0, "Invalid longname header"); break; } n = gsf_input_read (tar->source, length, NULL); if (!n) { tar->err = g_error_new (gsf_input_error_id (), 0, "Failed to read longname"); break; } pending_longname = g_strndup (n, length); break; } default: /* Other -- ignore */ break; } g_free (name); /* Round up to block size */ length = (length + (BLOCK_SIZE - 1)) / BLOCK_SIZE * BLOCK_SIZE; if (!tar->err && gsf_input_seek (tar->source, offset + length, G_SEEK_SET)) { tar->err = g_error_new (gsf_input_error_id (), 0, "Seek failed"); break; } } if (pending_longname) { if (!tar->err) tar->err = g_error_new (gsf_input_error_id (), 0, "Truncated archive"); g_free (pending_longname); } if (tar->err) gsf_input_seek (tar->source, pos0, G_SEEK_SET); }
static guint8 const * gsf_input_gzip_read (GsfInput *input, size_t num_bytes, guint8 *buffer) { GsfInputGZip *gzip = GSF_INPUT_GZIP (input); if (buffer == NULL) { if (gzip->buf_size < num_bytes) { gzip->buf_size = MAX (num_bytes, 256); g_free (gzip->buf); gzip->buf = g_new (guint8, gzip->buf_size); } buffer = gzip->buf; } gzip->stream.next_out = buffer; gzip->stream.avail_out = num_bytes; while (gzip->stream.avail_out != 0) { int zerr; if (gzip->stream.avail_in == 0) { gsf_off_t remain = gsf_input_remaining (gzip->source); if (remain <= gzip->trailer_size) { if (remain < gzip->trailer_size || gzip->stop_byte_added) { g_clear_error (&gzip->err); gzip->err = g_error_new (gsf_input_error_id (), 0, "truncated source"); return NULL; } /* zlib requires an extra byte. */ gzip->stream.avail_in = 1; gzip->gzipped_data = ""; gzip->stop_byte_added = TRUE; } else { size_t n = MIN (remain - gzip->trailer_size, Z_BUFSIZE); gzip->gzipped_data = gsf_input_read (gzip->source, n, NULL); if (!gzip->gzipped_data) { g_clear_error (&gzip->err); gzip->err = g_error_new (gsf_input_error_id (), 0, "Failed to read from source"); return NULL; } gzip->stream.avail_in = n; } gzip->stream.next_in = (Byte *)gzip->gzipped_data; } zerr = inflate (&(gzip->stream), Z_NO_FLUSH); if (zerr != Z_OK) { if (zerr != Z_STREAM_END) return NULL; /* Premature end of stream. */ if (gzip->stream.avail_out != 0) return NULL; } } gzip->crc = crc32 (gzip->crc, buffer, (uInt)(gzip->stream.next_out - buffer)); return buffer; }
/** * 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; }