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;
}