File: blob_funcs.cpp
Size: 8653
Date: Tue, 08 May 2012 23:13:40 +0200
Type: cpp
#include "pbvm.h"

BOOL copy_val_ptr(vm_state *vm, value *val, blob *b, DWORD &pos, int size, bool field){
	void *dest,*src;

	if (pos+size -1 > b->len) return FALSE;
	
	if (val->flags&IS_NULL||field){
		dest=(void *)pbstg_alc(vm, size, GET_HEAP(vm));
		val->value = (DWORD)dest;
		val->flags = val->flags - IS_NULL;
	}else{
		dest=(void *)val->value;
	}
	src=(void*)(b->data+pos -1);

	memcpy(dest, src, size);
	pos+=size;

	return TRUE;
}

BOOL extract(vm_state *vm, value *val, blob *b, DWORD &pos, bool field){
	if (pos > b->len) return FALSE;

	if (val->flags & IS_ARRAY){
		long count;
		value *v;
		pb_array *parray=(pb_array *)val->value;
		count=ot_array_num_items(vm, parray);
		for (long i=0;i<count;i++){
			v=ot_array_index(vm, parray, i);
			if (!extract(vm, v, b, pos, false)) return FALSE;
		}
		return TRUE;
	}

	if (val->type & 0xC000){
		long fields, first;
		value field;
		pb_class *pclass = (pb_class *)val->value;
		fields = ob_get_no_fields(vm, pclass);
		first = ob_get_first_user_field(vm, pclass);

		for (int i=first;i<fields;i++){
			ob_get_field(vm, pclass, i, &field);
			if (!extract(vm, &field, b, pos, true)) return FALSE;
			if (!(field.flags & IS_ARRAY)){
				ob_set_field(vm, pclass, i, &field);
			}
		}
		return TRUE;
	}
	
	//TODO, ansi / unicode conversions....

	switch(val->type){
		case pbvalue_int:
		case pbvalue_boolean:
		case pbvalue_uint:
		case pbvalue_char:
			{
				if (pos+1 > b->len) return FALSE;

				short *p = (short *)&b->data[pos -1];
				val->value = *p;
				val->flags=0x500;
				pos+=2;
			}
			return TRUE;

		case pbvalue_byte:
			{
				if (pos > b->len) return FALSE;

				char *p = (char *)&b->data[pos -1];
				val->value = *p;
				pos++;
			}
			return TRUE;

		case pbvalue_long:
		case pbvalue_ulong:
			{
				if (pos+3 > b->len) return FALSE;

				long *p = (long *)&b->data[pos -1];
				val->value = *p;
				val->flags=0x1d00;
				pos+=4;
			}
			return TRUE;

		case pbvalue_real:
			{
				if (pos+3 > b->len) return FALSE;

				long *p = (long *)&b->data[pos -1];
				val->value = *p;
				val->flags=0x0900;
				pos+=4;
			}
			return TRUE;
		case pbvalue_string:
			{
				int len;
				wchar_t *dest, *src;

				len=(b->len - pos +1)/2;
				src=(wchar_t*)(b->data+pos -1);
				len=wcsnlen(src, len);
				
				dest=(wchar_t *)pbstg_alc(vm, (len+1) *2, GET_HEAP(vm));

				if ((!field)&&(!(val->flags&IS_NULL)))
					ot_free_val_ptr(vm, val);

				val->value = (DWORD)dest;
				val->flags = 0x0d00;

				wcsncpy(dest, src, len);
				dest[len]=0;
				pos+=(len+1)*2;
			}
			return TRUE;

		case pbvalue_longlong:
		case pbvalue_double:
			return copy_val_ptr(vm, val, b, pos, 8, field);
		case pbvalue_dec:
			return copy_val_ptr(vm, val, b, pos, 16, field);
		case pbvalue_date:
		case pbvalue_time:
		case pbvalue_datetime:
			return copy_val_ptr(vm, val, b, pos, 12, field);
	}
	return FALSE;
}

