194 lines
7.1 KiB
C++
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 */
|