⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wipdb.c

📁 是一个手机功能的模拟程序
💻 C
📖 第 1 页 / 共 4 页
字号:
 * If element->blockId == 0, then this is the first time this 
 * element is saved. A new id then is allocated and set.
 *
 * Return TRUE if successful.
 */
static BOOL 
db_saveElement_wt (RecordPtr parent, ElementPtr element, ElementPtr prev)
{
	char buffer[10+DB_keyLen];

	ElementPtr tempElem;
	ElementPtr nextElem;

	UINT32     id;
	UINT32     nextId;
	UINT32     newId;
	UINT32     childId;
	UINT32     len;
	UINT32     dataLen;
	UINT32     blockLen;

	UINT16     type    = element->flags & DB_mask_type;
	UINT16     dataUse = element->flags & DB_mask_dataUse;
	UINT16     keyLen  = (element->flags & DB_mask_key) ? DB_keyLen : 0;

	/* block len */
	len = 10 + keyLen;
	if (type == DB_flag_str) {
 		dataLen = strlen((char*) element->data.s) + 1;
		len += dataLen;
	} else if (type == DB_flag_mem) {
		dataLen = *(UINT16*) element->data.p;
		len += dataLen;
	}
	
	/* Allocate block */
	id = db_getBlockId(element);

	if (id == 0) { /* First time */
		newId = 0;
		if (! Storage_AllocateBlock(&store, len, &newId))
			/* Out of persistent memory */
			return FALSE;
	} else { 
		blockLen = Storage_GetBlockSize(&store, id);
		if (len <= blockLen && len > blockLen - 8) { /* Rounded up, 8 byte alignment */
			/* Reuse block */
			newId = id;
		} else {
			/* New block */
			newId = 0;
			if (! Storage_AllocateBlock(&store, len, &newId))
				/* Out of persistent memory */
				return FALSE;
		}
	}

	if (parent == db_root)
		/* Cannot trust prev to point out an write-through element at root level, recalculate */
		prev = db_findPrev_wt(element);
	if (prev == NULL)
		nextId = 0;
	else
		nextId = db_getBlockId(prev);

	*(UINT32*) (buffer+0) = nextId;
	*(UINT16*) (buffer+8) = element->flags;

	
	/* Set data (buffer+4) */
	if (dataUse == DB_flag_dataChild) { /* rec, set */
		if (((RecordPtr) element)->data.e == element)
			childId = 0;
		else {
			/* End element is head in the reversed persistent list */
			for (tempElem = ((RecordPtr) element)->data.e; tempElem != element;
			                                                     tempElem = tempElem->next)
				prev = tempElem;
			childId = db_getBlockId(prev);
		}
		*(UINT32*) (buffer+4) = childId;
	} else if (dataUse == DB_flag_dataInternal) /* int */
		*(UINT32*) (buffer+4) = element->data.i;
	else /* str, mem */
		*(UINT32*) (buffer+4) = len;
	
	if (keyLen != 0)
		memcpy(buffer+10, ((FieldPtr) element)->key, DB_keyLen);
	Storage_Put(&store, newId, 0, 10 + keyLen, buffer);
	
	if (dataUse == DB_flag_dataExternal)
		Storage_Put(&store, newId, 10 + keyLen, dataLen, element->data.p);


	/* Insert into list in persistent memory */
	if (newId != id) {
		/* Find next write-through element in the same list as 'element'. */
		if (parent == db_root) {
			/* At top level, not all elements are write-through. Search for
			 * next write-through element. */
			for (nextElem = element->next; nextElem != (ElementPtr) parent; 
																					 nextElem = nextElem->next)
				if (nextElem->flags & DB_mask_writeThrough)
					break;
		} else
			nextElem = element->next;

		if (nextElem == (ElementPtr) parent)/* End element is head in the reversed persistent list */
			DB_SET_CHILD_ID(((RecordBlockPtr) parent)->blockId, newId)
		else
			DB_SET_NEXT_ID(nextElem, newId)

		if (id != 0)
			Storage_DeleteBlock(&store, id);
	}


	/* Update blockId */
	if (dataUse == DB_flag_dataChild)
		((RecordBlockPtr) element)->blockId = newId;
	else
		if (keyLen != 0)
			((FieldBlockPtr) element)->blockId = newId;
		else 
			((ElementBlockPtr) element)->blockId = newId;
	return TRUE;
}



