Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  serialize.c   Sprache: C

 
/****************************************************************************
**
**  This file is part of GAP, a system for computational discrete algebra.
**
**  Copyright of GAP belongs to its developers, whose names are too numerous
**  to list here. Please refer to the COPYRIGHT file for details.
**
**  SPDX-License-Identifier: GPL-2.0-or-later
*/


#include "serialize.h"

#include "../bool.h"
#include "../calls.h"
#include "../error.h"
#include "../gvars.h"
#include "../modules.h"
#include "../objset.h"
#include "../plist.h"
#include "../precord.h"
#include "../rational.h"
#include "../records.h"
#include "../stringobj.h"
#include "../trycatch.h"

#include "aobjects.h"

#include <stdio.h>

typedef struct SerializerState {
    Obj                   stack;
    Obj    obj;
    UInt   index;
    SerializerInterface * dispatcher;
    Obj    registry;
} SerializerState;

typedef struct DeserializerState {
    Obj                     stack;
    Obj                     obj;
    UInt                    index;
    DeserializerInterface * dispatcher;
} DeserializerState;


#ifndef WARD_ENABLED

static SerializationFunction   SerializationFuncByTNum[256];
static DeserializationFunction DeserializationFuncByTNum[256];


// Native string serialization

static void
WriteBytesNativeString(SerializerState * state, void * addr, UInt count)
{
    Obj  target = state->obj;
    UInt size = GET_LEN_STRING(target);
    GROW_STRING(target, size + count + 1);
    memcpy(CSTR_STRING(target) + size, addr, count);
    SET_LEN_STRING(target, size + count);
}

static void WriteTNumNativeString(SerializerState * state, UInt tnum)
{
    UChar buf[1];
    buf[0] = (UChar)tnum;
    WriteBytesNativeString(state, buf, 1);
}

static void WriteByteNativeString(SerializerState * state, UChar byte)
{
    UChar buf[1];
    buf[0] = (UChar)byte;
    WriteBytesNativeString(state, buf, 1);
}

#define ADDR_BYTE(obj) ((UChar *)ADDR_OBJ(obj))

static void WriteByteBlockNativeString(SerializerState * state,
                                       Obj               obj,
                                       UInt              offset,
                                       UInt              len)
{
    WriteBytesNativeString(state, &len, sizeof(len));
    WriteBytesNativeString(state, ADDR_BYTE(obj) + offset, len);
}

static void WriteImmediateObjNativeString(SerializerState * state, Obj obj)
{
    WriteBytesNativeString(state, &obj, sizeof(obj));
}

static SerializerInterface NativeStringSerializer = {
    WriteTNumNativeString,
    WriteByteNativeString,
    WriteByteBlockNativeString,
    WriteImmediateObjNativeString,
};

// Native string deserialization

static void
ReadBytesNativeString(DeserializerState * state, void * addr, UInt size)
{
    Obj  str = state->obj;
    UInt max = GET_LEN_STRING(str);
    UInt off = state->index;
    if (off + size > max)
        ErrorQuit("ReadBytesNativeString: Bad deserialization input", 0, 0);
    memcpy(addr, CONST_CSTR_STRING(str) + off, size);
    state->index += size;
}

static UInt ReadTNumNativeString(DeserializerState * state)
{
    UChar buf[1];
    ReadBytesNativeString(state, buf, 1);
    return buf[0];
}

static UChar ReadByteNativeString(DeserializerState * state)
{
    UChar buf[1];
    ReadBytesNativeString(state, buf, 1);
    return buf[0];
}

static UInt ReadByteBlockLengthNativeString(DeserializerState * state)
{
    UInt len;
    ReadBytesNativeString(state, &len, sizeof(len));
    /* The following is to prevent out-of-memory errors on malformed input,
     * where incorrect values can result in huge length values: */

    if (len + state->index > GET_LEN_STRING(state->obj))
        ErrorQuit("ReadByteBlockLengthNativeString: Bad deserialization input", 0, 0);
    return len;
}

static void ReadByteBlockDataNativeString(DeserializerState * state,
                                          Obj                 obj,
                                          UInt                offset,
                                          UInt                len)
{
    ReadBytesNativeString(state, ADDR_BYTE(obj) + offset, len);
}

static Obj ReadImmediateObjNativeString(DeserializerState * state)
{
    Obj obj;
    ReadBytesNativeString(state, &obj, sizeof(obj));
    return obj;
}

static DeserializerInterface NativeStringDeserializer = {
    ReadTNumNativeString,
    ReadByteNativeString,
    ReadByteBlockLengthNativeString,
    ReadByteBlockDataNativeString,
    ReadImmediateObjNativeString,
};

// Dispatch functions

static inline void WriteTNum(SerializerState * state, UInt tnum)
{
    state->dispatcher->WriteTNum(state, tnum);
}

static inline void WriteByte(SerializerState * state, UChar byte)
{
    state->dispatcher->WriteByte(state, byte);
}

static inline void
WriteByteBlock(SerializerState * state, Obj obj, UInt offset, UInt len)
{
    state->dispatcher->WriteByteBlock(state, obj, offset, len);
}

