/***************************************************************************
                          libdbx.c  -  DBX handling Library
                             -------------------
    begin                : April 2001
    copyright            : (C) 2001 by David Smith
    email                : Dave.S@Earthcorp.Com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

/*********************************************************/
/* Heavily patched to make it run on big-endian machines */
/*********************************************************/

/* #include <stdio.h> */
#include <stdlib.h>
#include <string.h>

#include "libdbx.h"
#include "define.h"

# if defined DBX_BIG_ENDIAN

/* '((x & 0xff000000) >> 24) & 0x000000ff' is a fix for Solaris' ucbcc */

#  define LE32_CPU(x) \
  x = (((((x) & 0xff000000) >> 24) & 0x000000ff) | \
        (((x) & 0x00ff0000) >> 8 ) | \
        (((x) & 0x0000ff00) << 8 ) | \
        (((x) & 0x000000ff) << 24));
#  define LE16_CPU(x) \
  x = ((((x) & 0xff00) >> 8) | \
       (((x) & 0x00ff) << 8));
# elif defined DBX_LITTLE_ENDIAN
#  define LE32_CPU(x) {}
#  define LE16_CPU(x) {}
# else
#  error "Byte order not supported by this library"
# endif

int dbx_errno = 0;
/* could be 0xE4 or 0x30 */
#define INDEX_POINTER 0xE4
#define ITEM_COUNT 0xC4

/* Internal Prototypes */

int _dbx_get            (FILE *fp, void *buf, unsigned int size);
int _dbx_getAtPos       (FILE *fp, int pos, void* buf, unsigned int size);
int _dbx_getitem        (FILE *fp, int pos, void** item, int type, int flags);
int _dbx_getindex       (FILE* fd, int pos, DBX *dbx);
int _dbx_getIndexes     (FILE* fd, DBX *dbx);
int _dbx_getstruct      (FILE *fp, int pos, DBXFOLDER* folder);
int _dbx_get_from_buf   (char* buffer, int pos, void** dest, int type, int max);
int _dbx_getBody        (FILE *fp, char** x, int ptr);

char * dbx_errmsgs[] = {
    /* DBX_NOERROR */
	"", 
    /* DBX_BADFILE */
	"DBX File operation failed. Open or close",  
    /* DBX_ITEMCOUNT */
	"Read of \"Item Count\" from DBX file failed",
    /* DBX_INDEX_READ */
	"Read of \"Index Pointer\" from DBX file failed", 
    /* DBX_INDEX_UNDERREAD */
	"Number of indexes read from dbx file is less than expected",
    /* DBX_INDEX_OVERREAD */
	"Number of indexes read from dbx file is greater than expected",
    /* DBX_INDEXCOUNT */
	"Request was made for index reference greater than exists (subscript out of range)",
    /* DBX_DATA_READ */
	"Reading of data from dbx file failed",
    /* DBX_NEWS_ITEM */
	"Item is a news item not an email"
};

/* dbx_open - Opens a dbx file and returns a DBX struct to the caller
	@fname - Filename of dbx file to open*/

DBX *dbx_open(const char * fname) 
{
    FILE *fp;
  
    if ( !(fp = fopen(fname, "rb")) ) {
        dbx_errno = DBX_BADFILE;
        return NULL;
    }

    return dbx_open_stream(fp);
}

DBX *dbx_open_stream(FILE *fp) {
    DBX *dbx = (DBX*) malloc (sizeof(DBX));
    int signature[4];
  
    dbx->fd = fp;
    
    /* SIGNATURE */
    _dbx_getAtPos(dbx->fd, 0x0, &signature, 16);
    
    LE32_CPU(signature[0]);
    LE32_CPU(signature[1]);
    LE32_CPU(signature[2]);
    LE32_CPU(signature[3]);

    if ( signature[0] == 0xFE12ADCF && signature[1] == 0x6F74FDC5 &&
         signature[2] == 0x11D1E366 && signature[3] == 0xC0004E9A ) {
        
        /* OE 5 & OE 5 BETA SIGNATURE */
        dbx->type = DBX_TYPE_EMAIL;
        
    } else if ( signature[0] == 0x36464D4A && signature[1] == 0x00010003 ) {
        
        /*It is an OE4 dbx file*/	
        dbx_errno = DBX_BADFILE;
        return NULL;
        
    } else if ( signature[0] == 0xFE12ADCF && signature[1] == 0x6F74FDC6 && 
                /*Difference is C6 instead of C5*/
	            signature[2] == 0x11D1E366 && signature[3] == 0xC0004E9A ) {
        
        /*It is a Folders.dbx type file*/
	    dbx->type = DBX_TYPE_FOLDER;
        
    } else {
	    dbx_errno = DBX_BADFILE;
	    return NULL;
    }
  
    if (_dbx_getIndexes(dbx->fd, dbx)) {
        /* dbx_errno is already set by getIndexes */
        return NULL;
    }
  
    dbx_errno = DBX_NOERROR;
    return dbx;
} 

 
/* dbx_close - Closes a dbx file and deletes the internal struct
	@dbx - DBX struct associated with dbx */

