mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-07-07 02:21:46 +00:00
Merge remote-tracking branch 'origin/stable'
This commit is contained in:
commit
69a829db91
@ -25,6 +25,8 @@ namespace pocketmine\world\format\io\region;
|
|||||||
|
|
||||||
use pocketmine\utils\AssumptionFailedError;
|
use pocketmine\utils\AssumptionFailedError;
|
||||||
use pocketmine\utils\Binary;
|
use pocketmine\utils\Binary;
|
||||||
|
use pocketmine\utils\BinaryDataException;
|
||||||
|
use pocketmine\utils\BinaryStream;
|
||||||
use pocketmine\world\format\ChunkException;
|
use pocketmine\world\format\ChunkException;
|
||||||
use pocketmine\world\format\io\exception\CorruptedChunkException;
|
use pocketmine\world\format\io\exception\CorruptedChunkException;
|
||||||
use function assert;
|
use function assert;
|
||||||
@ -135,34 +137,34 @@ class RegionLoader{
|
|||||||
|
|
||||||
fseek($this->filePointer, $this->locationTable[$index]->getFirstSector() << 12);
|
fseek($this->filePointer, $this->locationTable[$index]->getFirstSector() << 12);
|
||||||
|
|
||||||
$prefix = fread($this->filePointer, 4);
|
/*
|
||||||
if($prefix === false or strlen($prefix) !== 4){
|
* this might cause us to read some junk, but under normal circumstances it won't be any more than 4096 bytes wasted.
|
||||||
throw new CorruptedChunkException("Corrupted chunk header detected (unexpected end of file reading length prefix)");
|
* doing this in a single call is faster than making two seeks and reads to fetch the chunk.
|
||||||
}
|
* this relies on the assumption that the end of the file is always padded to a multiple of 4096 bytes.
|
||||||
$length = Binary::readInt($prefix);
|
*/
|
||||||
|
$bytesToRead = $this->locationTable[$index]->getSectorCount() << 12;
|
||||||
|
$payload = fread($this->filePointer, $bytesToRead);
|
||||||
|
|
||||||
|
if($payload === false || strlen($payload) !== $bytesToRead){
|
||||||
|
throw new CorruptedChunkException("Corrupted chunk detected (unexpected EOF, truncated or non-padded chunk found)");
|
||||||
|
}
|
||||||
|
$stream = new BinaryStream($payload);
|
||||||
|
|
||||||
|
try{
|
||||||
|
$length = $stream->getInt();
|
||||||
if($length <= 0){ //TODO: if we reached here, the locationTable probably needs updating
|
if($length <= 0){ //TODO: if we reached here, the locationTable probably needs updating
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if($length > self::MAX_SECTOR_LENGTH){ //corrupted
|
|
||||||
throw new CorruptedChunkException("Length for chunk x=$x,z=$z ($length) is larger than maximum " . self::MAX_SECTOR_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
if($length > ($this->locationTable[$index]->getSectorCount() << 12)){ //Invalid chunk, bigger than defined number of sectors
|
$compression = $stream->getByte();
|
||||||
throw new CorruptedChunkException("Chunk length mismatch (expected " . ($this->locationTable[$index]->getSectorCount() << 12) . " sectors, got $length sectors)");
|
|
||||||
}
|
|
||||||
|
|
||||||
$chunkData = fread($this->filePointer, $length);
|
|
||||||
if($chunkData === false or strlen($chunkData) !== $length){
|
|
||||||
throw new CorruptedChunkException("Corrupted chunk detected (unexpected end of file reading chunk data)");
|
|
||||||
}
|
|
||||||
|
|
||||||
$compression = ord($chunkData[0]);
|
|
||||||
if($compression !== self::COMPRESSION_ZLIB and $compression !== self::COMPRESSION_GZIP){
|
if($compression !== self::COMPRESSION_ZLIB and $compression !== self::COMPRESSION_GZIP){
|
||||||
throw new CorruptedChunkException("Invalid compression type (got $compression, expected " . self::COMPRESSION_ZLIB . " or " . self::COMPRESSION_GZIP . ")");
|
throw new CorruptedChunkException("Invalid compression type (got $compression, expected " . self::COMPRESSION_ZLIB . " or " . self::COMPRESSION_GZIP . ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
return substr($chunkData, 1);
|
return $stream->get($length - 1); //length prefix includes the compression byte
|
||||||
|
}catch(BinaryDataException $e){
|
||||||
|
throw new CorruptedChunkException("Corrupted chunk detected: " . $e->getMessage(), 0, $e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -321,6 +323,8 @@ class RegionLoader{
|
|||||||
/** @var int[] $usedOffsets */
|
/** @var int[] $usedOffsets */
|
||||||
$usedOffsets = [];
|
$usedOffsets = [];
|
||||||
|
|
||||||
|
$fileSize = filesize($this->filePath);
|
||||||
|
if($fileSize === false) throw new AssumptionFailedError("filesize() should not return false here");
|
||||||
for($i = 0; $i < 1024; ++$i){
|
for($i = 0; $i < 1024; ++$i){
|
||||||
$entry = $this->locationTable[$i];
|
$entry = $this->locationTable[$i];
|
||||||
if($entry === null){
|
if($entry === null){
|
||||||
@ -333,8 +337,7 @@ class RegionLoader{
|
|||||||
|
|
||||||
//TODO: more validity checks
|
//TODO: more validity checks
|
||||||
|
|
||||||
fseek($this->filePointer, $fileOffset);
|
if($fileOffset >= $fileSize){
|
||||||
if(feof($this->filePointer)){
|
|
||||||
throw new CorruptedRegionException("Region file location offset x=$x,z=$z points to invalid file location $fileOffset");
|
throw new CorruptedRegionException("Region file location offset x=$x,z=$z points to invalid file location $fileOffset");
|
||||||
}
|
}
|
||||||
if(isset($usedOffsets[$offset])){
|
if(isset($usedOffsets[$offset])){
|
||||||
|
Loading…
x
Reference in New Issue
Block a user