static inline void WriteImmediateObj(SerializerState * state, Obj obj)
{
    state->dispatcher->WriteImmediateObj(state, obj);
}

static inline UInt ReadTNum(DeserializerState * state)
{
    return state->dispatcher->ReadTNum(state);
}

static inline UChar ReadByte(DeserializerState * state)
{
    return state->dispatcher->ReadByte(state);
}

static inline UInt ReadByteBlockLength(DeserializerState * state)
{
    return state->dispatcher->ReadByteBlockLength(state);
}

static inline void
ReadByteBlockData(DeserializerState * state, Obj obj, UInt offset, UInt len)
{
    state->dispatcher->ReadByteBlockData(state, obj, offset, len);
}

static inline Obj ReadImmediateObj(DeserializerState * state)
{
    return state->dispatcher->ReadImmediateObj(state);
}

// Auxiliary serialization/deserialization functions

static void SerializeBinary(SerializerState * state, Obj obj)
{
    WriteTNum(state, TNUM_OBJ(obj));
    WriteByteBlock(state, obj, 0, SIZE_OBJ(obj));
}

static Obj DeserializeBinary(DeserializerState * state, UInt tnum)
{
    UInt len = ReadByteBlockLength(state);
    Obj  result = NewBag(tnum, len);
    ReadByteBlockData(state, result, 0, len);
    return result;
}

static inline BOOL IsBasicObj(Obj obj)
{
    // FIXME: hard coding T_MACFLOAT like this seems like a bad idea
    return !obj || TNUM_OBJ(obj) <= T_MACFLOAT;
}

#define T_BACKREF 255
#define OBJ_BACKREF(x) ((Obj)((x) << 2))
#define BACKREF_OBJ(obj) (((UInt)(obj)) >> 2)

static int SerializedAlready(SerializerState * state, Obj obj)
{
    Obj ref = LookupObjMap(state->registry, obj);
    if (ref) {
        WriteTNum(state, T_BACKREF);
        WriteImmediateObj(state, OBJ_BACKREF(INT_INTOBJ(ref)));
        return 1;
    }
    else {
        state->index++;
        AddObjMap(state->registry, obj, INTOBJ_INT(state->index));
        return 0;
    }
}

// TNum-specific serialization/deserialization functions

static void RegisterSerializerFunctions(UInt                    tnum,
                                        SerializationFunction   sfun,
                                        DeserializationFunction dfun)
{
    SerializationFuncByTNum[tnum] = sfun;
    DeserializationFuncByTNum[tnum] = dfun;
}

static void SerializeObj(SerializerState * state, Obj obj)
{
    if (!obj) {
        // Handle unbound list elements correctly
        WriteTNum(state, T_BACKREF);
        WriteImmediateObj(state, INTOBJ_INT(0));
        return;
    }
    SerializationFuncByTNum[TNUM_OBJ(obj)](state, obj);
}

static Obj DeserializeObj(DeserializerState * state)
{
    UInt tnum = ReadTNum(state);
    return DeserializationFuncByTNum[tnum](state, tnum);
}

static void SerializeInt(SerializerState * state, Obj obj)
{
    Int n = INT_INTOBJ(obj);
    WriteTNum(state, T_INT);
    if (n >= -32 && n <= 31) {
        WriteByte(state, ((n + 32) << 2) + 1);
    }
    else if (n >= -8192 && n <= 8191) {
        n += 8192;
        WriteByte(state, ((n >> 8) << 2) + 2);
        WriteByte(state, n & 0xff);
    }
    else {
        WriteByte(state, 0);
        WriteImmediateObj(state, obj);
    }
}

static Obj DeserializeInt(DeserializerState * state, UInt tnum)
{
    Int n = ReadByte(state);
    switch (n & 3) {
    case 1:
        n >>= 2;
        n -= 32;
        return INTOBJ_INT(n);
    case 2:
        n >>= 2;
        n <<= 8;
        n += ReadByte(state);
        n -= 8192;
        return INTOBJ_INT(n);
    default:
        if (n)
            ErrorQuit("DeserializeInt: Bad deserialization input (n = %d)", n, 0);
        return ReadImmediateObj(state);
    }
}

static void SerializeRat(SerializerState * state, Obj obj)
{
    WriteTNum(state, TNUM_OBJ(obj));
    SerializeObj(state, NUM_RAT(obj));
    SerializeObj(state, DEN_RAT(obj));
}

static Obj DeserializeRat(DeserializerState * state, UInt tnum)
{
    Obj result, n, d;
    n = DeserializeObj(state);
    d = DeserializeObj(state);
    result = NewBag(tnum, 2 * sizeof(Obj));
    SET_NUM_RAT(result, n);
    SET_DEN_RAT(result, d);
    return result;
}

static void SerializeFFE(SerializerState * state, Obj obj)
{
    UInt ffe = (UInt)obj;
    WriteTNum(state, T_FFE);
    WriteByte(state, (ffe >> 24) & 0xff);
    WriteByte(state, (ffe >> 16) & 0xff);
    WriteByte(state, (ffe >> 8) & 0xff);
    WriteByte(state, ffe & 0xff);
}