int dbx_close(DBX *dbx) 
{
    if (dbx == NULL || dbx->fd == NULL) {
        dbx_errno = DBX_BADFILE;
        return -1;
    }

    fclose(dbx->fd);
    if (dbx->indexes) {
        free(dbx->indexes);
    }
    free(dbx);

    dbx_errno = DBX_NOERROR;
    return 0;
}

int dbx_free(DBX *dbx, void *item) 
{
    return dbx_free_item(item);
}

int dbx_free_item(void *item) 
{
    DBXNON      *it = item;
    DBXEMAIL    *email;
    DBXFOLDER   *fol;

    if (!item)
        return 1;

    if (it->type == DBX_TYPE_EMAIL) {
        email = (DBXEMAIL*)item;    
        if (email->email)
            free(email->email);
        if (email->subject)
            free(email->subject);
        if (email->psubject)
    	    free(email->psubject);
        if (email->messageid)
            free(email->messageid);
        if (email->parent_message_ids)
            free(email->parent_message_ids);
        if (email->sender_name)
            free(email->sender_name);
        if (email->sender_address)
            free(email->sender_address);
        if (email->recip_name)
            free(email->recip_name);
        if (email->recip_address)
            free(email->recip_address);
        if (email->oe_account_name)
            free(email->oe_account_name);
        if (email->oe_account_num)
            free(email->oe_account_num);
        if (email->fetched_server)
            free(email->fetched_server);
        free(email);
    } else if (it->type == DBX_TYPE_FOLDER) {
        fol = (DBXFOLDER*)item;
        if (fol->name)
            free(fol->name);
        if (fol->fname)
            free(fol->fname);
        free(fol);
    } else {
  	    printf("Aaarghhh. Cannot free an unknown type!\n");
    }
    return 0;
}

/* dbx_get - Gets an item from a dbx file
	@dbx - dbx file to get item from
	@index - item 0..itemcount to fetch
	@flags - which parts to get */

void * dbx_get(DBX *dbx, int index, int flags) 
{
    int size;
    void * ret = NULL;
	
    if (!dbx || !dbx->fd) {
        dbx_errno = DBX_BADFILE;
        return NULL;
    }

    if (index >= dbx->indexCount || index < 0) {
        dbx_errno = DBX_INDEXCOUNT;
        return NULL;
    }

    if (dbx->type == DBX_TYPE_EMAIL || dbx->type == DBX_TYPE_FOLDER) {
        size = _dbx_getitem(dbx->fd, dbx->indexes[index], &ret, 
                            dbx->type, flags);
        ((DBXEMAIL*)ret)->num = index;
    } else {
        dbx_errno = DBX_BADFILE;
        return NULL;
    }
		
    dbx_errno = DBX_NOERROR;
    if (dbx->type == DBX_TYPE_EMAIL) {
        /* we explicitely need to swap the filetime */
        LE32_CPU(((DBXEMAIL*)ret)->date.dwLowDateTime);
        LE32_CPU(((DBXEMAIL*)ret)->date.dwHighDateTime);
        /* we weren't allowed to swap 'flag' because it
         * is treated rather like a char */
        LE32_CPU(((DBXEMAIL*)ret)->flag);
    }
    return ret;
}

/* dbx_perror - Print the error message to stderr
	@str - prepend this message */
int dbx_perror(const char *str) 
{
	fprintf(stderr, "%s: %s\n", str, dbx_errmsgs[dbx_errno]);
	return 0;
}

