public function hydrate($data)
{
$index = new Index();
$reader = new StringReader($data);
$signature = $reader->readString8(4);
$version = $reader->readUInt32BE();
if ($signature != Index::SIGNATURE || $version != Index::VERSION) {
throw new IndexVersionException("IndexHydrator only supports indexes with signature " . Index::SIGNATURE . " and version " . Index::VERSION);
}
$entries = $reader->readUInt32BE();
$extended_contents_start = $reader->getOffset();
for ($i = 0; $i < $entries; $i++) {
$entry = new IndexEntry();
$start = $reader->getOffset();
$entry->setCtime($this->readEntryTime($reader));
$entry->setMtime($this->readEntryTime($reader));
$entry->setDev($reader->readUInt32BE());
$entry->setInode($reader->readUInt32BE());
$entry->setMode($reader->readUInt32BE());
$entry->setUid($reader->readUInt32BE());
$entry->setGid($reader->readUInt32BE());
$entry->setFileSize($reader->readUInt32BE());
$entry->setBlob(new BlobProxy($this->repo, $reader->readHHex(20)));
$flags = $reader->readUInt16BE();
$entry->setName(rtrim($reader->readString16(($flags & 0xfff) + 1, $foo, true), ""));
//+1 is to capture mandatory NUL
$entry->setStage(($flags & 0x3000) >> 12);
$stop = $reader->getOffset();
$length = $stop - $start;
$padded_length = ceil($length / 8) * 8;
$reader->setOffset($start + $padded_length);
$index->addEntry($entry);
}
while ($reader->getOffset() < $reader->getSize() - 20) {
$name = $reader->readString8(4);
if (ord($name[0]) >= 0x41 && ord($name[0]) <= 0x5a) {
// Optional extension, just skip it
$data_size = $reader->readUInt32BE();
$reader->skip($data_size);
} else {
throw new IndexVersionException("IndexHydrator doesn't support the mandatory " . $name . " extension");
}
}
$extended_contents_stop = $reader->getOffset();
$reader->setOffset(0);
$calculated_sha = sha1($reader->read($extended_contents_stop));
$checksum = $reader->readHHex(20);
if ($checksum != $calculated_sha) {
throw new ChecksumException("Index checksum does not match");
}
return $index;
}