mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-14 10:05:44 -04:00
Split .dat parser into dat parser portion and java deserialiser portion
This commit is contained in:
parent
8e3acc9e61
commit
84356f0847
27
src/Errors.h
27
src/Errors.h
@ -78,19 +78,20 @@ enum CC_ERRORS {
|
||||
|
||||
LVL_ERR_VERSION = 0xCCDED03DUL, /* LVL stream byte #1-#2 aren't 1874 */
|
||||
|
||||
DAT_ERR_IDENTIFIER = 0xCCDED03EUL, /* DAT stream bytes #1-#4 aren't 0x271BB788 */
|
||||
DAT_ERR_VERSION = 0xCCDED03FUL, /* DAT stream byte #5 isn't 2 */
|
||||
DAT_ERR_JIDENTIFIER = 0xCCDED040UL, /* DAT stream bytes #6-#7 aren't 0xACED */
|
||||
DAT_ERR_JVERSION = 0xCCDED041UL, /* DAT stream bytes #8-#9 aren't 0x0005 */
|
||||
DAT_ERR_ROOT_TYPE = 0xCCDED042UL, /* Java root element type isn't Object */
|
||||
DAT_ERR_JSTRING_LEN = 0xCCDED043UL, /* Java string is too long */
|
||||
DAT_ERR_JFIELD_CLASS_NAME = 0xCCDED044UL, /* Java field classname type is invalid */
|
||||
DAT_ERR_JCLASS_TYPE = 0xCCDED045UL, /* Java class classdesc type is invalid */
|
||||
DAT_ERR_JCLASS_FIELDS = 0xCCDED046UL, /* Java class classdesc has too many fields */
|
||||
DAT_ERR_JCLASS_ANNOTATION = 0xCCDED047UL, /* Java classdesc uses unsupported annotations */
|
||||
DAT_ERR_JOBJECT_TYPE = 0xCCDED048UL, /* Java object field data type is invalid */
|
||||
DAT_ERR_JARRAY_TYPE = 0xCCDED049UL, /* Java array field data type is invalid */
|
||||
DAT_ERR_JARRAY_CONTENT = 0xCCDED04AUL, /* Java array field isn't a byte array */
|
||||
DAT_ERR_IDENTIFIER = 0xCCDED03EUL, /* DAT stream bytes #1-#4 aren't 0x271BB788 */
|
||||
DAT_ERR_VERSION = 0xCCDED03FUL, /* DAT stream byte #5 isn't 2 */
|
||||
DAT_ERR_JIDENTIFIER = 0xCCDED040UL, /* DAT stream bytes #6-#7 aren't 0xACED */
|
||||
DAT_ERR_JVERSION = 0xCCDED041UL, /* DAT stream bytes #8-#9 aren't 0x0005 */
|
||||
DAT_ERR_ROOT_TYPE = 0xCCDED042UL, /* Java root element type isn't Object */
|
||||
|
||||
JAVA_ERR_JSTRING_LEN = 0xCCDED043UL, /* Java string is too long */
|
||||
JAVA_ERR_JFIELD_CLASS_NAME = 0xCCDED044UL, /* Java field classname type is invalid */
|
||||
JAVA_ERR_JCLASS_TYPE = 0xCCDED045UL, /* Java class classdesc type is invalid */
|
||||
JAVA_ERR_JCLASS_FIELDS = 0xCCDED046UL, /* Java class classdesc has too many fields */
|
||||
JAVA_ERR_JCLASS_ANNOTATION = 0xCCDED047UL, /* Java classdesc uses unsupported annotations */
|
||||
JAVA_ERR_JOBJECT_TYPE = 0xCCDED048UL, /* Java object field data type is invalid */
|
||||
JAVA_ERR_JARRAY_TYPE = 0xCCDED049UL, /* Java array field data type is invalid */
|
||||
JAVA_ERR_JARRAY_CONTENT = 0xCCDED04AUL, /* Java array field isn't a byte array */
|
||||
|
||||
NBT_ERR_UNKNOWN = 0xCCDED04BUL, /* NBT tag has an unknown type */
|
||||
CW_ERR_ROOT_TAG = 0xCCDED04CUL, /* NBT root tag isn't a Compound tag */
|
||||
|
111
src/Formats.c
111
src/Formats.c
@ -716,9 +716,9 @@ cc_result Cw_Load(struct Stream* stream) {
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-------------------------------------------------Minecraft .dat format---------------------------------------------------*
|
||||
*-----------------------------------------------Java serialisation format-------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
/* .dat is a java serialised map format. Rather than bothering following this, I skip a lot of it.
|
||||
/* Rather than bothering following this, I skip a lot of the java serialisation format
|
||||
Stream BlockData BlockDataTiny BlockDataLong
|
||||
|--------------| |---------------| |---------------| |---------------|
|
||||
| U16 Magic | |>BlockDataTiny | | TC_BLOCKDATA | | TC_BLOCKLONG |
|
||||
@ -764,7 +764,7 @@ struct JClassDesc {
|
||||
struct JFieldDesc Fields[22];
|
||||
};
|
||||
|
||||
static cc_result Dat_ReadString(struct Stream* stream, cc_uint8* buffer) {
|
||||
static cc_result Java_ReadString(struct Stream* stream, cc_uint8* buffer) {
|
||||
int len;
|
||||
cc_result res;
|
||||
|
||||
@ -772,33 +772,33 @@ static cc_result Dat_ReadString(struct Stream* stream, cc_uint8* buffer) {
|
||||
len = Stream_GetU16_BE(buffer);
|
||||
|
||||
Mem_Set(buffer, 0, JNAME_SIZE);
|
||||
if (len > JNAME_SIZE) return DAT_ERR_JSTRING_LEN;
|
||||
if (len > JNAME_SIZE) return JAVA_ERR_JSTRING_LEN;
|
||||
return Stream_Read(stream, buffer, len);
|
||||
}
|
||||
|
||||
static cc_result Dat_ReadFieldDesc(struct Stream* stream, struct JFieldDesc* desc) {
|
||||
static cc_result Java_ReadFieldDesc(struct Stream* stream, struct JFieldDesc* desc) {
|
||||
cc_uint8 typeCode;
|
||||
cc_uint8 className1[JNAME_SIZE];
|
||||
cc_result res;
|
||||
|
||||
if ((res = stream->ReadU8(stream, &desc->Type))) return res;
|
||||
if ((res = Dat_ReadString(stream, desc->FieldName))) return res;
|
||||
if ((res = stream->ReadU8(stream, &desc->Type))) return res;
|
||||
if ((res = Java_ReadString(stream, desc->FieldName))) return res;
|
||||
|
||||
if (desc->Type == JFIELD_ARRAY || desc->Type == JFIELD_OBJECT) {
|
||||
if ((res = stream->ReadU8(stream, &typeCode))) return res;
|
||||
|
||||
if (typeCode == TC_STRING) {
|
||||
return Dat_ReadString(stream, className1);
|
||||
return Java_ReadString(stream, className1);
|
||||
} else if (typeCode == TC_REFERENCE) {
|
||||
return stream->Skip(stream, 4); /* (4) handle */
|
||||
} else {
|
||||
return DAT_ERR_JFIELD_CLASS_NAME;
|
||||
return JAVA_ERR_JFIELD_CLASS_NAME;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cc_result Dat_ReadClassDesc(struct Stream* stream, struct JClassDesc* desc) {
|
||||
static cc_result Java_ReadClassDesc(struct Stream* stream, struct JClassDesc* desc) {
|
||||
cc_uint8 typeCode;
|
||||
cc_uint8 count[2];
|
||||
struct JClassDesc superClassDesc;
|
||||
@ -807,26 +807,26 @@ static cc_result Dat_ReadClassDesc(struct Stream* stream, struct JClassDesc* des
|
||||
|
||||
if ((res = stream->ReadU8(stream, &typeCode))) return res;
|
||||
if (typeCode == TC_NULL) { desc->ClassName[0] = '\0'; desc->FieldsCount = 0; return 0; }
|
||||
if (typeCode != TC_CLASSDESC) return DAT_ERR_JCLASS_TYPE;
|
||||
if (typeCode != TC_CLASSDESC) return JAVA_ERR_JCLASS_TYPE;
|
||||
|
||||
if ((res = Dat_ReadString(stream, desc->ClassName))) return res;
|
||||
if ((res = Java_ReadString(stream, desc->ClassName))) return res;
|
||||
if ((res = stream->Skip(stream, 9))) return res; /* (8) serial version UID, (1) flags */
|
||||
|
||||
if ((res = Stream_Read(stream, count, 2))) return res;
|
||||
desc->FieldsCount = Stream_GetU16_BE(count);
|
||||
if (desc->FieldsCount > Array_Elems(desc->Fields)) return DAT_ERR_JCLASS_FIELDS;
|
||||
if (desc->FieldsCount > Array_Elems(desc->Fields)) return JAVA_ERR_JCLASS_FIELDS;
|
||||
|
||||
for (i = 0; i < desc->FieldsCount; i++) {
|
||||
if ((res = Dat_ReadFieldDesc(stream, &desc->Fields[i]))) return res;
|
||||
if ((res = Java_ReadFieldDesc(stream, &desc->Fields[i]))) return res;
|
||||
}
|
||||
|
||||
if ((res = stream->ReadU8(stream, &typeCode))) return res;
|
||||
if (typeCode != TC_ENDBLOCKDATA) return DAT_ERR_JCLASS_ANNOTATION;
|
||||
if (typeCode != TC_ENDBLOCKDATA) return JAVA_ERR_JCLASS_ANNOTATION;
|
||||
|
||||
return Dat_ReadClassDesc(stream, &superClassDesc);
|
||||
return Java_ReadClassDesc(stream, &superClassDesc);
|
||||
}
|
||||
|
||||
static cc_result Dat_ReadFieldData(struct Stream* stream, struct JFieldDesc* field) {
|
||||
static cc_result Java_ReadFieldData(struct Stream* stream, struct JFieldDesc* field) {
|
||||
cc_uint8 typeCode;
|
||||
cc_string fieldName;
|
||||
cc_uint32 count;
|
||||
@ -860,7 +860,7 @@ static cc_result Dat_ReadFieldData(struct Stream* stream, struct JFieldDesc* fie
|
||||
if ((res = stream->Skip(stream, 152))) return res;
|
||||
} else if (typeCode != TC_NULL) {
|
||||
/* WoM maps have this field as null, which makes things easier for us */
|
||||
return DAT_ERR_JOBJECT_TYPE;
|
||||
return JAVA_ERR_JOBJECT_TYPE;
|
||||
}
|
||||
} break;
|
||||
|
||||
@ -873,9 +873,9 @@ static cc_result Dat_ReadFieldData(struct Stream* stream, struct JFieldDesc* fie
|
||||
break;
|
||||
}
|
||||
|
||||
if (typeCode != TC_ARRAY) return DAT_ERR_JARRAY_TYPE;
|
||||
if ((res = Dat_ReadClassDesc(stream, &arrayClassDesc))) return res;
|
||||
if (arrayClassDesc.ClassName[1] != JFIELD_I8) return DAT_ERR_JARRAY_CONTENT;
|
||||
if (typeCode != TC_ARRAY) return JAVA_ERR_JARRAY_TYPE;
|
||||
if ((res = Java_ReadClassDesc(stream, &arrayClassDesc))) return res;
|
||||
if (arrayClassDesc.ClassName[1] != JFIELD_I8) return JAVA_ERR_JARRAY_CONTENT;
|
||||
|
||||
if ((res = Stream_ReadU32_BE(stream, &count))) return res;
|
||||
field->Value.Array.Size = count;
|
||||
@ -889,11 +889,34 @@ static cc_result Dat_ReadFieldData(struct Stream* stream, struct JFieldDesc* fie
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Dat_I32(struct JFieldDesc* field) {
|
||||
static int Java_I32(struct JFieldDesc* field) {
|
||||
if (field->Type != JFIELD_I32) Logger_Abort("Field type must be Int32");
|
||||
return field->Value.I32;
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-------------------------------------------------Minecraft .dat format---------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
/* Minecraft Classic used 3 different GZIP compressed binary map formats throughout its various versions
|
||||
Preclassic - Classic 0.12:
|
||||
U8* "Blocks" (256x64x256 array)
|
||||
Classic 0.13:
|
||||
U32 "Identifier" (must be 0x271BB788)
|
||||
U8 "Version" (must be 1)
|
||||
STR "Name" (ignored)
|
||||
STR "Author" (ignored)
|
||||
U64 "Creation" (ignored)
|
||||
U16 "Width"
|
||||
U16 "Length"
|
||||
U16 "Height"
|
||||
U8* "Blocks"
|
||||
Classic 0.15 to Classic 0.30:
|
||||
U32 "Identifier" (must be 0x271BB788)
|
||||
U8 "Version" (must be 2)
|
||||
VAR "Level" (Java serialised level object instance)
|
||||
}*/
|
||||
|
||||
static void UseClassic013Env(void) {
|
||||
/* Similiar env to how it appears in 0.13 classic client */
|
||||
Env.CloudsHeight = -30000;
|
||||
@ -902,21 +925,17 @@ static void UseClassic013Env(void) {
|
||||
}
|
||||
|
||||
static cc_result Dat_LoadFormat0(struct Stream* stream) {
|
||||
/* Map 'format' is just the 256x64x256 blocks of the level */
|
||||
#define PC_WIDTH 256
|
||||
#define PC_HEIGHT 64
|
||||
#define PC_LENGTH 256
|
||||
#define PC_VOLUME (PC_WIDTH * PC_HEIGHT * PC_LENGTH)
|
||||
|
||||
UseClassic013Env();
|
||||
/* Similiar env to how it appears in preclassic client */
|
||||
Env.EdgeBlock = BLOCK_AIR;
|
||||
Env.SidesBlock = BLOCK_AIR;
|
||||
|
||||
World.Width = PC_WIDTH;
|
||||
World.Height = PC_HEIGHT;
|
||||
World.Length = PC_LENGTH;
|
||||
/* Map 'format' is just the 256x64x256 blocks of the level */
|
||||
World.Width = 256;
|
||||
World.Height = 64;
|
||||
World.Length = 256;
|
||||
|
||||
#define PC_VOLUME (256 * 64 * 256)
|
||||
World.Volume = PC_VOLUME;
|
||||
World.Blocks = (BlockRaw*)Mem_TryAlloc(PC_VOLUME, 1);
|
||||
if (!World.Blocks) return ERR_OUT_OF_MEMORY;
|
||||
@ -933,8 +952,8 @@ static cc_result Dat_LoadFormat1(struct Stream* stream) {
|
||||
cc_result res;
|
||||
|
||||
UseClassic013Env();
|
||||
if ((res = Dat_ReadString(stream, level_name))) return res;
|
||||
if ((res = Dat_ReadString(stream, level_author))) return res;
|
||||
if ((res = Java_ReadString(stream, level_name))) return res;
|
||||
if ((res = Java_ReadString(stream, level_author))) return res;
|
||||
if ((res = Stream_Read(stream, header, sizeof(header)))) return res;
|
||||
|
||||
/* bytes 0-8 = created timestamp (currentTimeMillis) */
|
||||
@ -955,32 +974,32 @@ static cc_result Dat_LoadFormat2(struct Stream* stream) {
|
||||
if ((res = Stream_Read(stream, header, sizeof(header)))) return res;
|
||||
|
||||
/* Java seralisation headers */
|
||||
if (Stream_GetU16_BE(header + 0) != 0xACED) return DAT_ERR_JIDENTIFIER;
|
||||
if (Stream_GetU16_BE(header + 2) != 0x0005) return DAT_ERR_JVERSION;
|
||||
if (header[4] != TC_OBJECT) return DAT_ERR_ROOT_TYPE;
|
||||
if ((res = Dat_ReadClassDesc(stream, &obj))) return res;
|
||||
if (Stream_GetU16_BE(header + 0) != 0xACED) return DAT_ERR_JIDENTIFIER;
|
||||
if (Stream_GetU16_BE(header + 2) != 0x0005) return DAT_ERR_JVERSION;
|
||||
if (header[4] != TC_OBJECT) return DAT_ERR_ROOT_TYPE;
|
||||
if ((res = Java_ReadClassDesc(stream, &obj))) return res;
|
||||
|
||||
for (i = 0; i < obj.FieldsCount; i++) {
|
||||
field = &obj.Fields[i];
|
||||
if ((res = Dat_ReadFieldData(stream, field))) return res;
|
||||
if ((res = Java_ReadFieldData(stream, field))) return res;
|
||||
fieldName = String_FromRaw((char*)field->FieldName, JNAME_SIZE);
|
||||
|
||||
if (String_CaselessEqualsConst(&fieldName, "width")) {
|
||||
World.Width = Dat_I32(field);
|
||||
World.Width = Java_I32(field);
|
||||
} else if (String_CaselessEqualsConst(&fieldName, "height")) {
|
||||
World.Length = Dat_I32(field);
|
||||
World.Length = Java_I32(field);
|
||||
} else if (String_CaselessEqualsConst(&fieldName, "depth")) {
|
||||
World.Height = Dat_I32(field);
|
||||
World.Height = Java_I32(field);
|
||||
} else if (String_CaselessEqualsConst(&fieldName, "blocks")) {
|
||||
if (field->Type != JFIELD_ARRAY) Logger_Abort("Blocks field must be Array");
|
||||
World.Blocks = field->Value.Array.Ptr;
|
||||
World.Volume = field->Value.Array.Size;
|
||||
} else if (String_CaselessEqualsConst(&fieldName, "xSpawn")) {
|
||||
p->Spawn.X = (float)Dat_I32(field);
|
||||
p->Spawn.X = (float)Java_I32(field);
|
||||
} else if (String_CaselessEqualsConst(&fieldName, "ySpawn")) {
|
||||
p->Spawn.Y = (float)Dat_I32(field);
|
||||
p->Spawn.Y = (float)Java_I32(field);
|
||||
} else if (String_CaselessEqualsConst(&fieldName, "zSpawn")) {
|
||||
p->Spawn.Z = (float)Dat_I32(field);
|
||||
p->Spawn.Z = (float)Java_I32(field);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -1002,8 +1021,8 @@ cc_result Dat_Load(struct Stream* stream) {
|
||||
{
|
||||
/* Classic map format signature */
|
||||
case 0x271BB788: break;
|
||||
/* Not an actual signature, but 99% of preclassic to classic 0.12 */
|
||||
/* maps will start with these 4 bytes */
|
||||
/* Not an actual signature, but 99% of preclassic */
|
||||
/* to classic 0.12 maps start with these 4 bytes */
|
||||
case 0x01010101: return Dat_LoadFormat0(&compStream);
|
||||
/* Bogus .dat file */
|
||||
default: return DAT_ERR_IDENTIFIER;
|
||||
|
Loading…
x
Reference in New Issue
Block a user