/* dbx_get_body - Load the body for the current email
	@dbx - handle for the dbx file
	@start - file offset from email pointer
	@ptr - location to store data */
int dbx_get_body(DBX* dbx, int start, char** ptr) {
    if (!dbx || !dbx->fd) {
        dbx_errno = DBX_BADFILE;
        return -1;
    }
    return _dbx_getBody(dbx->fd, ptr, start);
}

/* dbx_get_email_body - Load the body of an email and store it in the email
	@dbx - handle for the dbx file
	@email - email to fillin */
int dbx_get_email_body(DBX *dbx, DBXEMAIL* email) 
{
    if (!dbx || !dbx->fd) {
        dbx_errno = DBX_BADFILE;
        return -1;
    }
    return _dbx_getBody(dbx->fd, &(email->email), email->data_offset);
}

/* dbx_free_email_body - Clear the body of an email. To be called after
 * dbx_get_email_body
	@email - email to remove body from */
int dbx_free_email_body(DBXEMAIL* email) 
{
    free (email->email);
    email->email = NULL;
    return 0;
}

const char* dbx_strerror(int err) 
{
	return dbx_errmsgs[err];
}

/* Private Functions */
struct _dbx_tableindexstruct {
	int self;
	int unknown1;
	int anotherTablePtr;
	int parent;
	char unknown2;
	char ptrCount;
	char reserve3;
	char reserve4;
	int indexCount;
};

struct _dbx_indexstruct {
	int indexptr;
	int anotherTablePtr;
	int indexCount;
};

struct _dbx_folder_hdrstruct {
	int self;
	int blocksize;
	short int unknown2;
	char intcount;
	char unknown3;
};

struct _dbx_block_hdrstruct {
	int self;
	int nextaddressoffset;
	short int blocksize;
	char intcount;
	char unknown1;
	int nextaddress;
};

struct _dbx_folderstruct {
	int id;
	int parent;
	int unknown6;
	char unknown61;
	char length1;
	char unknown7;
	char unknown8;
};

struct _dbx_email_headerstruct {
  int self;
  int size;
  short int u1;
  unsigned char count;
  unsigned char u2;
};

/* Email types - values thereof
    0x01 - buffer pointer to Flag (char?)
    0x02 - 
    0x04 - buffer pointer to file offset of email data
    0x05 - buffer pointer to asciiz string containing the subject of email
    0x06 -
    0x07 - buffer pointer to asciiz message id of email
    0x08 - buffer pointer to asciiz another string containing the subject 
           of email
    0x09 -
    0x0B -
    0x0A - buffer pointer to asciiz message ids of parent emails
    0x0C - buffer pointer to asciiz name of server where email was fetched from
    0x0D - buffer pointer to asciiz Name of sender
    0x0E - buffer pointer to asciiz Email address of sender
    0x11 -
    0x12 - 
    0x13 - buffer pointer to asciiz Name of recipient
    0x14 - buffer pointer to asciiz Email address of recipient
    0x1A - buffer pointer to asciiz name of email account used to fetch email
    0x1B - buffer pointer to asciiz number of email account (e.g. "00000001")
    0x1C - 
    0x80 -
    0x81 - email's flag (char?)
    0x84 - file offset to email data
    0x90 -
    0x91 -
*/

/* Folder types - values thereof
    0x02 - Descriptive Name
    0x03 - Filename
    0x80 - Folder ID
    0x81 - ID of parent
*/

struct _dbx_email_pointerstruct {
  unsigned char type;
  int           val; /* this is supposed to be a 3 byte int */
};


int _dbx_getIndexes (FILE* fp, DBX *dbx) 
{
	int indexptr;
	int itemcount;

    /* first table of indexes */
    if (_dbx_getAtPos(fp, INDEX_POINTER, &indexptr, sizeof(indexptr))) {
        dbx_errno = DBX_INDEX_READ;
        return 2;
    }
    LE32_CPU(indexptr);	
	/* count of items */
	if (_dbx_getAtPos(fp, ITEM_COUNT, &itemcount, sizeof(itemcount))) {
		dbx_errno = DBX_ITEMCOUNT;
		return 1;
	}
	LE32_CPU(itemcount);
	dbx->indexes = (int*) malloc(itemcount * sizeof(int));
	dbx->indexCount = itemcount;
	
	if (_dbx_getindex(fp, indexptr, dbx)) {
		return 4;
	}
	
	if (dbx->indexCount != 0) {	
		dbx_errno = DBX_INDEX_UNDERREAD;
		return 3;
	}
    /* reassign itemcount after call cause it should equal zero now */
	dbx->indexCount = itemcount; 
	return 0;
}