/*
 * Rebuilds database by reading write-through data. Recursive;
 * adds fields to an already existing record.
 *
 * 'parent' is a reference to the record corresponding to the
 * parent of 'id'.
 *
 * If the function returns FALSE, the reconstruction has failed
 * and the database has only been partially reconstructed.
 */
static BOOL 
db_rebuildDB_wt (UINT32 id, DB_ref parent)
{
	BYTE   buf[BUFSIZE];
	DataUnion  data;
	ElementPtr element;
	DB_ref     newRef;
	BYTE*      key;
	UINT32     blockLen;
	UINT32     offset;
	UINT32     readLen;
	UINT32     nextId;
	UINT16     flags;
	UINT8      error;

	while (id != 0) {
		blockLen = Storage_GetBlockSize(&store, id); /* blockLen rounded up */
		readLen = MIN(BUFSIZE, blockLen);

		Storage_Get(&store, id, 0, readLen, buf);

		nextId = *(UINT32*) (buf + 0);
		flags  = *(UINT16*) (buf + 8);
		/* DB_flag_lastElement contains trash value. It is recalculated
		 * in db_setItem, db_createRecord. */
		
		if (flags & DB_mask_key) {
			key = buf + 10;
			offset = 10 + DB_keyLen;
		} else
			offset = 10;

		switch (flags & DB_mask_dataUse) {
		case DB_flag_dataChild:
			newRef = db_createRecord(parent, key, flags, &error);
			if (error)
				return FALSE;
			((RecordBlockPtr) currentRecord)->blockId = id;
			if ( ! db_rebuildDB_wt(*(UINT32*)(buf + 4), newRef))
				return FALSE;
			goto Next_iteration;

		case DB_flag_dataExternal:
			blockLen = *(UINT32*) (buf + 4); /* Exact blockLen */
			readLen = MIN(BUFSIZE, blockLen);
			data.s = (BYTE*) OSConnectorAlloc(blockLen - offset);
			#ifndef HAS_SETJMP
			if (data.s == NULL)
				return FALSE;
			#endif
			memcpy(data.s, buf + offset, (size_t)(readLen - offset));
			if (readLen < blockLen)
				Storage_Get(&store, id, readLen, blockLen - readLen, data.s + readLen - offset);
			element = db_setItem(parent, key, flags, data, &error);
			if (error) {
				OSConnectorFree(data.s);
				return FALSE;
			}
			break;

		case DB_flag_dataInternal:
			data.i = *(UINT32*) (buf + 4);
			element = db_setItem(parent, key, flags, data, &error);
			if (error)
				return FALSE;
			break;
		}
		if (flags & DB_mask_key) {
			((FieldBlockPtr) element)->blockId   = id;
		} else {
			((ElementBlockPtr) element)->blockId   = id;
		}
Next_iteration:
		db_markId(id);
		id = nextId;
	}
	return TRUE;
}



/*
 * Load database from persistent memory and rebuld structure.
 * Only elements saved as write-through are recovered.
 *
 * Return FALSE if there is nothing to load.
 */
static BOOL 
db_loadDB_wt (void)
{
	UINT32  id;
	UINT16  len;
	BOOL    clearAll = FALSE;
	int     i;

	if (! Storage_GetAllBlockIds(&store, &idArr, &len) || len == 0)
		return FALSE;
	
	db_serviceMode = TRUE; /* Turn of write-through while rebulding */
	Storage_Get(&store, 1024, 4, 4, &id);
	db_markId(1024);

	if (! db_rebuildDB_wt(id, DB_root)) {
		/* Rebuild has failed. Delete everything. */
		db_clearRecord(db_root->ref);
		clearAll = TRUE;
	}
	
	db_serviceMode = FALSE;

	for (i=0; i < len; i++) {
		if ((idArr[i] <= 0x80000000 || clearAll) && idArr[i] > 1024) {
			/* Found a loose block */
			Storage_DeleteBlock(&store, idArr[i] & 0x7fffffff);
		}
	}

	OSConnectorFree(idArr);
	return ! clearAll;
}


/* ============================================ */
/* =======  persistent memory handling  ======= */
/* =======            backup            ======= */
/* ============================================ */

