mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 18:25:35 -04:00
56 lines
2.2 KiB
C++
56 lines
2.2 KiB
C++
#pragma once
|
|
#include <cstdint>
|
|
#include <cstddef>
|
|
#include <vector>
|
|
|
|
// Version/count followed by {stored size, aligned size}; no title addresses.
|
|
// Header and every member must exactly cover the supplied archive. The header
|
|
// is itself a legal request; following requests must span whole members.
|
|
class PSXAlignedArchiveIndex {
|
|
struct Span { uint32_t begin, end; };
|
|
std::vector<Span> spans;
|
|
static uint32_t word(const uint8_t* p) {
|
|
return uint32_t(p[0]) | uint32_t(p[1]) << 8 |
|
|
uint32_t(p[2]) << 16 | uint32_t(p[3]) << 24;
|
|
}
|
|
public:
|
|
bool assign(const uint8_t* data, uint32_t size,
|
|
uint32_t alignment = 2048, uint32_t version = 1) {
|
|
spans.clear();
|
|
if (!data || alignment < 16 || size < alignment ||
|
|
word(data) != version) return false;
|
|
const uint32_t count = word(data + 4);
|
|
if (!count || count > (alignment - 8) / 8) return false;
|
|
for (uint32_t i = 8 + count * 8; i < alignment; ++i)
|
|
if (data[i]) return false;
|
|
std::vector<Span> parsed{{0, alignment}};
|
|
uint64_t cursor = alignment;
|
|
for (uint32_t i = 0; i < count; ++i) {
|
|
const uint32_t stored = word(data + 8 + i * 8);
|
|
const uint32_t padded = word(data + 12 + i * 8);
|
|
const uint64_t expected = (uint64_t(stored) + alignment - 1) /
|
|
alignment * alignment;
|
|
if (!stored || padded != expected || cursor + padded > size)
|
|
return false;
|
|
parsed.push_back({uint32_t(cursor), uint32_t(cursor + padded)});
|
|
cursor += padded;
|
|
}
|
|
if (cursor != size) return false;
|
|
spans.swap(parsed);
|
|
return true;
|
|
}
|
|
bool matches(uint32_t offset, uint32_t bytes) const {
|
|
const uint64_t end = uint64_t(offset) + bytes;
|
|
if (!bytes || end > UINT32_MAX) return false;
|
|
for (size_t i = 0; i < spans.size(); ++i) {
|
|
if (spans[i].begin != offset) continue;
|
|
for (; i < spans.size(); ++i) {
|
|
if (spans[i].end == end) return true;
|
|
if (spans[i].end > end) return false;
|
|
}
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
};
|