Commit 8e5ed05d authored by Michael Meeks's avatar Michael Meeks
Browse files

Lots of fixes.

parent 20b5ea22
......@@ -49,6 +49,7 @@ excel_load (const char *filename)
if (!f)
return NULL;
printf ("Opening '%s'\n", filename);
wb = ms_excel_read_workbook (f);
if (wb) {
char *name = g_strconcat (filename, ".gnumeric", NULL);
......
1999-05-23 Michael Meeks <michael@imaginator.com>
* ms-ole.c (ms_ole_directory_create): Setup 'dir' properly
for streams tacked onto chain.
(PPS_SET_NAME_LEN): Removed factor of two.
(ms_ole_create): Updated magic from 0x0003003b to 0x0003003e
1999-05-22 Michael Meeks <michael@imaginator.com>
* ms-ole.c (pps_encode): Fix for NULL names.
(ms_ole_directory_create): Silly bug chaining in filenames.
(next_free_sb): Actually mark the blocks we are using as used.
Re-adjust the calculations for extending the sbf.
(ms_ole_stream_close): Add check on array before free.
(free_allocation): Write the Small block writing code.
(ms_ole_directory_next): Recurse over NULL names.
Cleaned debug: silent except for errors.
Added 'dirty' flag to MS_OLE *, fo write-backs.
(read_sb): Trancate the SB chain to remove appended
unused blocks.
(write_pps): Fiddled.
(pps_encode): Silly bug in PPS name length setting &
setting start to END_OF_CHAIN.
1999-05-21 Michael Meeks <michael@imaginator.com>
* ms-ole.c (ms_ole_stream_close): Leak fixed: thanks Morten.
(read_bb): Silly bug with lengths and header block.
(ms_ole_create): Changed creation method, parallel but discrete.
(ms_ole_directory_create): Cleaned up, bug not setting primary_entr
(ms_ole_cleanup): Fleshed out.
(next_free_pps): Serious bug klonked.
(write_pps, write_sb, write_bb): Implemented.
(ms_ole_append_block): Fix silly bug using sb not bb.
(next_free_bb): Add call to extend_file !
(ms_ole_write_sb): Simplified conversion and killed nasty
critical section checks.
1999-05-20 Michael Meeks <michael@imaginator.com>
......
......@@ -18,7 +18,7 @@
/* Implementational detail - not for global header */
#define OLE_DEBUG 1
#define OLE_DEBUG 2
/* These take a _guint8_ pointer */
#define GET_GUINT8(p) (*((const guint8 *)(p)+0))
......@@ -48,8 +48,6 @@
/* Very grim, but quite necessary */
# define ms_array_index(a,b,c) (b)my_array_hack ((a), sizeof(b), (c))
static int critical_section = 0;
static guint32
my_array_hack (GArray *a, guint s, guint32 idx)
{
......@@ -119,7 +117,7 @@ get_block_ptr (MS_OLE *f, BLP b)
It is not the case that pps_next(f, pps_prev(f, n)) = n ! For the final list
item there are no valid links. Cretins. */
#define PPS_GET_NAME_LEN(p) (GET_GUINT16(p + 0x40))
#define PPS_SET_NAME_LEN(p,i) (SET_GUINT16(p + 0x40, (i)*2))
#define PPS_SET_NAME_LEN(p,i) (SET_GUINT16(p + 0x40, (i)))
#define PPS_NAME(f,n) (pps_get_text (p, PPS_GET_NAME_LEN(f,n)))
#define PPS_GET_PREV(p) ((PPS_IDX) GET_GUINT32(p + 0x44))
#define PPS_GET_NEXT(p) ((PPS_IDX) GET_GUINT32(p + 0x48))
......@@ -146,12 +144,16 @@ pps_get_text (guint8 *ptr, int length)
guint16 c;
guint8 *inb;
length = (length+1)/2;
if (length <= 0 ||
length > PPS_BLOCK_SIZE/2)
length > (PPS_BLOCK_SIZE/4)) {
#if OLE_DEBUG > 0
printf ("Nulled name of length %d\n", length);
#endif
return 0;
}
length = (length+1)/2;
ans = (char *)g_malloc (sizeof(char) * length + 1);
c = GET_GUINT16(ptr);
......@@ -182,10 +184,16 @@ dump_header (MS_OLE *f)
printf ("Block %d -> block %d\n", lp,
g_array_index (f->bb, BLP, lp));
/* printf ("Root blocks : %d\n", h->root_list->len);
for (lp=0;lp<h->root_list->len;lp++)
printf ("root_list[%d] = %d\n", lp, (int)ms_array_index (h->root_list, BBPtr, lp));
if (f->pps) {
printf ("Root blocks : %d\n", f->pps->len);
for (lp=0;lp<f->pps->len;lp++) {
PPS *p = g_ptr_array_index (f->pps, lp);
printf ("root_list[%d] = '%s' ( <-%d, V %d, %d->)\n", lp, p->name?p->name:"Null",
p->prev, p->dir, p->next);
}
} else
printf ("No root yet\n");
/*
printf ("sbd blocks : %d\n", h->sbd_list->len);
for (lp=0;lp<h->sbd_list->len;lp++)
printf ("sbd_list[%d] = %d\n", lp, (int)ms_array_index (h->sbd_list, SBPtr, lp));*/
......@@ -203,7 +211,7 @@ static int
read_bb (MS_OLE *f)
{
guint32 numbbd;
BLP ptr, lp;
BLP lp;
GArray *ans;
g_return_val_if_fail (f, 0);
......@@ -211,10 +219,9 @@ read_bb (MS_OLE *f)
ans = g_array_new (FALSE, FALSE, sizeof(BLP));
numbbd = GET_NUM_BBD_BLOCKS (f);
ptr = GET_ROOT_STARTBLOCK (f);
/* Sanity checks */
if (numbbd < ((f->length + ((BB_BLOCK_SIZE*BB_BLOCK_SIZE)/4) - 1) /
if (numbbd < ((f->length - BB_BLOCK_SIZE + ((BB_BLOCK_SIZE*BB_BLOCK_SIZE)/4) - 1) /
((BB_BLOCK_SIZE*BB_BLOCK_SIZE)/4))) {
printf ("Duff block descriptors\n");
return 0;
......@@ -244,6 +251,157 @@ read_bb (MS_OLE *f)
return 1;
}
static void
extend_file (MS_OLE *f, guint blocks)
{
#ifndef OLE_MMAP
# error Simply add more blocks at the end in memory
#else
struct stat st;
int file;
guint8 *newptr, zero = 0;
guint32 oldlen;
guint32 blk, lp;
g_assert (f);
file = f->file_descriptor;
#if OLE_DEBUG > 5
printf ("Before extend\n");
dump_allocation(f);
#endif
g_assert (munmap(f->mem, f->length) != -1);
/* Extend that file by blocks */
if ((fstat(file, &st)==-1) ||
(lseek (file, st.st_size + BB_BLOCK_SIZE*blocks - 1, SEEK_SET)==(off_t)-1) ||
(write (file, &zero, 1)==-1))
{
printf ("Serious error extending file\n");
f->mem = 0;
return;
}
oldlen = st.st_size;
fstat(file, &st);
f->length = st.st_size;
g_assert (f->length == BB_BLOCK_SIZE*blocks + oldlen);
if (f->length%BB_BLOCK_SIZE)
printf ("Warning file %d non-integer number of blocks\n", f->length);
newptr = mmap (f->mem, f->length, PROT_READ|PROT_WRITE, MAP_SHARED, file, 0);
#if OLE_DEBUG > 0
if (newptr != f->mem)
printf ("Memory map moved from %p to %p\n",
f->mem, newptr);
#endif
f->mem = newptr;
#if OLE_DEBUG > 5
printf ("After extend\n");
dump_allocation(f);
#endif
#endif
}
static BLP
next_free_bb (MS_OLE *f)
{
BLP blk, tblk;
guint32 idx, lp;
g_assert (f);
blk = 0;
while (blk < f->bb->len)
if (g_array_index (f->bb, BLP, blk) == UNUSED_BLOCK)
return blk;
else
blk++;
extend_file (f, 2);
tblk = UNUSED_BLOCK;
g_array_append_val (f->bb, tblk);
g_array_append_val (f->bb, tblk);
#ifndef OLE_MMAP
# error Need to extend bbptr as well.
#endif
g_assert ((g_array_index (f->bb, BLP, blk) == UNUSED_BLOCK));
return blk;
}
static int
write_bb (MS_OLE *f)
{
guint32 numbbd;
BLP ptr, lp, lpblk;
GArray *ans;
g_return_val_if_fail (f, 0);
g_return_val_if_fail (f->mem, 0);
g_return_val_if_fail (f->bb, 0);
numbbd = (f->bb->len + (BB_BLOCK_SIZE*BB_BLOCK_SIZE/4) - 1) /
((BB_BLOCK_SIZE*BB_BLOCK_SIZE/4) - 1); /* Think carefully ! */
SET_NUM_BBD_BLOCKS (f, numbbd);
for (lp=0;lp<numbbd;lp++) {
BLP blk = next_free_bb(f);
SET_BBD_LIST (f, lp, blk);
g_array_index (f->bb, BLP, blk) = SPECIAL_BLOCK;
}
lpblk = 0;
while (lpblk<f->bb->len) { /* Described blocks */
guint8 *mem = BBPTR(f, GET_BBD_LIST(f, lpblk/(BB_BLOCK_SIZE/4)));
SET_GUINT32 (mem + (lpblk%(BB_BLOCK_SIZE/4))*4,
g_array_index (f->bb, BLP, lpblk));
lpblk++;
}
while (lpblk%(BB_BLOCK_SIZE/4) != 0) { /* Undescribed blocks */
guint8 *mem = BBPTR(f, GET_BBD_LIST(f, lpblk/(BB_BLOCK_SIZE/4)));
SET_GUINT32 (mem + (lpblk%(BB_BLOCK_SIZE/4))*4,
UNUSED_BLOCK);
lpblk++;
}
g_array_free (f->bb, TRUE);
f->bb = 0;
return 1;
}
static BLP
next_free_sb (MS_OLE *f)
{
BLP blk, tblk;
guint32 idx, lp;
g_assert (f);
blk = 0;
while (blk < f->sb->len)
if (g_array_index (f->sb, BLP, blk) == UNUSED_BLOCK)
return blk;
else
blk++;
tblk = UNUSED_BLOCK;
g_array_append_val (f->sb, tblk);
g_assert ((g_array_index (f->sb, BLP, blk) == UNUSED_BLOCK));
g_assert (blk < f->sb->len);
if ((f->sb->len + (BB_BLOCK_SIZE/SB_BLOCK_SIZE) - 1) / (BB_BLOCK_SIZE/SB_BLOCK_SIZE) >= f->sbf->len) {
/* Create an extra big block on the small block stream */
BLP new_sbf = next_free_bb(f);
g_array_append_val (f->sbf, new_sbf);
/* We don't need to chain it in as we have this info in f->sbf */
g_array_index (f->bb, BLP, new_sbf) = END_OF_CHAIN;
}
g_assert ((f->sb->len + (BB_BLOCK_SIZE/SB_BLOCK_SIZE) - 1) / (BB_BLOCK_SIZE/SB_BLOCK_SIZE) <= f->sbf->len);
return blk;
}
static PPS *
pps_decode (guint8 *mem)
{
......@@ -251,10 +409,17 @@ pps_decode (guint8 *mem)
pps->name = pps_get_text (mem, PPS_GET_NAME_LEN(mem));
pps->type = PPS_GET_TYPE (mem);
pps->size = PPS_GET_SIZE (mem);
pps->next = PPS_GET_NEXT (mem);
pps->prev = PPS_GET_PREV (mem);
pps->dir = PPS_GET_DIR (mem);
pps->start = PPS_GET_STARTBLOCK (mem);
if (pps->name) {
pps->next = PPS_GET_NEXT (mem);
pps->prev = PPS_GET_PREV (mem);
pps->dir = PPS_GET_DIR (mem);
pps->start = PPS_GET_STARTBLOCK (mem);
} else { /* Make safe */
pps->next = PPS_END_OF_CHAIN;
pps->prev = PPS_END_OF_CHAIN;
pps->dir = PPS_END_OF_CHAIN;
pps->start = PPS_END_OF_CHAIN;
}
#if OLE_DEBUG > 1
printf ("PPS decode : '%s'\n", pps->name?pps->name:"Null");
dump (mem, PPS_BLOCK_SIZE);
......@@ -263,7 +428,7 @@ pps_decode (guint8 *mem)
}
static void
pps_code (guint8 *mem, PPS *pps)
pps_encode (guint8 *mem, PPS *pps)
{
int lp, max;
......@@ -272,16 +437,22 @@ pps_code (guint8 *mem, PPS *pps)
/* Blank stuff I don't understand */
for (lp=0;lp<PPS_BLOCK_SIZE;lp++)
SET_GUINT8(mem+lp, 0);
if (pps->name) {
max = strlen (pps->name);
if (max >= (PPS_BLOCK_SIZE/4))
max = (PPS_BLOCK_SIZE/4);
for (lp=0;lp<max;lp++)
SET_GUINT16(mem + lp*2, pps->name[lp]);
} else {
printf ("No name %d\n", pps->pps);
max = -1;
}
max = strlen (pps->name);
if (max >= (PPS_BLOCK_SIZE/4))
max = (PPS_BLOCK_SIZE/4);
for (lp=0;lp<max;lp++)
SET_GUINT16(mem + lp*2, pps->name[lp]);
PPS_SET_NAME_LEN(mem + 0x40, (max+1)*2);
PPS_SET_NAME_LEN(mem, (max+1)*2);
/* Magic numbers */
SET_GUINT8 (mem + 0x43, 0x01); /* Or zero ? */
SET_GUINT32 (mem + 0x50, 0x00020900);
SET_GUINT32 (mem + 0x58, 0x000000c0);
SET_GUINT32 (mem + 0x5c, 0x46000000);
......@@ -291,7 +462,7 @@ pps_code (guint8 *mem, PPS *pps)
PPS_SET_NEXT (mem, pps->next);
PPS_SET_PREV (mem, pps->prev);
PPS_SET_DIR (mem, pps->dir);
PPS_SET_STARTBLOCK(mem, END_OF_CHAIN);
PPS_SET_STARTBLOCK(mem, pps->start);
}
static int
......@@ -303,7 +474,9 @@ read_pps (MS_OLE *f)
g_return_val_if_fail (f, 0);
blk = GET_ROOT_STARTBLOCK (f);
#if OLE_DEBUG > 0
printf ("Root start block %d\n", blk);
#endif
while (blk != END_OF_CHAIN) {
int lp;
BLP last;
......@@ -325,6 +498,47 @@ read_pps (MS_OLE *f)
}
f->pps = ans;
if (f->pps->len < 1) {
printf ("Root directory too small\n");
return 0;
}
return 1;
}
static int
write_pps (MS_OLE *f)
{
int ppslp;
BLP blk = END_OF_CHAIN;
BLP last = END_OF_CHAIN;
for (ppslp=0;ppslp<f->pps->len;ppslp++) {
PPS *cur;
if (ppslp%(BB_BLOCK_SIZE/PPS_BLOCK_SIZE)==0) {
last = blk;
blk = next_free_bb (f);
g_assert (g_array_index (f->bb, BLP, blk) == UNUSED_BLOCK);
if (last != END_OF_CHAIN)
g_array_index (f->bb, BLP, last) = blk;
else {
#if OLE_DEBUG > 0
printf ("Set root block to %d\n", blk);
#endif
SET_ROOT_STARTBLOCK (f, blk);
}
g_array_index (f->bb, BLP, blk) = END_OF_CHAIN;
}
cur = g_ptr_array_index (f->pps, ppslp);
pps_encode (BBPTR(f,blk) + (ppslp%(BB_BLOCK_SIZE/PPS_BLOCK_SIZE))*PPS_BLOCK_SIZE,
cur);
if (cur->name)
g_free (cur->name);
cur->name = 0;
}
g_ptr_array_free (f->pps, TRUE);
f->pps = 0;
return 1;
}
......@@ -332,7 +546,7 @@ static int
read_sb (MS_OLE *f)
{
BLP ptr;
int lp;
int lp, lastidx, idx;
PPS *root;
g_return_val_if_fail (f, 0);
......@@ -346,7 +560,9 @@ read_sb (MS_OLE *f)
/* List of big blocks in SB file */
ptr = root->start;
#if OLE_DEBUG > 0
printf ("Starting Small block file at %d\n", root->start);
#endif
while (ptr != END_OF_CHAIN) {
if (ptr == UNUSED_BLOCK ||
ptr == SPECIAL_BLOCK) {
......@@ -356,12 +572,13 @@ read_sb (MS_OLE *f)
f->sbf = 0;
return 0;
}
g_array_append_val (f->sbf, ptr);
ptr = NEXT_BB (f, ptr);
}
/* Description of small blocks */
lastidx = -1;
idx = 0;
ptr = GET_SBD_STARTBLOCK (f);
while (ptr != END_OF_CHAIN) {
guint32 lp;
......@@ -376,9 +593,83 @@ read_sb (MS_OLE *f)
for (lp=0;lp<BB_BLOCK_SIZE/4;lp++) {
BLP p = GET_GUINT32 (BBPTR(f, ptr) + lp*4);
g_array_append_val (f->sb, p);
if (p != UNUSED_BLOCK)
lastidx = idx;
idx++;
}
ptr = NEXT_BB (f, ptr);
}
if (lastidx>0)
g_array_set_size (f->sb, lastidx+1);
if (f->sbf->len * BB_BLOCK_SIZE < f->sb->len*SB_BLOCK_SIZE) {
printf ("Not enough small block file for descriptors\n"
"sbf->len == %d, sb->len == %d\n", f->sbf->len,
f->sb->len);
return 0;
}
return 1;
}
static int
write_sb (MS_OLE *f)
{
guint32 lp, lastused;
PPS *root;
BLP sbd_start = END_OF_CHAIN;
g_return_val_if_fail (f, 0);
g_return_val_if_fail (f->pps, 0);
root = g_ptr_array_index (f->pps, PPS_ROOT_BLOCK);
lastused = END_OF_CHAIN;
for (lp=0;lp<f->sb->len;lp++) {
if (g_array_index (f->sb, BLP, lp) != UNUSED_BLOCK)
lastused = lp;
}
if (lastused != END_OF_CHAIN) { /* Bother writing stuff */
guint8 *mem = 0;
guint32 num_sbdf = (lastused + (BB_BLOCK_SIZE/4)-1) /
(BB_BLOCK_SIZE/4);
BLP blk = END_OF_CHAIN, last;
#if OLE_DEBUG > 0
printf ("Num SB descriptor blocks : %d\n", num_sbdf);
#endif
for (lp=0;lp<num_sbdf*(BB_BLOCK_SIZE/4);lp++) {
BLP set;
if (lp%(BB_BLOCK_SIZE/4) == 0) {
last = blk;
blk = next_free_bb(f);
if (!lp)
sbd_start = blk;
if (last != END_OF_CHAIN)
g_array_index (f->bb, BLP, last) = blk;
g_array_index (f->bb, BLP, blk) = END_OF_CHAIN;
mem = BBPTR (f, blk);
}
if (lp<f->sb->len)
set = g_array_index (f->sb, BLP, lp);
else
set = UNUSED_BLOCK;
SET_GUINT32 (mem + (lp%(BB_BLOCK_SIZE/4))*4, set);
}
} else {
#if OLE_DEBUG > 0
printf ("Blank SB allocation\n");
#endif
root->start = END_OF_CHAIN;
}
SET_SBD_STARTBLOCK (f, sbd_start);
g_array_free (f->sb, TRUE);
g_array_free (f->sbf, TRUE);
f->sb = 0;
f->sbf = 0;
return 1;
}
......@@ -387,8 +678,13 @@ ms_ole_setup (MS_OLE *f)
{
if (read_bb (f) &&
read_pps (f) &&
read_sb (f))
read_sb (f)) {
#if OLE_DEBUG > 1
printf ("Just read header of\n");
dump_header (f);
#endif
return 1;
}
return 0;
}
......@@ -397,6 +693,14 @@ ms_ole_cleanup (MS_OLE *f)
{
if (f->mode != 'w') /* Nothing to write */
return 1;
#if OLE_DEBUG > 1
printf ("About to write header of: \n");
dump_header (f);
#endif
if (write_sb (f) &&
write_pps (f) &&
write_bb (f))
return 1;
return 0;
}
......@@ -415,6 +719,7 @@ new_null_msole ()
f->sb = 0;
f->sbf = 0;
f->pps = 0;
f->dirty = 0;
return f;
}
......@@ -433,13 +738,12 @@ ms_ole_open (const char *name)
#endif
f = new_null_msole();
#if OLE_MMAP
f->file_descriptor = file = open (name, O_RDWR);
mode = 'w';
f->mode = 'w';
if (file == -1) {
f->file_descriptor = file = open (name, O_RDONLY);
mode = 'r';
f->mode = 'r';
prot &= ~PROT_WRITE;
}
if (file == -1 || fstat(file, &st))
......@@ -465,18 +769,19 @@ ms_ole_open (const char *name)
if (GET_GUINT32(f->mem ) != 0xe011cfd0 ||
GET_GUINT32(f->mem + 4) != 0xe11ab1a1)
{
#if OLE_DEBUG > 0
printf ("Failed OLE2 magic number %x %x\n",
GET_GUINT32(f->mem), GET_GUINT32(f->mem+4));
#endif
ms_ole_destroy (f);
return 0;
}
if (f->length%BB_BLOCK_SIZE)
printf ("Warning file '%s':%d non-integer number of blocks\n", name, f->length);
if (!ms_ole_setup (f))
{
printf ("Directory error\n");
ms_ole_destroy(f);
if (!ms_ole_setup(f)) {
printf ("'%s' : duff file !\n", name);
ms_ole_destroy (f);
return 0;
}
......@@ -484,7 +789,6 @@ ms_ole_open (const char *name)
printf ("New OLE file '%s'\n", name);
#endif
/* If writing then when destroy commit it */
f->mode = mode;
return f;
}
......@@ -540,23 +844,33 @@ ms_ole_create (const char *name)
SET_GUINT32(f->mem + 4, 0xe11ab1a1);