static Obj DeserializeFFE(DeserializerState * state, UInt tnum)
{
    UInt ffe = 0;
    ffe = ReadByte(state);
    ffe <<= 8;
    ffe |= ReadByte(state);
    ffe <<= 8;
    ffe |= ReadByte(state);
    ffe <<= 8;
    ffe |= ReadByte(state);
    return (Obj)ffe;
}

static void SerializeChar(SerializerState * state, Obj obj)
{
    UChar ch = CHAR_VALUE(obj);
    WriteTNum(state, T_CHAR);
    WriteByte(state, ch);
}

static Obj DeserializeChar(DeserializerState * state, UInt tnum)
{
    UChar ch = ReadByte(state);
    return ObjsChar[ch];
}

// Defines from cyclotom.c:
#define SIZE_CYC(cyc) (SIZE_OBJ(cyc) / (sizeof(Obj) + sizeof(UInt4)))
#define COEFS_CYC(cyc) (ADDR_OBJ(cyc))
#define EXPOS_CYC(cyc, len) ((UInt4 *)(ADDR_OBJ(cyc) + (len)))

static void SerializeCyc(SerializerState * state, Obj obj)
{
    UInt len, i;
    WriteTNum(state, T_CYC);
    len = SIZE_CYC(obj);
    WriteImmediateObj(state, INTOBJ_INT(len));
    for (i = 0; i < len; i++) {
        SerializeObj(state, COEFS_CYC(obj)[i]);
    }
    for (i = 1; i < len; i++) {
        WriteImmediateObj(state, INTOBJ_INT(EXPOS_CYC(obj, len)[i]));
    }
}

static Obj DeserializeCyc(DeserializerState * state, UInt tnum)
{
    Obj  result;
    UInt i, len;
    len = INT_INTOBJ(ReadImmediateObj(state));
    result = NewBag(T_CYC, len * (sizeof(Obj) + sizeof(UInt4)));
    for (i = 0; i < len; i++)
        COEFS_CYC(result)[i] = DeserializeObj(state);
    for (i = 1; i < len; i++)
        EXPOS_CYC(result, len)[i] = INT_INTOBJ(ReadImmediateObj(state));
    return result;
}

static void SerializeBool(SerializerState * state, Obj obj)
{
    WriteTNum(state, T_BOOL);
    if (obj == False) {
        WriteByte(state, 0);
    }
    else if (obj == True) {
        WriteByte(state, 1);
    }
    else if (obj == Fail) {
        WriteByte(state, 2);
    }
    else
        ErrorQuit("Internal serialization error: Bad boolean value", 0, 0);
}

static Obj DeserializeBool(DeserializerState * state, UInt tnum)
{
    UChar byte = ReadByte(state);
    switch (byte) {
    case 0:
        return False;
    case 1:
        return True;
    case 2:
        return Fail;
    default:
        ErrorQuit("DeserializeBool: Bad deserialization input %d", (Int)byte, 0);
        return (Obj)0; // flow control hint
    }
}

static void SerializeList(SerializerState * state, Obj obj)
{
    UInt i, j, len;
    if (SerializedAlready(state, obj))
        return;
    len = LEN_PLIST(obj);
    WriteTNum(state, TNUM_OBJ(obj));
    WriteImmediateObj(state, INTOBJ_INT(len));
    for (i = 1; i <= len; i++) {
        Obj el = ELM_PLIST(obj, i);
        if (IsBasicObj(el))
            SerializeObj(state, el);
        else {
            break;
        }
    }
    for (j = len; j >= i; j--) {
        Obj el = ELM_PLIST(obj, j);
        PushPlist(state->stack, el);
    }
}

static Obj DeserializeList(DeserializerState * state, UInt tnum)
{
    UInt i, len = INT_INTOBJ(ReadImmediateObj(state));
    Obj  result = NEW_PLIST(tnum, len);
    SET_LEN_PLIST(result, len);
    PushPlist(state->stack, result);
    for (i = 1; i <= len; i++)
        SET_ELM_PLIST(result, i, DeserializeObj(state));
    return result;
}

static void SerializeObjSet(SerializerState * state, Obj obj)
{
    UInt i, len;
    if (SerializedAlready(state, obj))
        return;
    len = (UInt)(ADDR_OBJ(obj)[OBJSET_USED]);
    WriteTNum(state, TNUM_OBJ(obj));
    WriteImmediateObj(state, INTOBJ_INT(len));
    len = (UInt)(ADDR_OBJ(obj)[OBJSET_SIZE]);
    for (i = 0; i < len; i++) {
        Obj el = ADDR_OBJ(obj)[OBJSET_HDRSIZE + i];
        if (!el || el == Undefined)
            continue;
        if (IsBasicObj(el))
            SerializeObj(state, el);
        else {
            PushPlist(state->stack, el);
        }
    }
}