/*

	When saving the elements, the persistent flags of the flags field are reused. The DB_flag_backup must be set
	and DB_flag_writeThrough must be cleared. This means they can be used for storing other information when
	saving, since these flags can be reconstructed when the database is reloaded.

  FUNCTIONS

  This module contains four main functions:
  
	db_writeData_bu
  db_rebuildDB_bu
  db_saveDB_bu
  db_loadDB_bu

*/

/*
 *
 *
 */
static void 
db_writeDB_bu (wap_cvt_t* obj)
{
	ElementPtr current;
	ElementPtr nextCurrent;
	BYTE*      s;
	UINT16     flags;
	UINT16     len;
	short      direction;
	short      nextDirection;
	short      level;
	short      offset;

	level = 0;
	current = db_root->data.e;
	direction = GOING_DOWN;
	while (current != (ElementPtr) db_root) {
		if (! (current->flags & DB_mask_backup)) { /* Only save backup element subtrees */
			current = current->next;
			continue;
		}
		
		/* Calculate next element */
		if (direction != GOING_UP && (current->flags & DB_mask_dataUse) == DB_flag_dataChild &&
		                                                             current->data.e != current) {
			nextDirection = GOING_DOWN;
			nextCurrent = current->data.e;
			offset = 1;
		} else {
			if (current->flags & DB_mask_lastElement) {
				nextDirection = GOING_UP;
				offset = -1;
			} else {
				nextDirection = GOING_RIGHT;
				offset = 0;
			}

			nextCurrent = current->next;
		}
				
		/* Save element */
		if (direction != GOING_UP) {
			/* Write flags */
			flags = current->flags & ~ (DB_mask_backup | DB_mask_lastElement | DB_mask_lastElement2) |
			        (nextDirection == GOING_DOWN ? DB_flag_hasChild : 0) |
			        (current->flags & DB_flag_lastElement ? DB_flag_lastElement2 : 0) |
			        (level == 0 ? DB_flag_rootLevel : 0);
			        /* Set DB_flag_hasChild if next element is a child and
			         * copy DB_flag_lastElement to DB_flag_lastElement2.
			         * See comment in db_rebuildDB_bu for use of
			         * DB_flag_lastElement2. DB_flag_rootLevel is set on root
			         * level.
			         *
			         * DB_flag_hasChild and DB_flag_rootLevel are temprary flags,
			         * reusing other flags. See definitions. */
			wap_cvt_uint16(obj, &flags);

			/* Write key */
			if (current->flags & DB_mask_key)
				wap_cvt_static_bytevector(obj, DB_keyLen, ((FieldPtr) current)->key);

			/* Write data */
			if ((current->flags & DB_mask_dataUse) != DB_flag_dataChild) {
				if ((current->flags & DB_mask_type) == DB_flag_int) {   /* int */
						wap_cvt_uint32(obj, &current->data.i);
				} else {
					if ((current->flags & DB_mask_type) == DB_flag_str) { /* str */
						len = strlen((char*) current->data.s) + 1;
						s =	current->data.s;
					} else {                                              /* mem */
						len = *(UINT16*) current->data.s - 2;
						s =	current->data.s + 2;
					}
					wap_cvt_uint16(obj, &len);
					wap_cvt_static_bytevector(obj, len, s);
				}
			}
		}

		/* Move to next element */
		direction = nextDirection;
		current = nextCurrent;
		level += offset;
	}
}



/*
 *
 */
void 
db_saveDB_bu (void)
{
	BYTE*     buf;
	wap_cvt_t obj;
	UINT32    id;
	UINT16    wt = DB_flag_endOfBuffer;

	wap_cvt_init(&obj, WAP_CVT_ENCODE_SIZE, NULL, 0);
	db_writeDB_bu(&obj);
	if (obj.pos == 0)
		return;

	buf = OSConnectorAlloc(obj.pos + 2);
	#ifndef HAS_SETJMP
	if (buf == NULL)
		return;
	#endif

	wap_cvt_init(&obj, WAP_CVT_ENCODE, buf, obj.pos + 2);
	db_writeDB_bu(&obj);
	wap_cvt_uint16(&obj, &wt);

	id = 1023;
	Storage_DeleteBlock(&store, id);
	Storage_AllocateBlock(&store, obj.pos, &id);
	Storage_Put(&store, 1023, 0, obj.pos, buf);
	OSConnectorFree(buf);
}



/*
 * Rebuilds database by reading backup data. Recursive;
 * adds fields to an already existing record.
 *
 * If the function returns FALSE, the reconstruction has failed
 * and the database has only been partially reconstructed.
 */