int _dbx_getindex(FILE* fp, int pos, DBX *dbx) 
{
	int x;
	struct _dbx_tableindexstruct tindex;
	struct _dbx_indexstruct index;

	RET_ERROR(_dbx_getAtPos(fp, pos, &tindex, sizeof(tindex)), DBX_INDEX_READ);
	
    LE32_CPU(tindex.self);
    LE32_CPU(tindex.unknown1);
    LE32_CPU(tindex.anotherTablePtr);
    LE32_CPU(tindex.parent);
    LE32_CPU(tindex.indexCount);
    
	if (tindex.indexCount > 0) {
		_dbx_getindex (fp, tindex.anotherTablePtr, dbx);
	}

	pos += sizeof(struct _dbx_tableindexstruct);
	
    for (x = 1; x <= tindex.ptrCount; x++) {
        RET_ERROR(_dbx_getAtPos(fp, pos, &index, 
                  sizeof(struct _dbx_indexstruct)), DBX_INDEX_READ);
        LE32_CPU(index.indexptr);
        LE32_CPU(index.anotherTablePtr);
        LE32_CPU(index.indexCount);

        RET_ERROR(dbx->indexCount < 0, DBX_INDEX_OVERREAD);
		
        dbx->indexes[--dbx->indexCount] = index.indexptr;
        pos += sizeof(struct _dbx_indexstruct);
        if (index.indexCount > 0)
            _dbx_getindex(fp, index.anotherTablePtr, dbx);
    }
	return 0;
}

#define STRING_TYPE 0
#define INT_TYPE 1
#define W32FT_TYPE 2
#define CHAR_TYPE 3