static Obj DeserializeObjSet(DeserializerState * state, UInt tnum)
{
    UInt i, len = INT_INTOBJ(ReadImmediateObj(state));
    Obj  result = NewObjSet();
    PushPlist(state->stack, result);
    for (i = 1; i <= len; i++)
        AddObjSet(result, DeserializeObj(state));
    return result;
}

static void SerializeObjMap(SerializerState * state, Obj obj)
{
    UInt i, len;
    if (SerializedAlready(state, obj))
        return;
    len = (UInt)(ADDR_OBJ(obj)[OBJSET_USED]);
    WriteTNum(state, TNUM_OBJ(obj));
    WriteImmediateObj(state, INTOBJ_INT(len));
    len = (UInt)(ADDR_OBJ(obj)[OBJSET_SIZE]);
    for (i = 0; i < len; i++) {
        Obj key = ADDR_OBJ(obj)[OBJSET_HDRSIZE + 2 * i];
        Obj val = ADDR_OBJ(obj)[OBJSET_HDRSIZE + 2 * i + 1];
        if (!key || key == Undefined)
            continue;
        if (IsBasicObj(key) && IsBasicObj(val)) {
            SerializeObj(state, key);
            SerializeObj(state, val);
        }
        else {
            PushPlist(state->stack, val);
            PushPlist(state->stack, key);
        }
    }
}

static Obj DeserializeObjMap(DeserializerState * state, UInt tnum)
{
    UInt i, len = INT_INTOBJ(ReadImmediateObj(state));
    Obj  result = NewObjMap();
    PushPlist(state->stack, result);
    for (i = 1; i <= len; i++) {
        Obj key = DeserializeObj(state);
        Obj val = DeserializeObj(state);
        AddObjMap(result, key, val);
    }
    return result;
}

static void SerializeRecord(SerializerState * state, Obj obj)
{
    UInt i, j, len;
    if (SerializedAlready(state, obj))
        return;
    WriteTNum(state, TNUM_OBJ(obj));
    len = LEN_PREC(obj);
    WriteImmediateObj(state, INTOBJ_INT(len));
    for (i = 1; i <= len; i++) {
        // get the rnam, which may be negative (if the record was sorted)
        Int rnam = GET_RNAM_PREC(obj, i);
        // since rnams can change across sessions, we store only its name
        Obj rnams = NAME_RNAM(rnam >= 0 ? rnam : -rnam);
        WriteByteBlock(state, rnams, sizeof(UInt), GET_LEN_STRING(rnams));
    }
    for (i = 1; i <= len; i++) {
        Obj el = GET_ELM_PREC(obj, i);
        if (IsBasicObj(el))
            SerializeObj(state, el);
        else {
            break;
        }
    }
    for (j = len; j >= i; j--) {
        Obj el = GET_ELM_PREC(obj, j);
        PushPlist(state->stack, el);
    }
}

static Obj DeserializeRecord(DeserializerState * state, UInt tnum)
{
    UInt i, len = INT_INTOBJ(ReadImmediateObj(state));
    Obj  result = NEW_PREC(len);
    Obj  rnams = NEW_STRING(11);
    SET_LEN_PREC(result, len);
    PushPlist(state->stack, result);
    for (i = 1; i <= len; i++) {
        UInt rnam, rnamlen = ReadByteBlockLength(state);
        GROW_STRING(rnams, rnamlen + 1);
        ReadByteBlockData(state, rnams, sizeof(Obj), rnamlen);
        CSTR_STRING(rnams)[rnamlen] = '\0';
        rnam = RNamName(CONST_CSTR_STRING(rnams));
        SET_RNAM_PREC(result, i, rnam);
    }
    for (i = 1; i <= len; i++) {
        Obj el = DeserializeObj(state);
        SET_ELM_PREC(result, i, el);
    }
    SortPRecRNam(result);
    if (tnum == T_PREC + IMMUTABLE)
        RetypeBag(result, tnum);
    return result;
}

static void SerializeString(SerializerState * state, Obj obj)
{
    if (SerializedAlready(state, obj))
        return;
    WriteTNum(state, TNUM_OBJ(obj));
    WriteByteBlock(state, obj, sizeof(UInt), GET_LEN_STRING(obj));
}

static Obj DeserializeString(DeserializerState * state, UInt tnum)
{
    UInt len = ReadByteBlockLength(state);
    Obj  result = NewBag(tnum, SIZEBAG_STRINGLEN(len));
    SET_LEN_STRING(result, len);
    ReadByteBlockData(state, result, sizeof(UInt), len);
    CSTR_STRING(result)[len] = '\0';
    PushPlist(state->stack, result);
    return result;
}

static void SerializeBlist(SerializerState * state, Obj obj)
{
    if (SerializedAlready(state, obj))
        return;
    WriteTNum(state, TNUM_OBJ(obj));
    WriteByteBlock(state, obj, 0, SIZE_OBJ(obj));
}

static Obj DeserializeBlist(DeserializerState * state, UInt tnum)
{
    UInt len = ReadByteBlockLength(state);
    Obj  result = NewBag(tnum, len);
    ReadByteBlockData(state, result, 0, len);
    PushPlist(state->stack, result);
    return result;
}

