diff --git a/src/pocketmine/level/format/io/region/RegionLoader.php b/src/pocketmine/level/format/io/region/RegionLoader.php index e5fb6b39bd..d9a1cbf072 100644 --- a/src/pocketmine/level/format/io/region/RegionLoader.php +++ b/src/pocketmine/level/format/io/region/RegionLoader.php @@ -269,34 +269,56 @@ class RegionLoader{ } $data = unpack("N*", $headerRaw); - /** @var int[] $usedOffsets */ - $usedOffsets = []; + for($i = 0; $i < 1024; ++$i){ $index = $data[$i + 1]; $offset = $index >> 8; $timestamp = $data[$i + 1025]; - if($offset !== 0){ - self::getChunkCoords($i, $x, $z); - $fileOffset = $offset << 12; - fseek($this->filePointer, $fileOffset); - if(fgetc($this->filePointer) === false){ //Try and read from the location - throw new CorruptedRegionException("Region file location offset x=$x,z=$z points to invalid file location $fileOffset"); - }elseif(isset($usedOffsets[$offset])){ - self::getChunkCoords($usedOffsets[$offset], $existingX, $existingZ); - throw new CorruptedRegionException("Found two chunk offsets (chunk1: x=$existingX,z=$existingZ, chunk2: x=$x,z=$z) pointing to the file location $fileOffset"); - }else{ - $usedOffsets[$offset] = $i; - } + if($offset === 0){ + $this->locationTable[$i] = new RegionLocationTableEntry(0, 0, 0); + }else{ + $this->locationTable[$i] = new RegionLocationTableEntry($offset, $index & 0xff, $timestamp); + $this->bumpNextFreeSector($this->locationTable[$i]); } - - $this->locationTable[$i] = new RegionLocationTableEntry($offset, $index & 0xff, $timestamp); - $this->bumpNextFreeSector($this->locationTable[$i]); } + $this->checkLocationTableValidity(); + fseek($this->filePointer, 0); } + /** + * @throws CorruptedRegionException + */ + private function checkLocationTableValidity() : void{ + /** @var int[] $usedOffsets */ + $usedOffsets = []; + + for($i = 0; $i < 1024; ++$i){ + $entry = $this->locationTable[$i]; + if($entry->isNull()){ + continue; + } + + self::getChunkCoords($i, $x, $z); + $offset = $entry->getFirstSector(); + $fileOffset = $offset << 12; + + //TODO: more validity checks + + fseek($this->filePointer, $fileOffset); + if(fgetc($this->filePointer) === false){ //Try and read from the location + throw new CorruptedRegionException("Region file location offset x=$x,z=$z points to invalid file location $fileOffset"); + } + if(isset($usedOffsets[$offset])){ + self::getChunkCoords($usedOffsets[$offset], $existingX, $existingZ); + throw new CorruptedRegionException("Found two chunk offsets (chunk1: x=$existingX,z=$existingZ, chunk2: x=$x,z=$z) pointing to the file location $fileOffset"); + } + $usedOffsets[$offset] = $i; + } + } + private function writeLocationTable() : void{ $write = [];