// boolean blob_extract(ref any value, readonly blob data, ref ulong al_pos)
DWORD __declspec(dllexport) __stdcall Blob_Extract (vm_state *vm, DWORD arg_count){
	DWORD isnull;
	lvalue_ref *lv_val, *lv_pos;
	value ret, *val, *v_pos;
	blob *source;

	last_vm = vm;

	lv_val = ot_get_next_lvalue_arg(vm,&isnull);
	val = get_lvalue(vm, lv_val);

	source = (blob *)ot_get_valptr_arg(vm, &isnull);

	lv_pos=ot_get_next_lvalue_arg(vm, &isnull);
	v_pos = get_lvalue(vm, lv_pos);

	ret.value=extract(vm, val, source, v_pos->value, false);

	ret.type=pbvalue_boolean;
	ret.flags=0x500;

	ot_assign_ref_long(vm, lv_pos->ptr, v_pos->value, 0);
	ot_set_return_val(vm, &ret);
	return 1;
}

// PB10 only util function
DWORD __declspec(dllexport) __stdcall Get_Byte_Array (vm_state *vm, DWORD arg_count){
	DWORD start=0, len, isnull;
	blob *source;
	value ret;

	last_vm = vm;

	source=(blob *)ot_get_valptr_arg(vm, &isnull);
	len=source->len;
	if (arg_count>=2){
		start=ot_get_ulongarg(vm, &isnull) -1;
		if (start<0) start=0;
		len -= start;
		if (arg_count>=3){
			len=ot_get_ulongarg(vm, &isnull);
			if (len + start > source->len) len=source->len - start;
			if (len<0) len=0;
		}
	}
	
	pb_array *parray=ot_array_create_unbounded(vm, MAKELONG(-1,pbvalue_uint), 0);
	ret.value = (DWORD)parray;
	ret.type = pbvalue_uint;
	ret.flags = IS_ARRAY;
	
	for (DWORD i=0;i<len;i++){
		value *v=ot_array_index(vm, parray, i);
			
		v->value=source->data[start+i] & 0xFF;
		v->flags=0x0d00;
		v->type=pbvalue_uint;
	}
	ot_set_return_val(vm, &ret);
	return 1;
}

void expand_blob(vm_state *vm, value *bv, DWORD len){
	blob *b = (blob*)bv->value;
	if (b->len >= len) return;

	DWORD buff_size = pbstg_sz(vm, b);

	if (len+4 > buff_size){
		buff_size = len+4;
		if (buff_size>6144)
			buff_size|=0xFFF;

		b = (blob *)pbstg_realc(vm, b, buff_size, GET_HEAP(vm));
		bv->value = (DWORD)b;
	}
	b->len = len;
}

BOOL import(vm_state *vm, value *val, value *bv, DWORD &pos){
	if (val->flags&IS_NULL) return FALSE;

	if (val->flags & IS_ARRAY){
		long count;
		value *v;
		pb_array *parray=(pb_array *)val->value;
		count=ot_array_num_items(vm, parray);
		for (long i=0;i<count;i++){
			v=ot_array_index(vm, parray, i);
			if (!import(vm, v, bv, pos)) return FALSE;
		}
		return TRUE;
	}

	if (val->type & 0xC000){
		long fields, first;
		value field;
		pb_class *pclass=(pb_class *)val->value;
		fields = ob_get_no_fields(vm, pclass);
		first = ob_get_first_user_field(vm, pclass);

		for (int i=first;i<fields;i++){
			ob_get_field(vm, pclass, i, &field);
			if (!import(vm, &field, bv, pos)) return FALSE;
		}
		return TRUE;
	}

	int len;
	char *p;

	switch(val->type){
		case pbvalue_int:
		case pbvalue_boolean:
		case pbvalue_uint:
		case pbvalue_char:
			len=2;
			p=(char*)&val->value;
			break;
		case pbvalue_byte:
			len=1;
			p=(char*)&val->value;
			break;
		case pbvalue_long:
		case pbvalue_ulong:
		case pbvalue_real:
			len=4;
			p=(char*)&val->value;
			break;
		case pbvalue_string:
			len = (wcslen((wchar_t *)val->value)+1)*2;
			p=(char*)val->value;
			break;
		case pbvalue_longlong:
		case pbvalue_double:
			len=8;
			p=(char*)val->value;
			break;
		case pbvalue_dec:
			len=16;
			p=(char*)val->value;
			break;
		case pbvalue_date:
		case pbvalue_time:
		case pbvalue_datetime:
			len=12;
			p=(char*)val->value;
			break;
		case pbvalue_blob:
			{
				blob *b = (blob *)val->value;
				len=b->len;
				p=(char*)&b->data;
			}
	}

	expand_blob(vm, bv, pos+len-1);
	blob *b = (blob *)bv->value;

	memcpy(b->data+pos -1, p, len);
	pos+=len;
	return TRUE;
}

