| 1601 | } |
| 1602 | |
| 1603 | std::unique_ptr<Reader> createReader(std::unique_ptr<InputStream> stream, |
| 1604 | const ReaderOptions& options) { |
| 1605 | auto contents = std::make_shared<FileContents>(); |
| 1606 | contents->pool = options.getMemoryPool(); |
| 1607 | contents->errorStream = options.getErrorStream(); |
| 1608 | contents->readerMetrics = options.getReaderMetrics(); |
| 1609 | contents->cacheOptions = options.getCacheOptions(); |
| 1610 | std::string serializedFooter = options.getSerializedFileTail(); |
| 1611 | uint64_t fileLength; |
| 1612 | uint64_t postscriptLength; |
| 1613 | if (serializedFooter.length() != 0) { |
| 1614 | // Parse the file tail from the serialized one. |
| 1615 | proto::FileTail tail; |
| 1616 | if (!tail.ParseFromString(serializedFooter)) { |
| 1617 | throw ParseError("Failed to parse the file tail from string"); |
| 1618 | } |
| 1619 | contents->postscript = std::make_unique<proto::PostScript>(tail.postscript()); |
| 1620 | contents->footer = std::make_unique<proto::Footer>(tail.footer()); |
| 1621 | fileLength = tail.file_length(); |
| 1622 | postscriptLength = tail.postscript_length(); |
| 1623 | } else { |
| 1624 | // figure out the size of the file using the option or filesystem |
| 1625 | fileLength = std::min(options.getTailLocation(), static_cast<uint64_t>(stream->getLength())); |
| 1626 | |
| 1627 | // read last bytes into buffer to get PostScript |
| 1628 | uint64_t readSize = std::min(fileLength, DIRECTORY_SIZE_GUESS); |
| 1629 | if (readSize < 4) { |
| 1630 | throw ParseError("File size too small"); |
| 1631 | } |
| 1632 | auto buffer = std::make_unique<DataBuffer<char>>(*contents->pool, readSize); |
| 1633 | stream->read(buffer->data(), readSize, fileLength - readSize); |
| 1634 | |
| 1635 | postscriptLength = buffer->data()[readSize - 1] & 0xff; |
| 1636 | contents->postscript = readPostscript(stream.get(), buffer.get(), postscriptLength); |
| 1637 | uint64_t footerSize = contents->postscript->footer_length(); |
| 1638 | uint64_t tailSize = 1 + postscriptLength + footerSize; |
| 1639 | if (tailSize >= fileLength) { |
| 1640 | std::stringstream msg; |
| 1641 | msg << "Invalid ORC tailSize=" << tailSize << ", fileLength=" << fileLength; |
| 1642 | throw ParseError(msg.str()); |
| 1643 | } |
| 1644 | uint64_t footerOffset; |
| 1645 | |
| 1646 | if (tailSize > readSize) { |
| 1647 | buffer->resize(footerSize); |
| 1648 | stream->read(buffer->data(), footerSize, fileLength - tailSize); |
| 1649 | footerOffset = 0; |
| 1650 | } else { |
| 1651 | footerOffset = readSize - tailSize; |
| 1652 | } |
| 1653 | |
| 1654 | contents->footer = readFooter(stream.get(), buffer.get(), footerOffset, *contents->postscript, |
| 1655 | *contents->pool, contents->readerMetrics); |
| 1656 | } |
| 1657 | contents->isDecimalAsLong = false; |
| 1658 | if (contents->postscript->version_size() == 2) { |
| 1659 | FileVersion v(contents->postscript->version(0), contents->postscript->version(1)); |
| 1660 | if (v == FileVersion::UNSTABLE_PRE_2_0()) { |