mirror of
https://github.com/idolpx/libMeatloaf.git
synced 2025-12-06 04:38:49 -05:00
365 lines
12 KiB
C++
365 lines
12 KiB
C++
|
|
// #include "archive_ml.h"
|
|
|
|
// #include <archive.h>
|
|
// #include <archive_entry.h>
|
|
|
|
// #include "meat_io.h"
|
|
|
|
// /* Returns pointer and size of next block of data from archive. */
|
|
// // The read callback returns the number of bytes read, zero for end-of-file, or a negative failure code as above.
|
|
// // It also returns a pointer to the block of data read.
|
|
// // https://github.com/libarchive/libarchive/wiki/LibarchiveIO
|
|
// //
|
|
// // This callback is just a way to get bytes from srcStream into libarchive for processing
|
|
// ssize_t cb_read(struct archive *a, void *userData, const void **buff)
|
|
// {
|
|
// ArchiveStreamData *streamData = (ArchiveStreamData *)userData;
|
|
// // 1. we have to call srcStr.read(...)
|
|
// ssize_t bc = streamData->srcStream->read(streamData->srcBuffer, ArchiveStream::buffSize);
|
|
// //std::string dump((char*)streamData->srcBuffer, bc);
|
|
// //Debug_printv("Libarch pulling data from src MStream, got bytes:%d", bc);
|
|
// //Debug_printv("Dumping bytes: %s", dump.c_str());
|
|
// // 2. set *buff to the bufer read in 1.
|
|
// *buff = streamData->srcBuffer;
|
|
// // 3. return read bytes count
|
|
// return bc;
|
|
// }
|
|
|
|
// /*
|
|
// It must return the number of bytes actually skipped, or a negative failure code if skipping cannot be done.
|
|
// It can skip fewer bytes than requested but must never skip more.
|
|
// Only positive/forward skips will ever be requested.
|
|
// If skipping is not provided or fails, libarchive will call the read() function and simply ignore any data that it does not need.
|
|
|
|
// * Skips at most request bytes from archive and returns the skipped amount.
|
|
// * This may skip fewer bytes than requested; it may even skip zero bytes.
|
|
// * If you do skip fewer bytes than requested, libarchive will invoke your
|
|
// * read callback and discard data as necessary to make up the full skip.
|
|
// */
|
|
// // https://github.com/libarchive/libarchive/wiki/LibarchiveIO
|
|
// int64_t cb_skip(struct archive *a, void *userData, int64_t request)
|
|
// {
|
|
// Debug_printv("bytes[%d]", request);
|
|
// ArchiveStreamData *streamData = (ArchiveStreamData *)userData;
|
|
|
|
// if (streamData->srcStream->isOpen())
|
|
// {
|
|
// bool rc = streamData->srcStream->seek(request, SEEK_CUR);
|
|
// return (rc) ? request : ARCHIVE_WARN;
|
|
// }
|
|
// else
|
|
// {
|
|
// Debug_printv("ERROR! skip failed");
|
|
// return ARCHIVE_FATAL;
|
|
// }
|
|
// }
|
|
|
|
// int64_t cb_seek(struct archive *a, void *userData, int64_t offset, int whence)
|
|
// {
|
|
// Debug_printv("offset[%d] whence[%d] (0=begin, 1=curr, 2=end)", offset, whence);
|
|
// ArchiveStreamData *streamData = (ArchiveStreamData *)userData;
|
|
|
|
// if (streamData->srcStream->isOpen())
|
|
// {
|
|
// bool rc = streamData->srcStream->seek(offset, whence);
|
|
// return (rc) ? offset : ARCHIVE_WARN;
|
|
// }
|
|
// else
|
|
// {
|
|
// Debug_printv("ERROR! seek failed");
|
|
// return ARCHIVE_FATAL;
|
|
// }
|
|
// }
|
|
|
|
// int cb_close(struct archive *a, void *userData)
|
|
// {
|
|
// ArchiveStreamData *src_str = (ArchiveStreamData *)userData;
|
|
|
|
// Debug_printv("Libarch wants to close, but we do nothing here...");
|
|
|
|
// // do we want to close srcStream here???
|
|
// return (ARCHIVE_OK);
|
|
// }
|
|
|
|
// int cb_open(struct a *arch, void *userData)
|
|
// {
|
|
// // maybe we can use open for something? Check if stream is open?
|
|
// return (ARCHIVE_OK);
|
|
// }
|
|
|
|
|
|
// /********************************************************
|
|
// * Streams implementations
|
|
// ********************************************************/
|
|
|
|
// ArchiveStream::ArchiveStream(std::shared_ptr<MStream> srcStr)
|
|
// {
|
|
// // it should be possible to to pass a password parameter here and somehow
|
|
// // call archive_passphrase_callback(password) from here, right?
|
|
// streamData.srcStream = srcStr;
|
|
// a = archive_read_new();
|
|
// archive_read_support_filter_all(a);
|
|
// archive_read_support_format_all(a);
|
|
// streamData.srcBuffer = new uint8_t[buffSize];
|
|
// open();
|
|
// }
|
|
|
|
// ArchiveStream::~ArchiveStream()
|
|
// {
|
|
// close();
|
|
// if (streamData.srcBuffer != nullptr)
|
|
// delete[] streamData.srcBuffer;
|
|
// Debug_printv("Stream destructor OK!");
|
|
// }
|
|
|
|
// bool ArchiveStream::open()
|
|
// {
|
|
// if (!is_open)
|
|
// {
|
|
// // TODO enable seek only if the stream is random access
|
|
// archive_read_set_read_callback(a, cb_read);
|
|
// archive_read_set_skip_callback(a, cb_skip);
|
|
// archive_read_set_seek_callback(a, cb_seek);
|
|
// archive_read_set_close_callback(a, cb_close);
|
|
// // archive_read_set_open_callback(mpa->arch, cb_open); - what does it do?
|
|
// archive_read_set_callback_data(a, &streamData);
|
|
// Debug_printv("== BEGIN Calling open1 on archive instance ==========================");
|
|
// int r = archive_read_open1(a);
|
|
// Debug_printv("== END opening archive result=%d! (OK should be 0!) =======================================", r);
|
|
|
|
// //int r = archive_read_open2(a, &streamData, NULL, myRead, myskip, myclose);
|
|
// if (r == ARCHIVE_OK)
|
|
// is_open = true;
|
|
// }
|
|
// return is_open;
|
|
// };
|
|
|
|
// void ArchiveStream::close()
|
|
// {
|
|
// if (is_open)
|
|
// {
|
|
// archive_read_close(a);
|
|
// archive_read_free(a);
|
|
// is_open = false;
|
|
// }
|
|
// Debug_printv("Close called");
|
|
// }
|
|
|
|
// bool ArchiveStream::isOpen()
|
|
// {
|
|
// return is_open;
|
|
// };
|
|
|
|
// std::vector<uint8_t> leftovers;
|
|
|
|
// uint32_t ArchiveStream::read(uint8_t *buf, uint32_t size)
|
|
// {
|
|
// Debug_printv("calling read size[%d]", size);
|
|
// const void *incomingBuffer;
|
|
// size_t incomingSize;
|
|
// int64_t offset;
|
|
|
|
// int r = archive_read_data_block(a, &incomingBuffer, &incomingSize, &offset);
|
|
// Debug_printv("r[%d]", r);
|
|
// if ( r == ARCHIVE_EOF )
|
|
// return 0;
|
|
|
|
// if ( r < ARCHIVE_OK )
|
|
// return 0;
|
|
|
|
// // 'buff' contains the data of the current block
|
|
// // 'size' is the size of the current block
|
|
|
|
// std::vector<uint8_t> incomingVector((uint8_t*)incomingBuffer, (uint8_t*)incomingBuffer + incomingSize);
|
|
// // concatenate intermediate buffer with incomingVector
|
|
// leftovers.insert(leftovers.end(), incomingVector.begin(), incomingVector.end());
|
|
|
|
// if(leftovers.size() <= size) {
|
|
// // ok, we can fit everything that was left and new data to our buffer
|
|
// auto size = leftovers.size();
|
|
// _position += size;
|
|
// leftovers.clear();
|
|
// }
|
|
// else {
|
|
// // ok, so we can only write up to size and we have to keep leftovers for next time
|
|
// std::copy(leftovers.begin(), leftovers.begin() + size, buf);
|
|
// std::vector<uint8_t> leftovers2(leftovers.begin() + size, leftovers.end());
|
|
// leftovers = leftovers2;
|
|
// _position += size;
|
|
// }
|
|
// _position += size;
|
|
|
|
// Debug_printv("size[%d] position[%d]", size, _position);
|
|
|
|
// return size;
|
|
// }
|
|
|
|
// uint32_t ArchiveStream::write(const uint8_t *buf, uint32_t size)
|
|
// {
|
|
// return -1;
|
|
// }
|
|
|
|
// // For files with a browsable random access directory structure
|
|
// // d64, d74, d81, dnp, etc.
|
|
// bool ArchiveStream::seekPath(std::string path)
|
|
// {
|
|
// Debug_printv("seekPath called for path: %s", path.c_str());
|
|
|
|
// if ( seekEntry( path ) )
|
|
// {
|
|
// Debug_printv("entry[%s]", archive_entry_pathname(entry));
|
|
// return true;
|
|
// }
|
|
|
|
// return false;
|
|
// }
|
|
|
|
|
|
// bool ArchiveStream::seekEntry( std::string filename )
|
|
// {
|
|
// Debug_printv( "filename[%s] size[%d]", filename.c_str(), filename.size());
|
|
|
|
// // Read Directory Entries
|
|
// if ( filename.size() > 0 )
|
|
// {
|
|
// bool found = false;
|
|
// bool wildcard = ( mstr::contains(filename, "*") || mstr::contains(filename, "?") );
|
|
// while ( archive_read_next_header(a, &entry) == ARCHIVE_OK )
|
|
// {
|
|
// std::string entryPath = ""; //archive_entry_sourcepath(entry);
|
|
// std::string entryFilename = archive_entry_pathname(entry);
|
|
|
|
// Debug_printv("path[%s] filename[%s] entry.filename[%.16s]", entryPath.c_str(), filename.c_str(), entryFilename.c_str());
|
|
|
|
// // Check filetype
|
|
// if ( archive_entry_filetype(entry) != AE_IFDIR )
|
|
// {
|
|
// // Read Entry From Stream
|
|
// if (filename == "*") // Match first entry
|
|
// {
|
|
// filename = entryFilename;
|
|
// found = true;
|
|
// }
|
|
// else if ( filename == entryFilename ) // Match exact
|
|
// {
|
|
// found = true;
|
|
// }
|
|
// else if ( wildcard )
|
|
// {
|
|
// if ( mstr::compare(filename, entryFilename) ) // X?XX?X* Wildcard match
|
|
// {
|
|
// // Set filename to this filename
|
|
// Debug_printv( "Found! file[%s] -> entry[%s]", filename.c_str(), entryFilename.c_str() );
|
|
// found = true;
|
|
// }
|
|
// }
|
|
|
|
// if ( found )
|
|
// {
|
|
// _size = archive_entry_size(entry);
|
|
|
|
// return true;
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// Debug_printv( "Not Found! file[%s]", filename.c_str() );
|
|
// }
|
|
|
|
// return false;
|
|
// }
|
|
|
|
// // // For files with no directory structure
|
|
// // // tap, crt, tar
|
|
// // std::string ArchiveStream::seekNextEntry()
|
|
// // {
|
|
// // struct archive_entry *entry;
|
|
// // if (archive_read_next_header(a, &entry) == ARCHIVE_OK)
|
|
// // return archive_entry_pathname(entry);
|
|
// // else
|
|
// // return "";
|
|
// // };
|
|
|
|
|
|
// bool ArchiveStream::seek(uint32_t pos)
|
|
// {
|
|
// return streamData.srcStream->seek(pos);
|
|
// }
|
|
|
|
// /********************************************************
|
|
// * Files implementations
|
|
// ********************************************************/
|
|
|
|
// MStream *ArchiveContainerFile::getDecodedStream(std::shared_ptr<MStream> containerIstream)
|
|
// {
|
|
// // TODO - we can get password from this URL and pass it as a parameter to this constructor
|
|
// Debug_printv("calling getDecodedStream for ArchiveContainerFile, we should return open stream");
|
|
// auto stream = new ArchiveStream(containerIstream);
|
|
// return stream;
|
|
// }
|
|
|
|
// // archive file is always a directory
|
|
// bool ArchiveContainerFile::isDirectory()
|
|
// {
|
|
// //Debug_printv("pathInStream[%s]", pathInStream.c_str());
|
|
// if ( pathInStream == "" )
|
|
// return true;
|
|
// else
|
|
// return false;
|
|
// };
|
|
|
|
// bool ArchiveContainerFile::rewindDirectory()
|
|
// {
|
|
// dirIsOpen = true;
|
|
|
|
// return prepareDirListing();
|
|
// }
|
|
|
|
// MFile *ArchiveContainerFile::getNextFileInDir()
|
|
// {
|
|
// if(!dirIsOpen)
|
|
// rewindDirectory();
|
|
|
|
// struct archive_entry *entry;
|
|
|
|
// Debug_printv("getNextFileInDir calling archive_read_next_header");
|
|
// if (archive_read_next_header(getArchive(), &entry) == ARCHIVE_OK)
|
|
// {
|
|
// std::string fileName = archive_entry_pathname(entry);
|
|
// auto file = MFSOwner::File(streamFile->url + "/" + fileName);
|
|
// file->_size = archive_entry_size(entry);
|
|
// file->_exists = true;
|
|
// return file;
|
|
// }
|
|
// else
|
|
// {
|
|
// //Debug_printv( "END OF DIRECTORY");
|
|
// dirStream->close();
|
|
// dirIsOpen = false;
|
|
// return nullptr;
|
|
// }
|
|
// }
|
|
|
|
// bool ArchiveContainerFile::prepareDirListing()
|
|
// {
|
|
// if (dirStream.get() != nullptr)
|
|
// {
|
|
// dirStream->close();
|
|
// }
|
|
|
|
// Debug_printv("w prepare dir listing");
|
|
|
|
// dirStream = std::shared_ptr<MStream>(this->getSourceStream());
|
|
|
|
// if(dirStream->isOpen())
|
|
// {
|
|
// return true;
|
|
// }
|
|
// else
|
|
// {
|
|
// Debug_printv("opening Archive for dir nok");
|
|
// return false;
|
|
// }
|
|
// }
|