static void SerializeRange(SerializerState * state, Obj obj)
{
    WriteTNum(state, TNUM_OBJ(obj));
    WriteImmediateObj(state, ADDR_OBJ(obj)[0]);
    WriteImmediateObj(state, ADDR_OBJ(obj)[1]);
    WriteImmediateObj(state, ADDR_OBJ(obj)[2]);
}

static Obj DeserializeRange(DeserializerState * state, UInt tnum)
{
    Obj result, r1, r2, r3;
    r1 = ReadImmediateObj(state);
    r2 = ReadImmediateObj(state);
    r3 = ReadImmediateObj(state);
    result = NewBag(tnum, 3 * sizeof(Obj));
    ADDR_OBJ(result)[0] = r1;
    ADDR_OBJ(result)[1] = r2;
    ADDR_OBJ(result)[2] = r3;
    return result;
}

static GVarDescriptor SerializableRepresentationGVar;
static GVarDescriptor TYPE_UNKNOWN_GVar;
static GVarDescriptor DESERIALIZER_GVar;
static GVarDescriptor SERIALIZATION_TAG_GVar;
static GVarDescriptor DESERIALIZATION_TAG_INT_GVar;
static GVarDescriptor DESERIALIZATION_TAG_STRING_GVar;
static GVarDescriptor SERIALIZATION_UPDATE_TAGS_GVar;
static GVarDescriptor SERIALIZATION_TAGS_NEED_UPDATE_GVar;

static void SerRepError(void)
{
    ErrorQuit("SerializableRepresentation must return a list prefixed by a "
              "string or integer and string",
              0, 0);
}

static Obj PosObjToList(Obj obj)
{
    UInt i, len = SIZE_OBJ(obj) / sizeof(Obj) - 1;
    Obj  result = NEW_PLIST(T_PLIST, len);
    SET_LEN_PLIST(result, len);
    for (i = 1; i <= len; i++)
        SET_ELM_PLIST(result, i, ELM_PLIST(obj, i));
    return result;
}

/**
 *  Serialization of Typed Objects
 *  ------------------------------
 *
 *  Typed objects -- i.e., those with the T_DATOBJ, T_POSOBJ, or T_COMOBJ
 *  types that contain a type object to guide method selection -- require a
 *  special approach to serialization, as we cannot serialize the type objects
 *  themselves. Not only would that add considerable overhead, type objects
 *  are required to be unique for each type.
 *
 *  The easiest way is to associate a globally unique integer or string tag
 *  with each type for which objects need to be serialized. The global
 *  variable `SERIALIZATION_TAG` maps the unique numeric id of each type
 *  object to its corresponding tag. The global variables
 *  `DESERIALIZATION_TAG_INT` and `DESERIALIZATION_TAG_STRING` reverse this
 *  mapping.
 *
 *  It is recommended to use this approach whenever possible, because it is
 *  usually faster than the alternatives.
 *
 *  This mechanism is not always sufficient. For example, objects may contain
 *  attributes that would add excessive extra payload to the serialization
 *  process and may not be properly integrated with global data structures at
 *  the receiving end.
 *
 *  Thus, we also support a more general process to convert an object into a
 *  serializable representation. To that end, one needs to install a method
 *  `SerializableRepresentation` for such a type. This method must return a
 *  list using a specific format.
 *
 */


static Obj LookupIntTag(Obj tag)
{
    Obj map = GVarObj(&DESERIALIZATION_TAG_INT_GVar);
    Obj func = (Obj)0;
    Obj result;
retry:
    switch (map ? TNUM_OBJ(map) : -1) {
    case T_OBJMAP:
    case T_OBJMAP + IMMUTABLE:
        result = LookupObjMap(map, tag);
        if (result || func)
            return result;
        if (GVarObj(&SERIALIZATION_TAGS_NEED_UPDATE_GVar) == False)
            return (Obj)0;
        func = GVarFunction(&SERIALIZATION_UPDATE_TAGS_GVar);
        if (!func)
            return (Obj)0;
        CALL_0ARGS(func);
        map = GVarObj(&DESERIALIZATION_TAG_INT_GVar);
        goto retry; // more readable than a loop around the switch
    default:
        ErrorQuit("Deserialization tag map for int tags is corrupted", 0, 0);
        return (Obj)0; // flow control hint
    }
}

