data.c

来自「直接存取Access97数据库文件(MDB)的工具库源码」· C语言 代码 · 共 450 行

C
450
字号
/* MDB Tools - A library for reading MS Access database file * Copyright (C) 2000 Brian Bruns * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#include "mdbtools.h"char *mdb_money_to_string(MdbHandle *mdb, int start, char *s);static int _mdb_attempt_bind(MdbHandle *mdb, 	MdbColumn *col, unsigned char isnull, int offset, int len);#define MDB_DEBUG 0void mdb_bind_column(MdbTableDef *table, int col_num, void *bind_ptr){MdbColumn *col;	/* 	** the column arrary is 0 based, so decrement to get 1 based parameter 	*/	col=g_ptr_array_index(table->columns, col_num - 1);	col->bind_ptr = bind_ptr;}int mdb_find_end_of_row(MdbHandle *mdb, int row){int row_start, row_end, i;        /* Search the previous "row start" values for the first non-deletedone.         * If we don't find one, then the end of the page is the correct value.         */        for (i = row - 1; i >= 0; i--) {                row_start = mdb_get_int16(mdb, (10 + i * 2));                if (!(row_start & 0x8000)) {                        break;                }        }        if (i == -1) {                row_end = mdb->pg_size - 1;        } else {                row_end = row_start - 1;        }	return row_end;}static int mdb_is_null(unsigned char *null_mask, int col_num){int byte_num = (col_num - 1) / 8;int bit_num = (col_num - 1) % 8;	if ((1 << bit_num) & null_mask[byte_num]) {		return 0;	} else {		return 1;	}}/* bool has to be handled specially because it uses the null bit to store its ** value*/static int mdb_xfer_bound_bool(MdbHandle *mdb, MdbColumn *col, int value){	if (col->bind_ptr) {		strcpy(col->bind_ptr,  value ? "0" : "1");	}}static int mdb_xfer_bound_data(MdbHandle *mdb, int start, MdbColumn *col, int len){	if (col->bind_ptr) {		if (len) {			strcpy(col->bind_ptr, 				mdb_col_to_string(mdb, start, col->col_type, len));			return col->col_size;		} else {			strcpy(col->bind_ptr,  "");		}	}	return 0;}int mdb_read_row(MdbTableDef *table, int row){MdbHandle *mdb = table->entry->mdb;MdbColumn *col;int i, j, rc;int num_cols, var_cols, fixed_cols;int row_start, row_end;int fixed_cols_found, var_cols_found;int col_start, len;int num_of_jumps=0, jumps_used=0;int eod; /* end of data */int delflag, lookupflag;int bitmask_sz;unsigned char null_mask[33]; /* 256 columns max / 8 bits per byte */unsigned char isnull;	row_start = mdb_get_int16(mdb, 10+(row*2)); 	row_end = mdb_find_end_of_row(mdb, row);	delflag = lookupflag = 0;	if (row_start & 0x8000) delflag++;	if (row_start & 0x4000) lookupflag++;	row_start &= 0x0FFF; /* remove flags */#if DEBUG	fprintf(stdout,"Row %d bytes %d to %d %s %s\n", 		row, row_start, row_end,		lookupflag ? "[lookup]" : "",		delflag ? "[delflag]" : "");#endif		if (delflag || lookupflag) {		row_end = row_start-1;		return 0;	}#if MDB_DEBUG	buffer_dump(mdb->pg_buf, row_start, row_end);#endif	/* find out all the important stuff about the row */	num_cols = mdb->pg_buf[row_start];	var_cols = 0; /* mdb->pg_buf[row_end-1]; */	fixed_cols = 0; /* num_cols - var_cols; */	for (j = 0; j < table->num_cols; j++) {		col = g_ptr_array_index (table->columns, j);		if (mdb_is_fixed_col(col)) 			fixed_cols++;		else			var_cols++;	}	bitmask_sz = (num_cols - 1) / 8 + 1;	eod = mdb->pg_buf[row_end-1-var_cols-bitmask_sz];	for (i=0;i<bitmask_sz;i++) {		null_mask[i]=mdb->pg_buf[row_end - bitmask_sz + i + 1];	}#if MDB_DEBUG	fprintf(stdout,"#cols: %-3d #varcols %-3d EOD %-3d\n", 		num_cols, var_cols, eod);#endif	/* data starts at 1 */	col_start = 1;	fixed_cols_found = 0;	var_cols_found = 0;	/* fixed columns */	for (j=0;j<table->num_cols;j++) {		col = g_ptr_array_index(table->columns,j);		if (mdb_is_fixed_col(col) &&		    ++fixed_cols_found <= fixed_cols) {			isnull = mdb_is_null(null_mask, j+1); 			rc = _mdb_attempt_bind(mdb, col, isnull,				row_start + col_start, col->col_size);			if (!rc) return 0;			col_start += col->col_size;		}	}       if (col_start >= 256) {               num_of_jumps++;               jumps_used++;               row_start = row_start + col_start - (col_start % 256);       }       col_start = row_start;       while (col_start+256 < row_end-bitmask_sz-1-var_cols-num_of_jumps){               col_start += 256;               num_of_jumps++;       }       eod = mdb->pg_buf[row_end-1-var_cols-bitmask_sz-num_of_jumps];       col_start = mdb->pg_buf[row_end-bitmask_sz-1-num_of_jumps];	/* variable columns */	for (j=0;j<table->num_cols;j++) {		col = g_ptr_array_index(table->columns,j);		if (!mdb_is_fixed_col(col) &&		    ++var_cols_found <= var_cols) {			/* col_start = mdb->pg_buf[row_end-bitmask_sz-var_cols_found]; */			/* more code goes here but the diff is mangled */						if (var_cols_found == mdb->pg_buf[row_end-bitmask_sz-jumps_used-1] &&				jumps_used < num_of_jumps) {				row_start += 256;				col_start -= 256;				jumps_used++;			}			if (var_cols_found==var_cols) 				len=eod - col_start;			else 				len=mdb->pg_buf[row_end 					- bitmask_sz 					- var_cols_found 					- 1 - num_of_jumps ] - col_start;			isnull = mdb_is_null(null_mask, j+1); 			rc = _mdb_attempt_bind(mdb, col, isnull,				row_start + col_start, len);			if (!rc) return 0;			col_start += len;		}	}	return 1;}static int _mdb_attempt_bind(MdbHandle *mdb, 	MdbColumn *col, 	unsigned char isnull, 	int offset, 	int len){	if (col->col_type == MDB_BOOL) {		mdb_xfer_bound_bool(mdb, col, isnull);	} else if (isnull) {		mdb_xfer_bound_data(mdb, 0, col, 0);	} else {		if (!mdb_test_sargs(mdb, col, offset, len)) {			return 0;		}		mdb_xfer_bound_data(mdb, offset, col, len);	}	return 1;}int mdb_read_next_dpg(MdbTableDef *table){MdbCatalogEntry *entry = table->entry;MdbHandle *mdb = entry->mdb;	do {		if (!mdb_read_pg(mdb, table->cur_phys_pg++))			return 0;	} while (mdb->pg_buf[0]!=0x01 || mdb_get_int32(mdb, 4)!=entry->table_pg);	/* fprintf(stderr,"returning new page %ld\n", table->cur_phys_pg); */	return table->cur_phys_pg;}int mdb_rewind_table(MdbTableDef *table){	table->cur_pg_num=0;	table->cur_phys_pg=0;	table->cur_row=0;}int mdb_fetch_row(MdbTableDef *table){MdbHandle *mdb = table->entry->mdb;int rows;int rc;	if (table->num_rows==0)		return 0;	/* initialize */	if (!table->cur_pg_num) {		table->cur_pg_num=1;		table->cur_row=0;		mdb_read_next_dpg(table);	}	do { 		rows = mdb_get_int16(mdb,8);		/* if at end of page, find a new page */		if (table->cur_row >= rows) {			table->cur_row=0;			if (!mdb_read_next_dpg(table)) return 0;		}		rc = mdb_read_row(table, table->cur_row);		table->cur_row++;	} while (!rc);	return 1;}void mdb_data_dump(MdbTableDef *table){MdbHandle *mdb = table->entry->mdb;int i, j, pg_num;int rows;char *bound_values[MDB_MAX_COLS]; 	for (i=0;i<table->num_cols;i++) {		bound_values[i] = (char *) malloc(256);		mdb_bind_column(table, i+1, bound_values[i]);	}	mdb_rewind_table(table);	while (mdb_fetch_row(table)) {		for (j=0;j<table->num_cols;j++) {			fprintf(stdout, "column %d is %s\n", j+1, bound_values[j]);		}	}	for (i=0;i<table->num_cols;i++) {		free(bound_values[i]);	}}int mdb_is_fixed_col(MdbColumn *col){	return col->is_fixed;}static char *mdb_memo_to_string(MdbHandle *mdb, int start, int size){short memo_len;static char text[MDB_BIND_SIZE];	if (size<MDB_MEMO_OVERHEAD) {		return "";	} else if (size == MDB_MEMO_OVERHEAD) {		/* If the only thing here is the field information, the		* data is linked.  Go read it from another page.		* Question: Do we need to read and evaluate the whole page?		* Question: It seems to be the only record on the page.  If		*           it weren't, how do we know which record it is?		*		* WARNING: Assuming the storage area is at least 2048 bytes!		*/		/* The 16 bit integer at offset 0 is the length of the memo field.		* The 16 bit integer at offset 5 is the page it is stored on.		*/		memo_len = mdb_get_int16(mdb, start);		if(mdb_read_alt_pg(mdb, mdb_get_int16(mdb, start+5)) != mdb->pg_size) {			/* Failed to read */			return "";		}		strncpy(text, &mdb->alt_pg_buf[mdb->pg_size - memo_len], memo_len);		return text;	} else {		strncpy(text, &mdb->pg_buf[start + MDB_MEMO_OVERHEAD],			size - MDB_MEMO_OVERHEAD);		text[size - MDB_MEMO_OVERHEAD]='\0';		return text;	}#if 0			strncpy(text, &mdb->pg_buf[start + MDB_MEMO_OVERHEAD], 				size - MDB_MEMO_OVERHEAD);			text[size - MDB_MEMO_OVERHEAD]='\0';			return text;#endif}char *mdb_col_to_string(MdbHandle *mdb, int start, int datatype, int size){/* FIX ME -- not thread safe */static char text[MDB_BIND_SIZE];time_t t;	switch (datatype) {		case MDB_BOOL:			/* shouldn't happen.  bools are handled specially			** by mdb_xfer_bound_bool() */		break;		case MDB_BYTE:			sprintf(text,"%d",mdb_get_byte(mdb, start));			return text;		break;		case MDB_INT:			sprintf(text,"%ld",mdb_get_int16(mdb, start));			return text;		break;		case MDB_LONGINT:			sprintf(text,"%ld",mdb_get_int32(mdb, start));			return text;		break;		case MDB_FLOAT:			sprintf(text,"%f",mdb_get_double(mdb, start));			return text;		break;		case MDB_DOUBLE:			sprintf(text,"%f",mdb_get_double(mdb, start));			return text;		break;		case MDB_TEXT:			if (size<0) {				return "";			}			strncpy(text, &mdb->pg_buf[start], size);			text[size]='\0';			return text;		break;		case MDB_SDATETIME:			t = (long int)((mdb_get_double(mdb, start) - 25569.0) * 86400.0);			strftime(text, MDB_BIND_SIZE, "%x %X",				(struct tm*)gmtime(&t));			return text;		break;		case MDB_MEMO:			return mdb_memo_to_string(mdb, start, size);		break;		case MDB_MONEY:			mdb_money_to_string(mdb, start, text);			return text;		break;		default:			return "";		break;	}	return NULL;}int mdb_col_disp_size(MdbColumn *col){	switch (col->col_type) {		case MDB_BOOL:			return 1;		break;		case MDB_BYTE:			return 3;		break;		case MDB_INT:			return 5;		break;		case MDB_LONGINT:			return 7;		break;		case MDB_FLOAT:			return 10;		break;		case MDB_DOUBLE:			return 10;		break;		case MDB_TEXT:			return col->col_size;		break;		case MDB_SDATETIME:			return 20;		break;		case MDB_MEMO:			return 255; 		break;		case MDB_MONEY:			return 12;		break;	}	return 0;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?