// #include "archive_ml.h" // #include // #include // #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 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 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 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 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 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(this->getSourceStream()); // if(dirStream->isOpen()) // { // return true; // } // else // { // Debug_printv("opening Archive for dir nok"); // return false; // } // }