15 std::pair<MemBuffer<SectorBuffer>,
unsigned>
extractData();
18 static constexpr int MAX_STR_LEN = 254;
19 static constexpr int TBL_SIZE = 16;
20 static constexpr int MAX_HUF_CNT = 127;
22 [[nodiscard]]
inline uint8_t charIn();
25 [[nodiscard]]
unsigned rdStrLen();
26 [[nodiscard]]
int rdStrPos();
27 [[nodiscard]]
bool bitIn();
39 std::span<const uint8_t>::iterator inBufPos;
40 std::span<const uint8_t>::iterator inBufEnd;
44 std::array<int, TBL_SIZE + 1> cpDist;
45 std::array<int, TBL_SIZE> tblSizes;
46 std::array<HufNode, 2 * TBL_SIZE - 1> hufTbl;
51 static constexpr std::array<uint8_t, TBL_SIZE> cpdExt = {
52 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
68void XSADiskImage::readSectorsImpl(
69 std::span<SectorBuffer> buffers,
size_t startSector)
71 ranges::copy(std::span{&data[startSector], buffers.size()}, buffers);
74void XSADiskImage::writeSectorImpl(
size_t ,
const SectorBuffer& )
76 throw WriteProtectedException(
"Write protected");
79bool XSADiskImage::isWriteProtectedImpl()
const
89 auto mmap = file.
mmap();
90 inBufPos = mmap.begin();
91 inBufEnd = mmap.end();
93 if ((charIn() !=
'P') || (charIn() !=
'C') ||
94 (charIn() !=
'K') || (charIn() !=
'\010')) {
106 return {std::move(outBuf), sectors};
110uint8_t XSAExtractor::charIn()
112 if (inBufPos >= inBufEnd) {
113 throw MSXException(
"Corrupt XSA image: unexpected end of file");
119void XSAExtractor::chkHeader()
122 unsigned outBufLen = 0;
123 for (
auto i :
xrange(4)) {
124 outBufLen |= charIn() << (8 * i);
126 sectors = (outBufLen + 511) / 512;
127 outBuf.resize(sectors);
137void XSAExtractor::unLz77()
141 size_t remaining = sectors *
sizeof(SectorBuffer);
142 std::span out = outBuf.data()->raw;
147 unsigned strLen = rdStrLen();
148 if (strLen == (MAX_STR_LEN + 1)) {
151 unsigned strPos = rdStrPos();
152 if ((strPos == 0) || (strPos > outIdx)) {
154 "Corrupt XSA image: invalid offset");
156 if (remaining < strLen) {
158 "Invalid XSA image: too small output buffer");
162 out[outIdx] = out[outIdx - strPos];
167 if (remaining == 0) {
169 "Invalid XSA image: too small output buffer");
172 out[outIdx++] = charIn();
178unsigned XSAExtractor::rdStrLen()
180 if (!bitIn())
return 2;
181 if (!bitIn())
return 3;
182 if (!bitIn())
return 4;
185 while ((nrBits != 7) && bitIn()) {
191 len = (len << 1) | (bitIn() ? 1 : 0);
197int XSAExtractor::rdStrPos()
199 HufNode* hufPos = &hufTbl[2 * TBL_SIZE - 2];
201 while (hufPos->child1) {
203 hufPos = hufPos->child2;
205 hufPos = hufPos->child1;
208 auto cpdIndex = narrow<uint8_t>(hufPos - &hufTbl[0]);
209 ++tblSizes[cpdIndex];
211 auto getNBits = [&](
unsigned n) {
215 result = uint8_t((result << 1) | (bitIn() ? 1 : 0));
220 if (cpdExt[cpdIndex] >= 8) {
221 uint8_t strPosLsb = charIn();
222 uint8_t strPosMsb = getNBits(narrow_cast<uint8_t>(cpdExt[cpdIndex] - 8));
223 return strPosLsb + 256 * strPosMsb;
225 return int(getNBits(cpdExt[cpdIndex]));
228 if ((updHufCnt--) == 0) {
231 return strPos + cpDist[cpdIndex];
235bool XSAExtractor::bitIn()
241 bool temp = bitFlg & 1;
249void XSAExtractor::initHufInfo()
252 for (
auto i :
xrange(TBL_SIZE)) {
254 offs += 1 << cpdExt[i];
256 cpDist[TBL_SIZE] = offs;
258 for (
auto i :
xrange(TBL_SIZE)) {
260 hufTbl[i].child1 =
nullptr;
266void XSAExtractor::mkHufTbl()
269 HufNode* hufPos = &hufTbl[0];
270 for (
auto i :
xrange(TBL_SIZE)) {
271 (hufPos++)->weight = 1 + (tblSizes[i] >>= 1);
273 for (
int i = TBL_SIZE; i != 2 * TBL_SIZE - 1; ++i) {
274 (hufPos++)->weight = -1;
277 while (hufTbl[2 * TBL_SIZE - 2].weight == -1) {
278 for (hufPos = &hufTbl[0]; !(hufPos->weight); ++hufPos) {
281 HufNode* l1Pos = hufPos++;
282 while (!(hufPos->weight)) {
285 HufNode* l2Pos = [&] {
286 if (hufPos->weight < l1Pos->weight) {
295 while ((tempW = hufPos->weight) != -1) {
297 if (tempW < l1Pos->weight) {
300 }
else if (tempW < l2Pos->weight) {
306 hufPos->weight = l1Pos->weight + l2Pos->weight;
307 (hufPos->child1 = l1Pos)->weight = 0;
308 (hufPos->child2 = l2Pos)->weight = 0;
310 updHufCnt = MAX_HUF_CNT;
std::span< const uint8_t > mmap()
Map file in memory.
This class represents a filename.
This class manages the lifetime of a block of memory.
Abstract class for disk images that only represent the logical sector information (so not the raw tra...
void setNbSectors(size_t num)
XSADiskImage(const Filename &filename, File &file)
This file implemented 3 utility functions:
constexpr auto copy(InputRange &&range, OutputIter out)
constexpr void repeat(T n, Op op)
Repeat the given operation 'op' 'n' times.
constexpr auto xrange(T e)