int _dbx_getitem (FILE *fp, int pos, void **item, int type, int flags) {
	int x;
	char *bufptr, *buffer, **bufx;
	int readtype=STRING_TYPE;
	
	DBXEMAIL *email = NULL;
	DBXFOLDER *folder = NULL;

	struct _dbx_email_headerstruct blockhdr;
	struct _dbx_email_pointerstruct blockp;

	int body = (flags&DBX_FLAG_BODY?1:0);
	
	if (type == DBX_TYPE_EMAIL) {
	  email = (DBXEMAIL*) malloc(sizeof(DBXEMAIL));
	  memset (email, 0, sizeof(DBXEMAIL));
	  email->type = DBX_TYPE_EMAIL;
	  *item = email;
	  email->email = NULL;
	} else {
	  folder = (DBXFOLDER*) malloc(sizeof(DBXFOLDER));
	  memset (folder, 0, sizeof(DBXFOLDER));
	  folder->type = DBX_TYPE_FOLDER;
	  *item = folder;
	}

	RET_ERROR(_dbx_getAtPos(fp, pos, &blockhdr, sizeof(blockhdr)), 
              DBX_INDEX_READ);
   
    LE32_CPU(blockhdr.self);
    LE32_CPU(blockhdr.size);
    LE32_CPU(blockhdr.u1);
    
	/* we will load all the block into memory 
     * as we will be accessing it byte by byte */

	buffer = (char*) malloc(blockhdr.size);
	RET_ERROR(_dbx_get(fp, buffer, blockhdr.size), DBX_DATA_READ);
	bufptr = buffer;
	if (email)
		email->data_offset = -1;

	for (x = 0; x < blockhdr.count; x++) {
	  blockp.val = 0;

	  memcpy(&(blockp.type), bufptr, 1);    /* this will copy the type */
	  memcpy(&(blockp.val), bufptr+1, 3);   /* and the 3 byte int */
      
      /* we pretend it's a four byte integer */
      LE32_CPU(blockp.val); 
      
	  if (type == DBX_TYPE_EMAIL) {
	    switch (blockp.type) {
	    case 0x01: 
            /* pointer to flag */
	    	email->flag = 0;
	    	((int*)bufx) = &(email->flag);
	    	readtype = CHAR_TYPE;
	    	break;
	    case 0x04: 
            /*pointer to dataptr */
	        ((int*)bufx) = &(email->data_offset);
	        readtype = INT_TYPE;
	        break;
	    case 0x05: 
            /* asciiz string of subject (without RE: or FWD: etc...) */
	        bufx = &(email->psubject);
	        readtype = STRING_TYPE;
	        break;
	    case 0x07: 
            /* message id of email */
	        bufx = &(email->messageid);
	        readtype = STRING_TYPE;
	        break;
	    case 0x08: 
            /* second copy of subject. Original text (with RE: etc...) */
            bufx = &(email->subject);
	        readtype = STRING_TYPE;
	        break;
	    case 0x0A: 
            /* msg-id of parent(s) */
	        bufx = &(email->parent_message_ids);
	        readtype = STRING_TYPE;
	        break;
	    case 0x0C: 
            /* name of server used to fetch email */
	    	bufx = &(email->fetched_server);
	    	readtype = STRING_TYPE;
	    	break;
	    case 0x0D: 
            /* Sender's name */
	        bufx = &(email->sender_name);
	        readtype = STRING_TYPE;
	        break;
	    case 0x0E: 
            /* Sender's email address */
	        bufx = &(email->sender_address);
	        readtype = STRING_TYPE;
	        break;
	    case 0x12: 
            /* date - of what i'm not sure. 
             * It is in a win32 FILETIME structure. 
             * needs converting to something */
			((struct FILETIME*)bufx) = &(email->date);
			readtype = W32FT_TYPE;
			break;
	    case 0x13: 
            /* recipient's name */
	        bufx = &(email->recip_name);
	        readtype = STRING_TYPE;
	        break;
	    case 0x14: 
            /* recipient's email address */
	        bufx = &(email->recip_address);
	        readtype = STRING_TYPE;
	        break;
	    case 0x1A: 
            /* Name of Account used to fetch email */
	    	bufx = &(email->oe_account_name);
	    	readtype = STRING_TYPE;
	    	break;
	    case 0x1B: 
            /* String version of account number 
             * used to fetch email (eg "00000001") */
	    	bufx = &(email->oe_account_num);
	    	readtype = STRING_TYPE;
	    	break;
	    case 0x80: 
            /* email's ID */
	        bufx = NULL;
	        email->id = blockp.val;
	        break;
	    case 0x81: 
            /* email's flag */
	    	bufx=NULL;
	    	email->flag = blockp.val;
	    	break;
	    case 0x84: 
            /* direct offset of first email data block */
	        email->data_offset = blockp.val;
	        bufx = NULL;
	        break;
	    /*	    
        case 0x02: //currently unknown
	    case 0x06: //currently unknown
	    case 0x09:
	    case 0x0B:
	    case 0x0C:
	    case 0x11: //currently unknown
	    case 0x1A:
	    case 0x1B:
	    case 0x1C: //currently unknown
	    case 0x81: //currently unknown
	    case 0x90: //currently unknown
	    case 0x91: //currently unknown
	        bufx = NULL;
	        break; */
	    default:
	      bufx = NULL;
	    }
	  } else {
	    switch(blockp.type) {
	    case 0x02: 
            /* descriptive name */
	        bufx = &(folder->name);
	        readtype = STRING_TYPE;
	        break;
	    case 0x03: 
            /* filename */
	        bufx = &(folder->fname);
	        readtype = STRING_TYPE;
	        break;
	    case 0x80: 
            /* current id */
	        bufx = NULL;
	        folder->id = blockp.val;
	        break;
	    case 0x81: 
            /* parent id */
	        bufx = NULL;
	        folder->parentid = blockp.val;
	        break;
	    /*	    
        case 0x86: //unknown
	    case 0x87: //unknown
	    case 0x88: //unknown
	    case 0x8A: //unknown
	    case 0x8B: //unknown
	        bufx = NULL;
	        break;*/
	    default:
	      bufx = NULL;
	    }
	  }

	  if (bufx)
	        if (_dbx_get_from_buf(buffer, blockp.val + (blockhdr.count*4), 
                (void**)bufx, readtype, blockhdr.size))
	            return 1; /* an error occured */
	  bufptr += 4; /* size of data */
	}
	free (buffer);
    
	/* if we are doing folder types, we have now finished */
	if (type == DBX_TYPE_FOLDER || body == 0)
	    return 0;

    RET_ERROR(email->data_offset == -1, DBX_DATA_READ);

	return _dbx_getBody(fp, &(email->email), email->data_offset);
}