static Obj DeserializeTypedObj(DeserializerState * state, UInt tnum)
{
    UInt namelen, len, i;
    Obj  name, args, deserialization_rec, func, type, tag;
    Obj  result;
    UInt rnam, tagtnum;
    tagtnum = ReadTNum(state);
    switch (tagtnum) {
    case T_INT:
    case T_STRING:
    case T_STRING + IMMUTABLE:
        if (tagtnum == T_INT) {
            tag = DeserializeInt(state, T_INT);
            type = LookupIntTag(tag);
        }
        else {
            tag = DeserializeString(state, T_STRING);
            rnam = RNamObj(tag);
            type = ELM_REC(GVarObj(&DESERIALIZATION_TAG_STRING_GVar), rnam);
        }
        if (!type || TNUM_OBJ(type) != T_POSOBJ)
            ErrorQuit("DeserializeTypedObj: Failed to deserialize type", 0, 0);
        switch (tnum) {
        case T_DATOBJ:
            len = ReadByteBlockLength(state);
            result = NewBag(T_DATOBJ, len + sizeof(Obj));
            ReadByteBlockData(state, result, sizeof(Obj), len);
            break;
        case T_POSOBJ:
            result = DeserializeObj(state);
            if (!IS_PLIST(result))
                ErrorQuit("DeserializeTypedObj: expected plist, got %s", (Int)TNAM_OBJ(result), 0);
            break;
        case T_PREC:
            result = DeserializeObj(state);
            if (TNUM_OBJ(result) != T_COMOBJ)
                ErrorQuit("DeserializeTypedObj: expected component object, got %s", (Int)TNAM_OBJ(result), 0);
            break;
        default:
            ErrorQuit("DeserializeTypedObj: unexpected tnum %d (%s)", tnum, (Int)TNAM_TNUM(tnum));
            return (Obj)0; // flow control hint
        }
        SET_TYPE_OBJ(result, type);
        return result;
    case T_PLIST:
        // continue on to the more general deserialization method
        break;
    default:
        ErrorQuit("DeserializeTypedObj: unexpected tagtnum ", tagtnum, (Int)TNAM_TNUM(tagtnum));
        return (Obj)0; // flow control hint
    }
    namelen = ReadByteBlockLength(state);
    name = NEW_STRING(namelen);
    ReadByteBlockData(state, name, sizeof(UInt), namelen);
    rnam = RNamName(CONST_CSTR_STRING(name));
    len = INT_INTOBJ(ReadImmediateObj(state));
    args = NEW_PLIST(T_PLIST, len);
    SET_LEN_PLIST(args, len);
    for (i = 1; i <= len; i++) {
        if (ReadByte(state)) {
            Obj  obj;
            UInt blen;
            switch (ReadTNum(state)) {
            case T_DATOBJ:
                blen = ReadByteBlockLength(state);
                obj = NewBag(T_DATOBJ, blen + sizeof(Obj));
                ReadByteBlockData(state, obj, sizeof(Obj), blen);
                SET_TYPE_OBJ(obj, GVarObj(&TYPE_UNKNOWN_GVar));
                break;
            default:
                obj = DeserializeObj(state);
                break;
            }
            SET_ELM_PLIST(args, i, obj);
        }
        else {
            Obj obj = DeserializeObj(state);
            SET_ELM_PLIST(args, i, obj);
        }
    }
    deserialization_rec = GVarObj(&DESERIALIZER_GVar);
    if (!deserialization_rec)
        ErrorQuit("DeserializeTypedObj: failed to retrieve deserialization_rec", 0, 0);
    func = ELM_REC(deserialization_rec, rnam);
    if (!func || TNUM_OBJ(func) != T_FUNCTION)
        ErrorQuit("DeserializeTypedObj: deserialization_rec has bad function", 0, 0);
    result = CallFuncList(func, args);
    return result;
}

static Obj LookupTypeTag(Obj type)
{
    Obj tags = GVarObj(&SERIALIZATION_TAG_GVar);
    Obj func, result;
    if (tags && TNUM_OBJ(tags) == T_OBJMAP) {
        result = LookupObjMap(tags, type);
        if (result)
            return result;
        if (GVarObj(&SERIALIZATION_TAGS_NEED_UPDATE_GVar) == False)
            return (Obj)0;
        func = GVarFunction(&SERIALIZATION_UPDATE_TAGS_GVar);
        if (func)
            CALL_0ARGS(func);
        tags = GVarObj(&SERIALIZATION_TAG_GVar);
        result = LookupObjMap(tags, type);
        return result;
    }
    return (Obj)0;
}

