private void generateUnpackMethod(ClassDescriptor desc, MethodBuilder builder)
        {
            ILGenerator il = builder.GetILGenerator();

            il.Emit(OpCodes.Ldarg_2);
            il.Emit(OpCodes.Castclass, desc.cls);
            LocalBuilder obj = il.DeclareLocal(desc.cls);

            il.Emit(OpCodes.Stloc_0, obj);
            il.Emit(OpCodes.Ldc_I4, ObjectHeader.Sizeof);
            LocalBuilder offs = il.DeclareLocal(typeof(int));

            il.Emit(OpCodes.Stloc_1, offs);
            LocalBuilder val = il.DeclareLocal(typeof(object));

            ClassDescriptor.FieldDescriptor[] flds = desc.allFields;

            for (int i = 0, n = flds.Length; i < n; i++)
            {
                ClassDescriptor.FieldDescriptor fd = flds[i];
                FieldInfo f = fd.field;
                if (f == null)
                {
                    switch (fd.type)
                    {
                    case ClassDescriptor.FieldType.tpByte:
                    case ClassDescriptor.FieldType.tpSByte:
                    case ClassDescriptor.FieldType.tpBoolean:
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldc_I4_1);
                        il.Emit(OpCodes.Add);
                        il.Emit(OpCodes.Stloc_1, offs);
                        continue;

                    case ClassDescriptor.FieldType.tpShort:
                    case ClassDescriptor.FieldType.tpUShort:
                    case ClassDescriptor.FieldType.tpChar:
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldc_I4_2);
                        il.Emit(OpCodes.Add);
                        il.Emit(OpCodes.Stloc_1, offs);
                        continue;

                    case ClassDescriptor.FieldType.tpEnum:
                    case ClassDescriptor.FieldType.tpInt:
                    case ClassDescriptor.FieldType.tpUInt:
                    case ClassDescriptor.FieldType.tpFloat:
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldc_I4_4);
                        il.Emit(OpCodes.Add);
                        il.Emit(OpCodes.Stloc_1, offs);
                        continue;

                    case ClassDescriptor.FieldType.tpLong:
                    case ClassDescriptor.FieldType.tpULong:
                    case ClassDescriptor.FieldType.tpDate:
                    case ClassDescriptor.FieldType.tpDouble:
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldc_I4_8);
                        il.Emit(OpCodes.Add);
                        il.Emit(OpCodes.Stloc_1, offs);
                        continue;

                    case ClassDescriptor.FieldType.tpDecimal:
                    case ClassDescriptor.FieldType.tpGuid:
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldc_I4, 16);
                        il.Emit(OpCodes.Add);
                        il.Emit(OpCodes.Stloc_1, offs);
                        continue;

                    default:
                        il.Emit(OpCodes.Ldarg_1);    // storage
                        il.Emit(OpCodes.Ldarg_3);    // body
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldnull);     // fd
                        il.Emit(OpCodes.Ldc_I4, (int)fd.type);
                        il.Emit(OpCodes.Call, skipField);
                        il.Emit(OpCodes.Stloc_1, offs);     // offs
                        continue;
                    }
                }
                else
                {
                    switch (fd.type)
                    {
                    case ClassDescriptor.FieldType.tpByte:
                        il.Emit(OpCodes.Ldloc_0, obj);
                        il.Emit(OpCodes.Ldarg_3);     // body
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldelem_U1);
                        il.Emit(OpCodes.Stfld, f);
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldc_I4_1);
                        il.Emit(OpCodes.Add);
                        il.Emit(OpCodes.Stloc_1, offs);
                        continue;

                    case ClassDescriptor.FieldType.tpSByte:
                        il.Emit(OpCodes.Ldloc_0, obj);
                        il.Emit(OpCodes.Ldarg_3);     // body
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldelem_U1);
                        il.Emit(OpCodes.Conv_I1);
                        il.Emit(OpCodes.Stfld, f);
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldc_I4_1);
                        il.Emit(OpCodes.Add);
                        il.Emit(OpCodes.Stloc_1, offs);
                        continue;

                    case ClassDescriptor.FieldType.tpBoolean:
                        il.Emit(OpCodes.Ldloc_0, obj);
                        il.Emit(OpCodes.Ldarg_3);     // body
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldelem_U1);
                        il.Emit(OpCodes.Stfld, f);
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldc_I4_1);
                        il.Emit(OpCodes.Add);
                        il.Emit(OpCodes.Stloc_1, offs);
                        continue;

                    case ClassDescriptor.FieldType.tpShort:
                        il.Emit(OpCodes.Ldloc_0, obj);
                        il.Emit(OpCodes.Ldarg_3);     // body
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Call, unpackI2);
                        il.Emit(OpCodes.Stfld, f);
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldc_I4_2);
                        il.Emit(OpCodes.Add);
                        il.Emit(OpCodes.Stloc_1, offs);
                        continue;

                    case ClassDescriptor.FieldType.tpUShort:
                    case ClassDescriptor.FieldType.tpChar:
                        il.Emit(OpCodes.Ldloc_0, obj);
                        il.Emit(OpCodes.Ldarg_3);     // body
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Call, unpackI2);
                        il.Emit(OpCodes.Conv_U2);
                        il.Emit(OpCodes.Stfld, f);
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldc_I4_2);
                        il.Emit(OpCodes.Add);
                        il.Emit(OpCodes.Stloc_1, offs);
                        continue;

                    case ClassDescriptor.FieldType.tpEnum:
                    case ClassDescriptor.FieldType.tpInt:
                    case ClassDescriptor.FieldType.tpUInt:
                        il.Emit(OpCodes.Ldloc_0, obj);
                        il.Emit(OpCodes.Ldarg_3);     // body
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Call, unpackI4);
                        il.Emit(OpCodes.Stfld, f);
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldc_I4_4);
                        il.Emit(OpCodes.Add);
                        il.Emit(OpCodes.Stloc_1, offs);
                        continue;

                    case ClassDescriptor.FieldType.tpLong:
                    case ClassDescriptor.FieldType.tpULong:
                        il.Emit(OpCodes.Ldloc_0, obj);
                        il.Emit(OpCodes.Ldarg_3);     // body
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Call, unpackI8);
                        il.Emit(OpCodes.Stfld, f);
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldc_I4_8);
                        il.Emit(OpCodes.Add);
                        il.Emit(OpCodes.Stloc_1, offs);
                        continue;

                    case ClassDescriptor.FieldType.tpFloat:
                        il.Emit(OpCodes.Ldloc_0, obj);
                        il.Emit(OpCodes.Ldarg_3);     // body
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Call, unpackF4);
                        il.Emit(OpCodes.Stfld, f);
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldc_I4_4);
                        il.Emit(OpCodes.Add);
                        il.Emit(OpCodes.Stloc_1, offs);
                        continue;

                    case ClassDescriptor.FieldType.tpDouble:
                        il.Emit(OpCodes.Ldloc_0, obj);
                        il.Emit(OpCodes.Ldarg_3);     // body
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Call, unpackF8);
                        il.Emit(OpCodes.Stfld, f);
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldc_I4_8);
                        il.Emit(OpCodes.Add);
                        il.Emit(OpCodes.Stloc_1, offs);
                        continue;

                    case ClassDescriptor.FieldType.tpDecimal:
                        il.Emit(OpCodes.Ldloc_0, obj);
                        il.Emit(OpCodes.Ldarg_3);     // body
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Call, unpackDecimal);
                        il.Emit(OpCodes.Stfld, f);
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldc_I4, 16);
                        il.Emit(OpCodes.Add);
                        il.Emit(OpCodes.Stloc_1, offs);
                        continue;

                    case ClassDescriptor.FieldType.tpGuid:
                        il.Emit(OpCodes.Ldloc_0, obj);
                        il.Emit(OpCodes.Ldarg_3);     // body
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Call, unpackGuid);
                        il.Emit(OpCodes.Stfld, f);
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldc_I4, 16);
                        il.Emit(OpCodes.Add);
                        il.Emit(OpCodes.Stloc_1, offs);
                        continue;

                    case ClassDescriptor.FieldType.tpDate:
                        il.Emit(OpCodes.Ldloc_0, obj);
                        il.Emit(OpCodes.Ldarg_3);     // body
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Call, unpackDate);
                        il.Emit(OpCodes.Stfld, f);
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldc_I4_8);
                        il.Emit(OpCodes.Add);
                        il.Emit(OpCodes.Stloc_1, offs);
                        continue;

                    case ClassDescriptor.FieldType.tpString:
                        il.Emit(OpCodes.Ldarg_3);     // body
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldloc_0, obj);
                        il.Emit(OpCodes.Ldflda, f);
                        il.Emit(OpCodes.Ldarg_S, 5);     // encoding
                        il.Emit(OpCodes.Call, unpackString);
                        il.Emit(OpCodes.Stloc_1, offs);
                        continue;

                    default:
                        il.Emit(OpCodes.Ldarg_1);    // storage
                        il.Emit(OpCodes.Ldarg_3);    // body
                        il.Emit(OpCodes.Ldloc_1, offs);
                        il.Emit(OpCodes.Ldarg_S, 4); // recursiveLoading
                        il.Emit(OpCodes.Ldloca, val);
                        il.Emit(OpCodes.Ldnull);     // fd
                        il.Emit(OpCodes.Ldc_I4, (int)fd.type);
                        il.Emit(OpCodes.Ldloc_0, obj);
                        il.Emit(OpCodes.Call, unpackField);
                        il.Emit(OpCodes.Stloc_1, offs);     // offs
                        il.Emit(OpCodes.Ldloc_0, obj);
                        il.Emit(OpCodes.Ldloc, val);
                        il.Emit(OpCodes.Castclass, f.FieldType);
                        il.Emit(OpCodes.Stfld, f);
                        continue;
                    }
                }
            }
            il.Emit(OpCodes.Ret);
        }
        private void generatePackMethod(ClassDescriptor desc, MethodBuilder builder)
        {
            ILGenerator il = builder.GetILGenerator();

            il.Emit(OpCodes.Ldarg_2); // obj
            il.Emit(OpCodes.Castclass, desc.cls);
            obj = il.DeclareLocal(desc.cls);
            il.Emit(OpCodes.Stloc_0, obj);
            il.Emit(OpCodes.Ldc_I4, ObjectHeader.Sizeof);
            offs = il.DeclareLocal(typeof(int));
            il.Emit(OpCodes.Stloc_1, offs);

            ClassDescriptor.FieldDescriptor[] flds = desc.allFields;

            for (int i = 0, n = flds.Length; i < n; i++)
            {
                ClassDescriptor.FieldDescriptor fd = flds[i];
                FieldInfo f = fd.field;
                switch (fd.type)
                {
                case ClassDescriptor.FieldType.tpByte:
                case ClassDescriptor.FieldType.tpSByte:
                    generatePackField(il, f, packI1);
                    continue;

                case ClassDescriptor.FieldType.tpBoolean:
                    generatePackField(il, f, packBool);
                    continue;

                case ClassDescriptor.FieldType.tpShort:
                case ClassDescriptor.FieldType.tpUShort:
                case ClassDescriptor.FieldType.tpChar:
                    generatePackField(il, f, packI2);
                    continue;

                case ClassDescriptor.FieldType.tpEnum:
                case ClassDescriptor.FieldType.tpInt:
                case ClassDescriptor.FieldType.tpUInt:
                    generatePackField(il, f, packI4);
                    continue;

                case ClassDescriptor.FieldType.tpLong:
                case ClassDescriptor.FieldType.tpULong:
                    generatePackField(il, f, packI8);
                    continue;

                case ClassDescriptor.FieldType.tpFloat:
                    generatePackField(il, f, packF4);
                    continue;

                case ClassDescriptor.FieldType.tpDouble:
                    generatePackField(il, f, packF8);
                    continue;

                case ClassDescriptor.FieldType.tpDecimal:
                    generatePackField(il, f, packDecimal);
                    continue;

                case ClassDescriptor.FieldType.tpGuid:
                    generatePackField(il, f, packGuid);
                    continue;

                case ClassDescriptor.FieldType.tpDate:
                    generatePackField(il, f, packDate);
                    continue;

                case ClassDescriptor.FieldType.tpString:
                    generatePackField(il, f, packString);
                    continue;

                default:
                    il.Emit(OpCodes.Ldarg_1);     // storage
                    il.Emit(OpCodes.Ldarg_3);     // buf
                    il.Emit(OpCodes.Ldloc_1, offs);
                    il.Emit(OpCodes.Ldloc_0, obj);
                    il.Emit(OpCodes.Ldfld, f);
                    il.Emit(OpCodes.Ldnull);     // fd
                    il.Emit(OpCodes.Ldc_I4, (int)fd.type);
                    il.Emit(OpCodes.Call, packField);
                    il.Emit(OpCodes.Stloc_1, offs);
                    continue;
                }
            }
            il.Emit(OpCodes.Ldloc_1, offs);
            il.Emit(OpCodes.Ret);
        }
