Mercurial > libpst
view archive/patch1 @ 164:ab384fed78c5
Compensate for iconv conversion to utf-7 that produces strings that are not null terminated.
Don't produce empty attachment files in separate mode.
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Mon, 16 Mar 2009 18:31:39 -0700 |
parents | de3753c3160a |
children |
line wrap: on
line source
diff -Naur ../orig/libpst-0.5.1/define.h libpst64-060926/define.h --- ../orig/libpst-0.5.1/define.h 2004-11-17 07:48:03.000000000 -0700 +++ libpst64-060926/define.h 2006-09-26 14:09:55.000000000 -0600 @@ -5,7 +5,7 @@ * dave.s@earthcorp.com */ -//#define DEBUG_ALL +#define DEBUG_ALL #ifndef DEFINEH_H #define DEFINEH_H diff -Naur ../orig/libpst-0.5.1/generic.c libpst64-060926/generic.c --- ../orig/libpst-0.5.1/generic.c 1969-12-31 17:00:00.000000000 -0700 +++ libpst64-060926/generic.c 2006-09-26 14:09:55.000000000 -0600 @@ -0,0 +1,110 @@ +// {{{ includes + +#include <ctype.h> +#include <errno.h> +#include <malloc.h> +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "generic.h" + +#ifdef WITH_DMALLOC +#include <dmalloc.h> +#endif + +// }}} + +// {{{ Macros: ASSERT(), DIE(), F_MALLOC() +void pDIE( char *fmt, ... ) // {{{ Cough...cough +{ + va_list ap; + va_start( ap, fmt ); + //fprintf( stderr, "Fatal error (will segfault): "); + vfprintf( stderr, fmt, ap ); + fprintf( stderr, "\n" ); + va_end(ap); + raise( SIGSEGV ); +} +// }}} +void pWARN( char *fmt, ... ) // {{{ Cough...cough +{ + va_list ap; + va_start( ap, fmt ); + fprintf( stderr, "WARNING: "); + vfprintf( stderr, fmt, ap ); + fprintf( stderr, "\n" ); + va_end(ap); +} +// }}} +void *F_MALLOC( size_t size ) // {{{ malloc() but dumps core when it fails +{ + void *result; + + result = malloc( size ); + ASSERT( NULL != result, "malloc() failure." ); + + return result; +} +// }}} +void *F_REALLOC( void *p, size_t size ) // {{{ realloc() but dumps core when it fails +{ + void *result; + + //if( NULL != p ) hexdump((char*)p - 128, 0, 128, 1 ); + if(!p) { + ASSERT( NULL != ( result = malloc( size ) ), "malloc() failure." ); + } + else { + ASSERT( NULL != ( result = realloc( p, size ) ), "realloc() failure." ); + } + + //hexdump((char*)result - 128, 0, 128, 1 ); + fflush(stderr); + return result; +} +// }}} +// }}} +// {{{ Program logging/debug output +int DEBUG_LEVEL = DB_INFO; + +void db_default( char *file, int line, int level, char *fmt, ... ) // {{{ +{ + va_list ap; + if( level <= DEBUG_LEVEL ) { + switch( level ) { + case DB_CRASH: + fprintf(stderr, "CRASH"); + break; + case DB_ERR: + fprintf(stderr, "ERROR"); + break; + case DB_WARN: + fprintf(stderr, "WARNING"); + break; + case DB_INFO: + case DB_VERB: + break; + default: + fprintf(stderr, "DEBUG(%d)", level ); + } + + if( level <= DB_WARN ) + fprintf(stderr, " (%s:%d)", file, line ); + + if( DB_INFO != level && DB_VERB != level ) + fprintf(stderr, ": "); + + va_start( ap, fmt ); + vfprintf(stderr, fmt, ap ); + fprintf(stderr, "\n" ); + va_end( ap ); + } +} // }}} + +void (*dbfunc)(char *file, int line, int level, char *fmt, ...) = &db_default; + +//#define DEBUG(x) { x; } +//#define DEBUG(x) ; +// }}} diff -Naur ../orig/libpst-0.5.1/generic.h libpst64-060926/generic.h --- ../orig/libpst-0.5.1/generic.h 1969-12-31 17:00:00.000000000 -0700 +++ libpst64-060926/generic.h 2006-09-26 14:09:55.000000000 -0600 @@ -0,0 +1,48 @@ +/* {{{ Generic.h - thigns every program does: + * + * - user output (log, debug, etc) + * - crash and burn + * - allocate memory (or explode) + * }}} */ +#ifndef GENERIC_H +#define GENERIC_H +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +/***************************************************/ + +#define LOAD_DEBUG 1 + +#define DIE(...) { fprintf(stderr, "Fatal Error at %s,%d: ", __FILE__, __LINE__); pDIE(__VA_ARGS__); } + +//#define WARN(...) { fprintf(stderr, "WARN: %s,%d: ", __FILE__, __LINE__); pWARN(__VA_ARGS__); } +void pDIE( char *fmt, ... ); +//void pWARN( char *fmt, ... ); + +#define WARN(...) DB( DB_WARN, __VA_ARGS__ ) +#define ASSERT(x,...) { if( !(x) ) DIE( __VA_ARGS__ ); } + +void *F_MALLOC( size_t size ); +void *F_REALLOC( void *p, size_t size ); + +#define DO_DEBUG 0 +#define DEBUG(x) if( DO_DEBUG ) { x; } +#define STUPID_CR "\r\n" + +#define DB_CRASH 0 // crashing +#define DB_ERR 1 // error +#define DB_WARN 2 // warning +#define DB_INFO 3 // normal, but significant, condition +#define DB_VERB 4 // verbose information +#define DB_0 5 // debug-level message +#define DB_1 6 // debug-level message +#define DB_2 7 // debug-level message + +extern int DEBUG_LEVEL; +extern void (*dbfunc)(char *file, int line, int level, char *fmt, ...); + +#define DB(...) { dbfunc( __FILE__, __LINE__, __VA_ARGS__ ); } + +int set_db_function( void (*func)( char *file, int line, int level, char *fmt, ...) ); + +#endif diff -Naur ../orig/libpst-0.5.1/libpst.c libpst64-060926/libpst.c --- ../orig/libpst-0.5.1/libpst.c 2004-11-17 07:48:04.000000000 -0700 +++ libpst64-060926/libpst.c 2006-09-26 14:09:55.000000000 -0600 @@ -4,6 +4,7 @@ * Written by David Smith * dave.s@earthcorp.com */ +//{{{ #include <stdio.h> #include <stdlib.h> #include <time.h> @@ -12,11 +13,15 @@ #include <limits.h> #include <wchar.h> +#include <signal.h> #include <errno.h> #include <sys/stat.h> //mkdir #include <fcntl.h> // for Win32 definition of _O_BINARY #include "define.h" #include "libstrfunc.h" +#include "vbuf.h" + +#define ASSERT(x) { if(!(x)) raise( SIGSEGV ); } #ifdef _MSC_VER # include <windows.h> @@ -45,30 +50,54 @@ //#define LE32_CPU(x) {} //#define LE16_CPU(x) {} //#endif // _MSC_VER - -#define FILE_SIZE_POINTER 0xA8 -#define INDEX_POINTER 0xC4 -#define SECOND_POINTER 0xBC +// }}} +#define FILE_SIZE_POINTER32 0xA8 +#define INDEX_POINTER32 0xC4 +#define INDEX_COUNT32 0xC0 +#define SECOND_POINTER32 0xBC +#define SECOND_COUNT32 0xB8 #define INDEX_DEPTH 0x4C #define SECOND_DEPTH 0x5C // the encryption setting could be at 0x1CC. Will require field testing -#define ENC_OFFSET 0x1CD +#define ENC_OFFSET32 0x1CD // says the type of index we have -#define INDEX_TYPE_OFFSET 0x0A +#define INDEX_TYPE_OFFSET32 0x0A +#define INDEX_TYPE32 0x0E +#define INDEX_TYPE64 0x17 //I think this is wrong // for the 64bit 2003 outlook PST we need new file offsets // perhaps someone can figure out the header format for the pst files... -#define FILE_SIZE_POINTER_64 0xB8 -#define INDEX_POINTER_64 0xF0 -#define SECOND_POINTER_64 0xE0 +#define FILE_SIZE_POINTER64 0xB8 +#define INDEX_POINTER64 0xF0 +#define INDEX_COUNT64 0xE8 +#define SECOND_POINTER64 0xE0 +#define SECOND_COUNT64 0xD8 +#define INDEX_TYPE_OFFSET64 0x0A +#define ENC_OFFSET64 0x201 + +#define FILE_SIZE_POINTER ((do_read64)?FILE_SIZE_POINTER64:FILE_SIZE_POINTER32) +#define INDEX_POINTER ((do_read64)?INDEX_POINTER64:INDEX_POINTER32) +#define INDEX_TYPE_OFFSET ((do_read64)?INDEX_TYPE_OFFSET64:INDEX_TYPE_OFFSET32) +#define INDEX_TYPE ((do_read64)?INDEX_TYPE64:INDEX_TYPE32) +#define SECOND_POINTER ((do_read64)?SECOND_POINTER64:SECOND_POINTER32) +#define SECOND_COUNT ((do_read64)?SECOND_COUNT64:SECOND_COUNT32) +#define ENC_OFFSET ((do_read64)?ENC_OFFSET64:ENC_OFFSET32) +#define INDEX_COUNT ((do_read64)?INDEX_COUNT64:INDEX_COUNT32) #define PST_SIGNATURE 0x4E444221 -struct _pst_table_ptr_struct{ +int do_read64 = 0; //set this to 1 in order to try and read 64-bit pst files (Outlook 2003) + +struct _pst_table_ptr_struct32{ int32_t start; int32_t u1; int32_t offset; }; +struct _pst_table_ptr_structn{ + int64_t start; + int64_t u1; + int64_t offset; +}; typedef struct _pst_block_header { int16_t type; @@ -119,6 +148,26 @@ 0xd4, 0xe1, 0x11, 0xd0, 0x08, 0x8b, 0x2a, 0xf2, 0xed, 0x9a, 0x64, 0x3f, 0xc1, 0x6c, 0xf9, 0xec}; /*0xff*/ +void set_read64() { do_read64 = 1; } + +void dump_desc( off_t off, int depth, int i, pst_descn *desc_rec ) { // {{{ + + //desc_rec->d_id = 0x0102030405060708; + DEBUG_INDEX(("%08x [%i] Item(%#x) = [d_id = %#llx, desc_id = %#llx, " + "list_id = %#llx, parent_id = %#x, u1 = %#x] %#x %p %p\n", + off, + depth, i, desc_rec->d_id, + desc_rec->desc_id, desc_rec->list_id, desc_rec->parent_id, desc_rec->u1)); + DEBUG_HEXDUMPC( (char*)desc_rec, sizeof( pst_descn ), 0x10 ); + DEBUG_INDEX(("WTF? %d %x %x %x %x %x\n", + sizeof( u_int32_t ), + (int)(&desc_rec->d_id) - (int)desc_rec, + (int)(&desc_rec->desc_id) - (int)desc_rec, + (int)(&desc_rec->list_id) - (int)desc_rec, + (int)(&desc_rec->parent_id) - (int)desc_rec, + (int)(&desc_rec->u1) - (int)desc_rec )); +} // }}} + int32_t pst_open(pst_file *pf, char *name, char *mode) { u_int32_t sig; // unsigned char ind_type; @@ -158,9 +207,10 @@ DEBUG_RET(); return -1; } + _pst_getAtPos(pf->fp, INDEX_TYPE_OFFSET, &(pf->ind_type), sizeof(unsigned char)); DEBUG_INFO(("index_type = %i\n", pf->ind_type)); - if (pf->ind_type != 0x0E) { + if ( pf->ind_type != INDEX_TYPE) { WARN(("unknown index structure. Could this be a new Outlook 2003 PST file?\n")); DEBUG_RET(); return -1; @@ -170,23 +220,18 @@ DEBUG_INFO(("encrypt = %i\n", pf->encryption)); // pf->encryption = encrypt; - _pst_getAtPos(pf->fp, SECOND_POINTER-4, &(pf->index2_count), sizeof(pf->index2_count)); - _pst_getAtPos(pf->fp, SECOND_POINTER, &(pf->index2), sizeof(pf->index2)); - LE32_CPU(pf->index2_count); - LE32_CPU(pf->index2); + pf->index2_count = _pst_getIntAtPos(pf->fp, SECOND_COUNT); + pf->index2 = _pst_getIntAtPos(pf->fp, SECOND_POINTER ); - _pst_getAtPos(pf->fp, FILE_SIZE_POINTER, &(pf->size), sizeof(pf->size)); - LE32_CPU(pf->size); + pf->size = _pst_getIntAtPos( pf->fp, FILE_SIZE_POINTER ); // very tempting to leave these values set way too high and let the exploration of the tables set them... pf->index1_depth = pf->index2_depth = 255; DEBUG_INFO(("Pointer2 is %#X, count %i[%#x], depth %#x\n", pf->index2, pf->index2_count, pf->index2_count, pf->index2_depth)); - _pst_getAtPos(pf->fp, INDEX_POINTER-4, &(pf->index1_count), sizeof(pf->index1_count)); - _pst_getAtPos(pf->fp, INDEX_POINTER, &(pf->index1), sizeof(pf->index1)); - LE32_CPU(pf->index1_count); - LE32_CPU(pf->index1); + pf->index1_count = _pst_getIntAtPos(pf->fp, INDEX_COUNT); + pf->index1 = _pst_getIntAtPos(pf->fp, INDEX_POINTER); DEBUG_INFO(("Pointer1 is %#X, count %i[%#x], depth %#x\n", pf->index1, pf->index1_count, pf->index1_count, pf->index1_depth)); @@ -495,18 +540,110 @@ } #define BLOCK_SIZE 516 +int _pst_decode_desc( pst_descn *desc, char *buf ) { // {{{ + int r; + if( do_read64 ) { + + DEBUG_INDEX(("Decoding desc64 ")); + DEBUG_HEXDUMPC(buf, sizeof( pst_descn ), 0x10); + memcpy(desc, buf, sizeof( pst_descn )); + LE64_CPU(desc->d_id); + LE64_CPU(desc->desc_id); + LE64_CPU(desc->list_id); + LE32_CPU(desc->parent_id); + LE32_CPU(desc->u1); + r = sizeof( pst_descn ); + } + else { + pst_desc32 d32; + DEBUG_INDEX(("Decoding desc32 ")); + DEBUG_HEXDUMPC(buf, sizeof( d32 ), 0x10); + memcpy(&d32, buf, sizeof(d32)); + LE32_CPU(d32.d_id); + LE32_CPU(d32.desc_id); + LE32_CPU(d32.list_id); + LE32_CPU(d32.parent_id); + + desc->d_id = d32.d_id; + desc->desc_id = d32.desc_id; + desc->list_id = d32.list_id; + desc->parent_id = d32.parent_id; + desc->u1 = 0; + + r = sizeof( d32 ); + } + + return r; +} // }}} +int _pst_decode_table( struct _pst_table_ptr_structn *table, char *buf ) { // {{{ + + if( do_read64 ) { + + DEBUG_INDEX(("Decoding table64")); + DEBUG_HEXDUMPC(buf, sizeof( struct _pst_table_ptr_structn ), 0x10); + memcpy(table, buf, sizeof( struct _pst_table_ptr_structn ) ); + LE64_CPU(table->start); + LE64_CPU(table->u1); + LE64_CPU(table->offset); + + return sizeof( struct _pst_table_ptr_structn ); + } + else { + struct _pst_table_ptr_struct32 t32; + memcpy(&t32, buf, sizeof(t32)); + LE32_CPU(t32.start); + LE32_CPU(t32.u1); + LE32_CPU(t32.offset); + table->start = t32.start; + table->u1 = t32.u1; + table->offset = t32.offset; + + return sizeof( struct _pst_table_ptr_struct32 ); + } + return 0; +} // }}} +int _pst_decode_index( pst_index *index, char *buf ) { // {{{ + if( do_read64 ) { + + DEBUG_INDEX(("Decoding index64")); + DEBUG_HEXDUMPC(buf, sizeof( pst_index ), 0x10); + memcpy(index, buf, sizeof(pst_index)); + LE64_CPU(index->id); + LE64_CPU(index->offset); + LE16_CPU(index->size); + LE16_CPU(index->u0); + LE16_CPU(index->u1); + return sizeof( pst_index ); + } else { + pst_index32 index32; + memcpy(&index32, buf, sizeof(pst_index32)); + LE32_CPU(index32->id); + LE32_CPU(index32->offset); + LE16_CPU(index32->size); + LE16_CPU(index32->u1); + index->id = index32.id; + index->offset = index32.offset; + index->size = index32.size; + index->u1 = index32.u1; + + return sizeof( pst_index32 ); + } -int32_t _pst_build_id_ptr(pst_file *pf, int32_t offset, int32_t depth, int32_t start_val, int32_t end_val) { - struct _pst_table_ptr_struct table, table2; + return 0; +} // }}} + +int32_t _pst_build_id_ptr(pst_file *pf, off_t offset, int32_t depth, int32_t start_val, int32_t end_val) { + struct _pst_table_ptr_structn table, table2; pst_index_ll *i_ptr=NULL; pst_index index; // int fpos = ftell(pf->fp); int32_t x, ret; int32_t old = start_val; + off_t roff; char *buf = NULL, *bptr = NULL; DEBUG_ENT("_pst_build_id_ptr"); - if (pf->index1_depth - depth == 0) { + if (pf->index1_depth - depth == 0) { // {{{ Leaf table, add indexes to linked list // we must be at a leaf table. These are index items DEBUG_INDEX(("Reading Items\n")); // fseek(pf->fp, offset, SEEK_SET); @@ -519,15 +656,14 @@ } bptr = buf; // DEBUG_HEXDUMPC(buf, BLOCK_SIZE, 12); - memcpy(&index, bptr, sizeof(index)); - LE32_CPU(index.id); - LE32_CPU(index.offset); - LE16_CPU(index.size); - LE16_CPU(index.u1); - bptr += sizeof(index); + roff = offset; + bptr += _pst_decode_index( &index, bptr ); - while(index.id != 0 && x < 42 && bptr < buf+BLOCK_SIZE && index.id < end_val) { - DEBUG_INDEX(("[%i]%i Item [id = %#x, offset = %#x, u1 = %#x, size = %i(%#x)]\n", depth, ++x, index.id, index.offset, index.u1, index.size, index.size)); + while(index.id != 0 && x < 42 && bptr < buf+BLOCK_SIZE && index.id < end_val) { // {{{ + DEBUG_INDEX(("%08x [%i]%i Item [ id = %#llx, offset = %#llx, u1 = %#x, size = %i(%#x)] %p %p\n", + roff, + depth, ++x, index.id, index.offset, index.u1, + index.size, index.size, buf, bptr )); if (index.id & 0x02) { DEBUG_INDEX(("two-bit set!!\n")); } @@ -543,7 +679,7 @@ pf->id_depth_ok = 1; } // u1 could be a flag. if bit 0x2 is not set, it might be deleted - // if (index.u1 & 0x2 || index.u1 & 0x4) { + // if (index.u1 & 0x2 || index.u1 & 0x4) // ignore the above condition. it doesn't appear to hold if (old > index.id) { // then we have back-slid on the new values DEBUG_INDEX(("Back slider detected - Old value [%#x] greater than new [%#x]. Progressing to next table\n", old, index.id)); @@ -551,6 +687,7 @@ return 2; } old = index.id; + // {{{ Add index to linked list i_ptr = (pst_index_ll*) xmalloc(sizeof(pst_index_ll)); i_ptr->id = index.id; i_ptr->offset = index.offset; @@ -562,15 +699,12 @@ if (pf->i_head == NULL) pf->i_head = i_ptr; pf->i_tail = i_ptr; - memcpy(&index, bptr, sizeof(index)); - LE32_CPU(index.id); - LE32_CPU(index.offset); - LE16_CPU(index.size); - LE16_CPU(index.u1); - bptr += sizeof(index); - } - // fseek(pf->fp, fpos, SEEK_SET); - if (x < 42) { // we have stopped prematurley. Why? + // }}} + + roff = offset + (bptr - buf); + bptr +=_pst_decode_index( &index, bptr ); + } // }}} + if (x < 42) { // {{{ we have stopped prematurley. Why? if (index.id == 0) { DEBUG_INDEX(("Found index.id == 0\n")); } else if (!(bptr < buf+BLOCK_SIZE)) { @@ -581,12 +715,12 @@ } else { DEBUG_INDEX(("Stopped for unknown reason\n")); } - } + } // }}} if (buf) free (buf); DEBUG_RET(); return 2; - } else { - // this is then probably a table of offsets to more tables. + } // }}} + else { // {{{ probably a table of offsets to tables, recurse DEBUG_INDEX(("Reading Table Items\n")); x = 0; @@ -600,15 +734,10 @@ bptr = buf; // DEBUG_HEXDUMPC(buf, BLOCK_SIZE, 12); - memcpy(&table, bptr, sizeof(table)); - LE32_CPU(table.start); - LE32_CPU(table.u1); - LE32_CPU(table.offset); - bptr += sizeof(table); - memcpy(&table2, bptr, sizeof(table)); - LE32_CPU(table2.start); - LE32_CPU(table2.u1); - LE32_CPU(table2.offset); + + roff = offset; + bptr += _pst_decode_table( &table, bptr ); + _pst_decode_table( &table2, bptr ); if (start_val != -1 && table.start != start_val) { DEBUG_WARN(("This table isn't right. Must be corruption, or I got it wrong!\n")); @@ -619,7 +748,9 @@ } while (table.start != 0 && bptr < buf+BLOCK_SIZE && table.start < end_val) { - DEBUG_INDEX(("[%i] %i Table [start id = %#x, u1 = %#x, offset = %#x]\n", depth, ++x, table.start, table.u1, table.offset)); + DEBUG_INDEX(("%08x [%i] %i Table [start id = %#x, u1 = %#x, offset = %#x]\n", + roff, + depth, ++x, table.start, table.u1, table.offset)); if (table2.start <= table.start) // this should only be the case when we come to the end of the table @@ -643,15 +774,9 @@ } else { DEBUG_INDEX(("child has returned without a known error [%i]\n", ret)); } - memcpy(&table, bptr, sizeof(table)); - LE32_CPU(table.start); - LE32_CPU(table.u1); - LE32_CPU(table.offset); - bptr += sizeof(table); - memcpy(&table2, bptr, sizeof(table)); - LE32_CPU(table2.start); - LE32_CPU(table2.u1); - LE32_CPU(table2.offset); + bptr += _pst_decode_table( &table, bptr ); + roff = offset + ( bptr - buf ); + _pst_decode_table( &table2, bptr ); } if (table.start == 0) { @@ -669,21 +794,23 @@ DEBUG_INDEX(("End of table of pointers\n")); DEBUG_RET(); return 3; - } + } // }}} DEBUG_WARN(("ERROR ** Shouldn't be here!\n")); DEBUG_RET(); return 1; } + #define DESC_BLOCK_SIZE 520 -int32_t _pst_build_desc_ptr (pst_file *pf, int32_t offset, int32_t depth, int32_t *high_id, int32_t start_id, +int32_t _pst_build_desc_ptr (pst_file *pf, off_t offset, int32_t depth, int32_t *high_id, int32_t start_id, int32_t end_val) { - struct _pst_table_ptr_struct table, table2; - pst_desc desc_rec; + struct _pst_table_ptr_structn table, table2; + pst_descn desc_rec; pst_desc_ll *d_ptr=NULL, *d_par=NULL; int32_t i = 0, y, prev_id=-1; char *buf = NULL, *bptr; + off_t roff; struct _pst_d_ptr_ll { pst_desc_ll * ptr; @@ -696,8 +823,7 @@ int32_t d_ptr_count = 0; DEBUG_ENT("_pst_build_desc_ptr"); - if (pf->index2_depth-depth == 0) { - // leaf node + if (pf->index2_depth-depth == 0) { // {{{ leaf node, index it if (_pst_read_block_size(pf, offset, DESC_BLOCK_SIZE, &buf, 0, 0) < DESC_BLOCK_SIZE) { DEBUG_WARN(("I didn't get all the index that I wanted. _pst_read_block_size returned less than requested\n")); DEBUG_RET(); @@ -707,22 +833,17 @@ //DEBUG_HEXDUMPC(buf, DESC_BLOCK_SIZE, 16); - memcpy(&desc_rec, bptr, sizeof(desc_rec)); - LE32_CPU(desc_rec.d_id); - LE32_CPU(desc_rec.desc_id); - LE32_CPU(desc_rec.list_id); - LE32_CPU(desc_rec.parent_id); - bptr+= sizeof(desc_rec); + roff = offset; + bptr += _pst_decode_desc( &desc_rec, bptr ); if (end_val <= start_id) { DEBUG_WARN(("The end value is BEFORE the start value. This function will quit. Soz. [start:%#x, end:%#x]\n", start_id, end_val)); } - while (i < 0x1F && desc_rec.d_id < end_val && (prev_id == -1 || desc_rec.d_id > prev_id)) { - DEBUG_INDEX(("[%i] Item(%#x) = [d_id = %#x, desc_id = %#x, " - "list_id = %#x, parent_id = %#x]\n", depth, i, desc_rec.d_id, - desc_rec.desc_id, desc_rec.list_id, desc_rec.parent_id)); + while (i < 0x1F && desc_rec.d_id < end_val && (prev_id == -1 || desc_rec.d_id > prev_id)) { // {{{ + DEBUG_INDEX(("Bliss %d: %llx %p %p %p ", i, offset, buf, bptr, bptr )); + dump_desc( roff, depth, i, &desc_rec ); i++; if (start_id != -1 && desc_rec.d_id != start_id) { @@ -737,20 +858,16 @@ } if (desc_rec.d_id == 0) { - memcpy(&desc_rec, bptr, sizeof(desc_rec)); - LE32_CPU(desc_rec.d_id); - LE32_CPU(desc_rec.desc_id); - LE32_CPU(desc_rec.list_id); - LE32_CPU(desc_rec.parent_id); - bptr+=sizeof(desc_rec); - continue; + roff = offset + ( bptr - buf ); + bptr+=_pst_decode_desc( &desc_rec, bptr ); + continue; } prev_id = desc_rec.d_id; // When duplicates found, just update the info.... perhaps this is correct functionality DEBUG_INDEX(("Searching for existing record\n")); - if (desc_rec.d_id <= *high_id && (d_ptr = _pst_getDptr(pf, desc_rec.d_id)) != NULL) { + if (desc_rec.d_id <= *high_id && (d_ptr = _pst_getDptr(pf, desc_rec.d_id)) != NULL) { // {{{ DEBUG_INDEX(("Updating Existing Values\n")); d_ptr->list_index = _pst_getID(pf, desc_rec.list_id); d_ptr->desc = _pst_getID(pf, desc_rec.desc_id); @@ -802,7 +919,7 @@ d_ptr_ptr = d_ptr_ptr->next; } - if (d_ptr_ptr == NULL && (d_par = _pst_getDptr(pf, desc_rec.parent_id)) == NULL) { + if (d_ptr_ptr == NULL && (d_par = _pst_getDptr(pf, desc_rec.parent_id)) == NULL) { // {{{ // check in the lost/found list lf_ptr = lf_head; while (lf_ptr != NULL && lf_ptr->ptr->id != desc_rec.parent_id) { @@ -820,7 +937,7 @@ d_par = lf_ptr->ptr; DEBUG_INDEX(("Found parent (%#x) in Lost and Found\n", d_par->id)); } - } + } // }}} if (d_ptr_ptr != NULL || d_par != NULL) { if (d_ptr_ptr != NULL) @@ -857,7 +974,8 @@ } } - } else { + } // }}} + else { if (*high_id < desc_rec.d_id) { DEBUG_INDEX(("Updating New High\n")); *high_id = desc_rec.d_id; @@ -866,8 +984,10 @@ d_ptr = (pst_desc_ll*) xmalloc(sizeof(pst_desc_ll)); // DEBUG_INDEX(("Item pointer is %p\n", d_ptr)); d_ptr->id = desc_rec.d_id; + DEBUG_INDEX(("Weird %llx moo", desc_rec.list_id )); d_ptr->list_index = _pst_getID(pf, desc_rec.list_id); d_ptr->desc = _pst_getID(pf, desc_rec.desc_id); + //ASSERT( d_ptr->desc != NULL ); d_ptr->prev = NULL; d_ptr->next = NULL; d_ptr->parent = NULL; @@ -876,7 +996,7 @@ d_ptr->no_child = 0; DEBUG_INDEX(("Searching for parent\n")); - if (desc_rec.parent_id == 0 || desc_rec.parent_id == desc_rec.d_id) { + if (desc_rec.parent_id == 0 || desc_rec.parent_id == desc_rec.d_id) { // {{{ if (desc_rec.parent_id == 0) { DEBUG_INDEX(("No Parent\n")); } else { @@ -888,7 +1008,8 @@ pf->d_head = d_ptr; d_ptr->prev = pf->d_tail; pf->d_tail = d_ptr; - } else { + } // }}} + else { // {{{ d_ptr_ptr = d_ptr_head; while (d_ptr_ptr != NULL && d_ptr_ptr->ptr->id != desc_rec.parent_id) { d_ptr_ptr = d_ptr_ptr->next; @@ -947,7 +1068,7 @@ d_ptr->prev = d_par->child_tail; d_par->child_tail = d_ptr; } - } + } // }}} } // check here to see if d_ptr is the parent of any of the items in the lost / found list lf_ptr = lf_head; lf_shd = NULL; @@ -977,16 +1098,13 @@ lf_ptr = lf_ptr->next; } } - memcpy(&desc_rec, bptr, sizeof(desc_rec)); - LE32_CPU(desc_rec.d_id); - LE32_CPU(desc_rec.desc_id); - LE32_CPU(desc_rec.list_id); - LE32_CPU(desc_rec.parent_id); - bptr+= sizeof(desc_rec); - } + + roff = offset + ( bptr - buf ); + bptr+= _pst_decode_desc( &desc_rec, bptr ); + } // }}} // fseek(pf->fp, fpos, SEEK_SET); - } else { - // hopefully a table of offsets to more tables + } // }}} + else { // {{{ table of offsets to more tables, recurse if (_pst_read_block_size(pf, offset, DESC_BLOCK_SIZE, &buf, 0, 0) < DESC_BLOCK_SIZE) { DEBUG_WARN(("didn't read enough desc index. _pst_read_block_size returned less than requested\n")); DEBUG_RET(); @@ -995,15 +1113,8 @@ bptr = buf; // DEBUG_HEXDUMPC(buf, DESC_BLOCK_SIZE, 12); - memcpy(&table, bptr, sizeof(table)); - LE32_CPU(table.start); - LE32_CPU(table.u1); - LE32_CPU(table.offset); - bptr+=sizeof(table); - memcpy(&table2, bptr, sizeof(table)); - LE32_CPU(table2.start); - LE32_CPU(table2.u1); - LE32_CPU(table2.offset); + bptr+=_pst_decode_table( &table, bptr ); + _pst_decode_table( &table2, bptr ); if (start_id != -1 && table.start != start_id) { DEBUG_WARN(("This table isn't right. Perhaps we are too deep, or corruption\n")); @@ -1034,20 +1145,13 @@ _pst_build_desc_ptr(pf, table.offset, depth+1, high_id, table.start, table2.start); } - memcpy(&table, bptr, sizeof(table)); - LE32_CPU(table.start); - LE32_CPU(table.u1); - LE32_CPU(table.offset); - bptr+=sizeof(table); - memcpy(&table2, bptr, sizeof(table)); - LE32_CPU(table2.start); - LE32_CPU(table2.u1); - LE32_CPU(table2.offset); + bptr+=_pst_decode_table( &table, bptr ); + _pst_decode_table( &table2, bptr ); } if (buf) free(buf); DEBUG_RET(); return 3; - } + } // }}} // ok, lets try freeing the d_ptr_head cache here while (d_ptr_head != NULL) { d_ptr_ptr = d_ptr_head->next; @@ -1183,7 +1287,7 @@ return item; } -pst_num_array * _pst_parse_block(pst_file *pf, u_int32_t block_id, pst_index2_ll *i2_head) { +pst_num_array * _pst_parse_block(pst_file *pf, u_int32_t block_id, pst_index2_ll *i2_head) { // {{{ unsigned char *buf = NULL; pst_num_array *na_ptr = NULL, *na_head = NULL; pst_block_offset block_offset; @@ -1194,6 +1298,7 @@ size_t read_size=0; pst_x_attrib_ll *mapptr; + struct { u_int16_t type; u_int16_t ref_type; @@ -1238,13 +1343,13 @@ // DEBUG_EMAIL(("About to read %i bytes from offset %#x\n", block->size, block->offset)); - if ((read_size = _pst_ff_getIDblock_dec(pf, block_id, &buf)) == 0) { - // if (_pst_read_block_size(pf, block->offset, block->size, &buf, PST_ENC, 0) < block->size) { + if ((read_size = _pst_ff_getIDblock_dec(pf, block_id, &buf)) == 0) { // {{{ error + // if (_pst_read_block_size(pf, block->offset, block->size, &buf, PST_ENC, 0) < block->size) WARN(("Error reading block id %#x\n", block_id)); if (buf) free (buf); DEBUG_RET(); return NULL; - } + } // }}} DEBUG_EMAIL(("pointer to buf is %p\n", buf)); memcpy(&block_hdr, &(buf[0]), sizeof(block_hdr)); @@ -1255,7 +1360,7 @@ ind_ptr = block_hdr.index_offset; - if (block_hdr.type == 0xBCEC) { //type 1 + if (block_hdr.type == 0xBCEC) { // {{{ type 1, populate block_offset block_type = 1; _pst_getBlockOffset(buf, ind_ptr, block_hdr.offset, &block_offset); @@ -1281,7 +1386,8 @@ num_list = (to_ptr - fr_ptr)/sizeof(table_rec); num_recs = 1; // only going to one object in these blocks rec_size = 0; // doesn't matter cause there is only one object - } else if (block_hdr.type == 0x7CEC) { //type 2 + } // }}} + else if (block_hdr.type == 0x7CEC) { // {{{ type 2, populate block_offset from seven_c_blk block_type = 2; _pst_getBlockOffset(buf, ind_ptr, block_hdr.offset, &block_offset); @@ -1340,16 +1446,17 @@ _pst_getBlockOffset(buf, ind_ptr, seven_c_blk.ind2_offset, &block_offset); ind2_ptr = block_offset.from; - } else { + } // }}} + else { // {{{ error WARN(("ERROR: Unknown block constant - %#X for id %#x\n", block_hdr.type, block_id)); DEBUG_HEXDUMPC(buf, read_size,0x10); if (buf) free(buf); DEBUG_RET(); return NULL; - } + } // }}} DEBUG_EMAIL(("Mallocing number of items %i\n", num_recs)); - while (count_rec < num_recs) { + while (count_rec < num_recs) { // {{{ na_ptr = (pst_num_array*) xmalloc(sizeof(pst_num_array)); memset(na_ptr, 0, sizeof(pst_num_array)); if (na_head == NULL) { @@ -1371,13 +1478,14 @@ fr_ptr = list_start; // init fr_ptr to the start of the list. cur_list = 0; stop = 0; - while (!stop && cur_list < num_list) { //we will increase fr_ptr as we progress through index - if (block_type == 1) { + while (!stop && cur_list < num_list) { //{{{ we will increase fr_ptr as we progress through index + if (block_type == 1) { // {{{ memcpy(&table_rec, &(buf[fr_ptr]), sizeof(table_rec)); LE16_CPU(table_rec.type); LE16_CPU(table_rec.ref_type); fr_ptr += sizeof(table_rec); - } else if (block_type == 2) { + } // }}} + else if (block_type == 2) { // {{{ // we will copy the table2_rec values into a table_rec record so that we can keep the rest of the code memcpy(&table2_rec, &(buf[fr_ptr]), sizeof(table2_rec)); LE16_CPU(table2_rec.ref_type); @@ -1398,12 +1506,13 @@ } fr_ptr += sizeof(table2_rec); - } else { + } // }}} + else { // {{{ ERROR WARN(("Missing code for block_type %i\n", block_type)); if (buf) free(buf); DEBUG_RET(); return NULL; - } + } // }}} cur_list++; // get ready to read next bit from list DEBUG_EMAIL(("reading block %i (type=%#x, ref_type=%#x, value=%#x)\n", x, table_rec.type, table_rec.ref_type, table_rec.value)); @@ -1466,10 +1575,10 @@ || table_rec.ref_type == 0x001E || table_rec.ref_type == 0x0102 || table_rec.ref_type == 0x0040 || table_rec.ref_type == 0x101E || table_rec.ref_type == 0x0048 || table_rec.ref_type == 0x1102 - || table_rec.ref_type == 0x1014) { + || table_rec.ref_type == 0x1014 || table_rec.ref_type == 0x001F ) { //contains index_ref to data LE32_CPU(table_rec.value); - if ((table_rec.value & 0x0000000F) == 0xF) { + if ((table_rec.value & 0x0000000F) == 0xF) { // {{{ // if value ends in 'F' then this should be an id2 value DEBUG_EMAIL(("Found id2 [%#x] value. Will follow it\n", table_rec.value)); @@ -1483,7 +1592,8 @@ } DEBUG_EMAIL(("Read %i bytes to a buffer at %p\n", na_ptr->items[x]->size, na_ptr->items[x]->data)); - } else if (table_rec.value != 0) { + } // }}} + else if (table_rec.value != 0) { if ((table_rec.value >> 4)+ind_ptr > read_size) { // check that we will not be outside the buffer we have read DEBUG_WARN(("table_rec.value [%#x] is outside of block [%#x]\n", @@ -1507,10 +1617,30 @@ } // plus one for good luck (and strings) we will null terminate all reads - na_ptr->items[x]->data = (char*) xmalloc(size+1); - memcpy(na_ptr->items[x]->data, &(buf[t_ptr]), size); - na_ptr->items[x]->data[size] = '\0'; // null terminate buffer + if( 0x001F == table_rec.ref_type ) { + VBUF_STATIC( strbuf, 1024 ); + VBUF_STATIC( unibuf, 1024 ); + //need UTF-16 zero-termination + vbset( strbuf, &(buf[t_ptr]), size ); + vbappend( strbuf, "\0\0", 2 ); + DEBUG_INDEX(("Iconv in: ")); + DEBUG_HEXDUMPC( strbuf->b, strbuf->dlen, 0x10 ); + vb_utf16to8( unibuf, strbuf->b, strbuf->dlen ); + na_ptr->items[x]->data = (char*) xmalloc(unibuf->dlen); + memcpy(na_ptr->items[x]->data, unibuf->b, unibuf->dlen); + na_ptr->items[x]->size = unibuf->dlen; + DEBUG_INDEX(("Iconv out: ")); + DEBUG_HEXDUMPC(na_ptr->items[x]->data, na_ptr->items[x]->size, 0x10 ); + } + else { + na_ptr->items[x]->data = (char*) xmalloc(size+1); + memcpy(na_ptr->items[x]->data, &(buf[t_ptr]), size); + na_ptr->items[x]->data[size] = '\0'; // null terminate buffer + } + DEBUG_INDEX(("Item Puke: type: %x, ref_type: %x, value: %x\n", + table_rec.type, table_rec.ref_type, table_rec.value )); + DEBUG_HEXDUMPC(na_ptr->items[x]->data, size, 0x10 ); if (table_rec.ref_type == 0xd) { // there is still more to do for the type of 0xD type_d_rec = (struct _type_d_rec*) na_ptr->items[x]->data; @@ -1526,7 +1656,6 @@ } DEBUG_EMAIL(("Read %i bytes into a buffer at %p\n", na_ptr->items[x]->size, na_ptr->items[x]->data)); - // } } } else { DEBUG_EMAIL(("Ignoring 0 value in offset\n")); @@ -1548,18 +1677,18 @@ return NULL; } x++; - } + } // }}} DEBUG_EMAIL(("increasing ind2_ptr by %i [%#x] bytes. Was %#x, Now %#x\n", rec_size, rec_size, ind2_ptr, ind2_ptr+rec_size)); ind2_ptr += rec_size; count_rec++; - } + } // }}} if (buf != NULL) free(buf); DEBUG_RET(); return na_head; -} +} // }}} // check if item->email is NULL, and init if so #define MALLOC_EMAIL(x) { if (x->email == NULL) { x->email = (pst_item_email*) xmalloc(sizeof(pst_item_email)); memset (x->email, 0, sizeof(pst_item_email));} } @@ -3384,7 +3513,7 @@ } if (_pst_read_block_size(pf, list->offset, list->size, &buf, PST_NO_ENC,0) < list->size) { //an error occured in block read - WARN(("block read error occured. offset = %#x, size = %#x\n", list->offset, list->size)); + WARN(("block read error occured. offset = %#llx, size = %#llx\n", list->offset, list->size)); DEBUG_RET(); return NULL; } @@ -3394,7 +3523,7 @@ LE16_CPU(block_head.count); if (block_head.type != 0x0002) { // some sort of constant? - WARN(("Unknown constant [%#x] at start of id2 values [offset %#x].\n", block_head.type, list->offset)); + WARN(("Unknown constant [%#x] at start of id2 values [offset %#llx].\n", block_head.type, list->offset)); DEBUG_RET(); return NULL; } @@ -3678,7 +3807,7 @@ return 0; } -pst_index_ll * _pst_getID(pst_file* pf, u_int32_t id) { +pst_index_ll * _pst_getID(pst_file* pf, u_int64_t id) { // static pst_index_ll *old_val = NULL; //this should make it quicker pst_index_ll *ptr = NULL; DEBUG_ENT("_pst_getID"); @@ -3693,9 +3822,10 @@ // Dave: I don't think I should do this. next bit. I really think it doesn't work // it isn't based on sound principles either. // update: seems that the last two sig bits are flags. u tell me! - id &= 0xFFFFFFFE; // remove least sig. bit. seems that it might work if I do this + //id &= 0xFFFFFFFE; // remove least sig. bit. seems that it might work if I do this + id -= (id & 1 ); - DEBUG_INDEX(("Trying to find %#x\n", id)); + DEBUG_INDEX(("Trying to find %#llx\n", id)); if (ptr == NULL) ptr = pf->i_head; @@ -3927,6 +4057,9 @@ return -1; } + DEBUG_INDEX(("_pst_decrypt()")); + DEBUG_HEXDUMPC(buf, size, 0x10 ); + if (type == PST_COMP_ENCRYPT) { x = 0; while (x < size) { @@ -3935,6 +4068,9 @@ buf[x] = comp_enc[y]; // transpose from encrypt array x++; } + + DEBUG_INDEX(("_pst_decrypt() result")); + DEBUG_HEXDUMPC(buf, size, 0x10 ); } else { WARN(("Unknown encryption: %i. Cannot decrypt\n", type)); DEBUG_RET(); @@ -3944,7 +4080,23 @@ return 0; } -int32_t _pst_getAtPos(FILE *fp, int32_t pos, void* buf, u_int32_t size) { +int64_t _pst_getIntAtPos(FILE *fp, off_t pos ) { + int64_t buf64; + int32_t buf32; + + if(do_read64) { + _pst_getAtPos(fp, pos, &buf64, sizeof( buf64 ) ); + LE64_CPU(buf64); + return buf64; + } + else { + _pst_getAtPos(fp, pos, &buf32, sizeof( buf32 ) ); + LE32_CPU(buf32); + return buf32; + } +} + +int32_t _pst_getAtPos(FILE *fp, off_t pos, void* buf, u_int32_t size) { DEBUG_ENT("_pst_getAtPos"); if (fseek(fp, pos, SEEK_SET) == -1) { DEBUG_RET(); diff -Naur ../orig/libpst-0.5.1/libpst.h libpst64-060926/libpst.h --- ../orig/libpst-0.5.1/libpst.h 2004-11-17 07:48:03.000000000 -0700 +++ libpst64-060926/libpst.h 2006-09-26 14:09:55.000000000 -0600 @@ -117,6 +117,8 @@ #define PST_APP_LABEL_ANNIVERSARY 9 // Anniversary #define PST_APP_LABEL_PHONE_CALL 10// Phone Call +extern int do_read64; + typedef struct _pst_misc_6_struct { int32_t i1; int32_t i2; @@ -132,26 +134,72 @@ int32_t id; } pst_entryid; -typedef struct _pst_desc_struct { +typedef struct _pst_desc_struct32 { u_int32_t d_id; u_int32_t desc_id; u_int32_t list_id; u_int32_t parent_id; -} pst_desc; +} pst_desc32; -typedef struct _pst_index_struct{ +typedef struct _pst_desc_structn { + u_int64_t d_id; + u_int64_t desc_id; + u_int64_t list_id; +// u_int64_t parent_id; + u_int32_t parent_id; + u_int32_t u1; +} pst_descn; + +typedef struct _pst_index_struct32{ u_int32_t id; int32_t offset; u_int16_t size; int16_t u1; +} pst_index32; + +/* +typedef struct _pst_index_struct64{ + u_int64_t id; + int64_t offset; + u_int16_t size; + int16_t u1; +} pst_index64; +*/ + +typedef struct _pst_index_struct{ + u_int64_t id; + int64_t offset; + u_int16_t size; + int16_t u0; + int32_t u1; } pst_index; -typedef struct _pst_index_tree { +/* +typedef union _pst_index_struct { + pst_index32 i32; + pst_index64 i64; +} pst_index; + +#define INDEX_ID(x) ((do_read64)?x.i64.id:x.i32.id) +#define INDEX_OFFSET(x) ((do_read64)?x.i64.offset:x.i32.offset) +#define INDEX_SIZE(x) ((do_read64)?x.i64.size:x.i32.size) +#define INDEX_U1(x) ((do_read64)?x.i64.u1:x.i32.u1) +*/ + +typedef struct _pst_index_tree32 { u_int32_t id; int32_t offset; - size_t size; + int32_t size; int32_t u1; struct _pst_index_tree * next; +} pst_index_ll32; + +typedef struct _pst_index_tree { + u_int64_t id; + int64_t offset; + int64_t size; + int64_t u1; + struct _pst_index_tree * next; } pst_index_ll; typedef struct _pst_index2_tree { @@ -421,6 +469,10 @@ int32_t index1_count; int32_t index2; int32_t index2_count; + int64_t index1_64; + int64_t index1_count_64; + int64_t index2_64; + int64_t index2_count_64; FILE * fp; size_t size; unsigned char index1_depth; @@ -460,6 +512,7 @@ }; // prototypes +void set_read64(); int32_t pst_open(pst_file *pf, char *name, char *mode); int32_t pst_close(pst_file *pf); pst_desc_ll * pst_getTopOfFolders(pst_file *pf, pst_item *root); @@ -470,8 +523,8 @@ pst_desc_ll* pst_getNextDptr(pst_desc_ll* d); int32_t pst_load_extended_attributes(pst_file *pf); -int32_t _pst_build_id_ptr(pst_file *pf, int32_t offset, int32_t depth, int32_t start_val, int32_t end_val); -int32_t _pst_build_desc_ptr (pst_file *pf, int32_t offset, int32_t depth, int32_t *high_id, +int32_t _pst_build_id_ptr(pst_file *pf, off_t offset, int32_t depth, int32_t start_val, int32_t end_val); +int32_t _pst_build_desc_ptr (pst_file *pf, off_t offset, int32_t depth, int32_t *high_id, int32_t start_id, int32_t end_val); pst_item* _pst_getItem(pst_file *pf, pst_desc_ll *d_ptr); void * _pst_parse_item (pst_file *pf, pst_desc_ll *d_ptr); @@ -485,13 +538,14 @@ int32_t _pst_free_xattrib(pst_x_attrib_ll *x); int32_t _pst_getBlockOffset(char *buf, int32_t i_offset, int32_t offset, pst_block_offset *p); pst_index2_ll * _pst_build_id2(pst_file *pf, pst_index_ll* list, pst_index2_ll* head_ptr); -pst_index_ll * _pst_getID(pst_file* pf, u_int32_t id); +pst_index_ll * _pst_getID(pst_file* pf, u_int64_t id); pst_index_ll * _pst_getID2(pst_index2_ll * ptr, u_int32_t id); pst_desc_ll * _pst_getDptr(pst_file *pf, u_int32_t id); size_t _pst_read_block_size(pst_file *pf, int32_t offset, size_t size, char ** buf, int32_t do_enc, unsigned char is_index); int32_t _pst_decrypt(unsigned char *buf, size_t size, int32_t type); -int32_t _pst_getAtPos(FILE *fp, int32_t pos, void* buf, u_int32_t size); +int64_t _pst_getIntAtPos(FILE *fp, off_t pos); +int32_t _pst_getAtPos(FILE *fp, off_t pos, void* buf, u_int32_t size); int32_t _pst_get (FILE *fp, void *buf, u_int32_t size); size_t _pst_ff_getIDblock_dec(pst_file *pf, u_int32_t id, unsigned char **b); size_t _pst_ff_getIDblock(pst_file *pf, u_int32_t id, unsigned char** b); diff -Naur ../orig/libpst-0.5.1/libstrfunc.c libpst64-060926/libstrfunc.c --- ../orig/libpst-0.5.1/libstrfunc.c 2004-11-17 07:48:03.000000000 -0700 +++ libpst64-060926/libstrfunc.c 2006-09-26 14:09:55.000000000 -0600 @@ -67,3 +67,30 @@ return _sf_b64_buf=output; }; +void hexdump(char *hbuf, int start, int stop, int ascii) /* {{{ HexDump all or a part of some buffer */ +{ + char c; + int diff,i; + + while (start < stop ) { + diff = stop - start; + if (diff > 16) diff = 16; + + fprintf(stderr, ":%08X ",start); + + for (i = 0; i < diff; i++) { + if( 8 == i ) fprintf( stderr, " " ); + fprintf(stderr, "%02X ",(unsigned char)*(hbuf+start+i)); + } + if (ascii) { + for (i = diff; i < 16; i++) fprintf(stderr, " "); + for (i = 0; i < diff; i++) { + c = *(hbuf+start+i); + fprintf(stderr, "%c", isprint(c) ? c : '.'); + } + } + fprintf(stderr, "\n"); + start += 16; + } +} +// }}} diff -Naur ../orig/libpst-0.5.1/libstrfunc.h libpst64-060926/libstrfunc.h --- ../orig/libpst-0.5.1/libstrfunc.h 2004-11-17 07:48:03.000000000 -0700 +++ libpst64-060926/libstrfunc.h 2006-09-26 14:09:55.000000000 -0600 @@ -1,2 +1,4 @@ char * base64_encode(void *data, size_t size); + +void hexdump(char *hbuf, int start, int stop, int ascii); diff -Naur ../orig/libpst-0.5.1/lspst.c libpst64-060926/lspst.c --- ../orig/libpst-0.5.1/lspst.c 2004-11-17 07:48:03.000000000 -0700 +++ libpst64-060926/lspst.c 2006-09-26 14:09:55.000000000 -0600 @@ -37,6 +37,7 @@ char *rfc2426_escape(char *str); char *rfc2445_datetime_format(FILETIME *ft); // }}}1 +#undef DEBUG_MAIN #define DEBUG_MAIN(x) debug_print x; // int main(int argc, char** argv) {{{1 int main(int argc, char** argv) { diff -Naur ../orig/libpst-0.5.1/Makefile libpst64-060926/Makefile --- ../orig/libpst-0.5.1/Makefile 2004-11-17 09:16:02.000000000 -0700 +++ libpst64-060926/Makefile 2006-09-26 14:09:55.000000000 -0600 @@ -1,9 +1,12 @@ #!/usr/bin/make -f -CFLAGS ?= -g -Wall +CFLAGS ?= -g -Wall PREFIX ?= /usr/local INSTALL ?= install +# You might need this +#LDLIBS ?= -liconv + #---------------- Do not modify below this point ------------------ INSTALL_DIR := $(INSTALL) -p -d -o root -g root -m 0755 @@ -39,9 +42,11 @@ readpstlog.o: XGetopt.h define.h testdebug.o: define.h timeconv.o: timeconv.h common.h +vbuf.o: vbuf.h +generic.o: generic.h -readpst: readpst.o libpst.o timeconv.o libstrfunc.o debug.o lzfu.o -lspst: debug.o libpst.o libstrfunc.o lspst.o timeconv.o +readpst: readpst.o libpst.o timeconv.o libstrfunc.o debug.o lzfu.o vbuf.o generic.o +lspst: debug.o libpst.o libstrfunc.o lspst.o timeconv.o vbuf.o generic.o getidblock: getidblock.o libpst.o debug.o libstrfunc.o testdebug: testdebug.o debug.o readpstlog: readpstlog.o debug.o diff -Naur ../orig/libpst-0.5.1/readpst.c libpst64-060926/readpst.c --- ../orig/libpst-0.5.1/readpst.c 2004-11-17 07:48:03.000000000 -0700 +++ libpst64-060926/readpst.c 2006-09-26 14:09:55.000000000 -0600 @@ -13,6 +13,8 @@ #include <limits.h> #include <errno.h> +#include "vbuf.h" + #ifndef _WIN32 # include <unistd.h> # include <sys/stat.h> //mkdir @@ -70,19 +72,19 @@ // Function Declarations {{{1 void write_email_body(FILE *f, char *body); char *removeCR (char *c); -int32_t usage(); -int32_t version(); +int usage(); +int version(); char *mk_kmail_dir(char*); -int32_t close_kmail_dir(); +int close_kmail_dir(); char *mk_recurse_dir(char*); -int32_t close_recurse_dir(); +int close_recurse_dir(); char *mk_seperate_dir(char *dir, int overwrite); -int32_t close_seperate_dir(); -int32_t mk_seperate_file(struct file_ll *f); +int close_seperate_dir(); +int mk_seperate_file(struct file_ll *f); char *my_stristr(char *haystack, char *needle); char *check_filename(char *fname); char *rfc2426_escape(char *str); -int32_t chr_count(char *str, char x); +int chr_count(char *str, char x); char *rfc2425_datetime_format(FILETIME *ft); char *rfc2445_datetime_format(FILETIME *ft); char *skip_header_prologue(char *headers); @@ -107,6 +109,8 @@ // saved as email_no-filename (e.g. 1-samplefile.doc or 000001-Attachment2.zip) #define MODE_SEPERATE 3 +// Decrypt the whole file (even the parts that aren't encrypted) and ralph it to stdout +#define MODE_DECSPEW 4 // Output Normal just prints the standard information about what is going on #define OUTPUT_NORMAL 0 @@ -153,7 +157,7 @@ prog_name = argv[0]; // }}}2 - while ((c = getopt(argc, argv, "d:hko:qrSVwc:"))!= -1) { + while ((c = getopt(argc, argv, "C6d:hko:qrSVwc:"))!= -1) { switch (c) { case 'c': if (optarg!=NULL && optarg[0]=='v') @@ -168,6 +172,9 @@ case 'd': d_log = optarg; break; + case '6': + set_read64(); + break; case 'h': usage(); exit(0); @@ -191,6 +198,9 @@ case 'S': mode = MODE_SEPERATE; break; + case 'C': + mode = MODE_DECSPEW; + break; case 'w': overwrite = 1; break; @@ -201,6 +211,8 @@ } } + unicode_init(); + #ifdef DEBUG_ALL // initialize log file if (d_log == NULL) @@ -218,6 +230,29 @@ exit(2); } + + if ( mode == MODE_DECSPEW ) { + FILE *fp; + char buf[1024]; + int l=0; + if( NULL == ( fp = fopen(fname, "rb" ) ) ) { + fprintf(stderr, "Couldn't open file %s\n", fname ); + return 1; + } + + while( 0 != ( l = fread( buf, 1, 1024, fp ) ) ) { + if( 0 != _pst_decrypt( buf, l, PST_COMP_ENCRYPT ) ) + fprintf(stderr, "_pst_decrypt() failed (I'll try to continue)\n"); + + if( l != fwrite( buf, 1, l, stdout ) ) { + fprintf(stderr, "Couldn't output to stdout?\n"); + return 1; + } + } + + return 0; + } + if (output_mode != OUTPUT_QUIET) printf("Opening PST file and indexes...\n"); DEBUG_MAIN(("main: Opening PST file '%s'\n", fname)); @@ -1139,6 +1174,8 @@ printf("\t-S\t- Seperate. Write emails in the seperate format\n"); printf("\t-V\t- Version. Display program version\n"); printf("\t-w\t- Overwrite any output mbox files\n"); + printf("\t-6\t- Attempt to read 64-bit Outlook file (Outlook 2003)\n"); + printf("\t-C\t- Decrypt the entire file and output on stdout (not typically useful)\n"); DEBUG_RET(); return 0; } diff -Naur ../orig/libpst-0.5.1/vbuf.c libpst64-060926/vbuf.c --- ../orig/libpst-0.5.1/vbuf.c 1969-12-31 17:00:00.000000000 -0700 +++ libpst64-060926/vbuf.c 2006-09-26 14:09:55.000000000 -0600 @@ -0,0 +1,932 @@ +// {{{ includes + +#include <ctype.h> +//#include "defines.h" +#include <errno.h> +#include <iconv.h> +#include <malloc.h> +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "vbuf.h" +#include "generic.h" + +#ifdef WITH_DMALLOC +#include <dmalloc.h> +#endif + +// }}} + +int skip_nl( char *s ) // {{{ returns the width of the newline at s[0] +{ + if( s[0] == '\n' ) return 1; + if( s[0] == '\r' && s[1] == '\n' ) return 2; + if( s[0] == '\0' ) return 0; + return -1; +} // }}} +int find_nl( vstr *vs ) // {{{ find newline of type type in b +{ + char *nextr, *nextn; + + nextr = memchr( vs->b, '\r', vs->dlen ); + nextn = memchr( vs->b, '\n', vs->dlen ); + + //case 1: UNIX, we find \n first + if( nextn && (nextr == NULL || nextr > nextn ) ) { + return nextn - vs->b; + } + + //case 2: DOS, we find \r\n + if( NULL != nextr && NULL != nextn && 1 == (char*)nextn - (char*)nextr ) { + return nextr - vs->b; + } + + //case 3: we find nothing + + return -1; +} // }}} + +// {{{ UTF8 <-> UTF16 <-> ISO8859 Character set conversion functions and (ack) their globals + +//TODO: the following should not be +char *wwbuf=NULL; +size_t nwwbuf=0; +static int unicode_up=0; +iconv_t i16to8, i8to16, i8859_1to8, i8toi8859_1; + +void unicode_init() // {{{ +{ + char *wipe = ""; + char dump[4]; + + if( unicode_up ) unicode_close(); + + if( (iconv_t)-1 == (i16to8 = iconv_open( "UTF-8", "UTF-16" ) ) ) { + fprintf(stderr, "doexport(): Couldn't open iconv descriptor for UTF-16 to UTF-8.\n"); + exit( 1 ); + } + + if( (iconv_t)-1 == (i8to16 = iconv_open( "UTF-16", "UTF-8" ) ) ) { + fprintf(stderr, "doexport(): Couldn't open iconv descriptor for UTF-8 to UTF-16.\n"); + exit( 2 ); + } + + //iconv will prefix output with an FF FE (utf-16 start seq), the following dumps that. + memset( dump, 'x', 4 ); + ASSERT( 0 == utf8to16( wipe, 1, dump, 4 ), "unicode_init(): attempt to dump FF FE failed." ); + + if( (iconv_t)-1 == (i8859_1to8 = iconv_open( "UTF-8", "ISO_8859-1" ) ) ) { + fprintf(stderr, "doexport(): Couldn't open iconv descriptor for ASCII to UTF-8.\n"); + exit( 1 ); + } + + + if( (iconv_t)-1 == (i8toi8859_1 = iconv_open( "ISO_8859-1", "UTF-8" ) ) ) { + fprintf(stderr, "doexport(): Couldn't open iconv descriptor for UTF-8 to ASCII.\n"); + exit( 1 ); + } + + unicode_up = 1; +} +// }}} +void unicode_close() // {{{ +{ + unicode_up = 0; + iconv_close( i8to16 ); + iconv_close( i16to8 ); + iconv_close( i8859_1to8 ); + iconv_close( i8toi8859_1 ); +} +// }}} + +//int utf16_write( FILE* stream, const void *buf, size_t count ) // {{{ write utf-8 or iso_8869-1 to stream after converting it to utf-16 +//{ +// +// //TODO: if anything big comes through here we are sunk, should do it +// //bit-by-bit, not one-big-gulp +// +// size_t inbytesleft, outbytesleft; +// char *inbuf, *outbuf; +// size_t icresult; +// size_t rl; +// +// //do we have enough buffer space? +// if( !wwbuf || nwwbuf < (count * 2 + 2) ) { +// wwbuf = F_REALLOC( wwbuf, count * 2 +2 ); +// +// nwwbuf = count * 2 + 2; +// } +// +// inbytesleft = count; outbytesleft = nwwbuf; +// inbuf = (char*)buf; outbuf = wwbuf; +// +//// fprintf(stderr, "X%s, %dX", (char*)buf, strlen( buf )); +//// fflush(stderr); +// +// if( (rl = strlen( buf ) + 1) != count ) { +// fprintf(stderr, "utf16_write(): reported buffer size (%d) does not match string length (%d)\n", +// count, +// rl); +// +// //hexdump( (char*)buf, 0, count, 1 ); +// +// raise( SIGSEGV ); +// inbytesleft = rl; +// } +// +//// fprintf(stderr, " attempting to convert:\n"); +//// hexdump( (char*)inbuf, 0, count, 1 ); +// +// icresult = iconv( i8to16, &inbuf, &inbytesleft, &outbuf, &outbytesleft ); +// +//// fprintf(stderr, " converted:\n"); +//// hexdump( (char*)buf, 0, count, 1 ); +// +//// fprintf(stderr, " to:\n"); +//// hexdump( (char*)wwbuf, 0, nwwbuf, 1 ); +// +// if( (size_t)-1 == icresult ) { +// fprintf(stderr, "utf16_write(): iconv failure(%d): %s\n", errno, strerror( errno ) ); +// fprintf(stderr, " attempted to convert:\n"); +// hexdump( (char*)inbuf, 0, count, 1 ); +// +// fprintf(stderr, " result:\n"); +// hexdump( (char*)outbuf, 0, count, 1 ); +// +// fprintf(stderr, "I'm going to segfault now.\n"); +// raise( SIGSEGV ); +// exit(1); +// } +// +// if( inbytesleft > 0 ) { +// fprintf(stderr, "utf16_write(): iconv returned a short count.\n"); +// exit(1); +// } +// +// return fwrite( wwbuf, nwwbuf - outbytesleft - 2, 1, stream ); +//} +// }}} + +//char *utf16buf = NULL; +//int utf16buf_len = 0; +// +//int utf16_fprintf( FILE* stream, const char *fmt, ... ) // {{{ +//{ +// int result=0; +// va_list ap; +// +// if( utf16buf == NULL ) { +// utf16buf = (char*)F_MALLOC( SZ_MAX + 1 ); +// +// utf16buf_len = SZ_MAX + 1; +// } +// +// va_start( ap, fmt ); +// +// result = vsnprintf( utf16buf, utf16buf_len, fmt, ap ); +// +// if( result + 1 > utf16buf_len ) { //didn't have space, realloc() and try again +// fprintf(stderr, "utf16_fprintf(): buffer too small (%d), F_MALLOC(%d)\n", utf16buf_len, result); +// free( utf16buf ); +// utf16buf_len = result + 1; +// utf16buf = (char*)F_MALLOC( utf16buf_len ); +// +// result = vsnprintf( utf16buf, utf16buf_len, fmt, ap ); +// } +// +// +// //didn't have space...again...something weird is going on... +// ASSERT( result + 1 <= utf16buf_len, "utf16_fprintf(): Unpossible error!\n"); +// +// if( 1 != utf16_write( stream, utf16buf, result + 1 ) ) +// DIE( "Write error? -> %s or %s\n", strerror( errno ), uerr_str( uerr_get() ) ); +// +// return result; +//} +//// }}} +//int utf16to8( char *inbuf_o, char *outbuf_o, int length ) // {{{ +//{ +// int inbytesleft = length; +// int outbytesleft = length; +// char *inbuf = inbuf_o; +// char *outbuf = outbuf_o; +// int rlen = -1, tlen; +// int icresult = -1; +// +// int i, strlen=-1; +// +// DEBUG( +// fprintf(stderr, " utf16to8(): attempting to convert:\n"); +// //hexdump( (char*)inbuf_o, 0, length, 1 ); +// fflush(stderr); +// ); +// +// for( i=0; i<length ; i+=2 ) { +// if( inbuf_o[i] == 0 && inbuf_o[i + 1] == 0 ) { +// //fprintf(stderr, "End of string found at: %d\n", i ); +// strlen = i; +// } +// } +// +// //hexdump( (char*)inbuf_o, 0, strlen, 1 ); +// +// if( -1 == strlen ) WARN("String is not zero-terminated."); +// +// //iconv does not like it when the inbytesleft > actual string length +// //enum: zero terminated, length valid +// // zero terminated, length short //we won't go beyond length ever, so this is same as NZT case +// // zero terminated, length long +// // not zero terminated +// // TODO: MEMORY BUG HERE! +// for( tlen = 0; tlen <= inbytesleft - 2; tlen+=2 ) { +// if( inbuf_o[tlen] == 0 && inbuf_o[tlen+1] == 0 ){ +// rlen = tlen + 2; +// tlen = rlen; +// break; +// } +// if( tlen == inbytesleft )fprintf(stderr, "Space allocated for string > actual string length. Go windows!\n"); +// } +// +// if( rlen >= 0 ) +// icresult = iconv( i16to8, &inbuf, &rlen, &outbuf, &outbytesleft ); +// +// if( icresult == (size_t)-1 ) { +// fprintf(stderr, "utf16to8(): iconv failure(%d): %s\n", errno, strerror( errno ) ); +// fprintf(stderr, " attempted to convert:\n"); +// hexdump( (char*)inbuf_o, 0, length, 1 ); +// fprintf(stderr, " result:\n"); +// hexdump( (char*)outbuf_o, 0, length, 1 ); +// fprintf(stderr, " MyDirtyOut:\n"); +// for( i=0; i<length; i++) { +// if( inbuf_o[i] != '\0' ) fprintf(stderr, "%c", inbuf_o[i] ); +// } +// +// fprintf( stderr, "\n" ); +// raise( SIGSEGV ); +// exit(1); +// } +// +// DEBUG( +// fprintf(stderr, " result:\n"); +// hexdump( (char*)outbuf_o, 0, length, 1 ); +// ) +// +// //fprintf(stderr, "utf16to8() returning %s\n", outbuf ); +// +// return icresult; +//} +//// }}} +int utf16_is_terminated( char *str, int length ) // {{{ +{ + VSTR_STATIC( errbuf, 100 ); + int len = -1; + int i; + for( i=0; i<length ; i+=2 ) { + if( str[i] == 0 && str[i + 1] == 0 ) { + //fprintf(stderr, "End of string found at: %d\n", i ); + len = i; + } + } + + //hexdump( (char*)inbuf_o, 0, len, 1 ); + + if( -1 == len ) { + vshexdump( errbuf, str, 0, length, 1 ); + WARN("String is not zero terminated (probably broken data from registry) %s.", errbuf->b); + } + + return (-1 == len )?0:1; +} // }}} +int vb_utf16to8( vbuf *dest, char *buf, int len ) // {{{ +{ + int inbytesleft = len; + char *inbuf = buf; + //int rlen = -1, tlen; + int icresult = -1; + VBUF_STATIC( dumpster, 100 ); + + //int i; //, strlen=-1; + int outbytesleft; + char *outbuf; + + ASSERT( unicode_up, "vb_utf16to8() called before unicode started." ); + + if( 2 > dest->blen ) vbresize( dest, 2 ); + dest->dlen = 0; + + //Bad Things can happen if a non-zero-terminated utf16 string comes through here + if( !utf16_is_terminated( buf, len ) ) return -1; + + do { + outbytesleft = dest->blen - dest->dlen; + outbuf = dest->b + dest->dlen; + icresult = iconv( i16to8, &inbuf, &inbytesleft, &outbuf, &outbytesleft ); + dest->dlen = outbuf - dest->b; + vbgrow( dest, inbytesleft); + } while( (size_t)-1 == icresult && E2BIG == errno ); + + if( 0 != vb_utf8to16T( dumpster, dest->b, dest->dlen ) ) + DIE("Reverse conversion failed."); + + if( icresult == (size_t)-1 ) { + //TODO: error + //ERR_UNIX( errno, "vb_utf16to8():iconv failure: %s", strerror( errno ) ); + unicode_init(); + return -1; + /* + fprintf(stderr, " attempted to convert:\n"); + hexdump( (char*)cin, 0, inlen, 1 ); + fprintf(stderr, " result:\n"); + hexdump( (char*)bout->b, 0, bout->dlen, 1 ); + fprintf(stderr, " MyDirtyOut:\n"); + for( i=0; i<inlen; i++) { + if( inbuf[i] != '\0' ) fprintf(stderr, "%c", inbuf[i] ); + } + + fprintf( stderr, "\n" ); + raise( SIGSEGV ); + exit(1); + */ + } + + if( icresult ) { + //ERR_UNIX( EILSEQ, "Uhhhh...vb_utf16to8() returning icresult == %d", icresult ); + return -1; + } + return icresult; +} +// }}} + +int utf8to16( char *inbuf_o, int iblen, char *outbuf_o, int oblen) // {{{ iblen, oblen: bytes including \0 +{ + //TODO: this is *only* used to dump the utf16 preamble now... + //TODO: This (and 8to16) are the most horrible things I have ever seen... + int inbytesleft; + int outbytesleft = oblen; + char *inbuf = inbuf_o; + char *outbuf = outbuf_o; + //int rlen = -1, tlen; + int icresult = -1; + + char *stend; + + //int i; //, strlen=-1; + + DEBUG( + fprintf(stderr, " utf8to16(): attempting to convert:\n"); + //hexdump( (char*)inbuf_o, 0, length, 1 ); + fflush(stderr); + ); + + stend = memchr( inbuf_o, '\0', iblen ); + ASSERT( NULL != stend, "utf8to16(): in string not zero terminated." ); + + inbytesleft = ( stend - inbuf_o + 1 < iblen )? stend - inbuf_o + 1: iblen; + + //iconv does not like it when the inbytesleft > actual string length + //enum: zero terminated, length valid + // zero terminated, length short //we won't go beyond length ever, so this is same as NZT case + // zero terminated, length long + // not zero terminated + // TODO: MEMORY BUG HERE! + // + /* + for( tlen = 0; tlen <= inbytesleft - 2; tlen+=2 ) { + if( inbuf_o[tlen] == 0 && inbuf_o[tlen+1] == 0 ){ + rlen = tlen + 2; + tlen = rlen; + break; + } + if( tlen == inbytesleft )fprintf(stderr, "Space allocated for string > actual string length. Go windows!\n"); + } + */ + + //if( rlen >= 0 ) + icresult = iconv( i8to16, &inbuf, &inbytesleft, &outbuf, &outbytesleft ); + + if( icresult == (size_t)-1 ) { + DIE("iconv failure(%d): %s\n", errno, strerror( errno ) ); + //fprintf(stderr, " attempted to convert:\n"); + //hexdump( (char*)inbuf_o, 0, iblen, 1 ); + //fprintf(stderr, " result:\n"); + //hexdump( (char*)outbuf_o, 0, oblen, 1 ); + //fprintf(stderr, " MyDirtyOut:\n"); +// for( i=0; i<iblen; i++) { +// if( inbuf_o[i] != '\0' ) fprintf(stderr, "%c", inbuf_o[i] ); +// } +// +// fprintf( stderr, "\n" ); +// raise( SIGSEGV ); +// exit(1); + } + +// DEBUG( +// fprintf(stderr, " result:\n"); +// hexdump( (char*)outbuf_o, 0, oblen, 1 ); +// ) + + //fprintf(stderr, "utf8to16() returning %s\n", outbuf ); + + //TODO: error + if( icresult ) printf("Uhhhh...utf8to16() returning icresult == %d\n", icresult ); + return icresult; +} +// }}} + +int vb_utf8to16T( vbuf *bout, char *cin, int inlen ) // {{{ +{ + //TODO: This (and 8to16) are the most horrible things I have ever seen... + int inbytesleft = inlen; + char *inbuf = cin; + //int rlen = -1, tlen; + int icresult = -1; + + //int i; //, strlen=-1; + + //if( rlen >= 0 ) + int outbytesleft; + char *outbuf; + if( 2 > bout->blen ) vbresize( bout, 2 ); + bout->dlen = 0; + + do { + outbytesleft = bout->blen - bout->dlen; + outbuf = bout->b + bout->dlen; + icresult = iconv( i8to16, &inbuf, &inbytesleft, &outbuf, &outbytesleft ); + bout->dlen = outbuf - bout->b; + vbgrow( bout, 20 ); + } while( (size_t)-1 == icresult && E2BIG == errno ); + + if( icresult == (size_t)-1 ) { + WARN("iconv failure: %s", strerror( errno ) ); + //ERR_UNIX( errno, "vb_utf8to16():iconv failure: %s", strerror( errno ) ); + unicode_init(); + return -1; + /* + fprintf(stderr, "vb_utf8to16(): iconv failure(%d == %d?): %s\n", errno, E2BIG, strerror( errno ) ); + fprintf(stderr, " attempted to convert:\n"); + hexdump( (char*)cin, 0, inlen, 1 ); + fprintf(stderr, " result:\n"); + hexdump( (char*)bout->b, 0, bout->dlen, 1 ); + fprintf(stderr, " MyDirtyOut:\n"); + for( i=0; i<inlen; i++) { + if( inbuf[i] != '\0' ) fprintf(stderr, "%c", inbuf[i] ); + } + + fprintf( stderr, "\n" ); + raise( SIGSEGV ); + exit(1); + */ + } + + //TODO: error + if( icresult ) printf("Uhhhh...vb_utf8to16() returning icresult == %d\n", icresult ); + return icresult; +} +// }}} +#if 1 +void cheap_uni2ascii(char *src, char *dest, int l) /* {{{ Quick and dirty UNICODE to std. ascii */ +{ + + for (; l > 0; l -=2) { + *dest = *src; + dest++; src +=2; + } + *dest = 0; +} +// }}} +#endif + +void cheap_ascii2uni(char *src, char *dest, int l) /* {{{ Quick and dirty ascii to unicode */ +{ + for (; l > 0; l--) { + *dest++ = *src++; + *dest++ = 0; + + } +} +// }}} + +// }}} +// {{{ VARBUF Functions +vbuf *vballoc( size_t len ) // {{{ +{ + struct varbuf *result; + + result = F_MALLOC( sizeof( struct varbuf ) ); + + result->dlen = 0; + result->blen = 0; + result->buf = NULL; + + vbresize( result, len ); + + return result; + +} // }}} +void vbcheck( vbuf *vb ) // {{{ +{ + ASSERT( vb->b - vb->buf <= vb->blen, "vbcheck(): vb->b outside of buffer range."); + ASSERT( vb->dlen <= vb->blen, "vbcheck(): data length > buffer length."); + + ASSERT( vb->blen < 1024*1024, "vbcheck(): blen is a bit large...hmmm."); +} // }}} +void vbfree( vbuf *vb ) // {{{ +{ + free( vb->buf ); + free( vb ); +} // }}} +void vbclear( struct varbuf *vb ) // {{{ditch the data, keep the buffer +{ + vbresize( vb, 0 ); +} // }}} +void vbresize( struct varbuf *vb, size_t len ) // {{{ DESTRUCTIVELY grow or shrink buffer +{ + vb->dlen = 0; + + if( vb->blen >= len ) { + vb->b = vb->buf; + return; + } + + vb->buf = F_REALLOC( vb->buf, len ); + vb->b = vb->buf; + vb->blen = len; +} // }}} +int vbavail( vbuf *vb ) // {{{ +{ + return vb->blen - ((char*)vb->b - (char*)vb->buf + vb->dlen); +} // }}} +//void vbdump( vbuf *vb ) // {{{ TODO: to stdout? Yuck +//{ +// printf("vb dump-------------\n"); +// printf("dlen: %d\n", vb->dlen ); +// printf("blen: %d\n", vb->blen ); +// printf("b - buf: %d\n", vb->b - vb->buf ); +// printf("buf:\n"); +// hexdump( vb->buf, 0, vb->blen, 1 ); +// printf("b:\n"); +// hexdump( vb->b, 0, vb->dlen, 1 ); +// printf("^^^^^^^^^^^^^^^^^^^^\n"); +//} // }}} +void vbgrow( struct varbuf *vb, size_t len ) // {{{ out: vbavail(vb) >= len, data are preserved +{ + if( 0 == len ) return; + + if( 0 == vb->blen ) { + vbresize( vb, len ); + return; + } + + if( vb->dlen + len > vb->blen ) { + if( vb->dlen + len < vb->blen * 1.5 ) len = vb->blen * 1.5; + char *nb = F_MALLOC( vb->blen + len ); + //printf("vbgrow() got %p back from malloc(%d)\n", nb, vb->blen + len); + vb->blen = vb->blen + len; + memcpy( nb, vb->b, vb->dlen ); + + //printf("vbgrow() I am going to free %p\n", vb->buf ); + free( vb->buf ); + vb->buf = nb; + vb->b = vb->buf; + } else { + if( vb->b != vb->buf ) + memcpy( vb->buf, vb->b, vb->dlen ); + } + + vb->b = vb->buf; + + ASSERT( vbavail( vb ) >= len, "vbgrow(): I have failed in my mission." ); +} // }}} +void vbset( vbuf *vb, void *b, size_t len ) // {{{ set vbuf b size=len, resize if necessary, relen = how much to over-allocate +{ + vbresize( vb, len ); + + memcpy( vb->b, b, len ); + vb->dlen = len; +} // }}} +void vsskipws( vstr *vs ) // {{{ +{ + char *p = vs->b; + while( p - vs->b < vs->dlen && isspace( p[0] ) ) p++; + + vbskip( (vbuf*)vs, p - vs->b ); +} // }}} +void vbappend( struct varbuf *vb, void *b, size_t len ) // {{{ append len bytes of b to vbuf, resize if necessary +{ + if( 0 == vb->dlen ) { + vbset( vb, b, len ); + return; + } + + vbgrow( vb, len ); + + memcpy( vb->b + vb->dlen, b, len ); + vb->dlen += len; + + //printf("vbappend() end: >%s/%d<\n", vbuf->b, vbuf->dlen ); +} // }}} +void vbskip( struct varbuf *vb, size_t skip ) // {{{ dumps the first skip bytes from vbuf +{ + ASSERT( skip <= vb->dlen, "vbskip(): Attempt to seek past end of buffer." ); + //memmove( vbuf->b, vbuf->b + skip, vbuf->dlen - skip ); + vb->b += skip; + vb->dlen -= skip; +} // }}} +void vboverwrite( struct varbuf *vbdest, struct varbuf *vbsrc ) // {{{ overwrite vbdest with vbsrc +{ + vbresize( vbdest, vbsrc->blen ); + memcpy( vbdest->b, vbsrc->b, vbsrc->dlen ); + vbdest->blen = vbsrc->blen; + vbdest->dlen = vbsrc->dlen; +} // }}} +// }}} +// {{{ VARSTR Functions +vstr *vsalloc( size_t len ) // {{{ +{ + vstr *result = (vstr*)vballoc( len + 1 ); + vsset( result, "" ); + return result; +} // }}} +char *vsstr( vstr *vs ) // {{{ +{ + return vs->b; +} // }}} +size_t vslen( vstr *vs ) // {{{ +{ + return strlen( vsstr( vs )); +} // }}} +void vsfree( vstr *vs ) // {{{ +{ + vbfree( (vbuf*)vs ); +} // }}} +void vscharcat( vstr *vb, int ch ) // {{{ +{ + vbgrow( (vbuf*)vb, 1); + vb->b[vb->dlen-1] = ch; + vb->b[vb->dlen] = '\0'; + vb->dlen++; +} // }}} +void vsnprepend( vstr *vb, char *str, size_t len ) // {{{ prependappend string str to vbuf, vbuf must already contain a valid string +{ + ASSERT( vb->b[vb->dlen-1] == '\0', "vsncat(): attempt to append string to non-string."); + int sl = strlen( str ); + int n = (sl<len)?sl:len; + //string append + vbgrow( (vbuf*)vb, n + 1 ); + memmove( vb->b + n, vb->b, vb->dlen - 1 ); + memcpy( vb->b, str, n ); + //strncat( vb->b, str, n ); + + vb->dlen += n; + vb->b[ vb->dlen - 1 ] = '\0'; +} // }}} +void vsskip( vstr *vs, size_t len ) // {{{ len < dlen-1 -> skip len chars, else DIE +{ + ASSERT( len < vs->dlen - 1, "Attempt to skip past end of string" ); + vbskip( (vbuf*)vs, len ); +} // }}} +int vsskipline( vstr *vs ) // {{{ in: vb->b == "stuff\nmore_stuff"; out: vb->b == "more_stuff" +{ + int nloff = find_nl( vs ); + int nll = skip_nl( vs->b + nloff ); + + if( nloff < 0 ) { + //TODO: error + printf("vb_skipline(): there seems to be no newline here.\n"); + return -1; + } + if( skip_nl < 0 ) { + //TODO: error + printf("vb_skipline(): there seems to be no newline here...except there should be. :P\n"); + return -1; + } + + memmove( vs->b, vs->b + nloff + nll, vs->dlen - nloff - nll ); + + vs->dlen -= nloff + nll; + + return 0; +} // }}} +int vscatprintf( vstr *vs, char *fmt, ... ) // {{{ +{ + int size; + va_list ap; + + /* Guess we need no more than 100 bytes. */ + //vsresize( vb, 100 ); + if(!vs->b || vs->dlen == 0) { + vsset( vs, "" ); + } + + while (1) { + /* Try to print in the allocated space. */ + va_start(ap, fmt); + size = vsnprintf (vs->b + vs->dlen - 1, vs->blen - vs->dlen, fmt, ap); + va_end(ap); + + /* If that worked, return the string. */ + if (size > -1 && size < vs->blen - vs->dlen ) { + vs->dlen += size; + return size; + } + /* Else try again with more space. */ + if ( size >= 0 ) /* glibc 2.1 */ + vbgrow( (vbuf*)vs, size+1 ); /* precisely what is needed */ + else /* glibc 2.0 */ + vbgrow( (vbuf*)vs, vs->blen); + } +} // }}} +int vslast( vstr *vs ) // {{{ returns the last character stored in a vstr +{ + if( vs->dlen < 1 ) return -1; + if( vs->b[vs->dlen-1] != '\0' ) return -1; + if( vs->dlen == 1 ) return '\0'; + return vs->b[vs->dlen-2]; +} // }}} +void vs_printf( vstr *vs, char *fmt, ... ) // {{{ print over vb +{ + int size; + va_list ap; + + /* Guess we need no more than 100 bytes. */ + vbresize( (vbuf*)vs, 100 ); + + while (1) { + /* Try to print in the allocated space. */ + va_start(ap, fmt); + size = vsnprintf (vs->b, vs->blen, fmt, ap); + va_end(ap); + + /* If that worked, return the string. */ + if (size > -1 && size < vs->blen) { + vs->dlen = size + 1; + return; + } + /* Else try again with more space. */ + if ( size >= 0 ) /* glibc 2.1 */ + vbresize( (vbuf*)vs, size+1 ); /* precisely what is needed */ + else /* glibc 2.0 */ + vbresize( (vbuf*)vs, vs->blen*2); + } +} // }}} +void vs_printfa( vstr *vs, char *fmt, ... ) // {{{ printf append to vs +{ + int size; + va_list ap; + + if( vs->blen - vs->dlen < 50 ) + vbgrow( (vbuf*)vs, 100 ); + + while (1) { + /* Try to print in the allocated space. */ + va_start(ap, fmt); + size = vsnprintf (vs->b + vs->dlen - 1, vs->blen - vs->dlen + 1, fmt, ap); + va_end(ap); + + /* If that worked, return the string. */ + if (size > -1 && size < vs->blen) { + vs->dlen += size; + return; + } + /* Else try again with more space. */ + if ( size >= 0 ) /* glibc 2.1 */ + vbgrow( (vbuf*)vs, size+1 - vs->dlen ); /* precisely what is needed */ + else /* glibc 2.0 */ + vbgrow( (vbuf*)vs, size ); + } +} // }}} +void vshexdump( vstr *vs, char *b, size_t start, size_t stop, int ascii ) // {{{ +{ + char c; + int diff,i; + + while (start < stop ) { + diff = stop - start; + if (diff > 16) diff = 16; + + vs_printfa(vs, ":%08X ",start); + + for (i = 0; i < diff; i++) { + if( 8 == i ) vs_printfa( vs, " " ); + vs_printfa(vs, "%02X ",(unsigned char)*(b+start+i)); + } + if (ascii) { + for (i = diff; i < 16; i++) vs_printfa(vs, " "); + for (i = 0; i < diff; i++) { + c = *(b+start+i); + vs_printfa(vs, "%c", isprint(c) ? c : '.'); + } + } + vs_printfa(vs, "\n"); + start += 16; + } +} // }}} +void vsset( vstr *vs, char *s ) // {{{ Store string s in vs +{ + vsnset( vs, s, strlen( s ) ); +} // }}} +void vsnset( vstr *vs, char *s, size_t n ) // {{{ Store string s in vs +{ + vbresize( (vbuf*)vs, n + 1 ); + memcpy( vs->b, s, n); + vs->b[n] = '\0'; + vs->dlen = n+1; +} // }}} +void vsgrow( vstr *vs, size_t len ) // {{{ grow buffer by len bytes, data are preserved +{ + vbgrow( (vbuf*)vs, len ); +} // }}} +size_t vsavail( vstr *vs ) // {{{ +{ + return vbavail( (vbuf*)vs ); +} // }}} +void vsnset16( vstr *vs, char *s, size_t len ) // {{{ Like vbstrnset, but for UTF16 +{ + vbresize( (vbuf*)vs, len+1 ); + memcpy( vs->b, s, len ); + + vs->b[len] = '\0'; + vs->dlen = len+1; + vs->b[len] = '\0'; +} // }}} +void vscat( vstr *vs, char *str ) // {{{ +{ + vsncat( vs, str, strlen(str ) ); +} // }}} +int vscmp( vstr *vs, char *str ) // {{{ +{ + return strcmp( vs->b, str ); +} // }}} +void vsncat( vstr *vs, char *str, size_t len ) // {{{ append string str to vstr, vstr must already contain a valid string +{ + ASSERT( vs->b[vs->dlen-1] == '\0', "vsncat(): attempt to append string to non-string."); + int sl = strlen( str ); + int n = (sl<len)?sl:len; + //string append + vbgrow( (vbuf*)vs, n + 1 ); + memcpy( vs->b + vs->dlen - 1, str, n ); + //strncat( vs->b, str, n ); + + vs->dlen += n; + vs->b[ vs->dlen - 1 ] = '\0'; +} // }}} +void vstrunc( vstr *v, int off ) // {{{ Drop chars [off..dlen] +{ + if( off >= v->dlen - 1 ) return; //nothing to do + v->b[off] = '\0'; + v->dlen = off + 1; +} +// }}} +// }}} +// {{{ User input +// TODO: not sure how useful this stuff is here +int fmyinput(char *prmpt, char *ibuf, int maxlen) /* {{{ get user input */ +{ + printf("%s",prmpt); + + fgets(ibuf,maxlen+1,stdin); + + ibuf[strlen(ibuf)-1] = 0; + + return(strlen(ibuf)); +} +// }}} +//}}} +// +// +//{{{ String formatting and output to FILE *stream or just stdout, etc +// TODO: a lot of old, unused stuff in here +void vswinhex8(vstr *vs, unsigned char *hbuf, int start, int stop, int loff ) // {{{ Produce regedit-style hex output */ +{ + int i; + int lineflag=0; + + for( i=start; i<stop; i++) + { + loff += vscatprintf( vs, "%02x", hbuf[i] ); + if( i < stop - 1 ) { + loff+=vscatprintf( vs, "," ); + switch( lineflag ) { + case 0: + if( loff >= 77) { + lineflag=1; + loff=0; + vscatprintf( vs, "\\%s ", STUPID_CR ); + } + break; + case 1: + if( loff >= 75 ) { + loff=0; + vscatprintf( vs, "\\%s ", STUPID_CR ); + } + break; + } + // if( 24 < i || 0 == (i - 17) % 25 ) fprintf( stream, "\\\n " ); + } + } + + // fprintf( stream, "\n" ); +} // }}} diff -Naur ../orig/libpst-0.5.1/vbuf.h libpst64-060926/vbuf.h --- ../orig/libpst-0.5.1/vbuf.h 1969-12-31 17:00:00.000000000 -0700 +++ libpst64-060926/vbuf.h 2006-09-26 14:09:55.000000000 -0600 @@ -0,0 +1,142 @@ +/* {{{ vbuf.h - variable length buffer functions + * + * Functions that try to make dealing with buffers easier. + * + * vbuf + * + * vstr + * - should always contain a valid string + * + * }}} */ + +#ifndef VBUF_H +#define VBUF_H +#define SZ_MAX 4096 +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +/***************************************************/ + +// {{{ Tokenizer const TOK_EMPTY, TOK_ELEMENT, DELIM +#define DELIM '\\' + +#define TOK_EMPTY 0 +#define TOK_DELIM 1 +#define TOK_PARENT 2 +#define TOK_CURRENT 3 +#define TOK_ELEMENT 4 + +#define TOK_ERROR 10 +#define TOK_BUF_SMALL 11 +// }}} + + +// Variable-length buffers +struct varbuf { // {{{ + size_t dlen; //length of data stored in buffer + size_t blen; //length of buffer + char *buf; //buffer + char *b; //start of stored data +}; // }}} + + +// The exact same thing as a varbuf but should always contain at least '\0' +struct varstr { // {{{ + size_t dlen; //length of data stored in buffer + size_t blen; //length of buffer + char *buf; //buffer + char *b; //start of stored data +}; // }}} + + +typedef struct varbuf vbuf; +typedef struct varstr vstr; + +#define VBUF_STATIC(x,y) static vbuf *x = NULL; if(!x) x = vballoc(y); +#define VSTR_STATIC(x,y) static vstr *x = NULL; if(!x) x = vsalloc(y); + +// vbuf functions +struct varbuf *vballoc( size_t len ); +void vbfree( vbuf *vb ); +void vbclear( vbuf *vb ); //ditch the data, keep the buffer +void vbresize( vbuf *vb, size_t len ); +int vbavail( vbuf *vb ); +void vbdump( vbuf *vb ); +void vbgrow( vbuf *vb, size_t len ); // grow buffer by len bytes, data are preserved +void vbset( vbuf *vb, void *data, size_t len ); +void vbskipws( vbuf *vb ); +void vbappend( vbuf *vb, void *data, size_t length ); +void vbskip( vbuf *vb, size_t skip ); +void vboverwrite( vbuf *vbdest, vbuf *vbsrc ); + +// vstr functions +vstr *vsalloc( size_t len ); +char *vsb( vstr *vs ); +size_t vslen( vstr *vs ); //strlen +void vsfree( vstr *vs ); +void vsset( vstr *vs, char *s ); // Store string s in vb +void vsnset( vstr *vs, char *s, size_t n ); // Store string s in vb +void vsgrow( vstr *vs, size_t len ); // grow buffer by len bytes, data are preserved +size_t vsavail( vstr *vs ); +void vscat( vstr *vs, char *str ); +void vsncat( vstr *vs, char *str, size_t len ); +void vsnprepend( vstr *vs, char *str, size_t len ) ; +void vsskip( vstr *vs, size_t len ); +int vscmp( vstr *vs, char *str ); +void vsskipws( vstr *vs ); +void vs_printf( vstr *vs, char *fmt, ... ); +void vs_printfa( vstr *vs, char *fmt, ... ); +void vshexdump( vstr *vs, char *b, size_t start, size_t stop, int ascii ); +int vscatprintf( vstr *vs, char *fmt, ... ); +void vsvprintf( vstr *vs, char *fmt, va_list ap ); +void vstrunc( vstr *vs, int off ); // Drop chars [off..dlen] +int vslast( vstr *vs ); // returns the last character stored in a vstr string +void vscharcat( vstr *vs, int ch ); +int vsutf16( vstr *vs, vbuf *in ); //in: in=zero-terminated utf16; out: vs=utf8; returns: 0 on success, else on fail + +int vs_parse_escaped_string( vstr *vs, char *str, size_t len ); + + +/* + * Windows unicode output trash - this stuff sucks + * TODO: most of this should not be here + */ + +void unicode_init(); +void unicode_close(); +int utf16_write( FILE* stream, const void *buf, size_t count ); +int utf16_fprintf( FILE* stream, const char *fmt, ... ); +int utf16to8( char *inbuf_o, char *outbuf_o, int length ); +int utf8to16( char *inbuf_o, int iblen, char *outbuf_o, int oblen); +int vb_utf8to16T( vbuf *bout, char *cin, int inlen ); +int vb_utf16to8( vbuf *dest, char *buf, int len ); +int iso8859_1to8( char *inbuf_o, char *outbuf_o, int length ); +int utf8toascii( const char *inbuf_o, char *outbuf_o, int length ); + +/* dump ascii hex in windoze format */ +void winhex(FILE* stream, unsigned char *hbuf, int start, int stop, int loff); +void winhex8(FILE *stream, unsigned char *hbuf, int start, int stop, int loff ); + +void vbwinhex8(vbuf *vb, unsigned char *hbuf, int start, int stop, int loff ); + +/* general search routine, find something in something else */ +int find_in_buf(char *buf, char *what, int sz, int len, int start); + +/* Get INTEGER from memory. This is probably low-endian specific? */ +int get_int( char *array ); + +int find_nl( vstr *vs ); // find newline of type type in b +int skip_nl( char *s ); // returns the width of the newline at s[0] +//int vb_readline( struct varbuf *vb, int *ctype, FILE *in ); // read *AT LEAST* one full line of data from in +int vb_skipline( struct varbuf *vb ); // in: vb->b == "stuff\nmore_stuff"; out: vb->b == "more_stuff" +/* Get a string of HEX bytes (space separated), + * or if first char is ' get an ASCII string instead. */ +int gethexorstr(char **c, char *wb); +char *esc_index( char *s, int c ); // just like index(3), but works on strings with escape sequences +char *esc_rindex( char *s, int c ); // just like rindex(3), but works on strings with escape sequences + +char *tok_esc_char( char *s, int *is_esc, int *c ); +int vb_path_token( vbuf *tok, char **path ); // returns things like TOK_EMPTY, TOK_ERROR, complete list at top + +int gettoken( char *tok, int len, char **path, char delim ); // Path tokenizer: increments path, dumps token in tok +#endif