static void SerializeTypedObj(SerializerState * state, Obj obj)
{
    Obj         type, rep, el1, el2, name;
    Int         skip, start, len;
    static char typeerror[] =
        "Serialization has encountered an object with a missing type";
    if (SerializedAlready(state, obj))
        return;
    type = TYPE_OBJ(obj);
    if (!type)
        ErrorQuit(typeerror, 0, 0);
    rep = LookupTypeTag(type);
    if (rep) {
        WriteTNum(state, TNUM_OBJ(obj));
        switch (TNUM_OBJ(rep)) {
        case T_INT:
        case T_STRING:
        case T_STRING + IMMUTABLE:
            SerializeObj(state, rep);
            UInt sp = LEN_PLIST(state->stack);
            switch (TNUM_OBJ(obj)) {
            case T_DATOBJ:
                WriteByteBlock(state, obj, sizeof(Obj),
                               SIZE_OBJ(obj) - sizeof(Obj));
                break;
            case T_POSOBJ:
                SerializeList(state, PosObjToList(obj));
                break;
            case T_COMOBJ:
                SerializeRecord(state, obj);
                break;
            }
            while (LEN_PLIST(state->stack) > sp) {
                SerializeObj(state, PopPlist(state->stack));
            }
            return;
        }
    }
    WriteTNum(state, TNUM_OBJ(obj));
    rep = CALL_1ARGS(GVarFunction(&SerializableRepresentationGVar), obj);
    if (!rep || !IS_PLIST(rep) || LEN_PLIST(rep) == 0) {
        SerRepError();
        return;
    }
    WriteByte(state, T_PLIST);
    el1 = ELM_PLIST(rep, 1);
    len = LEN_PLIST(rep);
    if (len >= 2)
        el2 = ELM_PLIST(rep, 2);
    else
        el2 = 0;
    if (IS_STRING(el1)) {
        skip = 0;
        start = 2;
        name = el1;
    }
    else {
        if (!IS_INTOBJ(el1))
            SerRepError();
        skip = INT_INTOBJ(el1);
        if (skip < 0 || skip + 2 > len)
            SerRepError();
        start = 3;
        name = el2;
        if (!name || !IS_STRING(name))
            SerRepError();
    }
    WriteByteBlock(state, name, sizeof(UInt), GET_LEN_STRING(name));
    WriteImmediateObj(state, INTOBJ_INT(len - start + 1));
    while (start <= len && skip > 0) {
        Obj  el = ELM_PLIST(rep, start);
        UInt sp = LEN_PLIST(state->stack);
        switch (TNUM_OBJ(el)) {
        case T_DATOBJ:
            WriteByte(state, 1);
            WriteTNum(state, T_DATOBJ);
            WriteByteBlock(state, el, sizeof(Obj),
                           SIZE_OBJ(el) - sizeof(Obj));
            break;
        case T_POSOBJ:
            WriteByte(state, 0);
            SerializeList(state, PosObjToList(el));
            break;
        case T_COMOBJ:
            WriteByte(state, 0);
            SerializeRecord(state, el);
            break;
        case T_APOSOBJ:
            WriteByte(state, 0);
            SerializeObj(state, FromAtomicList(el));
            break;
        case T_ACOMOBJ:
            WriteByte(state, 0);
            SerializeObj(state, FromAtomicRecord(el));
            break;
        default:
            WriteByte(state, 0);
            SerializeObj(state, el);
        }
        while (LEN_PLIST(state->stack) > sp) {
            SerializeObj(state, PopPlist(state->stack));
        }
        start++;
        skip--;
    }
    while (start <= len) {
        Obj  el = ELM_PLIST(rep, start);
        UInt sp = LEN_PLIST(state->stack);
        WriteByte(state, 0);
        SerializeObj(state, el);
        while (LEN_PLIST(state->stack) > sp) {
            SerializeObj(state, PopPlist(state->stack));
        }
        start++;
    }
}

static Obj DeserializeBackRef(DeserializerState * state, UInt tnum)
{
    UInt ref = BACKREF_OBJ(ReadImmediateObj(state));
    if (!ref) // special case for unbound entries
        return (Obj)0;
    UInt len = LEN_PLIST(state->stack);
    if (ref > len)
        ErrorQuit("DeserializeBackRef: ref %d exceeds stack size %d", ref, len);
    return ELM_PLIST(state->stack, ref);
}

static void SerializeError(SerializerState * state, Obj obj)
{
    ErrorQuit("Cannot serialize objects of type %s, tnum %d", (Int)TNAM_OBJ(obj), (Int)TNUM_OBJ(obj));
}

static Obj DeserializeError(DeserializerState * state, UInt tnum)
{
    ErrorQuit("Cannot deserialize objects of type %s, tnum %d", (Int)TNAM_TNUM(tnum), (Int)tnum);
    return Fail;
}

static Obj FuncSERIALIZE_TO_NATIVE_STRING(Obj self, Obj obj)
{
    SerializerState state;

    state.stack = NEW_PLIST(T_PLIST, 0);
    state.registry = NewObjMap();
    state.dispatcher = &NativeStringSerializer;
    state.obj = NEW_STRING(0);
    state.index = 0;

    SerializeObj(&state, obj);
    while (LEN_PLIST(state.stack) > 0)
        SerializeObj(&state, PopPlist(state.stack));

    return state.obj;
}

static Obj FuncDESERIALIZE_NATIVE_STRING(Obj self, Obj string)
{
    DeserializerState state;

    if (!IS_STRING_REP(string))
        ErrorQuit("DESERIALIZE_NATIVE_STRING: argument must be a string", 0,
                  0);

    state.stack = NEW_PLIST(T_PLIST, 0);
    state.dispatcher = &NativeStringDeserializer;
    state.obj = string;
    state.index = 0;

    return DeserializeObj(&state);
}

/****************************************************************************
**
*V  GVarFuncs . . . . . . . . . . . . . . . . . . list of functions to export
*/


static StructGVarFunc GVarFuncs[] = {

    GVAR_FUNC_1ARGS(SERIALIZE_TO_NATIVE_STRING, obj),
    GVAR_FUNC_1ARGS(DESERIALIZE_NATIVE_STRING, string),
    { 0, 0, 0, 0, 0 }

};


/****************************************************************************
**
*F  InitKernel( <module> )  . . . . . . . . initialise kernel data structures
*/