int _dbx_getBody(FILE *fp, char** x, int ptr) 
{
    int bufsize = 0;
    struct _dbx_block_hdrstruct hdr;
    *x = NULL;
    
    while (ptr != 0) {
	    RET_ERROR(_dbx_getAtPos(fp, ptr, &hdr, sizeof(hdr)), DBX_DATA_READ);
        LE32_CPU(hdr.self);
        LE32_CPU(hdr.nextaddressoffset);
        LE16_CPU(hdr.blocksize);
        LE32_CPU(hdr.nextaddress);
        /* this plus one will not be accumulative cause we don't add it to
         * bufsize but we need it so we can terminate the buffer */
	    *x = realloc(*x, bufsize + hdr.blocksize + 1);
	    RET_ERROR(_dbx_get(fp, (*x)+bufsize, hdr.blocksize), DBX_DATA_READ);
	    bufsize += hdr.blocksize;
	    ptr = hdr.nextaddress;
	}
    
	if (*x) 
        (*x)[bufsize] = '\0'; /* terminate the buffer */

    /* size of data read */
	return bufsize; 
}

int _dbx_getstruct(FILE *fp, int pos, DBXFOLDER* folder) 
{
    struct _dbx_folder_hdrstruct hdr;
    struct _dbx_folderstruct fol;
    
    char *buf, *fname;
    int msgoffset, blockpos=0;
    
    folder->name = NULL;
    
	RET_ERROR(_dbx_getAtPos(fp, pos, &hdr, sizeof(hdr)), DBX_DATA_READ);

    LE32_CPU(hdr.self);
    LE32_CPU(hdr.blocksize);
    LE16_CPU(hdr.unknown2);

	RET_ERROR(_dbx_get(fp, &fol, sizeof(fol)), DBX_DATA_READ);

    LE32_CPU(fol.id);
    LE32_CPU(fol.parent);
    LE32_CPU(fol.unknown6)
    blockpos += sizeof(hdr);
    buf = (char*) malloc(fol.length1);
    msgoffset = hdr.intcount * sizeof(int);
	
    RET_ERROR(_dbx_getAtPos(fp, pos+blockpos+msgoffset, buf, fol.length1), 
               DBX_DATA_READ);
    
    if (strlen(buf) != fol.length1 - 1) { }

    /* Allocate space big enough to hold remainder of block */
    fname = (char*) malloc(hdr.blocksize - blockpos);
    if (!fname) {
        return -1;
	}
	
	RET_ERROR(_dbx_get(fp, fname, hdr.blocksize-blockpos), DBX_DATA_READ);
	
	folder->name = buf;
	folder->fname = fname;
	folder->id = fol.id;
	folder->parentid = fol.parent;
	dbx_errno = DBX_NOERROR;
	return strlen(buf);
}

int _dbx_getAtPos(FILE *fp, int pos, void* buf, unsigned int size) {
	if (fseek(fp, pos, SEEK_SET) == -1) {
		return 1;
	}

	if (fread(buf, 1, size, fp) < size) {
		return 2;
	}
	return 0;
}

int _dbx_get (FILE *fp, void *buf, unsigned int size) {
	if (fread(buf, 1,  size, fp) < size) {
		return 1;
	}
	return 0;
}

int _dbx_get_from_buf(char* buffer, int pos, void** dest, int type, int max) 
{
    int y;
    /* copy data from buffer to string pointed to by bufx */
    if (type == STRING_TYPE) {
        y = strlen(&buffer[pos]) + 1; /* plus one for string terminator */
        RET_ERROR(y > max, DBX_DATA_READ);
        if (!*dest)
            *dest = (char*) malloc(y);
        strncpy(*dest, &buffer[pos], y);
    } else if (type == INT_TYPE) {  
        memcpy((int*)dest, &buffer[pos], 4);
    } else if (type == W32FT_TYPE) {
        memcpy((struct FILETIME*)dest, &buffer[pos], 8);
    } else if (type == CHAR_TYPE) {
        memcpy((unsigned char*)dest, &buffer[pos], 1);
	}
	
  return 0;
}