mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-07 13:39:55 +00:00
Merge pull request #15050 from noamroger/claude/project-thread-od3mt9
feat(libSceFreeTypeOt): read Mac resource fork headers and data offsets
This commit is contained in:
7 files changed
+376
-11
No files matched your search
@@ -60,3 +60,20 @@ if(BUILD_TESTING)
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceFreeTypeOt>")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_sources(libSceFreeTypeOt PRIVATE src/Raccess.cpp)
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(guest_freetype_ot_raccess_tests ${LIBS_INCLUDE_DIR}/tests/GuestFreeTypeOtRaccess.cpp)
|
||||
target_include_directories(guest_freetype_ot_raccess_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_freetype_ot_raccess_tests PRIVATE libSceFreeTypeOt)
|
||||
if(WIN32)
|
||||
target_link_libraries(guest_freetype_ot_raccess_tests PRIVATE libc)
|
||||
endif()
|
||||
configure_windows_unwind(guest_freetype_ot_raccess_tests)
|
||||
add_test(NAME guest_freetype_ot_raccess COMMAND guest_freetype_ot_raccess_tests)
|
||||
set_tests_properties(guest_freetype_ot_raccess PROPERTIES TIMEOUT 20)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_freetype_ot_raccess PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceFreeTypeOt>")
|
||||
endif()
|
||||
endif()
|
||||
@@ -289,16 +289,6 @@ int APS5_VABI sceFreeTypeOtUnknown_KVbmKCGGowg_nid_no_patch() {
|
||||
}
|
||||
APS5_EXPORT("KVbmKCGGowg", sceFreeTypeOtUnknown_KVbmKCGGowg_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceFreeTypeOtUnknown_hF3stKUWbWg_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("hF3stKUWbWg", sceFreeTypeOtUnknown_hF3stKUWbWg_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceFreeTypeOtUnknown_p5GNJaXO2yE_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("p5GNJaXO2yE", sceFreeTypeOtUnknown_p5GNJaXO2yE_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceFreeTypeOtUnknown_8cnVx1yH9_I_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// Derived from FreeType include/freetype/internal/ftrfork.h (FreeType 2.4.12, commit cecf93ef90c660a8b0b45e5adbbfb5ea443fb6b9).
|
||||
// Copyright 2004, 2006, 2007, 2012 by Masatake YAMATO and Redhat K.K.
|
||||
// This file is part of the FreeType project, and may only be used, modified, and distributed
|
||||
// under the terms of the FreeType project license, LICENSE.TXT. By continuing to use, modify,
|
||||
// or distribute this file you indicate that you have read the license and understand and accept it fully.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "prx/libSceFreeTypeOt/include/Stream.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace FreeType {
|
||||
|
||||
struct GuestRaccessLibrary {
|
||||
GuestMemoryRec* memory;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI FT_Raccess_Get_HeaderInfo_nid_postfix(FreeType::GuestRaccessLibrary* library, FreeType::GuestStreamRec* stream, std::int64_t rforkOffset,
|
||||
std::int64_t* mapOffset, std::int64_t* rdataPos);
|
||||
int APS5_VABI FT_Raccess_Get_DataOffsets_nid_postfix(FreeType::GuestRaccessLibrary* library, FreeType::GuestStreamRec* stream, std::int64_t mapOffset,
|
||||
std::int64_t rdataPos, std::int64_t tag, std::int64_t** offsets, std::int64_t* count);
|
||||
|
||||
}
|
||||
@@ -4,3 +4,4 @@
|
||||
#include "prx/libSceFreeType/include/Api.hpp"
|
||||
#include "prx/libSceFreeTypeOt/include/Calc.hpp"
|
||||
#include "prx/libSceFreeTypeOt/include/Memory.hpp"
|
||||
#include "prx/libSceFreeTypeOt/include/Raccess.hpp"
|
||||
@@ -0,0 +1,142 @@
|
||||
// Derived from FreeType src/base/ftrfork.c (FreeType 2.4.12, commit cecf93ef90c660a8b0b45e5adbbfb5ea443fb6b9).
|
||||
// Copyright 2004-2010, 2013 by Masatake YAMATO and Redhat K.K.
|
||||
// This file is part of the FreeType project, and may only be used, modified, and distributed
|
||||
// under the terms of the FreeType project license, LICENSE.TXT. By continuing to use, modify,
|
||||
// or distribute this file you indicate that you have read the license and understand and accept it fully.
|
||||
|
||||
#include "prx/libSceFreeTypeOt/include/Raccess.hpp"
|
||||
#include "prx/libSceFreeTypeOt/include/Memory.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
using namespace FreeType;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int CannotOpenResource = 0x01;
|
||||
constexpr int UnknownFileFormat = 0x02;
|
||||
constexpr std::int64_t RefSize = 16;
|
||||
constexpr std::int64_t LongMax = std::numeric_limits<std::int64_t>::max();
|
||||
constexpr std::int64_t LongMin = std::numeric_limits<std::int64_t>::min();
|
||||
|
||||
struct GuestRForkRef {
|
||||
std::uint16_t resId;
|
||||
std::uint64_t offset;
|
||||
};
|
||||
|
||||
static_assert(sizeof(GuestRForkRef) == RefSize && offsetof(GuestRForkRef, offset) == 8);
|
||||
|
||||
std::int64_t Add(std::int64_t a, std::int64_t b, const char* function) {
|
||||
if ((b > 0 && a > LongMax - b) || (b < 0 && a < LongMin - b)) NotImplemented_nid_no_patch(function);
|
||||
return a + b;
|
||||
}
|
||||
|
||||
std::int64_t Field(const std::uint8_t* head, unsigned index, const char* function) {
|
||||
if (head[index] >= 0x80) NotImplemented_nid_no_patch(function);
|
||||
return static_cast<std::int64_t>(head[index]) << 24 | head[index + 1] << 16 | head[index + 2] << 8 | head[index + 3];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI FT_Raccess_Get_HeaderInfo_nid_postfix(GuestRaccessLibrary*, GuestStreamRec* stream, std::int64_t rforkOffset,
|
||||
std::int64_t* mapOffset, std::int64_t* rdataPos) {
|
||||
const char* function = __func__;
|
||||
std::uint8_t head[16];
|
||||
std::uint8_t head2[16];
|
||||
int error = FT_Stream_Seek_nid_postfix(stream, static_cast<std::uint64_t>(rforkOffset));
|
||||
if (error) return error;
|
||||
error = FT_Stream_Read_nid_postfix(stream, head, 16);
|
||||
if (error) return error;
|
||||
const std::int64_t dataStart = Add(rforkOffset, Field(head, 0, function), function);
|
||||
const std::int64_t mapPos = Add(rforkOffset, Field(head, 4, function), function);
|
||||
const std::int64_t dataLength = Field(head, 8, function);
|
||||
if (!rdataPos) NotImplemented_nid_no_patch(function);
|
||||
*rdataPos = dataStart;
|
||||
if (Add(dataStart, dataLength, function) != mapPos || mapPos == rforkOffset) return UnknownFileFormat;
|
||||
error = FT_Stream_Seek_nid_postfix(stream, static_cast<std::uint64_t>(mapPos));
|
||||
if (error) return error;
|
||||
head2[15] = static_cast<std::uint8_t>(head[15] + 1);
|
||||
error = FT_Stream_Read_nid_postfix(stream, head2, 16);
|
||||
if (error) return error;
|
||||
bool allZeros = true;
|
||||
bool allMatch = true;
|
||||
for (unsigned index = 0; index < 16; ++index) {
|
||||
if (head2[index] != 0) allZeros = false;
|
||||
if (head2[index] != head[index]) allMatch = false;
|
||||
}
|
||||
if (!allZeros && !allMatch) return UnknownFileFormat;
|
||||
FT_Stream_Skip_nid_postfix(stream, 8);
|
||||
const std::int64_t typeList = FT_Stream_ReadUShort_nid_postfix(stream, &error);
|
||||
if (error) return error;
|
||||
error = FT_Stream_Seek_nid_postfix(stream, static_cast<std::uint64_t>(Add(mapPos, typeList, function)));
|
||||
if (error) return error;
|
||||
if (!mapOffset) NotImplemented_nid_no_patch(function);
|
||||
*mapOffset = mapPos + typeList;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI FT_Raccess_Get_DataOffsets_nid_postfix(GuestRaccessLibrary* library, GuestStreamRec* stream, std::int64_t mapOffset,
|
||||
std::int64_t rdataPos, std::int64_t tag, std::int64_t** offsets, std::int64_t* count) {
|
||||
const char* function = __func__;
|
||||
if (!library) NotImplemented_nid_no_patch(function);
|
||||
GuestMemoryRec* memory = library->memory;
|
||||
int error = FT_Stream_Seek_nid_postfix(stream, static_cast<std::uint64_t>(mapOffset));
|
||||
if (error) return error;
|
||||
const int types = FT_Stream_ReadUShort_nid_postfix(stream, &error) + 1;
|
||||
if (error) return error;
|
||||
for (int type = 0; type < types; ++type) {
|
||||
const std::int64_t typeTag = FT_Stream_ReadLong_nid_postfix(stream, &error);
|
||||
if (error) return error;
|
||||
const int subCount = FT_Stream_ReadUShort_nid_postfix(stream, &error);
|
||||
if (error) return error;
|
||||
const std::int64_t refList = FT_Stream_ReadUShort_nid_postfix(stream, &error);
|
||||
if (error) return error;
|
||||
if (typeTag != tag) continue;
|
||||
if (!count) NotImplemented_nid_no_patch(function);
|
||||
const std::int64_t refs = subCount + 1;
|
||||
*count = refs;
|
||||
error = FT_Stream_Seek_nid_postfix(stream, static_cast<std::uint64_t>(Add(refList, mapOffset, function)));
|
||||
if (error) return error;
|
||||
if (!memory) NotImplemented_nid_no_patch(function);
|
||||
auto* ref = static_cast<GuestRForkRef*>(ft_mem_realloc_nid_postfix(memory, RefSize, 0, refs, nullptr, &error));
|
||||
if (error) return error;
|
||||
for (std::int64_t index = 0; index < refs; ++index) {
|
||||
ref[index].resId = FT_Stream_ReadUShort_nid_postfix(stream, &error);
|
||||
if (!error) error = FT_Stream_Skip_nid_postfix(stream, 2);
|
||||
std::int64_t value = 0;
|
||||
if (!error) value = FT_Stream_ReadLong_nid_postfix(stream, &error);
|
||||
if (!error) error = FT_Stream_Skip_nid_postfix(stream, 4);
|
||||
if (error) {
|
||||
ft_mem_free_nid_postfix(memory, ref);
|
||||
return error;
|
||||
}
|
||||
ref[index].offset = static_cast<std::uint64_t>(value) & 0xFFFFFF;
|
||||
}
|
||||
std::stable_sort(ref, ref + refs, [](const GuestRForkRef& a, const GuestRForkRef& b) { return a.resId < b.resId; });
|
||||
for (std::int64_t index = 1; index < refs; ++index) {
|
||||
if (ref[index].resId == ref[index - 1].resId && ref[index].offset != ref[index - 1].offset) {
|
||||
ft_mem_free_nid_postfix(memory, ref);
|
||||
NotImplemented_nid_no_patch(function);
|
||||
}
|
||||
}
|
||||
auto* result = static_cast<std::int64_t*>(ft_mem_realloc_nid_postfix(memory, sizeof(std::int64_t), 0, refs, nullptr, &error));
|
||||
if (!error) {
|
||||
for (std::int64_t index = 0; index < refs; ++index) {
|
||||
result[index] = Add(rdataPos, static_cast<std::int64_t>(ref[index].offset), function);
|
||||
}
|
||||
if (!offsets) NotImplemented_nid_no_patch(function);
|
||||
*offsets = result;
|
||||
}
|
||||
ft_mem_free_nid_postfix(memory, ref);
|
||||
return error;
|
||||
}
|
||||
return CannotOpenResource;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
#include "prx/libSceFreeTypeOt/include/Memory.hpp"
|
||||
#include "prx/libSceFreeTypeOt/include/Raccess.hpp"
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using FreeType::GuestMemoryRec;
|
||||
using FreeType::GuestRaccessLibrary;
|
||||
using FreeType::GuestStreamRec;
|
||||
|
||||
constexpr std::int64_t Post = 0x504F5354;
|
||||
constexpr std::int64_t Sfnt = 0x73666E74;
|
||||
|
||||
struct Recorder {
|
||||
GuestMemoryRec memory{};
|
||||
int allocs = 0;
|
||||
int frees = 0;
|
||||
};
|
||||
|
||||
void* APS5_VABI RecordAlloc(GuestMemoryRec* memory, std::int64_t size) {
|
||||
++static_cast<Recorder*>(memory->user)->allocs;
|
||||
return std::malloc(static_cast<std::size_t>(size));
|
||||
}
|
||||
|
||||
void APS5_VABI RecordFree(GuestMemoryRec* memory, void* block) {
|
||||
++static_cast<Recorder*>(memory->user)->frees;
|
||||
std::free(block);
|
||||
}
|
||||
|
||||
void* APS5_VABI RecordRealloc(GuestMemoryRec*, std::int64_t, std::int64_t size, void* block) {
|
||||
return std::realloc(block, static_cast<std::size_t>(size));
|
||||
}
|
||||
|
||||
void Require(bool condition, const char* message) {
|
||||
if (condition) return;
|
||||
std::fprintf(stderr, "FreeType Ot raccess: %s\n", message);
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
void Put16(std::vector<std::uint8_t>& bytes, std::size_t at, std::uint32_t value) {
|
||||
bytes[at] = static_cast<std::uint8_t>(value >> 8);
|
||||
bytes[at + 1] = static_cast<std::uint8_t>(value);
|
||||
}
|
||||
|
||||
void Put32(std::vector<std::uint8_t>& bytes, std::size_t at, std::uint32_t value) {
|
||||
Put16(bytes, at, value >> 16);
|
||||
Put16(bytes, at + 2, value);
|
||||
}
|
||||
|
||||
struct Fork {
|
||||
std::vector<std::uint8_t> bytes;
|
||||
std::size_t prefix;
|
||||
std::uint32_t dataStart = 0x100;
|
||||
std::uint32_t dataLength = 0x40;
|
||||
std::uint32_t mapPos = 0x140;
|
||||
std::uint32_t typeList = 28;
|
||||
};
|
||||
|
||||
Fork MakeFork(std::size_t prefix, bool zeroCopy) {
|
||||
Fork fork;
|
||||
fork.prefix = prefix;
|
||||
fork.bytes.assign(prefix + 0x140 + 0x70, 0xEE);
|
||||
const std::size_t base = prefix;
|
||||
Put32(fork.bytes, base, fork.dataStart);
|
||||
Put32(fork.bytes, base + 4, fork.mapPos);
|
||||
Put32(fork.bytes, base + 8, fork.dataLength);
|
||||
Put32(fork.bytes, base + 12, 0x60);
|
||||
const std::size_t map = base + fork.mapPos;
|
||||
for (std::size_t index = 0; index < 16; ++index) fork.bytes[map + index] = zeroCopy ? 0 : fork.bytes[base + index];
|
||||
Put16(fork.bytes, map + 24, fork.typeList);
|
||||
const std::size_t types = map + fork.typeList;
|
||||
Put16(fork.bytes, types, 1);
|
||||
Put32(fork.bytes, types + 2, Sfnt);
|
||||
Put16(fork.bytes, types + 6, 0);
|
||||
Put16(fork.bytes, types + 8, 22);
|
||||
Put32(fork.bytes, types + 10, Post);
|
||||
Put16(fork.bytes, types + 14, 2);
|
||||
Put16(fork.bytes, types + 16, 34);
|
||||
const std::uint32_t refs[4][2] = {{0x0080, 0x00000010}, {0x0102, 0xA0000020}, {0x0100, 0x00000030}, {0x0101, 0x7F000008}};
|
||||
for (std::size_t index = 0; index < 4; ++index) {
|
||||
const std::size_t ref = types + 22 + index * 12;
|
||||
Put16(fork.bytes, ref, refs[index][0]);
|
||||
Put16(fork.bytes, ref + 2, 0xFFFF);
|
||||
Put32(fork.bytes, ref + 4, refs[index][1]);
|
||||
Put32(fork.bytes, ref + 8, 0);
|
||||
}
|
||||
return fork;
|
||||
}
|
||||
|
||||
struct Session {
|
||||
Recorder recorder;
|
||||
GuestRaccessLibrary library{};
|
||||
GuestStreamRec stream{};
|
||||
|
||||
explicit Session(const std::vector<std::uint8_t>& bytes) {
|
||||
recorder.memory = {&recorder, RecordAlloc, RecordFree, RecordRealloc};
|
||||
library.memory = &recorder.memory;
|
||||
FT_Stream_OpenMemory_nid_postfix(&stream, bytes.data(), bytes.size());
|
||||
}
|
||||
};
|
||||
|
||||
void HeaderAndOffsets(std::size_t prefix, bool zeroCopy) {
|
||||
const Fork fork = MakeFork(prefix, zeroCopy);
|
||||
Session session(fork.bytes);
|
||||
std::int64_t mapOffset = -1;
|
||||
std::int64_t rdataPos = -1;
|
||||
const auto offset = static_cast<std::int64_t>(prefix);
|
||||
Require(FT_Raccess_Get_HeaderInfo_nid_postfix(&session.library, &session.stream, offset, &mapOffset, &rdataPos) == 0, "a resource fork header is accepted");
|
||||
Require(rdataPos == offset + 0x100 && mapOffset == offset + 0x140 + 28, "header info adds the fork offset to the data and type list positions");
|
||||
Require(session.stream.pos == static_cast<std::uint64_t>(mapOffset), "header info leaves the stream at the type list");
|
||||
|
||||
std::int64_t* offsets = nullptr;
|
||||
std::int64_t count = 0;
|
||||
Require(FT_Raccess_Get_DataOffsets_nid_postfix(&session.library, &session.stream, mapOffset, rdataPos, Post, &offsets, &count) == 0, "a present tag is found");
|
||||
Require(count == 3 && offsets, "the subcount plus one references are returned");
|
||||
Require(offsets[0] == rdataPos + 0x30 && offsets[1] == rdataPos + 0x08 && offsets[2] == rdataPos + 0x20, "offsets are sorted by resource ID and drop the attribute byte");
|
||||
Require(session.recorder.allocs == 2 && session.recorder.frees == 1, "the reference array is freed and the offsets array is kept");
|
||||
ft_mem_free_nid_postfix(&session.recorder.memory, offsets);
|
||||
|
||||
offsets = nullptr;
|
||||
count = 0;
|
||||
Require(FT_Raccess_Get_DataOffsets_nid_postfix(&session.library, &session.stream, mapOffset, rdataPos, Sfnt, &offsets, &count) == 0, "the first type is found");
|
||||
Require(count == 1 && offsets[0] == rdataPos + 0x10, "a single reference is returned");
|
||||
ft_mem_free_nid_postfix(&session.recorder.memory, offsets);
|
||||
|
||||
offsets = nullptr;
|
||||
count = -1;
|
||||
const int allocs = session.recorder.allocs;
|
||||
Require(FT_Raccess_Get_DataOffsets_nid_postfix(&session.library, &session.stream, mapOffset, rdataPos, 0x4E464E54, &offsets, &count) == 0x01, "a missing tag is Cannot_Open_Resource");
|
||||
Require(count == -1 && !offsets && session.recorder.allocs == allocs, "a missing tag writes and allocates nothing");
|
||||
}
|
||||
|
||||
void RejectedHeaders() {
|
||||
Fork fork = MakeFork(0, false);
|
||||
Put32(fork.bytes, 8, 0x41);
|
||||
Session lengths(fork.bytes);
|
||||
std::int64_t mapOffset = -1;
|
||||
std::int64_t rdataPos = -1;
|
||||
Require(FT_Raccess_Get_HeaderInfo_nid_postfix(&lengths.library, &lengths.stream, 0, &mapOffset, &rdataPos) == 0x02, "data that does not end at the map is Unknown_File_Format");
|
||||
Require(rdataPos == 0x100 && mapOffset == -1, "the data position is written before the length check");
|
||||
|
||||
fork = MakeFork(0, false);
|
||||
fork.bytes[0x140 + 3] ^= 1;
|
||||
Session copy(fork.bytes);
|
||||
rdataPos = -1;
|
||||
Require(FT_Raccess_Get_HeaderInfo_nid_postfix(©.library, ©.stream, 0, &mapOffset, &rdataPos) == 0x02, "a map header that neither matches nor is zero is Unknown_File_Format");
|
||||
|
||||
fork = MakeFork(0, false);
|
||||
Put32(fork.bytes, 0, 0);
|
||||
Put32(fork.bytes, 4, 0);
|
||||
Put32(fork.bytes, 8, 0);
|
||||
Session empty(fork.bytes);
|
||||
Require(FT_Raccess_Get_HeaderInfo_nid_postfix(&empty.library, &empty.stream, 0, &mapOffset, &rdataPos) == 0x02, "a map at the fork offset is Unknown_File_Format");
|
||||
|
||||
const std::vector<std::uint8_t> shortStream(10, 0);
|
||||
Session truncated(shortStream);
|
||||
Require(FT_Raccess_Get_HeaderInfo_nid_postfix(&truncated.library, &truncated.stream, 0, &mapOffset, &rdataPos) == 0x55, "a short header is Invalid_Stream_Operation");
|
||||
Require(FT_Raccess_Get_HeaderInfo_nid_postfix(&truncated.library, &truncated.stream, 11, &mapOffset, &rdataPos) == 0x55, "a fork offset past the stream is Invalid_Stream_Operation");
|
||||
}
|
||||
|
||||
void TruncatedReferences() {
|
||||
Fork fork = MakeFork(0, false);
|
||||
fork.bytes.resize(0x140 + 28 + 22 + 12 + 6);
|
||||
Session session(fork.bytes);
|
||||
std::int64_t* offsets = nullptr;
|
||||
std::int64_t count = 0;
|
||||
Require(FT_Raccess_Get_DataOffsets_nid_postfix(&session.library, &session.stream, 0x140 + 28, 0x100, Post, &offsets, &count) == 0x55, "a cut reference list is Invalid_Stream_Operation");
|
||||
Require(count == 3 && !offsets, "the count is written before the references are read");
|
||||
Require(session.recorder.allocs == 1 && session.recorder.frees == 1, "the reference array is freed on a read error");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
HeaderAndOffsets(0, false);
|
||||
HeaderAndOffsets(0x80, true);
|
||||
RejectedHeaders();
|
||||
TruncatedReferences();
|
||||
std::puts("Guest FreeType Ot raccess tests passed");
|
||||
return 0;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# libSceFreeTypeOt technical debt
|
||||
|
||||
- The FT_Glyph_Copy, FT_Outline_Get_Orientation, FT_Request_Size, FT_Sin, FT_Tan, FT_Vector_Unit, FT_New_Size, FT_Outline_Copy, FT_Outline_Decompose, FT_Stroker_New, FT_Stroker_Done, FT_Stroker_GetCounts, FT_Stroker_BeginSubPath, FT_Stroker_LineTo, FT_Stroker_EndSubPath, FT_Stroker_Set, FT_Stroker_Rewind, FT_Stroker_GetBorderCounts, FT_Stroker_ConicTo and FT_Stroker_CubicTo NIDs in [Export.cpp](../../../core/libs/prx/libSceFreeTypeOt/Export.cpp) are identified, but their provider-specific prototypes and behavior remain unverified. Their named helpers retain the explicit inventory aliases and throw; the separate libSceFreeType implementations do not supply this provider.
|
||||
- The 68 `sceFreeTypeOtUnknown_*_nid_no_patch` exports in [Export.cpp](../../../core/libs/prx/libSceFreeTypeOt/Export.cpp) are present in the PS5 3.20 export inventory from [PS5-3.20_Libs](https://github.com/DNNDHH/PS5-3.20_Libs). Their prototypes and behavior are unverified. Each uses the no-parameter import-resolution convention and throws through `NotImplemented_nid_no_patch`; these declarations make no ABI or behavior claim.
|
||||
- The 66 `sceFreeTypeOtUnknown_*_nid_no_patch` exports in [Export.cpp](../../../core/libs/prx/libSceFreeTypeOt/Export.cpp) are present in the PS5 3.20 export inventory from [PS5-3.20_Libs](https://github.com/DNNDHH/PS5-3.20_Libs). Their prototypes and behavior are unverified. Each uses the no-parameter import-resolution convention and throws through `NotImplemented_nid_no_patch`; these declarations make no ABI or behavior claim.
|
||||
### Unknown function info
|
||||
|
||||
- [FT_Outline_GetInsideBorder, FT_Outline_GetOutsideBorder](../../../core/libs/prx/libSceFreeTypeOt/CMakeLists.txt) (libSceFreeTypeOl, libSceFreeTypeOt) - console prototypes, enum/layout equivalence, FreeType configuration and module/library versions are unverified. The existing LP64 outline layout and unsigned 16-bit counts follow bundled FreeType 2.13.3; border selection follows [ftstroke.c](https://github.com/freetype/freetype/blob/42608f77f20749dd6ddc9e0536788eaad70ea4b5/src/base/ftstroke.c), with the shifted polygon area from [ftoutln.c](https://github.com/freetype/freetype/blob/42608f77f20749dd6ddc9e0536788eaad70ea4b5/src/base/ftoutln.c) accumulated in 64 bits. Null positive-count arrays and out-of-range or non-increasing contour endpoints throw when reached; their console behavior is unknown. Tags and flags are not read, and input arrays remain caller-owned.
|
||||
@@ -19,3 +19,5 @@
|
||||
- [ft_mem_alloc, ft_mem_qalloc, ft_mem_realloc, ft_mem_qrealloc, ft_mem_free, ft_mem_dup, ft_mem_strdup, ft_mem_strcpyn](../../../core/libs/prx/libSceFreeTypeOt/src/Memory.cpp) (libSceFreeTypeOt) - the exports carry the NIDs of these FreeType names; console prototypes and FreeType version equivalence are unverified. The LP64 signatures, the guest `FT_MemoryRec` callbacks and the error codes (Invalid_Argument 0x06, Array_Too_Large 0x0A, Out_Of_Memory 0x40) follow FreeType 2.4.12 [ftutil.c](https://github.com/freetype/freetype/blob/cecf93ef90c660a8b0b45e5adbbfb5ea443fb6b9/src/base/ftutil.c#L49-L221). Bundled FreeType 2.13.3 differs only in `ft_mem_qrealloc` from a count of 0, which it does not zero. As in a release build, `ft_mem_qrealloc` does not check the `FT_ASSERT` that a block with no current items is null. The current byte size passed to `realloc` wraps where the source's signed product would overflow.
|
||||
|
||||
- [FT_Sin, FT_Tan, FT_Vector_Unit, FT_Outline_Get_Orientation, FT_Outline_Copy, FT_Outline_Decompose](../../../core/libs/prx/libSceFreeTypeOt/CMakeLists.txt) (libSceFreeTypeOt) - built from the 2.13.3-based libSceFreeType sources; the provider is dated to 2.4.11-2.4.12 elsewhere and its version is unmeasured. Against [2.4.12](https://github.com/freetype/freetype/blob/cecf93ef90c660a8b0b45e5adbbfb5ea443fb6b9/src/base/ftoutln.c): `FT_Outline_Copy` returns `Invalid_Outline`, not `Invalid_Argument`, for a null outline; `FT_Outline_Get_Orientation` returns `FT_ORIENTATION_NONE` for a zero-width or zero-height box and beyond ±0x1000000, and shifts coordinates rather than differences; counts of 0x8000 or more are not negative `short`s. 2.4.11 does not shift the area and uses other CORDIC constants than the 2.4.12 ones used here. FT_Cos and FT_Angle_Diff are also exported but absent from the 3.20 inventory.
|
||||
|
||||
- [FT_Raccess_Get_HeaderInfo, FT_Raccess_Get_DataOffsets](../../../core/libs/prx/libSceFreeTypeOt/src/Raccess.cpp) (libSceFreeTypeOt) - console prototypes and FreeType version equivalence are unverified. Both follow 2.4.12 [ftrfork.c](https://github.com/freetype/freetype/blob/cecf93ef90c660a8b0b45e5adbbfb5ea443fb6b9/src/base/ftrfork.c#L49-L237) and read only `memory` from the library record. `FT_Raccess_Get_DataOffsets` takes the seven arguments of 2.4.11-2.5.2; from 2.5.3 `FT_Bool sort_by_res_id` precedes `offsets`. Header fields with the top bit set and overflowing `FT_Long` sums, undefined in that source, throw; 2.13.3 adds overlap, stream size and count checks that 2.4.12 lacks. Equal resource IDs with different offsets throw, since `ft_qsort` leaves their order unspecified. Null pointers throw where 2.4.12 dereferences them. `FT_Raccess_Guess` still throws.
|
||||
Reference in new issue
Block a user