/* TessesFramework a library to make C++ easier for me, used in CrossLang: https://git.tesses.org/tesses50/crosslang Copyright (C) 2026 Mike Nolan SPDX-License-Identifier: GPL-3.0-or-later WITH TessesFramework-Exception-1.0 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "TessesFramework/BitTorrent/TorrentStream.hpp" namespace Tesses::Framework::BitTorrent { TorrentFileEntry::TorrentFileEntry() {} TorrentFileEntry::TorrentFileEntry(Tesses::Framework::Filesystem::VFSPath path, int64_t length) : path(path), length(length) {} ReadWriteAt::~ReadWriteAt() {} TorrentFileStream::TorrentFileStream( std::shared_ptr vfs, Tesses::Framework::Filesystem::VFSPath path, uint64_t length) : vfs(vfs), path(path), length(length) {} bool TorrentFileStream::ReadBlockAt(uint64_t offset, uint8_t *data, size_t len) { if (!vfs->FileExists(path)) return false; auto strm = vfs->OpenFile(path, "rb"); strm->Seek((int64_t)offset, Streams::SeekOrigin::Begin); strm->ReadBlock(data, len); return true; } void TorrentFileStream::WriteBlockAt(uint64_t offset, const uint8_t *data, size_t len) { len = (size_t)std::min((int64_t)len, (int64_t)this->length - (int64_t)offset); if (len == 0) return; mtx.Lock(); auto strm = vfs->OpenFile(path, "wb"); strm->Seek((int64_t)offset, Streams::SeekOrigin::Begin); strm->WriteBlock(data, len); mtx.Unlock(); } TorrentDirectoryStream::TorrentDirectoryStream( std::shared_ptr vfs, Tesses::Framework::Filesystem::VFSPath path, std::vector entries) : vfs(vfs), path(path), entries(entries) { if (!vfs->DirectoryExists(path)) this->vfs->CreateDirectory(path); this->mtxs.resize(entries.size()); } // From https://www.seanjoflynn.com/research/bittorrent.html , which is licensed // under MIT based on code repo bool TorrentDirectoryStream::ReadBlockAt(uint64_t offset, uint8_t *data, size_t len) { uint64_t currentOffset = 0; uint64_t end = offset + len; for (size_t i = 0; i < this->entries.size(); i++) { if (offset < currentOffset && end < currentOffset) { currentOffset += this->entries[i].length; continue; } if (offset > currentOffset + this->entries[i].length && end > currentOffset + this->entries[i].length) { currentOffset += this->entries[i].length; continue; } auto path = this->path / this->entries[i].path; if (!vfs->FileExists(path)) return false; int64_t fstart = std::max((int64_t)0, (int64_t)offset - (int64_t)currentOffset); int64_t fend = std::min((int64_t)end - (int64_t)currentOffset, (int64_t)this->entries[i].length); int flength = (int)(fend - fstart); int bstart = std::max((int)0, (int)((int64_t)currentOffset - (int64_t)offset)); auto strm = vfs->OpenFile(path, "rb"); strm->Seek(fstart, Streams::SeekOrigin::Begin); strm->ReadBlock(data + bstart, flength); currentOffset += this->entries[i].length; } return true; } // From https://www.seanjoflynn.com/research/bittorrent.html , which is licensed // under MIT based on code repo void TorrentDirectoryStream::WriteBlockAt(uint64_t offset, const uint8_t *data, size_t len) { uint64_t currentOffset = 0; uint64_t end = offset + len; for (size_t i = 0; i < this->entries.size(); i++) { if (offset < currentOffset && end < currentOffset) { currentOffset += this->entries[i].length; continue; } if (offset > currentOffset + this->entries[i].length && end > currentOffset + this->entries[i].length) { currentOffset += this->entries[i].length; continue; } auto path = this->path / this->entries[i].path; auto parent = path.GetParent(); if (!vfs->DirectoryExists(parent)) vfs->CreateDirectory(parent); int64_t fstart = std::max((int64_t)0, (int64_t)offset - (int64_t)currentOffset); int64_t fend = std::min((int64_t)end - (int64_t)currentOffset, (int64_t)this->entries[i].length); int flength = (int)(fend - fstart); int bstart = std::max((int)0, (int)((int64_t)currentOffset - (int64_t)offset)); this->mtxs[i].Lock(); { auto strm = vfs->OpenFile(path, "wb"); strm->Seek(fstart, Streams::SeekOrigin::Begin); strm->WriteBlock(data + bstart, flength); } this->mtxs[i].Unlock(); currentOffset += this->entries[i].length; } } } // namespace Tesses::Framework::BitTorrent