static inline unsigned ole_bytes_left_in_block (GsfOutfileMSOle *ole) { /* blocks are multiples of bb.size (the header is padded out to bb.size) */ unsigned r = gsf_output_tell (ole->sink) % ole->bb.size; return (r != 0) ? (ole->bb.size - r) : 0; }
/* write the metadata (dirents, small block, xbats) and close the sink */ static gboolean gsf_outfile_msole_close_root (GsfOutfileMSOle *ole) { GsfOutfile *tmp; guint8 buf [OLE_HEADER_SIZE]; guint32 sbat_start, num_sbat, sb_data_start, sb_data_size, sb_data_blocks; guint32 bat_start, num_bat, dirent_start, num_dirent_blocks, next, child_index; unsigned i, j, blocks, num_xbat, xbat_pos; gsf_off_t data_size; unsigned metabat_size = ole->bb.size / BAT_INDEX_SIZE - 1; GPtrArray *elem = ole->root->content.dir.root_order; /* write small block data */ blocks = 0; sb_data_start = ole_cur_block (ole); data_size = gsf_output_tell (ole->sink); for (i = 0 ; i < elem->len ; i++) { GsfOutfileMSOle *child = g_ptr_array_index (elem, i); if (child->type == MSOLE_SMALL_BLOCK) { gsf_off_t size = gsf_output_size (GSF_OUTPUT (child)); if (size > 0) { child->blocks = ((size - 1) >> ole->sb.shift) + 1; gsf_output_write (ole->sink, child->blocks << ole->sb.shift, child->content.small_block.buf); child->first_block = blocks; blocks += child->blocks; } else {
static void gsf_output_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { GsfOutput *output = GSF_OUTPUT (object); /* gsf_off_t is typedef'd to gint64 */ switch (property_id) { case PROP_NAME: g_value_set_string (value, gsf_output_name (output)); break; case PROP_SIZE: g_value_set_int64 (value, gsf_output_size (output)); break; case PROP_CLOSED: g_value_set_boolean (value, gsf_output_is_closed (output)); break; case PROP_POS: g_value_set_int64 (value, gsf_output_tell (output)); break; case PROP_MODTIME: g_value_set_boxed (value, gsf_output_get_modtime (output)); break; case PROP_CONTAINER: g_value_set_object (value, output->container); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } }
static void gsf_output_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { /* gsf_off_t is typedef'd to gint64 */ switch (property_id) { case PROP_NAME: g_value_set_string (value, gsf_output_name (GSF_OUTPUT (object))); break; case PROP_SIZE: g_value_set_int64 (value, gsf_output_size (GSF_OUTPUT (object))); break; case PROP_POS: g_value_set_int64 (value, gsf_output_tell (GSF_OUTPUT (object))); break; case PROP_CLOSED: g_value_set_boolean (value, gsf_output_is_closed (GSF_OUTPUT (object))); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } }
static gboolean zip_close_root (GsfOutput *output) { GsfOutfileZip *zip = GSF_OUTFILE_ZIP (output); GsfOutfileZip *child; gsf_off_t dirpos = gsf_output_tell (zip->sink); GPtrArray *elem = zip->root_order; unsigned entries = elem->len; unsigned i; /* Check that children are closed */ for (i = 0 ; i < elem->len ; i++) { child = g_ptr_array_index (elem, i); if (!gsf_output_is_closed (GSF_OUTPUT (child))) { g_warning ("Child still open"); return FALSE; } } /* Write directory */ for (i = 0 ; i < entries ; i++) { child = g_ptr_array_index (elem, i); if (!zip_dirent_write (zip->sink, child->vdir->dirent)) return FALSE; } disconnect_children (zip); return zip_trailer_write (zip, entries, dirpos); }
static gboolean zip_trailer_write (GsfOutfileZip *zip, unsigned entries, gsf_off_t dirpos) { static guint8 const trailer_signature[] = { 'P', 'K', 0x05, 0x06 }; guint8 buf[ZIP_TRAILER_SIZE]; gsf_off_t pos = gsf_output_tell (zip->sink); memset (buf, 0, sizeof buf); memcpy (buf, trailer_signature, sizeof trailer_signature); GSF_LE_SET_GUINT16 (buf + ZIP_TRAILER_ENTRIES, entries); GSF_LE_SET_GUINT16 (buf + ZIP_TRAILER_TOTAL_ENTRIES, entries); GSF_LE_SET_GUINT32 (buf + ZIP_TRAILER_DIR_SIZE, pos - dirpos); GSF_LE_SET_GUINT32 (buf + ZIP_TRAILER_DIR_POS, dirpos); return gsf_output_write (zip->sink, sizeof buf, buf); }
static gboolean zip_init_write (GsfOutput *output) { GsfOutfileZip *zip = GSF_OUTFILE_ZIP (output); GsfZipDirent *dirent; int ret; if (zip->root->writing) { g_warning ("Already writing to another stream in archive"); return FALSE; } if (!gsf_output_wrap (G_OBJECT (output), zip->sink)) return FALSE; dirent = zip_dirent_new_out (zip); dirent->offset = gsf_output_tell (zip->sink); if (zip->vdir->dirent) g_warning ("Leak."); zip->vdir->dirent = dirent; zip_header_write (zip); zip->writing = TRUE; zip->root->writing = TRUE; dirent->crc32 = crc32 (0L, Z_NULL, 0); if (zip->compression_method == GSF_ZIP_DEFLATED) { if (!zip->stream) { zip->stream = g_new0 (z_stream, 1); } ret = deflateInit2 (zip->stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY); if (ret != Z_OK) return FALSE; if (!zip->buf) { zip->buf_size = ZIP_BUF_SIZE; zip->buf = g_new (guint8, zip->buf_size); } zip->stream->next_out = zip->buf; zip->stream->avail_out = zip->buf_size; } return TRUE; }
static gboolean zip_header_write_sizes (GsfOutfileZip *zip) { guint8 hbuf[ZIP_HEADER_SIZE]; GsfZipDirent *dirent = zip->vdir->dirent; gsf_off_t pos = gsf_output_tell (zip->sink); if (!gsf_output_seek (zip->sink, dirent->offset + ZIP_HEADER_CRC, G_SEEK_SET)) return FALSE; GSF_LE_SET_GUINT32 (hbuf + ZIP_HEADER_CRC, dirent->crc32); GSF_LE_SET_GUINT32 (hbuf + ZIP_HEADER_COMP_SIZE, dirent->csize); GSF_LE_SET_GUINT32 (hbuf + ZIP_HEADER_UNCOMP_SIZE, dirent->usize); if (!gsf_output_write (zip->sink, 12, hbuf + ZIP_HEADER_CRC)) return FALSE; if (!gsf_output_seek (zip->sink, pos, G_SEEK_SET)) return FALSE; return TRUE; }
/* Calculate the block of the current offset in the file. A useful idiom is to * pad_zero to move to the start of the next block, then get the block number. * This avoids fence post type problems with partial blocks. */ static inline guint32 ole_cur_block (GsfOutfileMSOle const *ole) { return (gsf_output_tell (ole->sink) - OLE_HEADER_SIZE) >> ole->bb.shift; }