2025-07-03 12:53:49 +04:00

194 lines
7.1 KiB
C++

#include "il2cpp-config.h"
#include <stdint.h>
#include "BlobReader.h"
#include "gc/GarbageCollector.h"
#include "metadata/CustomAttributeDataReader.h"
#include "vm/Array.h"
#include "vm/Class.h"
#include "vm/Object.h"
#include "vm/MetadataCache.h"
#include "vm/Reflection.h"
#include "vm/String.h"
#include "utils/MemoryRead.h"
#include "il2cpp-object-internals.h"
const uint8_t kArrayTypeWithSameElements = 0;
const uint8_t kArrayTypeWithDifferentElements = 1;
namespace il2cpp
{
namespace utils
{
bool BlobReader::GetConstantValueFromBlob(const Il2CppImage* image, Il2CppTypeEnum type, const char* blob, void* value)
{
return GetConstantValueFromBlob(image, type, &blob, value, true);
}
bool BlobReader::GetConstantValueFromBlob(const Il2CppImage* image, Il2CppTypeEnum type, const char **blob, void *value, bool deserializeManagedObjects)
{
switch (type)
{
case IL2CPP_TYPE_BOOLEAN:
case IL2CPP_TYPE_U1:
case IL2CPP_TYPE_I1:
*(uint8_t*)value = Read8(blob);
break;
case IL2CPP_TYPE_CHAR:
*(Il2CppChar*)value = ReadChar(blob);
break;
case IL2CPP_TYPE_U2:
case IL2CPP_TYPE_I2:
*(uint16_t*)value = Read16(blob);
break;
case IL2CPP_TYPE_U4:
*(uint32_t*)value = ReadCompressedUInt32(blob);
break;
case IL2CPP_TYPE_I4:
*(int32_t*)value = ReadCompressedInt32(blob);
break;
case IL2CPP_TYPE_U8:
case IL2CPP_TYPE_I8:
*(uint64_t*)value = Read64(blob);
break;
case IL2CPP_TYPE_R4:
*(float*)value = ReadFloat(blob);
break;
case IL2CPP_TYPE_R8:
*(double*)value = ReadDouble(blob);
break;
case IL2CPP_TYPE_STRING:
{
*(void**)value = NULL;
if (*blob != NULL)
{
// int32_t length followed by non-null terminated utf-8 byte stream
int32_t length = ReadCompressedInt32(blob);
// A length of -1 is a null string
if (length != -1)
{
if (deserializeManagedObjects)
{
*(Il2CppString**)value = il2cpp::vm::String::NewLen(*blob, length);
il2cpp::gc::GarbageCollector::SetWriteBarrier((void**)value);
}
*blob += length;
}
}
break;
}
case IL2CPP_TYPE_SZARRAY:
{
if (*blob == NULL)
{
*(void**)value = NULL;
return true;
}
int32_t arrayLen = ReadCompressedInt32(blob);
if (arrayLen == -1)
{
// A length of -1 is a null array
*(void**)value = NULL;
return true;
}
Il2CppClass* arrayElementClass;
Il2CppTypeEnum arrayElementType = ReadEncodedTypeEnum(image, blob, &arrayElementClass);
uint8_t arrayElementsAreDifferent = Read8(blob);
IL2CPP_ASSERT(arrayElementClass);
IL2CPP_ASSERT(arrayElementsAreDifferent != kArrayTypeWithDifferentElements || arrayElementType == IL2CPP_TYPE_OBJECT);
Il2CppArray* arr = NULL;
if (deserializeManagedObjects)
arr = il2cpp::vm::Array::New(arrayElementClass, arrayLen);
for (int32_t i = 0; i < arrayLen; i++)
{
Il2CppClass* elementClass = NULL;
Il2CppTypeEnum elementType = arrayElementType;
if (arrayElementsAreDifferent == kArrayTypeWithDifferentElements)
elementType = ReadEncodedTypeEnum(image, blob, &elementClass);
// Assumption: The array code is only called for custom attribute data
il2cpp::metadata::CustomAttributeDataStorage dataBuffer;
IL2CPP_ASSERT(arrayElementClass->element_size <= sizeof(il2cpp::metadata::CustomAttributeDataStorage));
if (!GetConstantValueFromBlob(image, elementType, blob, &dataBuffer, deserializeManagedObjects))
return false;
if (deserializeManagedObjects)
{
if (elementType != arrayElementType)
{
IL2CPP_ASSERT(arrayElementType == IL2CPP_TYPE_OBJECT);
IL2CPP_ASSERT(elementClass);
il2cpp_array_setref(arr, i, il2cpp::vm::Object::Box(elementClass, &dataBuffer));
}
else
{
il2cpp_array_setrefwithsize(arr, arr->klass->element_size, i, &dataBuffer);
}
}
}
*(Il2CppArray**)value = arr;
il2cpp::gc::GarbageCollector::SetWriteBarrier((void**)value);
break;
}
case IL2CPP_TYPE_CLASS:
case IL2CPP_TYPE_OBJECT:
case IL2CPP_TYPE_GENERICINST:
IL2CPP_ASSERT(*blob == NULL);
*(void**)value = NULL;
break;
case IL2CPP_TYPE_IL2CPP_TYPE_INDEX:
{
TypeIndex typeIndex = ReadCompressedInt32(blob);
if (typeIndex == -1)
{
*(void**)value = NULL;
}
else if (deserializeManagedObjects)
{
Il2CppClass* klass = il2cpp::vm::MetadataCache::GetTypeInfoFromTypeIndex(image, typeIndex);
*(Il2CppReflectionType**)value = il2cpp::vm::Reflection::GetTypeObject(&klass->byval_arg);
il2cpp::gc::GarbageCollector::SetWriteBarrier((void**)value);
}
break;
}
default:
IL2CPP_ASSERT(0);
return false;
}
return true;
}
Il2CppTypeEnum BlobReader::ReadEncodedTypeEnum(const Il2CppImage* image, const char** blob, Il2CppClass** klass)
{
Il2CppTypeEnum type = (Il2CppTypeEnum)Read8(blob);
if (type == IL2CPP_TYPE_ENUM)
{
TypeIndex enumTypeIndex = ReadCompressedInt32(blob);
*klass = il2cpp::vm::MetadataCache::GetTypeInfoFromTypeIndex(image, enumTypeIndex);
type = il2cpp::vm::Class::GetEnumBaseType(*klass)->type;
}
else if (type == IL2CPP_TYPE_SZARRAY)
{
// Array class is good enough for this call
// An array with specific element types will be created if needed
*klass = il2cpp_defaults.array_class;
}
else
{
*klass = il2cpp::vm::Class::FromIl2CppTypeEnum(type);
}
return type;
}
} /* utils */
} /* il2cpp */