Ejemplo n.º 3
0
        internal int exportObject(ClassDescriptor desc, byte[] body, int offs, int indent)
        {
            ClassDescriptor.FieldDescriptor[] all = desc.allFields;

            for (int i = 0, n = all.Length; i < n; i++)
            {
                ClassDescriptor.FieldDescriptor fd = all[i];
                FieldInfo f = fd.field;
                indentation(indent);
                String fieldName = exportIdentifier(fd.fieldName);
                writer.Write("<" + fieldName + ">");
                switch (fd.type)
                {
                case ClassDescriptor.FieldType.tpBoolean:
                    writer.Write(body[offs++] != 0?"1":"0");
                    break;

                case ClassDescriptor.FieldType.tpByte:
                    writer.Write(System.Convert.ToString((byte)body[offs++]));
                    break;

                case ClassDescriptor.FieldType.tpSByte:
                    writer.Write(System.Convert.ToString((sbyte)body[offs++]));
                    break;

                case ClassDescriptor.FieldType.tpChar:
                    writer.Write(System.Convert.ToString((ushort)Bytes.unpack2(body, offs)));
                    offs += 2;
                    break;

                case ClassDescriptor.FieldType.tpShort:
                    writer.Write(System.Convert.ToString((ushort)Bytes.unpack2(body, offs)));
                    offs += 2;
                    break;

                case ClassDescriptor.FieldType.tpUShort:
                    writer.Write(System.Convert.ToString((ushort)Bytes.unpack2(body, offs)));
                    offs += 2;
                    break;

                case ClassDescriptor.FieldType.tpInt:
                    writer.Write(System.Convert.ToString(Bytes.unpack4(body, offs)));
                    offs += 4;
                    break;

                case ClassDescriptor.FieldType.tpEnum:
                    writer.Write(Enum.ToObject(f.FieldType, Bytes.unpack4(body, offs)));
                    offs += 4;
                    break;

                case ClassDescriptor.FieldType.tpUInt:
                    writer.Write(System.Convert.ToString((uint)Bytes.unpack4(body, offs)));
                    offs += 4;
                    break;

                case ClassDescriptor.FieldType.tpLong:
                    writer.Write(System.Convert.ToString(Bytes.unpack8(body, offs)));
                    offs += 8;
                    break;

                case ClassDescriptor.FieldType.tpULong:
                    writer.Write(System.Convert.ToString((ulong)Bytes.unpack8(body, offs)));
                    offs += 8;
                    break;

                case ClassDescriptor.FieldType.tpFloat:
                    writer.Write(System.Convert.ToString(Bytes.unpackF4(body, offs)));
                    offs += 4;
                    break;

                case ClassDescriptor.FieldType.tpDouble:
                    writer.Write(System.Convert.ToString(Bytes.unpackF8(body, offs)));
                    offs += 8;
                    break;

                case ClassDescriptor.FieldType.tpGuid:
                    writer.Write("\"" + Bytes.unpackGuid(body, offs) + "\"");
                    offs += 16;
                    break;

                case ClassDescriptor.FieldType.tpDecimal:
                    writer.Write("\"" + Bytes.unpackDecimal(body, offs) + "\"");
                    offs += 16;
                    break;

                case ClassDescriptor.FieldType.tpString:
                    offs = exportString(body, offs);
                    break;

                case ClassDescriptor.FieldType.tpDate:
                {
                    long msec = Bytes.unpack8(body, offs);
                    offs += 8;
                    if (msec >= 0)
                    {
                        writer.Write("\"" + new System.DateTime(msec) + "\"");
                    }
                    else
                    {
                        writer.Write("null");
                    }
                    break;
                }

                case ClassDescriptor.FieldType.tpObject:
                    exportRef(Bytes.unpack4(body, offs));
                    offs += 4;
                    break;

                case ClassDescriptor.FieldType.tpValue:
                    writer.Write('\n');
                    offs = exportObject(fd.valueDesc, body, offs, indent + 1);
                    indentation(indent);
                    break;

#if SUPPORT_RAW_TYPE
                case ClassDescriptor.FieldType.tpRaw:
#endif
                case ClassDescriptor.FieldType.tpArrayOfByte:
                case ClassDescriptor.FieldType.tpArrayOfSByte:
                    offs = exportBinary(body, offs);
                    break;

                case ClassDescriptor.FieldType.tpArrayOfBoolean:
                {
                    int len = Bytes.unpack4(body, offs);
                    offs += 4;
                    if (len < 0)
                    {
                        writer.Write("null");
                    }
                    else
                    {
                        writer.Write('\n');
                        while (--len >= 0)
                        {
                            indentation(indent + 1);
                            writer.Write("<element>" + (body[offs++] != 0?"1":"0") + "</element>\n");
                        }
                        indentation(indent);
                    }
                    break;
                }

                case ClassDescriptor.FieldType.tpArrayOfChar:
                {
                    int len = Bytes.unpack4(body, offs);
                    offs += 4;
                    if (len < 0)
                    {
                        writer.Write("null");
                    }
                    else
                    {
                        writer.Write('\n');
                        while (--len >= 0)
                        {
                            indentation(indent + 1);
                            writer.Write("<element>" + (Bytes.unpack2(body, offs) & 0xFFFF) + "</element>\n");
                            offs += 2;
                        }
                        indentation(indent);
                    }
                    break;
                }

                case ClassDescriptor.FieldType.tpArrayOfShort:
                {
                    int len = Bytes.unpack4(body, offs);
                    offs += 4;
                    if (len < 0)
                    {
                        writer.Write("null");
                    }
                    else
                    {
                        writer.Write('\n');
                        while (--len >= 0)
                        {
                            indentation(indent + 1);
                            writer.Write("<element>" + Bytes.unpack2(body, offs) + "</element>\n");
                            offs += 2;
                        }
                        indentation(indent);
                    }
                    break;
                }

                case ClassDescriptor.FieldType.tpArrayOfUShort:
                {
                    int len = Bytes.unpack4(body, offs);
                    offs += 4;
                    if (len < 0)
                    {
                        writer.Write("null");
                    }
                    else
                    {
                        writer.Write('\n');
                        while (--len >= 0)
                        {
                            indentation(indent + 1);
                            writer.Write("<element>" + (ushort)Bytes.unpack2(body, offs) + "</element>\n");
                            offs += 2;
                        }
                        indentation(indent);
                    }
                    break;
                }

                case ClassDescriptor.FieldType.tpArrayOfInt:
                {
                    int len = Bytes.unpack4(body, offs);
                    offs += 4;
                    if (len < 0)
                    {
                        writer.Write("null");
                    }
                    else
                    {
                        writer.Write('\n');
                        while (--len >= 0)
                        {
                            indentation(indent + 1);
                            writer.Write("<element>" + Bytes.unpack4(body, offs) + "</element>\n");
                            offs += 4;
                        }
                        indentation(indent);
                    }
                    break;
                }

                case ClassDescriptor.FieldType.tpArrayOfEnum:
                {
                    int len = Bytes.unpack4(body, offs);
                    offs += 4;
                    if (len < 0)
                    {
                        writer.Write("null");
                    }
                    else
                    {
                        Type elemType = f.FieldType.GetElementType();
                        writer.Write('\n');
                        while (--len >= 0)
                        {
                            indentation(indent + 1);
                            writer.Write("<element>" + Enum.ToObject(elemType, Bytes.unpack4(body, offs)) + "</element>\n");
                            offs += 4;
                        }
                        indentation(indent);
                    }
                    break;
                }

                case ClassDescriptor.FieldType.tpArrayOfUInt:
                {
                    int len = Bytes.unpack4(body, offs);
                    offs += 4;
                    if (len < 0)
                    {
                        writer.Write("null");
                    }
                    else
                    {
                        writer.Write('\n');
                        while (--len >= 0)
                        {
                            indentation(indent + 1);
                            writer.Write("<element>" + (uint)Bytes.unpack4(body, offs) + "</element>\n");
                            offs += 4;
                        }
                        indentation(indent);
                    }
                    break;
                }

                case ClassDescriptor.FieldType.tpArrayOfLong:
                {
                    int len = Bytes.unpack4(body, offs);
                    offs += 4;
                    if (len < 0)
                    {
                        writer.Write("null");
                    }
                    else
                    {
                        writer.Write('\n');
                        while (--len >= 0)
                        {
                            indentation(indent + 1);
                            writer.Write("<element>" + Bytes.unpack8(body, offs) + "</element>\n");
                            offs += 8;
                        }
                        indentation(indent);
                    }
                    break;
                }

                case ClassDescriptor.FieldType.tpArrayOfULong:
                {
                    int len = Bytes.unpack4(body, offs);
                    offs += 4;
                    if (len < 0)
                    {
                        writer.Write("null");
                    }
                    else
                    {
                        writer.Write('\n');
                        while (--len >= 0)
                        {
                            indentation(indent + 1);
                            writer.Write("<element>" + (ulong)Bytes.unpack8(body, offs) + "</element>\n");
                            offs += 8;
                        }
                        indentation(indent);
                    }
                    break;
                }

                case ClassDescriptor.FieldType.tpArrayOfFloat:
                {
                    int len = Bytes.unpack4(body, offs);
                    offs += 4;
                    if (len < 0)
                    {
                        writer.Write("null");
                    }
                    else
                    {
                        writer.Write('\n');
                        while (--len >= 0)
                        {
                            indentation(indent + 1);
                            writer.Write("<element>" + Bytes.unpackF4(body, offs) + "</element>\n");
                            offs += 4;
                        }
                        indentation(indent);
                    }
                    break;
                }

                case ClassDescriptor.FieldType.tpArrayOfDouble:
                {
                    int len = Bytes.unpack4(body, offs);
                    offs += 4;
                    if (len < 0)
                    {
                        writer.Write("null");
                    }
                    else
                    {
                        writer.Write('\n');
                        while (--len >= 0)
                        {
                            indentation(indent + 1);
                            writer.Write("<element>" + Bytes.unpackF8(body, offs) + "</element>\n");
                            offs += 8;
                        }
                        indentation(indent);
                    }
                    break;
                }

                case ClassDescriptor.FieldType.tpArrayOfDate:
                {
                    int len = Bytes.unpack4(body, offs);
                    offs += 4;
                    if (len < 0)
                    {
                        writer.Write("null");
                    }
                    else
                    {
                        writer.Write('\n');
                        while (--len >= 0)
                        {
                            indentation(indent + 1);
                            writer.Write("<element>\"" + Bytes.unpackDate(body, offs) + "\"</element>\n");
                            offs += 8;
                        }
                    }
                    break;
                }

                case ClassDescriptor.FieldType.tpArrayOfGuid:
                {
                    int len = Bytes.unpack4(body, offs);
                    offs += 4;
                    if (len < 0)
                    {
                        writer.Write("null");
                    }
                    else
                    {
                        writer.Write('\n');
                        while (--len >= 0)
                        {
                            writer.Write("<element>\"" + Bytes.unpackGuid(body, offs) + "\"</element>\n");
                            offs += 16;
                        }
                    }
                    break;
                }

                case ClassDescriptor.FieldType.tpArrayOfDecimal:
                {
                    int len = Bytes.unpack4(body, offs);
                    offs += 4;
                    if (len < 0)
                    {
                        writer.Write("null");
                    }
                    else
                    {
                        writer.Write('\n');
                        while (--len >= 0)
                        {
                            writer.Write("<element>\"" + Bytes.unpackDecimal(body, offs) + "\"</element>\n");
                            offs += 16;
                        }
                    }
                    break;
                }

                case ClassDescriptor.FieldType.tpArrayOfString:
                {
                    int len = Bytes.unpack4(body, offs);
                    offs += 4;
                    if (len < 0)
                    {
                        writer.Write("null");
                    }
                    else
                    {
                        writer.Write('\n');
                        while (--len >= 0)
                        {
                            indentation(indent + 1);
                            writer.Write("<element>");
                            offs = exportString(body, offs);
                            writer.Write("</element>\n");
                        }
                        indentation(indent);
                    }
                    break;
                }

                case ClassDescriptor.FieldType.tpLink:
                case ClassDescriptor.FieldType.tpArrayOfObject:
                {
                    int len = Bytes.unpack4(body, offs);
                    offs += 4;
                    if (len < 0)
                    {
                        writer.Write("null");
                    }
                    else
                    {
                        writer.Write('\n');
                        while (--len >= 0)
                        {
                            indentation(indent + 1);
                            int oid = Bytes.unpack4(body, offs);
                            if (oid != 0 && (exportedBitmap[oid >> 5] & (1 << (oid & 31))) == 0)
                            {
                                markedBitmap[oid >> 5] |= 1 << (oid & 31);
                            }
                            writer.Write("<element><ref id=\"" + oid + "\"/></element>\n");
                            offs += 4;
                        }
                        indentation(indent);
                    }
                    break;
                }

                case ClassDescriptor.FieldType.tpArrayOfValue:
                {
                    int len = Bytes.unpack4(body, offs);
                    offs += 4;
                    if (len < 0)
                    {
                        writer.Write("null");
                    }
                    else
                    {
                        writer.Write('\n');
                        while (--len >= 0)
                        {
                            indentation(indent + 1);
                            writer.Write("<element>\n");
                            offs = exportObject(fd.valueDesc, body, offs, indent + 2);
                            indentation(indent + 1);
                            writer.Write("</element>\n");
                        }
                        indentation(indent);
                    }
                    break;
                }

#if SUPPORT_RAW_TYPE
                case ClassDescriptor.FieldType.tpArrayOfRaw:
                {
                    int len = Bytes.unpack4(body, offs);
                    offs += 4;
                    if (len < 0)
                    {
                        writer.Write("null");
                    }
                    else
                    {
                        writer.Write('\n');
                        while (--len >= 0)
                        {
                            indentation(indent + 1);
                            writer.Write("<element>");
                            offs = exportBinary(body, offs);
                            writer.Write("</element>\n");
                        }
                        indentation(indent);
                    }
                    break;
                }
#endif
                }
                writer.Write("</" + fieldName + ">\n");
            }
            return(offs);
        }