static BOOL 
db_rebuildDB_bu (void)
{
	ElementPtr toElement;
	ElementPtr newElement;
	RecordPtr  toRec;
	BYTE*      buf;
	wap_cvt_t  obj;
	DataUnion  data;
	UINT32     size;
	short      direction;
	UINT8      error;
	BOOL       skipSubtree;

	UINT16     len;
	UINT16     flags;
	BYTE       key[DB_keyLen];

	size = Storage_GetBlockSize(&store, 1023);
	buf = OSConnectorAlloc(size);
	Storage_Get(&store, 1023, 0, size, buf);
	wap_cvt_init(&obj, WAP_CVT_DECODE, buf, size);
	
	toRec       = db_root;
	toElement   = (ElementPtr) toRec;
	direction   = GOING_DOWN;
	skipSubtree = FALSE;

	while (TRUE) {
		/* Load element */
		if (direction != GOING_UP) {

			/* Read flags */
			wap_cvt_uint16(&obj, &flags);
			if (flags & DB_mask_endOfBuffer) 
				break;
			if (flags & DB_mask_rootLevel)
				skipSubtree = FALSE; /* Turn skipping off, if on; subtree finished. */

			/* Read key */
			if (flags & DB_mask_key) {
				wap_cvt_static_bytevector(&obj, DB_keyLen, key);
				if (flags & DB_mask_rootLevel) {
					currentRef = DB_root;
					currentRecord = db_root;
					if (db_findField (key) != NULL)
						skipSubtree = TRUE; /* A record with the same name has been	saved
						                     * using write-through after the backup. The
						                     * other copy is newer, use it instead. */
				}
			}


			/* Create and add new element */
			if (skipSubtree) {
				if ((flags & DB_mask_dataUse) == DB_flag_dataExternal) {
					wap_cvt_uint16(&obj, &len);
					obj.pos += len;
				} else if ((flags & DB_mask_type) == DB_flag_int)
					obj.pos += 4;
				continue;
			}

			if ((flags & DB_mask_dataUse) == DB_flag_dataChild) /* -------  rec, set */
				newElement = (ElementPtr) db_createNewRecord(toRec, key, flags,
				                              direction == GOING_DOWN ? NULL : toElement, &error);
			else { /* ----------------------------------------------------  int, str, mem */
				/* Read data */
				if ((flags & DB_mask_type) == DB_flag_int)                /* int */
					wap_cvt_uint32(&obj, &data.i);
				else {
					wap_cvt_uint16(&obj, &len);
					if ((flags & DB_mask_type) == DB_flag_mem) {            /* mem */
						obj.pos -= 2; /* The length is to be included in the copy */
						len += 2;
					}
					wap_cvt_bytevector(&obj, len, &data.s);
					if ((flags & DB_mask_type) == DB_flag_mem) {            /* mem */
						*(UINT16*) data.s = len; /* Maybe different endian */
					}
				}

				newElement = db_createNewElement(toRec, key, flags, data,
				                              direction == GOING_DOWN ? NULL : toElement, NULL, &error);
			}

			if (error != DB_err_success)
				return FALSE;

			toElement = newElement;
		}

		/* Move to next element */
		if (direction != GOING_UP && flags & DB_mask_hasChild) {
			direction = GOING_DOWN;
			toRec = (RecordPtr) toElement;
		} else {
			if (! (toElement->flags & DB_mask_lastElement2) || toRec == db_root) {
				/* Note: check lastElement2 instead of lastElement since
				 * lastElement is recalculated in db_createNewRecord
				 * and db_createNewElement. lastElement2 is what is found
				 * on persistent memory, lastElement is the current status.*/
				direction = GOING_RIGHT;
			} else {
				direction = GOING_UP;
				toElement = toElement->next;
				toRec = (RecordPtr) toRec->next;
			}
		}
	}


	OSConnectorFree(buf);
	return TRUE;
}



/*
 * Load database from persistent memory and rebuld structure.
 * Only elements saved as backup are recovered.
 *
 * Return FALSE if there is nothing to load.
 */
static BOOL 
db_loadDB_bu (void)
{
	int dummy;

	if (! Storage_Get(&store, 1023, 0, 0, &dummy))
		return FALSE;
	if (! db_rebuildDB_bu()) {
	}
	return FALSE;
}


⌨️ 快捷键说明

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