public static BasicObjectInfo parse(ByteBuf objectTailBuf,
            S3ObjectMetadata s3ObjectMetadata) throws ObjectParseException {
            objectTailBuf = objectTailBuf.slice();
            long footerMagic = objectTailBuf.getLong(objectTailBuf.readableBytes() - 8);
            if (footerMagic != ObjectWriter.Footer.MAGIC) {
                throw new ObjectParseException("Invalid footer magic: " + footerMagic);
            }

            long indexBlockPosition = objectTailBuf.getLong(objectTailBuf.readableBytes() - FOOTER_SIZE);
            int indexBlockSize = objectTailBuf.getInt(objectTailBuf.readableBytes() - 40);
            if (indexBlockPosition + objectTailBuf.readableBytes() < s3ObjectMetadata.objectSize()) {
                objectTailBuf.release();
                throw new ObjectParseException(indexBlockPosition);
            } else {
                int indexRelativePosition = objectTailBuf.readableBytes() - (int) (s3ObjectMetadata.objectSize() - indexBlockPosition);

                // trim the ByteBuf to avoid extra memory occupy.
                ByteBuf indexBlockBuf = objectTailBuf.slice(objectTailBuf.readerIndex() + indexRelativePosition, indexBlockSize);
                ByteBuf copy = ByteBufAlloc.byteBuffer(indexBlockBuf.readableBytes(), READ_INDEX_BLOCK);
                indexBlockBuf.readBytes(copy, indexBlockBuf.readableBytes());
                objectTailBuf.release();
                indexBlockBuf = copy;
                return new BasicObjectInfo(indexBlockPosition, new IndexBlock(s3ObjectMetadata, indexBlockBuf));
            }
        }
@param dataBlockSize The total size of the data blocks, which equals to index start position.
@param indexBlock    raw index data.
s3stream/src/main/java/com/automq/stream/s3/ObjectReader.java