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> cpdBmask;
46 std::array<int, TBL_SIZE> tblSizes;
47 std::array<HufNode, 2 * TBL_SIZE - 1> hufTbl;
52 static constexpr std::array<uint8_t, TBL_SIZE> cpdExt = {
53 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
69void XSADiskImage::readSectorsImpl(
70 std::span<SectorBuffer> buffers,
size_t startSector)
72 ranges::copy(std::span{&data[startSector], buffers.size()}, buffers);
75void XSADiskImage::writeSectorImpl(
size_t ,
const SectorBuffer& )
77 throw WriteProtectedException(
"Write protected");
80bool XSADiskImage::isWriteProtectedImpl()
const
90 auto mmap = file.
mmap();
91 inBufPos = mmap.begin();
92 inBufEnd = mmap.end();
94 if ((charIn() !=
'P') || (charIn() !=
'C') ||
95 (charIn() !=
'K') || (charIn() !=
'\010')) {
107 return {std::move(outBuf), sectors};
111uint8_t XSAExtractor::charIn()
113 if (inBufPos >= inBufEnd) {
114 throw MSXException(
"Corrupt XSA image: unexpected end of file");
120void XSAExtractor::chkHeader()
123 unsigned outBufLen = 0;
124 for (
auto i :
xrange(4)) {
125 outBufLen |= charIn() << (8 * i);
127 sectors = (outBufLen + 511) / 512;
128 outBuf.resize(sectors);
138void XSAExtractor::unLz77()
142 size_t remaining = sectors *
sizeof(SectorBuffer);
143 std::span out = outBuf.data()->raw;
148 unsigned strLen = rdStrLen();
149 if (strLen == (MAX_STR_LEN + 1)) {
152 unsigned strPos = rdStrPos();
153 if ((strPos == 0) || (strPos > outIdx)) {
155 "Corrupt XSA image: invalid offset");
157 if (remaining < strLen) {
159 "Invalid XSA image: too small output buffer");
163 out[outIdx] = out[outIdx - strPos];
168 if (remaining == 0) {
170 "Invalid XSA image: too small output buffer");
173 out[outIdx++] = charIn();
179unsigned XSAExtractor::rdStrLen()
181 if (!bitIn())
return 2;
182 if (!bitIn())
return 3;
183 if (!bitIn())
return 4;
186 while ((nrBits != 7) && bitIn()) {
192 len = (len << 1) | (bitIn() ? 1 : 0);
198int XSAExtractor::rdStrPos()
200 HufNode* hufPos = &hufTbl[2 * TBL_SIZE - 2];
202 while (hufPos->child1) {
204 hufPos = hufPos->child2;
206 hufPos = hufPos->child1;
209 auto cpdIndex = narrow<uint8_t>(hufPos - &hufTbl[0]);
210 ++tblSizes[cpdIndex];
213 if (cpdBmask[cpdIndex] >= 256) {
214 uint8_t strPosLsb = charIn();
215 uint8_t strPosMsb = 0;
216 for (
auto nrBits = narrow_cast<uint8_t>(cpdExt[cpdIndex] - 8);
218 strPosMsb |= uint8_t(bitIn() ? 1 : 0)) {
221 return strPosLsb + 256 * strPosMsb;
224 for (uint8_t nrBits = cpdExt[cpdIndex]; nrBits--;
225 pos |= (bitIn() ? 1 : 0)) {
231 if ((updHufCnt--) == 0) {
234 return strPos + cpDist[cpdIndex];
238bool XSAExtractor::bitIn()
244 bool temp = bitFlg & 1;
252void XSAExtractor::initHufInfo()
255 for (
auto i :
xrange(TBL_SIZE)) {
257 cpdBmask[i] = 1 << cpdExt[i];
260 cpDist[TBL_SIZE] = offs;
262 for (
auto i :
xrange(TBL_SIZE)) {
264 hufTbl[i].child1 =
nullptr;
270void XSAExtractor::mkHufTbl()
273 HufNode* hufPos = &hufTbl[0];
274 for (
auto i :
xrange(TBL_SIZE)) {
275 (hufPos++)->weight = 1 + (tblSizes[i] >>= 1);
277 for (
int i = TBL_SIZE; i != 2 * TBL_SIZE - 1; ++i) {
278 (hufPos++)->weight = -1;
281 while (hufTbl[2 * TBL_SIZE - 2].weight == -1) {
282 for (hufPos = &hufTbl[0]; !(hufPos->weight); ++hufPos) {
285 HufNode* l1Pos = hufPos++;
286 while (!(hufPos->weight)) {
289 HufNode* l2Pos = [&] {
290 if (hufPos->weight < l1Pos->weight) {
299 while ((tempW = hufPos->weight) != -1) {
301 if (tempW < l1Pos->weight) {
304 }
else if (tempW < l2Pos->weight) {
310 hufPos->weight = l1Pos->weight + l2Pos->weight;
311 (hufPos->child1 = l1Pos)->weight = 0;
312 (hufPos->child2 = l2Pos)->weight = 0;
314 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(Filename &filename, File &file)
This file implemented 3 utility functions:
auto copy(InputRange &&range, OutputIter out)
constexpr auto xrange(T e)