static PHYSFS_sint64 RGSS_ioRead(PHYSFS_Io *self, void *buffer, PHYSFS_uint64 len) { RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque); PHYSFS_Io *io = entry->io; uint64_t toRead = std::min<uint64_t>(entry->data.size - entry->currentOffset, len); uint64_t offs = entry->currentOffset; io->seek(io, entry->data.offset + offs); /* We divide up the bytes to be read in 3 categories: * * preAlign: If the current read address is not dword * aligned, this is the number of bytes to read til * we reach alignment again (therefore can only be * 3 or less). * * align: The number of aligned dwords we can read * times 4 (= number of bytes). * * postAlign: The number of bytes to read after the * last aligned dword. Always 3 or less. * * Treating the pre- and post aligned reads specially, * we can read all aligned dwords in one syscall directly * into the write buffer and then run the xor chain on * it afterwards. */ uint8_t preAlign = 4 - (offs % 4); if (preAlign == 4) preAlign = 0; else preAlign = std::min<uint64_t>(preAlign, len); uint8_t postAlign = (len > preAlign) ? (offs + len) % 4 : 0; uint64_t align = len - (preAlign + postAlign); /* Byte buffer pointer */ uint8_t *bBufferP = static_cast<uint8_t*>(buffer); if (preAlign > 0) { uint32_t dword; io->read(io, &dword, preAlign); /* Need to align the bytes with the * magic before xoring */ dword <<= 8 * (offs % 4); dword ^= entry->currentMagic; /* Shift them back to normal */ dword >>= 8 * (offs % 4); memcpy(bBufferP, &dword, preAlign); bBufferP += preAlign; /* Only advance the magic if we actually * reached the next alignment */ if ((offs+preAlign) % 4 == 0) advanceMagic(entry->currentMagic); }