// boolean blob_import(readonly any value, ref blob data, ref ulong al_pos)
DWORD __declspec(dllexport) __stdcall Blob_Import (vm_state *vm, DWORD arg_count){
	DWORD isnull;
	DWORD pos;
	value ret;
	lvalue_ref *lv_pos;
	value *v_pos;

	last_vm = vm;

	value *v_value = ot_get_next_evaled_arg_no_convert(vm);

	lvalue_ref *lv_data = ot_get_next_lvalue_arg(vm,&isnull);
	value *data = get_lvalue(vm, lv_data);

	if (arg_count==3){
		lv_pos=ot_get_next_lvalue_arg(vm, &isnull);
		v_pos = get_lvalue(vm, lv_pos);
		pos=v_pos->value;
	}else{
		pos=((blob *)data->value)->len +1;
	}

	ret.value=import(vm, v_value, data, pos);
	ret.type=pbvalue_boolean;
	ret.flags=0x500;
	
	if (arg_count==3){
		v_pos->value=pos;
		ot_assign_ref_long(vm, lv_pos->ptr, v_pos->value, 0);
	}
	ot_set_return_val(vm, &ret);
	return 1;
}

DWORD __declspec(dllexport) __stdcall Blob_Mid (vm_state *vm, DWORD arg_count){
	DWORD start, len, isnull;
	blob *source, *dest;
	value v;

	last_vm = vm;

	source = (blob *)ot_get_valptr_arg(vm, &isnull);
	if (isnull || source==NULL || source->len==0){
		len =0;
	}else{
		start=ot_get_ulongarg(vm, &isnull);
		if (isnull||start<1) start=1;
		if (start>source->len){
			len=0;
		}else{
			if (arg_count>=3){
				len=ot_get_ulongarg(vm, &isnull);
				if (isnull) len=0;
				if (len>source->len - start+1) len = source->len - start+1;
			}else{
				len=source->len - start+1;
			}
		}
	}

	v.type=pbvalue_blob;
	v.flags=0xd00;
	
	dest = (blob *)pbstg_alc(vm, len +5, GET_HEAP(vm));
	dest->len=len;
	v.value=(DWORD)dest;
	if (len>0)
		memcpy(&dest->data[0], &source->data[start -1], len);
	ot_set_return_val(vm, &v);
	return 1;
}

DWORD __declspec(dllexport) __stdcall Blob_Alloc (vm_state *vm, DWORD arg_count){
	DWORD isnull, new_size;
	blob *dest;
	int zero_memory=FALSE;
	value v;

	last_vm = vm;

	new_size=ot_get_ulongarg(vm, &isnull);
	if (isnull) new_size=0;
	
	if (arg_count>=2){
		zero_memory=ot_get_simple_intarg(vm, &isnull);
		if (isnull) zero_memory=FALSE;
	}

	v.type=pbvalue_blob;
	v.flags=0xd00;
	
	dest = (blob *)pbstg_alc(vm, new_size +5, GET_HEAP(vm));
	dest->len=new_size;
	if (zero_memory){
		ZeroMemory(&dest->data[0],new_size);
	}
	v.value=(DWORD)dest;

	ot_set_return_val(vm, &v);
	return 1;
}