mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
Type-size info added to archives
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@3594 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
3968a4bf41
commit
7d0afe2c3e
12 changed files with 1444 additions and 797 deletions
16
ChangeLog
16
ChangeLog
|
@ -1,3 +1,19 @@
|
|||
Wed Jan 27 12:00:00 1999 Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||
|
||||
* configure.n: More type-size stuff
|
||||
* src/include/GSConfig.h.in: More type-size stuff
|
||||
* src/include/NSData.h: Changed GNUstep extensions and added constants
|
||||
for coder support.
|
||||
* src/include/NSArchiver.h: Changes for handling systems with differing
|
||||
type sizes.
|
||||
* src/include/NSByteOrder.h: Changes and additions for handling systems
|
||||
with differing type sizes.
|
||||
* src/NSData.m: Changed GNUstep extensions for coder support in order
|
||||
to make handling of type-size information easier.
|
||||
* src/NSArchiver.m: Encode type-size info and write more efficiently.
|
||||
* src/NSUnarchiver.m: Decode type-size info.
|
||||
* src/UnixFileHanlde.m: Use localhost if given no host for connect.
|
||||
|
||||
Tue Jan 26 15:45:00 1999 Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||
|
||||
* configure.in: More stuff for type-size info
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
* Definition to specify if your processor stores words with the most
|
||||
* significant byte first (like Motorola and SPARC, unlike Intel and VAX).
|
||||
*/
|
||||
#define GS_WORDS_BIGENDIAN @GS_WORDS_BIGENDIAN@
|
||||
#define GS_WORDS_BIGENDIAN @GS_WORDS_BIGENDIAN@
|
||||
|
||||
/*
|
||||
* Size definitions for standard types
|
||||
|
@ -43,8 +43,16 @@ typedef @GS_SINT32@ gss32;
|
|||
typedef @GS_UINT32@ gsu32;
|
||||
typedef @GS_SINT64@ gss64;
|
||||
typedef @GS_UINT64@ gsu64;
|
||||
typedef @GS_SINT128@ gss128;
|
||||
typedef @GS_UINT128@ gsu128;
|
||||
typedef @GS_FLT32@ gsf32;
|
||||
typedef @GS_FLT64@ gsf64;
|
||||
|
||||
/*
|
||||
* Do we have real 64-bit and 128-bit integers or are we just pretending.
|
||||
*/
|
||||
#define GS_HAVE_I64 @GS_HAVE_I64@
|
||||
#define GS_HAVE_I128 @GS_HAVE_I128@
|
||||
|
||||
#endif /* included_GSConfig_h */
|
||||
|
||||
|
|
|
@ -28,10 +28,6 @@
|
|||
|
||||
@class NSMutableDictionary, NSMutableData, NSData, NSString;
|
||||
|
||||
#define _C_NONE 0x00 /* No type information. */
|
||||
#define _C_MASK 0x7f /* Basic type info. */
|
||||
#define _C_XREF 0x80 /* Cross reference to an item. */
|
||||
|
||||
@interface NSArchiver : NSCoder
|
||||
{
|
||||
NSMutableData *data; /* Data to write into. */
|
||||
|
@ -160,8 +156,7 @@
|
|||
Class dataClass; /* What sort of data is it? */
|
||||
id src; /* Deserialization source. */
|
||||
IMP desImp; /* Method to deserialize with. */
|
||||
unsigned char (*tagImp)(id, SEL, unsigned*);
|
||||
unsigned (*xRefImp)(id, SEL, unsigned*);
|
||||
void (*tagImp)(id, SEL, unsigned char*, unsigned*,unsigned*);
|
||||
IMP dValImp; /* Method to decode data with. */
|
||||
#ifndef _IN_NSUNARCHIVER_M
|
||||
#define FastArray void*
|
||||
|
|
|
@ -29,8 +29,8 @@
|
|||
/*
|
||||
* OPENSTEP type definitions for Byte ordering.
|
||||
*/
|
||||
typedef unsigned long NSSwappedFloat;
|
||||
typedef unsigned long long NSSwappedDouble;
|
||||
typedef gsu32 NSSwappedFloat;
|
||||
typedef gsu64 NSSwappedDouble;
|
||||
|
||||
typedef enum {
|
||||
NSLittleEndian,
|
||||
|
@ -45,6 +45,96 @@ typedef enum {
|
|||
# define __attribute__(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* First the GNUstep functions for byte swapping
|
||||
*/
|
||||
static inline gsu16
|
||||
GSSwapI16(gsu16 in) __attribute__((unused));
|
||||
static inline gsu32
|
||||
GSSwapI32(gsu32 in) __attribute__((unused));
|
||||
static inline gsu64
|
||||
GSSwapI64(gsu64 in) __attribute__((unused));
|
||||
static inline gsu128
|
||||
GSSwapI128(gsu128 in) __attribute__((unused));
|
||||
|
||||
|
||||
static inline gsu16
|
||||
GSSwapI16(gsu16 in)
|
||||
{
|
||||
union swap {
|
||||
gsu16 num;
|
||||
gsu8 byt[2];
|
||||
} dst;
|
||||
union swap *src = (union swap*)∈
|
||||
dst.byt[0] = src->byt[1];
|
||||
dst.byt[1] = src->byt[0];
|
||||
return dst.num;
|
||||
}
|
||||
|
||||
static inline gsu32
|
||||
GSSwapI32(gsu32 in)
|
||||
{
|
||||
union swap {
|
||||
gsu32 num;
|
||||
gsu8 byt[4];
|
||||
} dst;
|
||||
union swap *src = (union swap*)∈
|
||||
dst.byt[0] = src->byt[3];
|
||||
dst.byt[1] = src->byt[2];
|
||||
dst.byt[2] = src->byt[1];
|
||||
dst.byt[3] = src->byt[0];
|
||||
return dst.num;
|
||||
}
|
||||
|
||||
static inline gsu64
|
||||
GSSwapI64(gsu64 in)
|
||||
{
|
||||
union swap {
|
||||
gsu64 num;
|
||||
gsu8 byt[8];
|
||||
} dst;
|
||||
union swap *src = (union swap*)∈
|
||||
dst.byt[0] = src->byt[7];
|
||||
dst.byt[1] = src->byt[6];
|
||||
dst.byt[2] = src->byt[5];
|
||||
dst.byt[3] = src->byt[4];
|
||||
dst.byt[4] = src->byt[3];
|
||||
dst.byt[5] = src->byt[2];
|
||||
dst.byt[6] = src->byt[1];
|
||||
dst.byt[7] = src->byt[0];
|
||||
return dst.num;
|
||||
}
|
||||
|
||||
static inline gsu128
|
||||
GSSwapI128(gsu128 in)
|
||||
{
|
||||
union swap {
|
||||
gsu128 num;
|
||||
gsu8 byt[16];
|
||||
} dst;
|
||||
union swap *src = (union swap*)∈
|
||||
dst.byt[0] = src->byt[15];
|
||||
dst.byt[1] = src->byt[14];
|
||||
dst.byt[2] = src->byt[13];
|
||||
dst.byt[3] = src->byt[12];
|
||||
dst.byt[4] = src->byt[11];
|
||||
dst.byt[5] = src->byt[10];
|
||||
dst.byt[6] = src->byt[9];
|
||||
dst.byt[7] = src->byt[8];
|
||||
dst.byt[8] = src->byt[7];
|
||||
dst.byt[9] = src->byt[6];
|
||||
dst.byt[10] = src->byt[5];
|
||||
dst.byt[11] = src->byt[4];
|
||||
dst.byt[12] = src->byt[3];
|
||||
dst.byt[13] = src->byt[2];
|
||||
dst.byt[14] = src->byt[1];
|
||||
dst.byt[15] = src->byt[0];
|
||||
return dst.num;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now the OpenStep functions
|
||||
*/
|
||||
static inline NSSwappedDouble
|
||||
NSConvertHostDoubleToSwapped(double num) __attribute__((unused));
|
||||
static inline NSSwappedFloat
|
||||
|
@ -213,75 +303,85 @@ NSConvertSwappedFloatToHost(NSSwappedFloat num)
|
|||
static inline unsigned int
|
||||
NSSwapInt(unsigned int in)
|
||||
{
|
||||
union swap {
|
||||
unsigned int num;
|
||||
unsigned char byt[4];
|
||||
} dst;
|
||||
union swap *src = (union swap*)∈
|
||||
dst.byt[0] = src->byt[3];
|
||||
dst.byt[1] = src->byt[2];
|
||||
dst.byt[2] = src->byt[1];
|
||||
dst.byt[3] = src->byt[0];
|
||||
return dst.num;
|
||||
#if GS_SIZEOF_INT == 2
|
||||
return GSSwapI16(in);
|
||||
#else
|
||||
#if GS_SIZEOF_INT == 4
|
||||
return GSSwapI32(in);
|
||||
#else
|
||||
#if GS_SIZEOF_INT == 8
|
||||
return GSSwapI64(in);
|
||||
#else
|
||||
return GSSwapI128(in);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline unsigned long long
|
||||
NSSwapLongLong(unsigned long long in)
|
||||
{
|
||||
union swap {
|
||||
unsigned long long num;
|
||||
unsigned char byt[8];
|
||||
} dst;
|
||||
union swap *src = (union swap*)∈
|
||||
dst.byt[0] = src->byt[7];
|
||||
dst.byt[1] = src->byt[6];
|
||||
dst.byt[2] = src->byt[5];
|
||||
dst.byt[3] = src->byt[4];
|
||||
dst.byt[4] = src->byt[3];
|
||||
dst.byt[5] = src->byt[2];
|
||||
dst.byt[6] = src->byt[1];
|
||||
dst.byt[7] = src->byt[0];
|
||||
return dst.num;
|
||||
#if GS_SIZEOF_LONG_LONG == 2
|
||||
return GSSwapI16(in);
|
||||
#else
|
||||
#if GS_SIZEOF_LONG_LONG == 4
|
||||
return GSSwapI32(in);
|
||||
#else
|
||||
#if GS_SIZEOF_LONG_LONG == 8
|
||||
return GSSwapI64(in);
|
||||
#else
|
||||
return GSSwapI128(in);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
NSSwapLong(unsigned long in)
|
||||
{
|
||||
union swap {
|
||||
unsigned long num;
|
||||
unsigned char byt[4];
|
||||
} dst;
|
||||
union swap *src = (union swap*)∈
|
||||
dst.byt[0] = src->byt[3];
|
||||
dst.byt[1] = src->byt[2];
|
||||
dst.byt[2] = src->byt[1];
|
||||
dst.byt[3] = src->byt[0];
|
||||
return dst.num;
|
||||
#if GS_SIZEOF_LONG == 2
|
||||
return GSSwapI16(in);
|
||||
#else
|
||||
#if GS_SIZEOF_LONG == 4
|
||||
return GSSwapI32(in);
|
||||
#else
|
||||
#if GS_SIZEOF_LONG == 8
|
||||
return GSSwapI64(in);
|
||||
#else
|
||||
return GSSwapI128(in);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline unsigned short
|
||||
NSSwapShort(unsigned short in)
|
||||
{
|
||||
union swap {
|
||||
unsigned short num;
|
||||
unsigned char byt[2];
|
||||
} dst;
|
||||
union swap *src = (union swap*)∈
|
||||
dst.byt[0] = src->byt[1];
|
||||
dst.byt[1] = src->byt[0];
|
||||
return dst.num;
|
||||
#if GS_SIZEOF_SHORT == 2
|
||||
return GSSwapI16(in);
|
||||
#else
|
||||
#if GS_SIZEOF_SHORT == 4
|
||||
return GSSwapI32(in);
|
||||
#else
|
||||
#if GS_SIZEOF_SHORT == 8
|
||||
return GSSwapI64(in);
|
||||
#else
|
||||
return GSSwapI128(in);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline NSSwappedDouble
|
||||
NSSwapDouble(NSSwappedDouble num)
|
||||
{
|
||||
return NSSwapLongLong(num);
|
||||
return GSSwapI64(num);
|
||||
}
|
||||
|
||||
static inline NSSwappedFloat
|
||||
NSSwapFloat(NSSwappedFloat num)
|
||||
{
|
||||
return NSSwapLong(num);
|
||||
return GSSwapI32(num);
|
||||
}
|
||||
|
||||
#if GS_WORDS_BIGENDIAN
|
||||
|
|
|
@ -91,19 +91,89 @@
|
|||
@end
|
||||
|
||||
#ifndef NO_GNUSTEP
|
||||
|
||||
/*
|
||||
* We include special support for coding/decoding - adding methods for
|
||||
* serializing/deserializing type-tags and cross-references.
|
||||
*
|
||||
* A type-tag is a byte containing -
|
||||
* Bit7 Set to indicate that the tag is for a cross-reference.
|
||||
* Bit5-6 A value for the size of the type or cross-reference.
|
||||
* Bit0-4 A value representing an Objective-C type.
|
||||
*/
|
||||
|
||||
#define _GSC_NONE 0x00 /* No type information. */
|
||||
#define _GSC_XREF 0x80 /* Cross reference to an item. */
|
||||
#define _GSC_SIZE 0x60 /* Type-size info mask. */
|
||||
#define _GSC_MASK 0x1f /* Basic type info mask. */
|
||||
|
||||
/*
|
||||
* If the tag is for a cross-reference, the size field defines the
|
||||
* size of the cross-reference value -
|
||||
* _GSC_X_0 (no crossref), _GSC_X_1, _GSC_X_2, _GSC_X_4
|
||||
*/
|
||||
#define _GSC_X_0 0x00 /* nil or null pointer */
|
||||
#define _GSC_X_1 0x20 /* 8-bit cross-ref */
|
||||
#define _GSC_X_2 0x40 /* 16-bit cross-ref */
|
||||
#define _GSC_X_4 0x60 /* 32-bit cross-ref */
|
||||
|
||||
/*
|
||||
* If the tag is for an integer value, the size field defines the
|
||||
* size of the the encoded integer -
|
||||
* _GSC_I16, _GSC_I32, _GSC_I64, _GSC_I128
|
||||
* The file GSConfig.h (produced by the configure script) defines the
|
||||
* size codes for this machines 'natural' integers -
|
||||
* _GSC_S_SHT, _GSC_S_INT, _GSC_S_LNG, _GSC_S_LNG_LNG
|
||||
*/
|
||||
#define _GSC_I16 0x00
|
||||
#define _GSC_I32 0x20
|
||||
#define _GSC_I64 0x40
|
||||
#define _GSC_I128 0x60
|
||||
|
||||
/*
|
||||
* For the first sixteen types, the size information applies to the
|
||||
* size of the type, for the second sixteen it applies to the
|
||||
* following cross-reference number (or is zero if no crossref follows).
|
||||
*/
|
||||
#define _GSC_MAYX 0x10 /* Item may have crossref. */
|
||||
|
||||
/*
|
||||
* These are the types that can be archived -
|
||||
*/
|
||||
#define _GSC_CHR 0x01
|
||||
#define _GSC_UCHR 0x02
|
||||
#define _GSC_SHT 0x03
|
||||
#define _GSC_USHT 0x04
|
||||
#define _GSC_INT 0x05
|
||||
#define _GSC_UINT 0x06
|
||||
#define _GSC_LNG 0x07
|
||||
#define _GSC_ULNG 0x08
|
||||
#define _GSC_LNG_LNG 0x09
|
||||
#define _GSC_ULNG_LNG 0x0a
|
||||
#define _GSC_FLT 0x0b
|
||||
#define _GSC_DBL 0x0c
|
||||
|
||||
#define _GSC_ID 0x10
|
||||
#define _GSC_CLASS 0x11
|
||||
#define _GSC_SEL 0x12
|
||||
#define _GSC_PTR 0x13
|
||||
#define _GSC_CHARPTR 0x14
|
||||
#define _GSC_ARY_B 0x15
|
||||
#define _GSC_STRUCT_B 0x16
|
||||
|
||||
@interface NSData (GNUstepExtensions)
|
||||
+ (id) dataWithShmID: (int)anID length: (unsigned) length;
|
||||
+ (id) dataWithSharedBytes: (const void*)bytes length: (unsigned) length;
|
||||
+ (id) dataWithStaticBytes: (const void*)bytes length: (unsigned) length;
|
||||
|
||||
/*
|
||||
* -deserializeTypeTagAtCursor:
|
||||
* -deserializeCrossRefAtCursor:
|
||||
* These methods are provided in order to give the GNUstep version of
|
||||
* -deserializeTypeTag:andCrossRef:atCursor:
|
||||
* This method is provided in order to give the GNUstep version of
|
||||
* NSUnarchiver maximum possible performance.
|
||||
*/
|
||||
- (unsigned char) deserializeTypeTagAtCursor: (unsigned*)cursor;
|
||||
- (unsigned) deserializeCrossRefAtCursor: (unsigned*)cursor;
|
||||
- (void) deserializeTypeTag: (unsigned char*)tag
|
||||
andCrossRef: (unsigned int*)xref
|
||||
atCursor: (unsigned*)cursor;
|
||||
|
||||
/*
|
||||
* -initWithBytesNoCopy:length:fromZone:
|
||||
|
@ -192,12 +262,13 @@
|
|||
|
||||
/*
|
||||
* -serializeTypeTag:
|
||||
* -serializeCrossRef:
|
||||
* -serializeTypeTag:andCrossRef:
|
||||
* These methods are provided in order to give the GNUstep version of
|
||||
* NSArchiver maximum possible performance.
|
||||
*/
|
||||
- (void) serializeTypeTag: (unsigned char)tag;
|
||||
- (void) serializeCrossRef: (unsigned)xref;
|
||||
- (void) serializeTypeTag: (unsigned char)tag
|
||||
andCrossRef: (unsigned)xref;
|
||||
|
||||
@end
|
||||
#endif
|
||||
|
|
|
@ -216,6 +216,18 @@ $(GNUSTEP_OBJ_DIR)/NSMethodSignature.o \
|
|||
$(GNUSTEP_OBJ_DIR)/NSObjCRuntime.o \
|
||||
: $(GNUSTEP_TARGET_CPU)/$(GNUSTEP_TARGET_OS)/mframe.h
|
||||
|
||||
#
|
||||
# Files that need a rebuild if GSConfig.h is changed.
|
||||
#
|
||||
$(GNUSTEP_OBJ_DIR)/mframe.o \
|
||||
$(GNUSTEP_OBJ_DIR)/NSArchiver.o \
|
||||
$(GNUSTEP_OBJ_DIR)/NSConnection.o \
|
||||
$(GNUSTEP_OBJ_DIR)/NSData.o \
|
||||
$(GNUSTEP_OBJ_DIR)/NSInvocation.o \
|
||||
$(GNUSTEP_OBJ_DIR)/NSMethodSignature.o \
|
||||
$(GNUSTEP_OBJ_DIR)/NSUnarchiver.o \
|
||||
: $(GNUSTEP_TARGET_CPU)/$(GNUSTEP_TARGET_OS)/GSConfig.h
|
||||
|
||||
#
|
||||
# Files that include FastArray.x will need a rebuild if it is changed.
|
||||
#
|
||||
|
|
|
@ -55,7 +55,7 @@ typedef unsigned char uchar;
|
|||
|
||||
static SEL serSel = @selector(serializeDataAt:ofObjCType:context:);
|
||||
static SEL tagSel = @selector(serializeTypeTag:);
|
||||
static SEL xRefSel = @selector(serializeCrossRef:);
|
||||
static SEL xRefSel = @selector(serializeTypeTag:andCrossRef:);
|
||||
static SEL eObjSel = @selector(encodeObject:);
|
||||
static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
||||
|
||||
|
@ -195,33 +195,33 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
|||
|
||||
switch (*type)
|
||||
{
|
||||
case _C_ID: info = _C_NONE; break;
|
||||
case _C_CHR: info = _C_CHR; break;
|
||||
case _C_UCHR: info = _C_UCHR; break;
|
||||
case _C_SHT: info = _C_SHT; break;
|
||||
case _C_USHT: info = _C_USHT; break;
|
||||
case _C_INT: info = _C_INT; break;
|
||||
case _C_UINT: info = _C_UINT; break;
|
||||
case _C_LNG: info = _C_LNG; break;
|
||||
case _C_ULNG: info = _C_ULNG; break;
|
||||
case _C_ID: info = _GSC_NONE; break;
|
||||
case _C_CHR: info = _GSC_CHR; break;
|
||||
case _C_UCHR: info = _GSC_UCHR; break;
|
||||
case _C_SHT: info = _GSC_SHT | _GSC_S_SHT; break;
|
||||
case _C_USHT: info = _GSC_USHT | _GSC_S_SHT; break;
|
||||
case _C_INT: info = _GSC_INT | _GSC_S_INT; break;
|
||||
case _C_UINT: info = _GSC_UINT | _GSC_S_INT; break;
|
||||
case _C_LNG: info = _GSC_LNG | _GSC_S_LNG; break;
|
||||
case _C_ULNG: info = _GSC_ULNG | _GSC_S_LNG; break;
|
||||
#ifdef _C_LNG_LNG
|
||||
case _C_LNG_LNG: info = _C_LNG_LNG; break;
|
||||
case _C_ULNG_LNG: info = _C_ULNG_LNG; break;
|
||||
case _C_LNG_LNG: info = _GSC_LNG_LNG | _GSC_S_LNG_LNG; break;
|
||||
case _C_ULNG_LNG: info = _GSC_ULNG_LNG | _GSC_S_LNG_LNG; break;
|
||||
#endif
|
||||
case _C_FLT: info = _C_FLT; break;
|
||||
case _C_DBL: info = _C_DBL; break;
|
||||
default: info = _C_NONE; break;
|
||||
case _C_FLT: info = _GSC_FLT; break;
|
||||
case _C_DBL: info = _GSC_DBL; break;
|
||||
default: info = _GSC_NONE; break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple types can be serialized immediately, more complex ones
|
||||
* are dealt with by our [encodeValueOfObjCType:at:] method.
|
||||
*/
|
||||
if (info == _C_NONE)
|
||||
if (info == _GSC_NONE)
|
||||
{
|
||||
if (isInPreparatoryPass == NO)
|
||||
{
|
||||
(*tagImp)(dst, tagSel, _C_ARY_B);
|
||||
(*tagImp)(dst, tagSel, _GSC_ARY_B);
|
||||
(*serImp)(dst, serSel, &count, @encode(unsigned), nil);
|
||||
}
|
||||
for (i = 0; i < count; i++)
|
||||
|
@ -232,7 +232,7 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
|||
}
|
||||
else if (isInPreparatoryPass == NO)
|
||||
{
|
||||
(*tagImp)(dst, tagSel, _C_ARY_B);
|
||||
(*tagImp)(dst, tagSel, _GSC_ARY_B);
|
||||
(*serImp)(dst, serSel, &count, @encode(unsigned), nil);
|
||||
|
||||
(*tagImp)(dst, tagSel, info);
|
||||
|
@ -264,10 +264,6 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
|||
type++;
|
||||
}
|
||||
|
||||
if (isInPreparatoryPass == NO)
|
||||
{
|
||||
(*tagImp)(dst, tagSel, _C_ARY_B);
|
||||
}
|
||||
[self encodeArrayOfObjCType: type count: count at: buf];
|
||||
}
|
||||
return;
|
||||
|
@ -278,7 +274,7 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
|||
|
||||
if (isInPreparatoryPass == NO)
|
||||
{
|
||||
(*tagImp)(dst, tagSel, _C_STRUCT_B);
|
||||
(*tagImp)(dst, tagSel, _GSC_STRUCT_B);
|
||||
}
|
||||
|
||||
while (*type != _C_STRUCT_E && *type++ != '='); /* skip "<name>=" */
|
||||
|
@ -314,8 +310,7 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
|||
/*
|
||||
* Special case - a nul pointer gets an xref of zero
|
||||
*/
|
||||
(*tagImp)(dst, tagSel, _C_PTR | _C_XREF);
|
||||
(*xRefImp)(dst, xRefSel, 0);
|
||||
(*tagImp)(dst, tagSel, _GSC_PTR | _GSC_XREF | _GSC_X_0);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -352,8 +347,7 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
|||
{
|
||||
node->value.I = ++xRefP;
|
||||
}
|
||||
(*tagImp)(dst, tagSel, _C_PTR);
|
||||
(*xRefImp)(dst, xRefSel, node->value.I);
|
||||
(*xRefImp)(dst, xRefSel, _GSC_PTR, node->value.I);
|
||||
type++;
|
||||
buf = *(char**)buf;
|
||||
(*eValImp)(self, eValSel, type, buf);
|
||||
|
@ -363,8 +357,7 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
|||
/*
|
||||
* Second pass, write a cross-reference number.
|
||||
*/
|
||||
(*tagImp)(dst, tagSel, _C_PTR | _C_XREF);
|
||||
(*xRefImp)(dst, xRefSel, node->value.I);
|
||||
(*xRefImp)(dst, xRefSel, _GSC_PTR | _GSC_XREF, node->value.I);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -385,8 +378,7 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
|||
/*
|
||||
* Special case - a nul pointer gets an xref of zero
|
||||
*/
|
||||
(*tagImp)(dst, tagSel, _C_CLASS | _C_XREF);
|
||||
(*xRefImp)(dst, xRefSel, 0);
|
||||
(*tagImp)(dst, tagSel, _GSC_CLASS | _GSC_XREF | _GSC_X_0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -398,8 +390,7 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
|||
|
||||
if (node != 0)
|
||||
{
|
||||
(*tagImp)(dst, tagSel, _C_CLASS | _C_XREF);
|
||||
(*xRefImp)(dst, xRefSel, node->value.I);
|
||||
(*xRefImp)(dst, xRefSel, _GSC_CLASS | _GSC_XREF, node->value.I);
|
||||
return;
|
||||
}
|
||||
while (done == NO)
|
||||
|
@ -418,8 +409,7 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
|||
/*
|
||||
* Encode tag and crossref number.
|
||||
*/
|
||||
(*tagImp)(dst, tagSel, _C_CLASS);
|
||||
(*xRefImp)(dst, xRefSel, node->value.I);
|
||||
(*xRefImp)(dst, xRefSel, _GSC_CLASS, node->value.I);
|
||||
/*
|
||||
* Encode class, and version.
|
||||
*/
|
||||
|
@ -445,7 +435,7 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
|||
/*
|
||||
* Encode an empty tag to terminate the list of classes.
|
||||
*/
|
||||
(*tagImp)(dst, tagSel, _C_NONE);
|
||||
(*tagImp)(dst, tagSel, _GSC_NONE);
|
||||
}
|
||||
return;
|
||||
|
||||
|
@ -455,8 +445,7 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
|||
/*
|
||||
* Special case - a nul pointer gets an xref of zero
|
||||
*/
|
||||
(*tagImp)(dst, tagSel, _C_SEL | _C_XREF);
|
||||
(*xRefImp)(dst, xRefSel, 0);
|
||||
(*tagImp)(dst, tagSel, _GSC_SEL | _GSC_XREF | _GSC_X_0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -467,8 +456,7 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
|||
{
|
||||
node = FastMapAddPair(ptrMap,
|
||||
(FastMapItem)(void*)s, (FastMapItem)++xRefP);
|
||||
(*tagImp)(dst, tagSel, _C_SEL);
|
||||
(*xRefImp)(dst, xRefSel, node->value.I);
|
||||
(*xRefImp)(dst, xRefSel, _GSC_SEL, node->value.I);
|
||||
/*
|
||||
* Encode selector.
|
||||
*/
|
||||
|
@ -476,8 +464,7 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
|||
}
|
||||
else
|
||||
{
|
||||
(*tagImp)(dst, tagSel, _C_SEL | _C_XREF);
|
||||
(*xRefImp)(dst, xRefSel, node->value.I);
|
||||
(*xRefImp)(dst, xRefSel, _GSC_SEL | _GSC_XREF, node->value.I);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -488,8 +475,7 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
|||
/*
|
||||
* Special case - a nul pointer gets an xref of zero
|
||||
*/
|
||||
(*tagImp)(dst, tagSel, _C_CHARPTR | _C_XREF);
|
||||
(*xRefImp)(dst, xRefSel, 0);
|
||||
(*tagImp)(dst, tagSel, _GSC_CHARPTR | _GSC_XREF | _GSC_X_0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -500,77 +486,75 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
|||
{
|
||||
node = FastMapAddPair(ptrMap,
|
||||
(FastMapItem)*(char**)buf, (FastMapItem)++xRefP);
|
||||
(*tagImp)(dst, tagSel, _C_CHARPTR);
|
||||
(*xRefImp)(dst, xRefSel, node->value.I);
|
||||
(*xRefImp)(dst, xRefSel, _GSC_CHARPTR, node->value.I);
|
||||
(*serImp)(dst, serSel, buf, type, nil);
|
||||
}
|
||||
else
|
||||
{
|
||||
(*tagImp)(dst, tagSel, _C_CHARPTR | _C_XREF);
|
||||
(*xRefImp)(dst, xRefSel, node->value.I);
|
||||
(*xRefImp)(dst, xRefSel, _GSC_CHARPTR|_GSC_XREF, node->value.I);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
case _C_CHR:
|
||||
(*tagImp)(dst, tagSel, _C_CHR);
|
||||
(*tagImp)(dst, tagSel, _GSC_CHR);
|
||||
(*serImp)(dst, serSel, (void*)buf, @encode(char), nil);
|
||||
return;
|
||||
|
||||
case _C_UCHR:
|
||||
(*tagImp)(dst, tagSel, _C_UCHR);
|
||||
(*tagImp)(dst, tagSel, _GSC_UCHR);
|
||||
(*serImp)(dst, serSel, (void*)buf, @encode(unsigned char), nil);
|
||||
return;
|
||||
|
||||
case _C_SHT:
|
||||
(*tagImp)(dst, tagSel, _C_SHT);
|
||||
(*tagImp)(dst, tagSel, _GSC_SHT | _GSC_S_SHT);
|
||||
(*serImp)(dst, serSel, (void*)buf, @encode(short), nil);
|
||||
return;
|
||||
|
||||
case _C_USHT:
|
||||
(*tagImp)(dst, tagSel, _C_USHT);
|
||||
(*tagImp)(dst, tagSel, _GSC_USHT | _GSC_S_SHT);
|
||||
(*serImp)(dst, serSel, (void*)buf, @encode(unsigned short), nil);
|
||||
return;
|
||||
|
||||
case _C_INT:
|
||||
(*tagImp)(dst, tagSel, _C_INT);
|
||||
(*tagImp)(dst, tagSel, _GSC_INT | _GSC_S_INT);
|
||||
(*serImp)(dst, serSel, (void*)buf, @encode(int), nil);
|
||||
return;
|
||||
|
||||
case _C_UINT:
|
||||
(*tagImp)(dst, tagSel, _C_UINT);
|
||||
(*tagImp)(dst, tagSel, _GSC_UINT | _GSC_S_INT);
|
||||
(*serImp)(dst, serSel, (void*)buf, @encode(unsigned int), nil);
|
||||
return;
|
||||
|
||||
case _C_LNG:
|
||||
(*tagImp)(dst, tagSel, _C_LNG);
|
||||
(*tagImp)(dst, tagSel, _GSC_LNG | _GSC_S_LNG);
|
||||
(*serImp)(dst, serSel, (void*)buf, @encode(long), nil);
|
||||
return;
|
||||
|
||||
case _C_ULNG:
|
||||
(*tagImp)(dst, tagSel, _C_ULNG);
|
||||
(*tagImp)(dst, tagSel, _GSC_ULNG | _GSC_S_LNG);
|
||||
(*serImp)(dst, serSel, (void*)buf, @encode(unsigned long), nil);
|
||||
return;
|
||||
|
||||
#ifdef _C_LNG_LNG
|
||||
case _C_LNG_LNG:
|
||||
(*tagImp)(dst, tagSel, _C_LNG_LNG);
|
||||
(*tagImp)(dst, tagSel, _GSC_LNG_LNG | _GSC_S_LNG_LNG);
|
||||
(*serImp)(dst, serSel, (void*)buf, @encode(long long), nil);
|
||||
return;
|
||||
|
||||
case _C_ULNG_LNG:
|
||||
(*tagImp)(dst, tagSel, _C_ULNG_LNG);
|
||||
(*tagImp)(dst, tagSel, _GSC_ULNG_LNG | _GSC_S_LNG_LNG);
|
||||
(*serImp)(dst, serSel, (void*)buf, @encode(unsigned long long), nil);
|
||||
return;
|
||||
|
||||
#endif
|
||||
case _C_FLT:
|
||||
(*tagImp)(dst, tagSel, _C_FLT);
|
||||
(*tagImp)(dst, tagSel, _GSC_FLT);
|
||||
(*serImp)(dst, serSel, (void*)buf, @encode(float), nil);
|
||||
return;
|
||||
|
||||
case _C_DBL:
|
||||
(*tagImp)(dst, tagSel, _C_DBL);
|
||||
(*tagImp)(dst, tagSel, _GSC_DBL);
|
||||
(*serImp)(dst, serSel, (void*)buf, @encode(double), nil);
|
||||
return;
|
||||
|
||||
|
@ -699,8 +683,7 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
|||
/*
|
||||
* Special case - encode a nil pointer as a crossref of zero.
|
||||
*/
|
||||
(*tagImp)(dst, tagSel, _C_ID | _C_XREF);
|
||||
(*xRefImp)(dst, xRefSel, 0);
|
||||
(*tagImp)(dst, tagSel, _GSC_ID | _GSC_XREF, _GSC_X_0);
|
||||
}
|
||||
}
|
||||
else if (fastIsInstance(anObject) == NO)
|
||||
|
@ -748,7 +731,6 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
|||
{
|
||||
Class cls;
|
||||
id obj;
|
||||
uchar info = _C_ID;
|
||||
|
||||
if (node == 0)
|
||||
{
|
||||
|
@ -763,8 +745,7 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
|||
obj = [anObject replacementObjectForArchiver: self];
|
||||
cls = [anObject classForArchiver];
|
||||
|
||||
(*tagImp)(dst, tagSel, _C_ID);
|
||||
(*xRefImp)(dst, xRefSel, node->value.I);
|
||||
(*xRefImp)(dst, xRefSel, _GSC_ID, node->value.I);
|
||||
if (namMap->nodeCount)
|
||||
{
|
||||
FastMapNode node;
|
||||
|
@ -781,8 +762,7 @@ static SEL eValSel = @selector(encodeValueOfObjCType:at:);
|
|||
}
|
||||
else if(!isInPreparatoryPass)
|
||||
{
|
||||
(*tagImp)(dst, tagSel, _C_ID | _C_XREF);
|
||||
(*xRefImp)(dst, xRefSel, node->value.I);
|
||||
(*xRefImp)(dst, xRefSel, _GSC_ID | _GSC_XREF, node->value.I);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
883
Source/NSData.m
883
Source/NSData.m
File diff suppressed because it is too large
Load diff
|
@ -46,12 +46,10 @@
|
|||
|
||||
#include <base/fast.x>
|
||||
|
||||
typedef unsigned char uchar;
|
||||
|
||||
static const char*
|
||||
typeToName(char type)
|
||||
typeToName1(char type)
|
||||
{
|
||||
switch (type & _C_MASK)
|
||||
switch (type)
|
||||
{
|
||||
case _C_CLASS: return "class";
|
||||
case _C_ID: return "object";
|
||||
|
@ -94,22 +92,107 @@ typeToName(char type)
|
|||
}
|
||||
}
|
||||
|
||||
static const char*
|
||||
typeToName2(char type)
|
||||
{
|
||||
switch (type & _GSC_MASK)
|
||||
{
|
||||
case _GSC_CLASS: return "class";
|
||||
case _GSC_ID: return "object";
|
||||
case _GSC_SEL: return "selector";
|
||||
case _GSC_CHR: return "char";
|
||||
case _GSC_UCHR: return "unsigned char";
|
||||
case _GSC_SHT: return "short";
|
||||
case _GSC_USHT: return "unsigned short";
|
||||
case _GSC_INT: return "int";
|
||||
case _GSC_UINT: return "unsigned int";
|
||||
case _GSC_LNG: return "long";
|
||||
case _GSC_ULNG: return "unsigned long";
|
||||
#ifdef _GSC_LNG_LNG
|
||||
case _GSC_LNG_LNG: return "long long";
|
||||
case _GSC_ULNG_LNG: return "unsigned long long";
|
||||
#endif
|
||||
case _GSC_FLT: return "float";
|
||||
case _GSC_DBL: return "double";
|
||||
case _GSC_PTR: return "pointer";
|
||||
case _GSC_CHARPTR: return "cstring";
|
||||
case _GSC_ARY_B: return "array";
|
||||
case _GSC_STRUCT_B: return "struct";
|
||||
default:
|
||||
{
|
||||
static char buf1[32];
|
||||
static char buf2[32];
|
||||
static char *bufptr = buf1;
|
||||
|
||||
if (bufptr == buf1)
|
||||
{
|
||||
bufptr = buf2;
|
||||
}
|
||||
else
|
||||
{
|
||||
bufptr = buf1;
|
||||
}
|
||||
sprintf(bufptr, "unknown type info - 0x%x", type);
|
||||
return bufptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* There are thirtyone possible basic types. We reserve a type of zero
|
||||
* to mean that no information is specified. The slots in this array
|
||||
* MUST correspond to the definitions in NSData.h
|
||||
*/
|
||||
static char type_map[32] = {
|
||||
0,
|
||||
_C_CHR,
|
||||
_C_UCHR,
|
||||
_C_SHT,
|
||||
_C_USHT,
|
||||
_C_INT,
|
||||
_C_UINT,
|
||||
_C_LNG,
|
||||
_C_ULNG,
|
||||
_C_LNG_LNG,
|
||||
_C_ULNG_LNG,
|
||||
_C_FLT,
|
||||
_C_DBL,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
_C_ID,
|
||||
_C_CLASS,
|
||||
_C_SEL,
|
||||
_C_PTR,
|
||||
_C_CHARPTR,
|
||||
_C_ARY_B,
|
||||
_C_STRUCT_B,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
static inline void
|
||||
typeCheck(char t1, char t2)
|
||||
{
|
||||
if (t1 != t2)
|
||||
if (type_map[(t2 & _GSC_MASK)] != t1)
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"expected %s and got %s",
|
||||
typeToName(t1), typeToName(t2)];
|
||||
typeToName1(t1), typeToName2(t2)];
|
||||
}
|
||||
}
|
||||
|
||||
#define PREFIX "GNUstep archive"
|
||||
|
||||
static SEL desSel = @selector(deserializeDataAt:ofObjCType:atCursor:context:);
|
||||
static SEL tagSel = @selector(deserializeTypeTagAtCursor:);
|
||||
static SEL xRefSel = @selector(deserializeCrossRefAtCursor:);
|
||||
static SEL tagSel = @selector(deserializeTypeTag:andCrossRef:atCursor:);
|
||||
static SEL dValSel = @selector(decodeValueOfObjCType:at:);
|
||||
|
||||
@interface NSUnarchiverClassInfo : NSObject
|
||||
|
@ -288,10 +371,8 @@ mapClassName(NSUnarchiverObjectInfo *info)
|
|||
{
|
||||
src = self; /* Default object to handle serialisation */
|
||||
desImp = [src methodForSelector: desSel];
|
||||
tagImp = (unsigned char (*)(id, SEL, unsigned*))
|
||||
tagImp = (void (*)(id, SEL, unsigned char*, unsigned*, unsigned*))
|
||||
[src methodForSelector: tagSel];
|
||||
xRefImp = (unsigned (*)(id, SEL, unsigned*))
|
||||
[src methodForSelector: xRefSel];
|
||||
}
|
||||
/*
|
||||
* objDict is a dictionary of objects for mapping classes of
|
||||
|
@ -314,15 +395,15 @@ mapClassName(NSUnarchiverObjectInfo *info)
|
|||
int i;
|
||||
int offset = 0;
|
||||
int size = objc_sizeof_type(type);
|
||||
uchar info;
|
||||
unsigned char info;
|
||||
unsigned count;
|
||||
|
||||
info = (*tagImp)(src, tagSel, &cursor);
|
||||
(*tagImp)(src, tagSel, &info, 0, &cursor);
|
||||
(*desImp)(src, desSel, &count, @encode(unsigned), &cursor, nil);
|
||||
if (info != _C_ARY_B)
|
||||
if (info != _GSC_ARY_B)
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"expected array and got %s", typeToName(info)];
|
||||
format: @"expected array and got %s", typeToName2(info)];
|
||||
}
|
||||
if (count != expected)
|
||||
{
|
||||
|
@ -333,25 +414,25 @@ mapClassName(NSUnarchiverObjectInfo *info)
|
|||
|
||||
switch (*type)
|
||||
{
|
||||
case _C_ID: info = _C_NONE; break;
|
||||
case _C_CHR: info = _C_CHR; break;
|
||||
case _C_UCHR: info = _C_UCHR; break;
|
||||
case _C_SHT: info = _C_SHT; break;
|
||||
case _C_USHT: info = _C_USHT; break;
|
||||
case _C_INT: info = _C_INT; break;
|
||||
case _C_UINT: info = _C_UINT; break;
|
||||
case _C_LNG: info = _C_LNG; break;
|
||||
case _C_ULNG: info = _C_ULNG; break;
|
||||
case _C_ID: info = _GSC_NONE; break;
|
||||
case _C_CHR: info = _GSC_CHR; break;
|
||||
case _C_UCHR: info = _GSC_UCHR; break;
|
||||
case _C_SHT: info = _GSC_SHT; break;
|
||||
case _C_USHT: info = _GSC_USHT; break;
|
||||
case _C_INT: info = _GSC_INT; break;
|
||||
case _C_UINT: info = _GSC_UINT; break;
|
||||
case _C_LNG: info = _GSC_LNG; break;
|
||||
case _C_ULNG: info = _GSC_ULNG; break;
|
||||
#ifdef _C_LNG_LNG
|
||||
case _C_LNG_LNG: info = _C_LNG_LNG; break;
|
||||
case _C_ULNG_LNG: info = _C_ULNG_LNG; break;
|
||||
case _C_LNG_LNG: info = _GSC_LNG_LNG; break;
|
||||
case _C_ULNG_LNG: info = _GSC_ULNG_LNG; break;
|
||||
#endif
|
||||
case _C_FLT: info = _C_FLT; break;
|
||||
case _C_DBL: info = _C_DBL; break;
|
||||
default: info = _C_NONE; break;
|
||||
case _C_FLT: info = _GSC_FLT; break;
|
||||
case _C_DBL: info = _GSC_DBL; break;
|
||||
default: info = _GSC_NONE; break;
|
||||
}
|
||||
|
||||
if (info == _C_NONE)
|
||||
if (info == _GSC_NONE)
|
||||
{
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
|
@ -361,15 +442,16 @@ mapClassName(NSUnarchiverObjectInfo *info)
|
|||
}
|
||||
else
|
||||
{
|
||||
uchar ainfo;
|
||||
unsigned char ainfo;
|
||||
|
||||
(*tagImp)(src, tagSel, &ainfo, 0, &cursor);
|
||||
if (info != (ainfo & _GSC_MASK))
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"expected %s and got %s",
|
||||
typeToName2(info), typeToName2(ainfo)];
|
||||
}
|
||||
|
||||
ainfo = (*tagImp)(src, tagSel, &cursor);
|
||||
if (info != ainfo)
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"expected %s and got %s",
|
||||
typeToName(info), typeToName(ainfo)];
|
||||
}
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
(*desImp)(src, desSel, (char*)buf + offset, type, &cursor, nil);
|
||||
|
@ -381,27 +463,37 @@ mapClassName(NSUnarchiverObjectInfo *info)
|
|||
- (void) decodeValueOfObjCType: (const char*)type
|
||||
at: (void*)address
|
||||
{
|
||||
uchar info = (*tagImp)(src, tagSel, &cursor);
|
||||
unsigned xref;
|
||||
unsigned char info;
|
||||
#if GS_HAVE_I128
|
||||
gsu128 bigval;
|
||||
#else
|
||||
#if GS_HAVE_I64
|
||||
gsu64 bigval;
|
||||
#else
|
||||
gsu32 bigval;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
switch (info & _C_MASK)
|
||||
(*tagImp)(src, tagSel, &info, &xref, &cursor);
|
||||
|
||||
switch (info & _GSC_MASK)
|
||||
{
|
||||
case _C_ID:
|
||||
case _GSC_ID:
|
||||
{
|
||||
unsigned xref;
|
||||
id obj;
|
||||
|
||||
typeCheck(*type, _C_ID);
|
||||
xref = (*xRefImp)(src, xRefSel, &cursor);
|
||||
typeCheck(*type, _GSC_ID);
|
||||
/*
|
||||
* Special case - a zero crossref value is a nil pointer.
|
||||
* Special case - a zero crossref value size is a nil pointer.
|
||||
*/
|
||||
if (xref == 0)
|
||||
if ((info & _GSC_SIZE) == 0)
|
||||
{
|
||||
obj = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (info & _C_XREF)
|
||||
if (info & _GSC_XREF)
|
||||
{
|
||||
if (xref >= FastArrayCount(objMap))
|
||||
{
|
||||
|
@ -451,24 +543,23 @@ mapClassName(NSUnarchiverObjectInfo *info)
|
|||
*(id*)address = obj;
|
||||
return;
|
||||
}
|
||||
case _C_CLASS:
|
||||
|
||||
case _GSC_CLASS:
|
||||
{
|
||||
unsigned xref;
|
||||
Class c;
|
||||
NSUnarchiverObjectInfo *classInfo;
|
||||
Class dummy;
|
||||
|
||||
typeCheck(*type, _C_CLASS);
|
||||
xref = (*xRefImp)(src, xRefSel, &cursor);
|
||||
if (xref == 0)
|
||||
typeCheck(*type, _GSC_CLASS);
|
||||
/*
|
||||
* Special case - a zero crossref value size is a nil pointer.
|
||||
*/
|
||||
if ((info & _GSC_SIZE) == 0)
|
||||
{
|
||||
/*
|
||||
* Special case - an xref of zero is a nul pointer.
|
||||
*/
|
||||
*(SEL*)address = 0;
|
||||
return;
|
||||
}
|
||||
if (info & _C_XREF)
|
||||
if (info & _GSC_XREF)
|
||||
{
|
||||
if (xref >= FastArrayCount(clsMap))
|
||||
{
|
||||
|
@ -479,7 +570,7 @@ mapClassName(NSUnarchiverObjectInfo *info)
|
|||
*(Class*)address = mapClassObject(classInfo);
|
||||
return;
|
||||
}
|
||||
while (info == _C_CLASS)
|
||||
while ((info & _GSC_MASK) == _GSC_CLASS)
|
||||
{
|
||||
unsigned cver;
|
||||
NSString *className;
|
||||
|
@ -513,35 +604,30 @@ mapClassName(NSUnarchiverObjectInfo *info)
|
|||
* next tag - if it is another class, loop to get it.
|
||||
*/
|
||||
address = &dummy;
|
||||
info = (*tagImp)(src, tagSel, &cursor);
|
||||
if (info == _C_CLASS)
|
||||
{
|
||||
xref = (*xRefImp)(src, xRefSel, &cursor);
|
||||
}
|
||||
(*tagImp)(src, tagSel, &info, &xref, &cursor);
|
||||
}
|
||||
if (info != _C_NONE)
|
||||
if (info != _GSC_NONE)
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"class list improperly terminated"];
|
||||
}
|
||||
return;
|
||||
}
|
||||
case _C_SEL:
|
||||
|
||||
case _GSC_SEL:
|
||||
{
|
||||
unsigned xref;
|
||||
SEL sel;
|
||||
|
||||
typeCheck(*type, _C_SEL);
|
||||
xref = (*xRefImp)(src, xRefSel, &cursor);
|
||||
if (xref == 0)
|
||||
typeCheck(*type, _GSC_SEL);
|
||||
/*
|
||||
* Special case - a zero crossref value size is a nil pointer.
|
||||
*/
|
||||
if ((info & _GSC_SIZE) == 0)
|
||||
{
|
||||
/*
|
||||
* Special case - an xref of zero is a nul pointer.
|
||||
*/
|
||||
*(SEL*)address = 0;
|
||||
return;
|
||||
}
|
||||
if (info & _C_XREF)
|
||||
if (info & _GSC_XREF)
|
||||
{
|
||||
if (xref >= FastArrayCount(ptrMap))
|
||||
{
|
||||
|
@ -563,11 +649,12 @@ mapClassName(NSUnarchiverObjectInfo *info)
|
|||
*(SEL*)address = sel;
|
||||
return;
|
||||
}
|
||||
case _C_ARY_B:
|
||||
|
||||
case _GSC_ARY_B:
|
||||
{
|
||||
int count;
|
||||
|
||||
typeCheck(*type, _C_ARY_B);
|
||||
typeCheck(*type, _GSC_ARY_B);
|
||||
count = atoi(++type);
|
||||
while (isdigit(*type))
|
||||
{
|
||||
|
@ -576,11 +663,12 @@ mapClassName(NSUnarchiverObjectInfo *info)
|
|||
[self decodeArrayOfObjCType: type count: count at: address];
|
||||
return;
|
||||
}
|
||||
case _C_STRUCT_B:
|
||||
|
||||
case _GSC_STRUCT_B:
|
||||
{
|
||||
int offset = 0;
|
||||
|
||||
typeCheck(*type, _C_STRUCT_B);
|
||||
typeCheck(*type, _GSC_STRUCT_B);
|
||||
while (*type != _C_STRUCT_E && *type++ != '='); /* skip "<name>=" */
|
||||
for (;;)
|
||||
{
|
||||
|
@ -604,21 +692,19 @@ mapClassName(NSUnarchiverObjectInfo *info)
|
|||
}
|
||||
return;
|
||||
}
|
||||
case _C_PTR:
|
||||
{
|
||||
unsigned xref;
|
||||
|
||||
typeCheck(*type, _C_PTR);
|
||||
xref = (*xRefImp)(src, xRefSel, &cursor);
|
||||
if (xref == 0)
|
||||
case _GSC_PTR:
|
||||
{
|
||||
typeCheck(*type, _GSC_PTR);
|
||||
/*
|
||||
* Special case - a zero crossref value size is a nil pointer.
|
||||
*/
|
||||
if ((info & _GSC_SIZE) == 0)
|
||||
{
|
||||
/*
|
||||
* Special case - an xref of zero is a nul pointer.
|
||||
*/
|
||||
*(void**)address = 0;
|
||||
return;
|
||||
}
|
||||
if (info & _C_XREF)
|
||||
if (info & _GSC_XREF)
|
||||
{
|
||||
if (xref >= FastArrayCount(ptrMap))
|
||||
{
|
||||
|
@ -653,22 +739,21 @@ mapClassName(NSUnarchiverObjectInfo *info)
|
|||
}
|
||||
return;
|
||||
}
|
||||
case _C_CHARPTR:
|
||||
|
||||
case _GSC_CHARPTR:
|
||||
{
|
||||
unsigned xref;
|
||||
char *str;
|
||||
|
||||
typeCheck(*type, _C_CHARPTR);
|
||||
xref = (*xRefImp)(src, xRefSel, &cursor);
|
||||
if (xref == 0)
|
||||
typeCheck(*type, _GSC_CHARPTR);
|
||||
/*
|
||||
* Special case - a zero crossref value size is a nil pointer.
|
||||
*/
|
||||
if ((info & _GSC_SIZE) == 0)
|
||||
{
|
||||
/*
|
||||
* Special case - an xref of zero is a nul pointer.
|
||||
*/
|
||||
*(char**)address = 0;
|
||||
return;
|
||||
}
|
||||
if (info & _C_XREF)
|
||||
if (info & _GSC_XREF)
|
||||
{
|
||||
if (xref >= FastArrayCount(ptrMap))
|
||||
{
|
||||
|
@ -691,59 +776,171 @@ mapClassName(NSUnarchiverObjectInfo *info)
|
|||
}
|
||||
return;
|
||||
}
|
||||
case _C_CHR:
|
||||
typeCheck(*type, _C_CHR);
|
||||
|
||||
case _GSC_CHR:
|
||||
case _GSC_UCHR:
|
||||
typeCheck(*type, info & _GSC_MASK);
|
||||
(*desImp)(src, desSel, address, type, &cursor, nil);
|
||||
return;
|
||||
|
||||
case _GSC_SHT:
|
||||
case _GSC_USHT:
|
||||
typeCheck(*type, info & _GSC_MASK);
|
||||
if ((info & _GSC_SIZE) == _GSC_S_SHT)
|
||||
{
|
||||
(*desImp)(src, desSel, address, type, &cursor, nil);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case _C_UCHR:
|
||||
typeCheck(*type, _C_UCHR);
|
||||
(*desImp)(src, desSel, address, type, &cursor, nil);
|
||||
break;
|
||||
case _C_SHT:
|
||||
typeCheck(*type, _C_SHT);
|
||||
(*desImp)(src, desSel, address, type, &cursor, nil);
|
||||
break;
|
||||
case _C_USHT:
|
||||
typeCheck(*type, _C_USHT);
|
||||
(*desImp)(src, desSel, address, type, &cursor, nil);
|
||||
break;
|
||||
case _C_INT:
|
||||
typeCheck(*type, _C_INT);
|
||||
(*desImp)(src, desSel, address, type, &cursor, nil);
|
||||
break;
|
||||
case _C_UINT:
|
||||
typeCheck(*type, _C_UINT);
|
||||
(*desImp)(src, desSel, address, type, &cursor, nil);
|
||||
break;
|
||||
case _C_LNG:
|
||||
typeCheck(*type, _C_LNG);
|
||||
(*desImp)(src, desSel, address, type, &cursor, nil);
|
||||
break;
|
||||
case _C_ULNG:
|
||||
typeCheck(*type, _C_ULNG);
|
||||
(*desImp)(src, desSel, address, type, &cursor, nil);
|
||||
break;
|
||||
|
||||
case _GSC_INT:
|
||||
case _GSC_UINT:
|
||||
typeCheck(*type, info & _GSC_MASK);
|
||||
if ((info & _GSC_SIZE) == _GSC_S_INT)
|
||||
{
|
||||
(*desImp)(src, desSel, address, type, &cursor, nil);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case _GSC_LNG:
|
||||
case _GSC_ULNG:
|
||||
typeCheck(*type, info & _GSC_MASK);
|
||||
if ((info & _GSC_SIZE) == _GSC_S_LNG)
|
||||
{
|
||||
(*desImp)(src, desSel, address, type, &cursor, nil);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef _C_LNG_LNG
|
||||
case _C_LNG_LNG:
|
||||
typeCheck(*type, _C_LNG_LNG);
|
||||
(*desImp)(src, desSel, address, type, &cursor, nil);
|
||||
break;
|
||||
case _C_ULNG_LNG:
|
||||
typeCheck(*type, _C_ULNG_LNG);
|
||||
(*desImp)(src, desSel, address, type, &cursor, nil);
|
||||
break;
|
||||
case _GSC_LNG_LNG:
|
||||
case _GSC_ULNG_LNG:
|
||||
typeCheck(*type, info & _GSC_MASK);
|
||||
if ((info & _GSC_SIZE) == _GSC_S_LNG_LNG)
|
||||
{
|
||||
(*desImp)(src, desSel, address, type, &cursor, nil);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
#endif
|
||||
case _C_FLT:
|
||||
typeCheck(*type, _C_FLT);
|
||||
(*desImp)(src, desSel, address, type, &cursor, nil);
|
||||
break;
|
||||
case _C_DBL:
|
||||
typeCheck(*type, _C_DBL);
|
||||
(*desImp)(src, desSel, address, type, &cursor, nil);
|
||||
break;
|
||||
case _GSC_FLT:
|
||||
typeCheck(*type, _GSC_FLT);
|
||||
(*desImp)(src, desSel, address, type, &cursor, nil);
|
||||
return;
|
||||
|
||||
case _GSC_DBL:
|
||||
typeCheck(*type, _GSC_DBL);
|
||||
(*desImp)(src, desSel, address, type, &cursor, nil);
|
||||
return;
|
||||
|
||||
default:
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"read unknown type info - %d", info];
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"read unknown type info - %d", info];
|
||||
}
|
||||
|
||||
/*
|
||||
* We fall through to here only when we have to decode a value
|
||||
* whose natural size on this system is not the same as on the
|
||||
* machine on which the archive was created.
|
||||
*/
|
||||
|
||||
/*
|
||||
* First, we read the data and convert it to the largest size
|
||||
* this system can support.
|
||||
*/
|
||||
switch (info & _GSC_SIZE)
|
||||
{
|
||||
case _GSC_I16: /* Encoded as 16-bit */
|
||||
{
|
||||
gsu16 val;
|
||||
|
||||
(*desImp)(src, desSel, &val, @encode(gsu16), &cursor, nil);
|
||||
bigval = val;
|
||||
break;
|
||||
}
|
||||
|
||||
case _GSC_I32: /* Encoded as 32-bit */
|
||||
{
|
||||
gsu32 val;
|
||||
|
||||
(*desImp)(src, desSel, &val, @encode(gsu32), &cursor, nil);
|
||||
bigval = val;
|
||||
break;
|
||||
}
|
||||
|
||||
case _GSC_I64: /* Encoded as 64-bit */
|
||||
{
|
||||
gsu64 val;
|
||||
|
||||
(*desImp)(src, desSel, &val, @encode(gsu64), &cursor, nil);
|
||||
#if GS_HAVE_I64
|
||||
bigval = val;
|
||||
#else
|
||||
#if GS_WORDS_BIGENDIAN == 0
|
||||
val = GSSwapI64(val);
|
||||
#endif
|
||||
bigval = *(gsu32*)&val;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
default: /* A 128-bit value */
|
||||
{
|
||||
gsu128 val;
|
||||
|
||||
(*desImp)(src, desSel, &val, @encode(gsu128), &cursor, nil);
|
||||
#if GS_HAVE_I128
|
||||
bigval = val;
|
||||
#else
|
||||
#if GS_WORDS_BIGENDIAN == 0
|
||||
val = GSSwapI128(val);
|
||||
#endif
|
||||
#if GS_HAVE_I64
|
||||
bigval = *(gsu64*)&val;
|
||||
#else
|
||||
bigval = *(gsu32*)&val;
|
||||
#endif
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we copy from the 'bigval' to the destination location.
|
||||
*/
|
||||
switch (info & _GSC_MASK)
|
||||
{
|
||||
case _GSC_SHT:
|
||||
*(short*)address = (short)bigval;
|
||||
return;
|
||||
case _GSC_USHT:
|
||||
*(unsigned short*)address = (unsigned short)bigval;
|
||||
return;
|
||||
case _GSC_INT:
|
||||
*(int*)address = (int)bigval;
|
||||
return;
|
||||
case _GSC_UINT:
|
||||
*(unsigned int*)address = (unsigned int)bigval;
|
||||
return;
|
||||
case _GSC_LNG:
|
||||
*(long*)address = (long)bigval;
|
||||
return;
|
||||
case _GSC_ULNG:
|
||||
*(unsigned long*)address = (unsigned long)bigval;
|
||||
return;
|
||||
#ifdef _C_LNG_LNG
|
||||
case _GSC_LNG_LNG:
|
||||
*(long long*)address = (long long)bigval;
|
||||
return;
|
||||
case _GSC_ULNG_LNG:
|
||||
*(unsigned long long*)address = (unsigned long long)bigval;
|
||||
return;
|
||||
#endif
|
||||
default:
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"type/size information error"];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -755,27 +952,26 @@ mapClassName(NSUnarchiverObjectInfo *info)
|
|||
*/
|
||||
- (id) decodeObject
|
||||
{
|
||||
uchar info;
|
||||
unsigned char info;
|
||||
unsigned xref;
|
||||
id obj;
|
||||
|
||||
info = (*tagImp)(src, tagSel, &cursor);
|
||||
if ((info & _C_MASK) != _C_ID)
|
||||
(*tagImp)(src, tagSel, &info, &xref, &cursor);
|
||||
if ((info & _GSC_MASK) != _GSC_ID)
|
||||
{
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"expected object and got %s", typeToName(info)];
|
||||
format: @"expected object and got %s", typeToName2(info)];
|
||||
}
|
||||
|
||||
xref = (*xRefImp)(src, xRefSel, &cursor);
|
||||
/*
|
||||
* Special case - a zero crossref value is a nil pointer.
|
||||
*/
|
||||
if (xref == 0)
|
||||
if ((info & _GSC_SIZE) == 0)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (info & _C_XREF)
|
||||
if (info & _GSC_XREF)
|
||||
{
|
||||
if (xref >= FastArrayCount(objMap))
|
||||
{
|
||||
|
@ -987,10 +1183,8 @@ mapClassName(NSUnarchiverObjectInfo *info)
|
|||
* Cache methods for deserialising from the data object.
|
||||
*/
|
||||
desImp = [src methodForSelector: desSel];
|
||||
tagImp = (unsigned char (*)(id, SEL, unsigned*))
|
||||
tagImp = (void (*)(id, SEL, unsigned char*, unsigned*, unsigned*))
|
||||
[src methodForSelector: tagSel];
|
||||
xRefImp = (unsigned (*)(id, SEL, unsigned*))
|
||||
[src methodForSelector: xRefSel];
|
||||
}
|
||||
}
|
||||
dataClass = c;
|
||||
|
|
|
@ -256,6 +256,8 @@ getAddr(NSString* name, NSString* svc, NSString* pcl, struct sockaddr_in *sin)
|
|||
int net;
|
||||
struct sockaddr_in sin;
|
||||
|
||||
if (a == nil || [a isEqualToString: @""])
|
||||
a = @"localhost";
|
||||
if (s == nil)
|
||||
{
|
||||
NSLog(@"bad argument - service is nil");
|
||||
|
|
84
configure.in
84
configure.in
|
@ -181,7 +181,7 @@ AC_DEFINE_UNQUOTED(NeXT_cc, $NeXT_cc)
|
|||
AC_SUBST(NEXT_INCLUDES)
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Byte order and type size information needed for foundation headers.
|
||||
# Byte order information needed for foundation headers.
|
||||
#--------------------------------------------------------------------
|
||||
AC_C_BIGENDIAN
|
||||
if test $ac_cv_c_bigendian = yes; then
|
||||
|
@ -191,6 +191,9 @@ else
|
|||
fi
|
||||
AC_SUBST(GS_WORDS_BIGENDIAN)
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Type size information needed for foundation headers.
|
||||
#--------------------------------------------------------------------
|
||||
GS_SINT8="signed char"
|
||||
GS_UINT8="unsigned char"
|
||||
AC_SUBST(GS_SINT8)
|
||||
|
@ -249,59 +252,88 @@ fi
|
|||
AC_SUBST(GS_SINT32)
|
||||
AC_SUBST(GS_UINT32)
|
||||
|
||||
if test $ac_cv_sizeof_long_long = 8; then
|
||||
GS_SINT64="signed long long"
|
||||
GS_UINT64="unsigned long long"
|
||||
GS_HAVE_I64=1
|
||||
if test $ac_cv_sizeof_int = 8; then
|
||||
GS_SINT64="signed int"
|
||||
GS_UINT64="unsigned int"
|
||||
else
|
||||
if test $ac_cv_sizeof_long = 8; then
|
||||
GS_SINT64="signed long"
|
||||
GS_UINT64="unsigned long"
|
||||
else
|
||||
echo "Unable to determine type for 64-bit integer - abort configuration"
|
||||
exit
|
||||
if test $ac_cv_sizeof_long_long = 8; then
|
||||
GS_SINT64="signed long long"
|
||||
GS_UINT64="unsigned long long"
|
||||
else
|
||||
# 64-bit ints not supported - but we need a dummy type for byte-swapping
|
||||
# of 64-bit values arriving from another system.
|
||||
GS_SINT64="struct { gsu8 a[8]; }"
|
||||
GS_SINT64="struct { gsu8 a[9]; }"
|
||||
GS_HAVE_I64=0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(GS_SINT64)
|
||||
AC_SUBST(GS_UINT64)
|
||||
AC_SUBST(GS_HAVE_I64)
|
||||
|
||||
GS_HAVE_I128=1
|
||||
if test $ac_cv_sizeof_long = 16; then
|
||||
GS_SINT128="signed long"
|
||||
GS_UINT128="unsigned long"
|
||||
else
|
||||
if test $ac_cv_sizeof_long_long = 16; then
|
||||
GS_SINT128="signed long long"
|
||||
GS_UINT128="unsigned long long"
|
||||
else
|
||||
# 128-bit ints not supported - but we need a dummy type for byte-swapping
|
||||
# of 128-bit values arriving from another system.
|
||||
GS_SINT128="struct { gsu8 a[16]; }"
|
||||
GS_SINT128="struct { gsu8 a[16]; }"
|
||||
GS_HAVE_I128=0
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(GS_SINT128)
|
||||
AC_SUBST(GS_UINT128)
|
||||
AC_SUBST(GS_HAVE_I128)
|
||||
|
||||
if test $ac_cv_sizeof_float = 4; then
|
||||
GS_FLT32="float"
|
||||
else
|
||||
echo "Unable to determine type for 32-bit float - abort configuration"
|
||||
exit
|
||||
echo "Unable to determine type for 32-bit float - abort configuration"
|
||||
exit
|
||||
fi
|
||||
AC_SUBST(GS_FLT32)
|
||||
|
||||
if test $ac_cv_sizeof_double = 8; then
|
||||
GS_FLT64="double"
|
||||
else
|
||||
echo "Unable to determine type for 64-bit float - abort configuration"
|
||||
exit
|
||||
echo "Unable to determine type for 64-bit float - abort configuration"
|
||||
exit
|
||||
fi
|
||||
AC_SUBST(GS_FLT64)
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Type-size information for encoding into archives using NSArchiver etc.
|
||||
# 0x00 == 2 bytes, 0x20 == 4 bytes, 0x40 == 8 bytes, 0x60 == 16 bytes
|
||||
#--------------------------------------------------------------------
|
||||
if test $ac_cv_sizeof_short = 4; then
|
||||
_GSC_S_SHT=0x20
|
||||
if test $ac_cv_sizeof_short = 2; then
|
||||
_GSC_S_SHT=_GSC_I16
|
||||
else
|
||||
_GSC_S_SHT=0x00
|
||||
_GSC_S_SHT=_GSC_I32
|
||||
fi
|
||||
AC_SUBST(_GSC_S_SHT)
|
||||
|
||||
if test $ac_cv_sizeof_int = 4; then
|
||||
_GSC_S_INT=0x20
|
||||
if test $ac_cv_sizeof_int = 2; then
|
||||
_GSC_S_INT=_GSC_I16
|
||||
else
|
||||
if test $ac_cv_sizeof_int = 2; then
|
||||
_GSC_S_INT=0x00
|
||||
if test $ac_cv_sizeof_int = 4; then
|
||||
_GSC_S_INT=_GSC_I32
|
||||
else
|
||||
if test $ac_cv_sizeof_int = 8; then
|
||||
_GSC_S_INT=0x40
|
||||
_GSC_S_INT=_GSC_I64
|
||||
else
|
||||
if test $ac_cv_sizeof_int = 16; then
|
||||
_GSC_S_INT=0x60
|
||||
_GSC_S_INT=_GSC_I128
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
@ -309,26 +341,26 @@ fi
|
|||
AC_SUBST(_GSC_S_INT)
|
||||
|
||||
if test $ac_cv_sizeof_long = 4; then
|
||||
_GSC_S_LNG=0x20
|
||||
_GSC_S_LNG=_GSC_I32
|
||||
else
|
||||
if test $ac_cv_sizeof_long = 8; then
|
||||
_GSC_S_LNG=0x40
|
||||
_GSC_S_LNG=_GSC_I_64
|
||||
else
|
||||
if test $ac_cv_sizeof_long = 16; then
|
||||
_GSC_S_LNG=0x60
|
||||
_GSC_S_LNG=_GSC_I128
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(_GSC_S_LNG)
|
||||
|
||||
if test $ac_cv_sizeof_long_long = 4; then
|
||||
_GSC_S_LNG_LNG=0x20
|
||||
_GSC_S_LNG_LNG=_GSC_I32
|
||||
else
|
||||
if test $ac_cv_sizeof_long_long = 8; then
|
||||
_GSC_S_LNG_LNG=0x40
|
||||
_GSC_S_LNG_LNG=_GSC_I64
|
||||
else
|
||||
if test $ac_cv_sizeof_long_long = 16; then
|
||||
_GSC_S_LNG_LNG=0x60
|
||||
_GSC_S_LNG_LNG=_GSC_I128
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
|
Loading…
Reference in a new issue