static Int InitKernel(StructInitInfo * module)
{
    UInt                 i;

    for (i = 0; i <= T_BACKREF; i++) {
        RegisterSerializerFunctions(i, SerializeError, DeserializeError);
    }

    RegisterSerializerFunctions(T_INT, SerializeInt, DeserializeInt);
    RegisterSerializerFunctions(T_INTPOS, SerializeBinary, DeserializeBinary);
    RegisterSerializerFunctions(T_INTNEG, SerializeBinary, DeserializeBinary);
    RegisterSerializerFunctions(T_RAT, SerializeRat, DeserializeRat);
    RegisterSerializerFunctions(T_CYC, SerializeCyc, DeserializeCyc);
    RegisterSerializerFunctions(T_FFE, SerializeFFE, DeserializeFFE);
    RegisterSerializerFunctions(T_MACFLOAT, SerializeBinary, DeserializeBinary);
    RegisterSerializerFunctions(T_PERM2, SerializeBinary, DeserializeBinary);
    RegisterSerializerFunctions(T_PERM4, SerializeBinary, DeserializeBinary);
    // TODO: add support for T_TRANS2/4, T_PPERM2/4
    RegisterSerializerFunctions(T_BOOL, SerializeBool, DeserializeBool);
    RegisterSerializerFunctions(T_CHAR, SerializeChar, DeserializeChar);

    for (i = FIRST_RECORD_TNUM; i <= LAST_RECORD_TNUM; i++) {
        RegisterSerializerFunctions(i, SerializeRecord, DeserializeRecord);
    }
    for (i = FIRST_PLIST_TNUM; i <= LAST_PLIST_TNUM; i++) {
        RegisterSerializerFunctions(i, SerializeList, DeserializeList);
    }
    for (i = T_RANGE_NSORT; i <= T_RANGE_SSORT + IMMUTABLE; i++) {
        RegisterSerializerFunctions(i, SerializeRange, DeserializeRange);
    }
    for (i = T_BLIST; i <= T_BLIST_SSORT + IMMUTABLE; i++) {
        RegisterSerializerFunctions(i, SerializeBlist, DeserializeBlist);
    }
    for (i = T_STRING; i <= T_STRING_SSORT + IMMUTABLE; i++) {
        RegisterSerializerFunctions(i, SerializeString, DeserializeString);
    }

    RegisterSerializerFunctions(T_OBJSET, SerializeObjSet, DeserializeObjSet);
    RegisterSerializerFunctions(T_OBJMAP, SerializeObjMap, DeserializeObjMap);

    RegisterSerializerFunctions(T_COMOBJ, SerializeTypedObj, DeserializeTypedObj);
    RegisterSerializerFunctions(T_POSOBJ, SerializeTypedObj, DeserializeTypedObj);
    RegisterSerializerFunctions(T_DATOBJ, SerializeTypedObj, DeserializeTypedObj);
    RegisterSerializerFunctions(T_ACOMOBJ, SerializeTypedObj, DeserializeTypedObj);
    RegisterSerializerFunctions(T_APOSOBJ, SerializeTypedObj, DeserializeTypedObj);

    RegisterSerializerFunctions(T_BACKREF, SerializeError, DeserializeBackRef);

    // gvars
    DeclareGVar(&SerializableRepresentationGVar,
                "SerializableRepresentation");
    DeclareGVar(&TYPE_UNKNOWN_GVar, "TYPE_UNKNOWN");
    DeclareGVar(&DESERIALIZER_GVar, "DESERIALIZER");
    DeclareGVar(&SERIALIZATION_TAG_GVar, "SERIALIZATION_TAG");
    DeclareGVar(&DESERIALIZATION_TAG_INT_GVar, "DESERIALIZATION_TAG_INT");
    DeclareGVar(&DESERIALIZATION_TAG_STRING_GVar,
                "DESERIALIZATION_TAG_STRING");
    DeclareGVar(&SERIALIZATION_UPDATE_TAGS_GVar, "SERIALIZATION_UPDATE_TAGS");
    DeclareGVar(&SERIALIZATION_TAGS_NEED_UPDATE_GVar,
                "SERIALIZATION_TAGS_NEED_UPDATE");

    return 0;
}


/****************************************************************************
**
*F  InitLibrary( <module> ) . . . . . . .  initialise library data structures
*/

static Int InitLibrary(StructInitInfo * module)
{
    // init filters and functions
    InitGVarFuncsFromTable(GVarFuncs);

    return 0;
}

/****************************************************************************
**
*F  InitInfoObjSet() . . . . . . . . . . . . . . . table of init functions
*/

static StructInitInfo module = {
    // init struct using C99 designated initializers; for a full list of
    // fields, please refer to the definition of StructInitInfo
    .type = MODULE_BUILTIN,
    .name = "serialize",
    .initKernel = InitKernel,
    .initLibrary = InitLibrary,
};

StructInitInfo * InitInfoSerialize(void)
{
    return &module;
}

#endif

94%


¤ Dauer der Verarbeitung: 0.21 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge